Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3D Tiles in 2D/CV #4884

Merged
merged 15 commits into from
Jan 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions Apps/Sandcastle/gallery/3D Tiles Batch Table Hierarchy.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,22 @@
// * doorknob_size
// * doorknob_name

var viewer = new Cesium.Viewer('cesiumContainer', {
scene3DOnly : true
});
var viewer = new Cesium.Viewer('cesiumContainer');

var scene = viewer.scene;
var tilesetUrl = '../../../Specs/Data/Cesium3DTiles/Hierarchy/BatchTableHierarchy';
var tileset = scene.primitives.add(new Cesium.Cesium3DTileset({
url : tilesetUrl
}));

tileset.readyPromise.then(function(tileset) {
function zoomToTileset() {
var boundingSphere = tileset.boundingSphere;
viewer.camera.viewBoundingSphere(boundingSphere, new Cesium.HeadingPitchRange(0, -2.0, 0));
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
});
}

tileset.readyPromise.then(zoomToTileset);
scene.morphComplete.addEventListener(zoomToTileset);

var styles = [];
function addStyle(name, style) {
Expand Down Expand Up @@ -226,6 +227,10 @@

// Highlight feature on mouse over
handler.setInputAction(function(movement) {
if (scene.mode === Cesium.SceneMode.MORPHING) {
return;
}

if (!pickingEnabled) {
return;
}
Expand Down
12 changes: 7 additions & 5 deletions Apps/Sandcastle/gallery/3D Tiles Point Cloud Styling.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@
'use strict';
//Sandcastle_Begin

var viewer = new Cesium.Viewer('cesiumContainer', {
scene3DOnly : true
});
var viewer = new Cesium.Viewer('cesiumContainer');

var scene = viewer.scene;
var url = '../../../Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithPerPointProperties/';
Expand All @@ -40,10 +38,14 @@
url : url
}));

tileset.readyPromise.then(function(tileset) {
function zoomToTileset() {
var boundingSphere = tileset.boundingSphere;
viewer.camera.viewBoundingSphere(boundingSphere, new Cesium.HeadingPitchRange(0, -2.0, 0));
});
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}

tileset.readyPromise.then(zoomToTileset);
scene.morphComplete.addEventListener(zoomToTileset);

var styles = [];
function addStyle(name, style) {
Expand Down
5 changes: 4 additions & 1 deletion Apps/Sandcastle/gallery/3D Tiles.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
//Sandcastle_Begin

var viewer = new Cesium.Viewer('cesiumContainer', {
scene3DOnly : true,
shadows : true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this from the other 3D Tiles Sandcastle examples.

});

Expand Down Expand Up @@ -188,6 +187,10 @@

// Highlight feature on mouse over
handler.setInputAction(function(movement) {
if (scene.mode === Cesium.SceneMode.MORPHING) {
return;
}

if (!pickingEnabled) {
return;
}
Expand Down
42 changes: 42 additions & 0 deletions Source/Core/Transforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -1001,5 +1001,47 @@ define([
return result;
};

var swizzleMatrix = new Matrix4(
0.0, 0.0, 1.0, 0.0,
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 0.0, 1.0);

/**
* @private
*/
Transforms.wgs84To2DModelMatrix = function(projection, center, result) {
//>>includeStart('debug', pragmas.debug);
if (!defined(projection)) {
throw new DeveloperError('projection is required.');
}
if (!defined(center)) {
throw new DeveloperError('center is required.');
}
if (!defined(result)) {
throw new DeveloperError('result is required.');
}
//>>includeEnd('debug');

var ellipsoid = projection.ellipsoid;

var fromENU = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, scratchFromENU);
var toENU = Matrix4.inverseTransformation(fromENU, scratchToENU);

var cartographic = ellipsoid.cartesianToCartographic(center, scratchCartographic);
var projectedPosition = projection.project(cartographic, scratchCartesian3Projection);
var newOrigin = scratchCartesian4NewOrigin;
newOrigin.x = projectedPosition.z;
newOrigin.y = projectedPosition.x;
newOrigin.z = projectedPosition.y;
newOrigin.w = 1.0;

var translation = Matrix4.fromTranslation(newOrigin, scratchFromENU);
Matrix4.multiply(swizzleMatrix, toENU, result);
Matrix4.multiply(translation, result, result);

return result;
};

return Transforms;
});
50 changes: 38 additions & 12 deletions Source/Scene/Cesium3DTile.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*global define*/
define([
'../Core/BoundingSphere',
'../Core/BoxOutlineGeometry',
'../Core/Cartesian3',
'../Core/Color',
Expand Down Expand Up @@ -27,11 +28,12 @@ define([
'./Empty3DTileContent',
'./PerInstanceColorAppearance',
'./Primitive',
'./SceneMode',
'./TileBoundingRegion',
'./TileBoundingSphere',
'./TileOrientedBoundingBox',
'./Tileset3DTileContent'
'./TileOrientedBoundingBox'
], function(
BoundingSphere,
BoxOutlineGeometry,
Cartesian3,
Color,
Expand Down Expand Up @@ -59,10 +61,10 @@ define([
Empty3DTileContent,
PerInstanceColorAppearance,
Primitive,
SceneMode,
TileBoundingRegion,
TileBoundingSphere,
TileOrientedBoundingBox,
Tileset3DTileContent) {
TileOrientedBoundingBox) {
'use strict';

/**
Expand Down Expand Up @@ -98,6 +100,7 @@ define([
this._transformDirty = true;

this._boundingVolume = this.createBoundingVolume(header.boundingVolume, computedTransform);
this._boundingVolume2D = undefined;

var contentBoundingVolume;

Expand All @@ -110,6 +113,7 @@ define([
contentBoundingVolume = this.createBoundingVolume(contentHeader.boundingVolume, computedTransform);
}
this._contentBoundingVolume = contentBoundingVolume;
this._contentBoundingVolume2D = undefined;

var viewerRequestVolume;
if (defined(header.viewerRequestVolume)) {
Expand Down Expand Up @@ -502,37 +506,58 @@ define([
this._debugViewerRequestVolume = this._debugViewerRequestVolume && this._debugViewerRequestVolume.destroy();
};

var scratchProjectedBoundingSphere = new BoundingSphere();

function getBoundingVolume(tile, frameState) {
if (frameState.mode !== SceneMode.SCENE3D && !defined(tile._boundingVolume2D)) {
var boundingSphere = tile._boundingVolume.boundingSphere;
var sphere = BoundingSphere.projectTo2D(boundingSphere, frameState.mapProjection, scratchProjectedBoundingSphere);
tile._boundingVolume2D = new TileBoundingSphere(sphere.center, sphere.radius);
}

return frameState.mode !== SceneMode.SCENE3D ? tile._boundingVolume2D : tile._boundingVolume;
}

/**
* Determines whether the tile's bounding volume intersects the culling volume.
*
* @param {CullingVolume} cullingVolume The culling volume whose intersection with the tile is to be tested.
* @param {FrameState} frameState The frame state.
* @param {Number} parentVisibilityPlaneMask The parent's plane mask to speed up the visibility check.
* @returns {Number} A plane mask as described above in {@link CullingVolume#computeVisibilityWithPlaneMask}.
*
* @private
*/
Cesium3DTile.prototype.visibility = function(cullingVolume, parentVisibilityPlaneMask) {
return cullingVolume.computeVisibilityWithPlaneMask(this._boundingVolume, parentVisibilityPlaneMask);
Cesium3DTile.prototype.visibility = function(frameState, parentVisibilityPlaneMask) {
var cullingVolume = frameState.cullingVolume;
var boundingVolume = getBoundingVolume(this, frameState);
return cullingVolume.computeVisibilityWithPlaneMask(boundingVolume, parentVisibilityPlaneMask);
};

/**
* Assuming the tile's bounding volume intersects the culling volume, determines
* whether the tile's content's bounding volume intersects the culling volume.
*
* @param {CullingVolume} cullingVolume The culling volume whose intersection with the tile's content is to be tested.
* @param {FrameState} frameState The frame state.
* @returns {Intersect} The result of the intersection: the tile's content is completely outside, completely inside, or intersecting the culling volume.
*
* @private
*/
Cesium3DTile.prototype.contentsVisibility = function(cullingVolume) {
Cesium3DTile.prototype.contentsVisibility = function(frameState) {
// Assumes the tile's bounding volume intersects the culling volume already, so
// just return Intersect.INSIDE if there is no content bounding volume.
var boundingVolume = this._contentBoundingVolume;
if (!defined(boundingVolume)) {
if (!defined(this._contentBoundingVolume)) {
return Intersect.INSIDE;
}

if (frameState.mode !== SceneMode.SCENE3D && !defined(this._contentBoundingVolume2D)) {
var boundingSphere = this._contentBoundingVolume.boundingSphere;
this._contentBoundingVolume2D = BoundingSphere.projectTo2D(boundingSphere);
}

// PERFORMANCE_IDEA: is it possible to burn less CPU on this test since we know the
// tile's (not the content's) bounding volume intersects the culling volume?
var cullingVolume = frameState.cullingVolume;
var boundingVolume = frameState.mode !== SceneMode.SCENE3D ? this._contentBoundingVolume2D : this._contentBoundingVolume;
return cullingVolume.computeVisibility(boundingVolume);
};

Expand All @@ -545,7 +570,8 @@ define([
* @private
*/
Cesium3DTile.prototype.distanceToTile = function(frameState) {
return this._boundingVolume.distanceToCamera(frameState);
var boundingVolume = getBoundingVolume(this, frameState);
return boundingVolume.distanceToCamera(frameState);
};

/**
Expand Down
48 changes: 28 additions & 20 deletions Source/Scene/Cesium3DTileset.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ define([

/**
* Determines whether the tileset casts or receives shadows from each light source.
*
*
* @type {ShadowMode}
* @default ShadowMode.ENABLED
*/
Expand Down Expand Up @@ -776,7 +776,7 @@ define([
throw new DeveloperError('The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true.');
}
//>>includeEnd('debug');

return this._root._boundingVolume;
}
},
Expand Down Expand Up @@ -1053,25 +1053,35 @@ define([
}

function getScreenSpaceError(tileset, geometricError, tile, frameState) {
// TODO: screenSpaceError2D like QuadtreePrimitive.js
if (geometricError === 0.0) {
// Leaf nodes do not have any error so save the computation
return 0.0;
}

// Avoid divide by zero when viewer is inside the tile
var camera = frameState.camera;
var distance = Math.max(tile.distanceToCamera, CesiumMath.EPSILON7);
var height = frameState.context.drawingBufferHeight;
var sseDenominator = camera.frustum.sseDenominator;
var context = frameState.context;
var height = context.drawingBufferHeight;

var error = (geometricError * height) / (distance * sseDenominator);
var error;
if (frameState.mode === SceneMode.SCENE2D) {
var frustum = camera.frustum;
var width = context.drawingBufferWidth;

if (tileset.dynamicScreenSpaceError) {
var density = tileset._dynamicScreenSpaceErrorComputedDensity;
var factor = tileset.dynamicScreenSpaceErrorFactor;
var dynamicError = CesiumMath.fog(distance, density) * factor;
error -= dynamicError;
var pixelSize = Math.max(frustum.top - frustum.bottom, frustum.right - frustum.left) / Math.max(width, height);
error = geometricError / pixelSize;
} else {
// Avoid divide by zero when viewer is inside the tile
var distance = Math.max(tile.distanceToCamera, CesiumMath.EPSILON7);
var sseDenominator = camera.frustum.sseDenominator;
error = (geometricError * height) / (distance * sseDenominator);

if (tileset.dynamicScreenSpaceError) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we still account for this in CV? What about 2D?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it would make sense in 2D. Maybe CV, but we don't have fog in CV either.

var density = tileset._dynamicScreenSpaceErrorComputedDensity;
var factor = tileset.dynamicScreenSpaceErrorFactor;
var dynamicError = CesiumMath.fog(distance, density) * factor;
error -= dynamicError;
}
}

return error;
Expand Down Expand Up @@ -1132,7 +1142,7 @@ define([
function selectTile(tileset, tile, fullyVisible, frameState) {
// There may also be a tight box around just the tile's contents, e.g., for a city, we may be
// zoomed into a neighborhood and can cull the skyscrapers in the root node.
if (tile.contentReady && (fullyVisible || (tile.contentsVisibility(frameState.cullingVolume) !== Intersect.OUTSIDE))) {
if (tile.contentReady && (fullyVisible || (tile.contentsVisibility(frameState) !== Intersect.OUTSIDE))) {
tileset._selectedTiles.push(tile);
tile.selected = true;

Expand Down Expand Up @@ -1169,7 +1179,6 @@ define([
}

var maximumScreenSpaceError = tileset._maximumScreenSpaceError;
var cullingVolume = frameState.cullingVolume;

tileset._selectedTiles.length = 0;
tileset._selectedTilesToStyle.length = 0;
Expand All @@ -1196,7 +1205,7 @@ define([
return;
}

root.visibilityPlaneMask = root.visibility(cullingVolume, CullingVolume.MASK_INDETERMINATE);
root.visibilityPlaneMask = root.visibility(frameState, CullingVolume.MASK_INDETERMINATE);
if (root.visibilityPlaneMask === CullingVolume.MASK_OUTSIDE) {
return;
}
Expand Down Expand Up @@ -1276,7 +1285,7 @@ define([
if (child.insideViewerRequestVolume(frameState)) {
// Use parent's geometric error with child's box to see if we already meet the SSE
if (getScreenSpaceError(tileset, t.geometricError, child, frameState) > maximumScreenSpaceError) {
child.visibilityPlaneMask = child.visibility(cullingVolume, visibilityPlaneMask);
child.visibilityPlaneMask = child.visibility(frameState, visibilityPlaneMask);
if (isVisible(child.visibilityPlaneMask)) {
if (child.contentUnloaded) {
requestContent(tileset, child, outOfCore);
Expand Down Expand Up @@ -1344,7 +1353,7 @@ define([
for (k = 0; k < childrenLength; ++k) {
child = children[k];
if (child.insideViewerRequestVolume(frameState)) {
child.visibilityPlaneMask = child.visibility(frameState.cullingVolume, visibilityPlaneMask);
child.visibilityPlaneMask = child.visibility(frameState, visibilityPlaneMask);
} else {
child.visibilityPlaneMask = CullingVolume.MASK_OUTSIDE;
}
Expand Down Expand Up @@ -1382,7 +1391,7 @@ define([
child = children[k];
child.updateTransform(t.computedTransform);
if (child.insideViewerRequestVolume(frameState)) {
child.visibilityPlaneMask = child.visibility(frameState.cullingVolume, visibilityPlaneMask);
child.visibilityPlaneMask = child.visibility(frameState, visibilityPlaneMask);
} else {
child.visibilityPlaneMask = CullingVolume.MASK_OUTSIDE;
}
Expand Down Expand Up @@ -1736,8 +1745,7 @@ define([
* @exception {DeveloperError} The tileset must be 3D Tiles version 0.0. See https://github.com/AnalyticalGraphicsInc/3d-tiles#spec-status
*/
Cesium3DTileset.prototype.update = function(frameState) {
// TODO: Support 2D and CV
if (!this.show || !this.ready || (frameState.mode !== SceneMode.SCENE3D)) {
if (!this.show || !this.ready) {
return;
}

Expand Down
Loading