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

Fix clipping planes for tiles with RTC and/or no transforms #7034

Merged
merged 29 commits into from
Sep 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ad7abcd
Always use root tileset's transform
Sep 11, 2018
9f55539
Apply RTC & bounding sphere fallback for clipping planes
Sep 11, 2018
9ed3695
Fixed crash if root tile wasn't loaded
Sep 14, 2018
bdb8799
Apply eastNorthUp to RTC center
Sep 14, 2018
6cb0426
Fixed RTC for b3dm
Sep 17, 2018
aa71e96
Traversal uses correct tileset transforms for clipping
Sep 18, 2018
0ec49a5
Sinplified BoundingSphere fallback check
Sep 18, 2018
0a07e56
No need to keep track of RTC anymore
Sep 18, 2018
5aee22a
Simplify clipping sandcastle example
Sep 18, 2018
1f1cd16
Use correct matrix for point clouds
Sep 18, 2018
8996da6
Fixed old tests
Sep 18, 2018
7d5bb57
Fix point cloud tests
Sep 18, 2018
b605a61
Added bounding sphere tests
Sep 18, 2018
0d2dd5f
Added clipping plane doc example
Sep 18, 2018
814c5ae
Fix 'Many Clipping Planes' example
Sep 19, 2018
dd3a7c6
Put back point cloud clipping plane matrix
Sep 19, 2018
9db4500
Style and wording edits
Sep 19, 2018
2dac9f4
Moved clippingPlaneOffsetMatrix to Tileset
Sep 19, 2018
2fadcf9
Updated tests
Sep 19, 2018
b251c6b
Fixed old clipping planes test
Sep 19, 2018
e879cca
Fix lint
Sep 19, 2018
5245643
Remove underscore from _clippingPlaneOffsetMatrix
Sep 20, 2018
65a8496
Moved clippingPlaneOffset update to tileset
Sep 20, 2018
3cc7aa0
No need to use setter for clippingPlaneOffsetMatrix
Sep 20, 2018
888e2b2
Added breaking change to CHANGES.md
Sep 20, 2018
f56c71c
Fix sign in doc
Sep 20, 2018
911a520
Reworded unionClippingRegions
Sep 20, 2018
a43ab57
Fix edge color for union clipping planes
Sep 21, 2018
79a49e0
Added terrain union example
Sep 21, 2018
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
21 changes: 8 additions & 13 deletions Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,18 @@
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

var scratchPlane = new Cesium.ClippingPlane(Cesium.Cartesian3.UNIT_X, 0.0);
function createPlaneUpdateFunction(plane, transform) {
function createPlaneUpdateFunction(plane) {
return function () {
plane.distance = targetY;
return Cesium.Plane.transform(plane, transform, scratchPlane);
return plane;
};
}

var tileset;
function loadTileset(url) {
clippingPlanes = new Cesium.ClippingPlaneCollection({
planes : [
new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), -100.0)
new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), 0.0)
],
edgeWidth : viewModel.edgeStylingEnabled ? 1.0 : 0.0
});
Expand All @@ -140,7 +139,7 @@
plane : {
dimensions : new Cesium.Cartesian2(radius * 2.5, radius * 2.5),
material : Cesium.Color.WHITE.withAlpha(0.1),
plane : new Cesium.CallbackProperty(createPlaneUpdateFunction(plane, tileset.modelMatrix), false),
plane : new Cesium.CallbackProperty(createPlaneUpdateFunction(plane), false),
outline : true,
outlineColor : Cesium.Color.WHITE
}
Expand All @@ -157,7 +156,7 @@
function loadModel(url) {
clippingPlanes = new Cesium.ClippingPlaneCollection({
planes : [
new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), -100.0)
new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), 0.0)
],
edgeWidth : viewModel.edgeStylingEnabled ? 1.0 : 0.0
});
Expand Down Expand Up @@ -189,7 +188,7 @@
plane : {
dimensions : new Cesium.Cartesian2(300.0, 300.0),
material : Cesium.Color.WHITE.withAlpha(0.1),
plane : new Cesium.CallbackProperty(createPlaneUpdateFunction(plane, Cesium.Matrix4.IDENTITY), false),
plane : new Cesium.CallbackProperty(createPlaneUpdateFunction(plane), false),
outline : true,
outlineColor : Cesium.Color.WHITE
}
Expand Down Expand Up @@ -218,13 +217,9 @@
if (newValue === clipObjects[0]) {
loadTileset(bimUrl);
} else if (newValue === clipObjects[1]) {
loadTileset(pointCloudUrl).then(function(tileset) {
tileset.clippingPlanes.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(tileset.boundingSphere.center);
});
loadTileset(pointCloudUrl);
Copy link
Contributor

Choose a reason for hiding this comment

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

The point cloud example might be a good use case showing when to use the clipping plane's model matrix since the clipping plane is visually off-center from the church due to the offset bounding sphere.

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 tried doing this but one issue is that, you only really need to offset the entity, so it wouldn't really need to use the clipping planes' model matrix.

The other issue is that it requires converting back and forth from Cartographic to Cartesian and it kind of makes creating a clipping plane look complicated.

Copy link
Contributor

Choose a reason for hiding this comment

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

Makes sense too. And I remember now that the terrain example uses a model matrix, so one example is enough to illustrate the point.

} else if (newValue === clipObjects[2]) {
loadTileset(instancedUrl).then(function(tileset) {
tileset.clippingPlanes.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(tileset.boundingSphere.center);
});
loadTileset(instancedUrl);
} else {
loadModel(modelUrl);
}
Expand Down
25 changes: 24 additions & 1 deletion Apps/Sandcastle/gallery/Terrain Clipping Planes.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
});
var globe = viewer.scene.globe;

var exampleTypes = ['Cesium Man', 'St. Helens'];
var exampleTypes = ['Cesium Man', 'St. Helens', 'Grand Canyon Isolated'];
var viewModel = {
exampleTypes : exampleTypes,
currentExampleType : exampleTypes[0],
Expand Down Expand Up @@ -191,6 +191,27 @@
});
}

function loadGrandCanyon(){
// Pick a position at the Grand Canyon
var position = Cesium.Cartographic.toCartesian(new Cesium.Cartographic.fromDegrees(-113.2665534, 36.0939345, 100));
var distance = 3000.0;
var boundingSphere = new Cesium.BoundingSphere(position, distance);

globe.clippingPlanes = new Cesium.ClippingPlaneCollection({
modelMatrix : Cesium.Transforms.eastNorthUpToFixedFrame(position),
planes : [
new Cesium.ClippingPlane(new Cesium.Cartesian3( 1.0, 0.0, 0.0), distance),
new Cesium.ClippingPlane(new Cesium.Cartesian3(-1.0, 0.0, 0.0), distance),
new Cesium.ClippingPlane(new Cesium.Cartesian3( 0.0, 1.0, 0.0), distance),
new Cesium.ClippingPlane(new Cesium.Cartesian3( 0.0, -1.0, 0.0), distance)
],
unionClippingRegions : true
});

viewer.camera.viewBoundingSphere(boundingSphere, new Cesium.HeadingPitchRange(0.5, -0.5, boundingSphere.radius * 5.0));
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}

Cesium.knockout.getObservable(viewModel, 'clippingPlanesEnabled').subscribe(function(value) {
globe.clippingPlanes.enabled = value;
clippingPlanesEnabled = value;
Expand All @@ -207,6 +228,8 @@
loadCesiumMan();
} else if (newValue === exampleTypes[1]) {
loadStHelens();
} else if (newValue === exampleTypes[2]) {
loadGrandCanyon();
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,7 @@
});
} else if (newValue === clipObjects[3]) {
// i3dm
loadTileset(instancedUrl, 100.0).then(function() {
tileset.clippingPlanes.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(tileset.boundingSphere.center);
});
loadTileset(instancedUrl, 100.0);
} else if (newValue === clipObjects[4]) {
// Terrain
var position = Cesium.Cartesian3.fromRadians(-2.0872979473351286, 0.6596620013036164, 2380.0);
Expand Down
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ Change Log

### 1.50 - 2018-10-01

##### Breaking Changes :mega:
* Clipping planes on tilesets now use the root tile's transform, or the root tile's bounding sphere if a transform is not defined. [#7034](https://github.com/AnalyticalGraphicsInc/cesium/pull/7034)
* This is to make clipping planes' coordinates always relative to the object they're attached to. So if you were positioning the clipping planes as in the example below, this is no longer necessary:
```javascript
clippingPlanes.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(tileset.boundingSphere.center);
```
* This also fixes several issues with clipping planes not using the correct transform for tilesets with children.

##### Additions :tada:
* Added `cartographicLimitRectangle` to `Globe`. Use this to limit terrain and imagery to a specific `Rectangle` area. [#6987](https://github.com/AnalyticalGraphicsInc/cesium/pull/6987)

Expand Down
9 changes: 5 additions & 4 deletions Source/Scene/Batched3DModel3DTileContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ define([
'../Core/destroyObject',
'../Core/DeveloperError',
'../Core/FeatureDetection',
'../Core/getBaseUri',
'../Core/getStringFromTypedArray',
'../Core/Matrix4',
'../Core/RequestType',
'../Core/RuntimeError',
'../Core/Transforms',
'../Renderer/Pass',
'./Axis',
'./Cesium3DTileBatchTable',
Expand All @@ -33,11 +33,11 @@ define([
destroyObject,
DeveloperError,
FeatureDetection,
getBaseUri,
getStringFromTypedArray,
Matrix4,
RequestType,
RuntimeError,
Transforms,
Pass,
Axis,
Cesium3DTileBatchTable,
Expand Down Expand Up @@ -355,10 +355,10 @@ define([
primitive : tileset
};

content._rtcCenterTransform = Matrix4.clone(Matrix4.IDENTITY);
content._rtcCenterTransform = Matrix4.IDENTITY;
var rtcCenter = featureTable.getGlobalProperty('RTC_CENTER', ComponentDatatype.FLOAT, 3);
if (defined(rtcCenter)) {
content._rtcCenterTransform = Matrix4.fromTranslation(Cartesian3.fromArray(rtcCenter), content._rtcCenterTransform);
content._rtcCenterTransform = Matrix4.fromTranslation(Cartesian3.fromArray(rtcCenter));
}

content._contentModelMatrix = Matrix4.multiply(tile.computedTransform, content._rtcCenterTransform, new Matrix4());
Expand Down Expand Up @@ -465,6 +465,7 @@ define([
// Update clipping planes
var tilesetClippingPlanes = this._tileset.clippingPlanes;
if (this._tile.clippingPlanesDirty && defined(tilesetClippingPlanes)) {
this._model.clippingPlaneOffsetMatrix = this._tileset.clippingPlaneOffsetMatrix;
// Dereference the clipping planes from the model if they are irrelevant.
// Link/Dereference directly to avoid ownership checks.
// This will also trigger synchronous shader regeneration to remove or add the clipping plane and color blending code.
Expand Down
11 changes: 4 additions & 7 deletions Source/Scene/Cesium3DTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ define([
'../Core/RequestType',
'../Core/Resource',
'../Core/RuntimeError',
'../Core/Transforms',
'../ThirdParty/when',
'./Cesium3DTileContentFactory',
'./Cesium3DTileContentState',
Expand Down Expand Up @@ -60,6 +61,7 @@ define([
RequestType,
Resource,
RuntimeError,
Transforms,
when,
Cesium3DTileContentFactory,
Cesium3DTileContentState,
Expand Down Expand Up @@ -199,7 +201,6 @@ define([
Cesium3DTile._deprecationWarning('contentUrl', 'This tileset JSON uses the "content.url" property which has been deprecated. Use "content.uri" instead.');
contentHeaderUri = contentHeader.url;
}

hasEmptyContent = false;
contentState = Cesium3DTileContentState.UNLOADED;
contentResource = baseResource.getDerivedResource({
Expand Down Expand Up @@ -333,7 +334,6 @@ define([
this._priority = 0.0;
this._isClipped = true;
this._clippingPlanesState = 0; // encapsulates (_isClipped, clippingPlanes.enabled) and number/function

this._debugBoundingVolume = undefined;
this._debugContentBoundingVolume = undefined;
this._debugViewerRequestVolume = undefined;
Expand Down Expand Up @@ -702,7 +702,6 @@ define([
}

var contentFailedFunction = getContentFailedFunction(this);

promise.then(function(arrayBuffer) {
if (that.isDestroyed()) {
// Tile is unloaded before the content finishes loading
Expand Down Expand Up @@ -821,8 +820,7 @@ define([
var tileset = this._tileset;
var clippingPlanes = tileset.clippingPlanes;
if (defined(clippingPlanes) && clippingPlanes.enabled) {
var tileTransform = tileset.root.computedTransform;
var intersection = clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume, tileTransform);
var intersection = clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume, tileset.clippingPlaneOffsetMatrix);
this._isClipped = intersection !== Intersect.INSIDE;
if (intersection === Intersect.OUTSIDE) {
return CullingVolume.MASK_OUTSIDE;
Expand Down Expand Up @@ -856,8 +854,7 @@ define([
var tileset = this._tileset;
var clippingPlanes = tileset.clippingPlanes;
if (defined(clippingPlanes) && clippingPlanes.enabled) {
var tileTransform = tileset.root.computedTransform;
var intersection = clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume, tileTransform);
var intersection = clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume, tileset.clippingPlaneOffsetMatrix);
this._isClipped = intersection !== Intersect.INSIDE;
if (intersection === Intersect.OUTSIDE) {
return Intersect.OUTSIDE;
Expand Down
25 changes: 24 additions & 1 deletion Source/Scene/Cesium3DTileset.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ define([
'../Core/Matrix4',
'../Core/Resource',
'../Core/RuntimeError',
'../Core/Transforms',
'../Renderer/ClearCommand',
'../Renderer/Pass',
'../ThirdParty/when',
Expand Down Expand Up @@ -60,6 +61,7 @@ define([
Matrix4,
Resource,
RuntimeError,
Transforms,
ClearCommand,
Pass,
when,
Expand Down Expand Up @@ -209,6 +211,9 @@ define([

this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);

this._useBoundingSphereForClipping = false;
this._clippingPlaneOffsetMatrix = undefined;

/**
* Optimization option. Whether the tileset should refine based on a dynamic screen space error. Tiles that are further
* away will be rendered with lower detail than closer tiles. This improves performance by rendering fewer
Expand Down Expand Up @@ -697,6 +702,10 @@ define([
that._extensionsUsed = tilesetJson.extensionsUsed;
that._gltfUpAxis = gltfUpAxis;
that._extras = tilesetJson.extras;
if (!defined(tilesetJson.root.transform)) {
that._useBoundingSphereForClipping = true;
that._clippingPlaneOffsetMatrix = Transforms.eastNorthUpToFixedFrame(that.boundingSphere.center);
}
that._readyPromise.resolve(that);
}).otherwise(function(error) {
that._readyPromise.reject(error);
Expand Down Expand Up @@ -1107,6 +1116,18 @@ define([
}
},

/**
* @private
*/
clippingPlaneOffsetMatrix : {
get : function() {
if (this._useBoundingSphereForClipping) {
return this._clippingPlaneOffsetMatrix;
}
return this.root.computedTransform;
}
},

/**
* @private
*/
Expand Down Expand Up @@ -1478,7 +1499,6 @@ define([
filterProcessingQueue(tileset);
var tiles = tileset._processingQueue;
var length = tiles.length;

// Process tiles in the PROCESSING state so they will eventually move to the READY state.
for (var i = 0; i < length; ++i) {
tiles[i].process(tileset, frameState);
Expand Down Expand Up @@ -1809,6 +1829,9 @@ define([
var clippingPlanes = this._clippingPlanes;
if (defined(clippingPlanes) && clippingPlanes.enabled) {
clippingPlanes.update(frameState);
if (this._useBoundingSphereForClipping) {
this._clippingPlaneOffsetMatrix = Transforms.eastNorthUpToFixedFrame(this.boundingSphere.center);
}
}

this._timeSinceLoad = Math.max(JulianDate.secondsDifference(frameState.time, this._loadTimestamp) * 1000, 0.0);
Expand Down
40 changes: 36 additions & 4 deletions Source/Scene/ClippingPlaneCollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ define([
/**
* Specifies a set of clipping planes. Clipping planes selectively disable rendering in a region on the
* outside of the specified list of {@link ClippingPlane} objects for a single gltf model, 3D Tileset, or the globe.
* <p>
* In general the clipping planes' coordinates are relative to the object they're attached to, so a plane with distance set to 0 will clip
* through the center of the object.
* </p>
* <p>
* For 3D Tiles, the root tile's transform is used to position the clipping planes. If a transform is not defined, the root tile's {@link Cesium3DTile#boundingSphere} is used instead.
* </p>
*
* @alias ClippingPlaneCollection
* @constructor
Expand All @@ -63,9 +70,33 @@ define([
* @param {ClippingPlane[]} [options.planes=[]] An array of {@link ClippingPlane} objects used to selectively disable rendering on the outside of each plane.
* @param {Boolean} [options.enabled=true] Determines whether the clipping planes are active.
* @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix specifying an additional transform relative to the clipping planes original coordinate system.
* @param {Boolean} [options.unionClippingRegions=false] If true, a region will be clipped if included in any plane in the collection. Otherwise, the region to be clipped must intersect the regions defined by all planes in this collection.
* @param {Boolean} [options.unionClippingRegions=false] If true, a region will be clipped if it is on the outside of any plane in the collection. Otherwise, a region will only be clipped if it is on the outside of every plane.
* @param {Color} [options.edgeColor=Color.WHITE] The color applied to highlight the edge along which an object is clipped.
* @param {Number} [options.edgeWidth=0.0] The width, in pixels, of the highlight applied to the edge along which an object is clipped.
*
* @demo {@link https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/?src=3D%20Tiles%20Clipping%20Planes.html|Clipping 3D Tiles and glTF models.}
* @demo {@link https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/?src=Terrain%20Clipping%20Planes.html|Clipping the Globe.}
*
* @example
* // This clipping plane's distance is positive, which means its normal
* // is facing the origin. This will clip everything that is behind
* // the plane, which is anything with y coordinate < -5.
* var clippingPlanes = new Cesium.ClippingPlaneCollection({
* planes : [
* new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 1.0, 0.0), 5.0)
* ],
* });
* // Create an entity and attach the ClippingPlaneCollection to the model.
* var entity = viewer.entities.add({
* position : Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, 10000),
* model : {
* uri : 'model.gltf',
* minimumPixelSize : 128,
* maximumScale : 20000,
* clippingPlanes : clippingPlanes
* }
* });
* viewer.zoomTo(entity);
*/
function ClippingPlaneCollection(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
Expand Down Expand Up @@ -168,8 +199,9 @@ define([
},

/**
* If true, a region will be clipped if included in any plane in the collection. Otherwise, the region
* to be clipped must intersect the regions defined by all planes in this collection.
* If true, a region will be clipped if it is on the outside of any plane in the
* collection. Otherwise, a region will only be clipped if it is on the
* outside of every plane.
*
* @memberof ClippingPlaneCollection.prototype
* @type {Boolean}
Expand Down Expand Up @@ -587,7 +619,7 @@ define([

var modelMatrix = this.modelMatrix;
if (defined(transform)) {
modelMatrix = Matrix4.multiply(modelMatrix, transform, scratchMatrix);
modelMatrix = Matrix4.multiply(transform, modelMatrix, scratchMatrix);
}

// If the collection is not set to union the clipping regions, the volume must be outside of all planes to be
Expand Down
1 change: 1 addition & 0 deletions Source/Scene/Instanced3DModel3DTileContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ define([
// Update for clipping planes
var tilesetClippingPlanes = this._tileset.clippingPlanes;
if (this._tile.clippingPlanesDirty && defined(tilesetClippingPlanes)) {
model.clippingPlaneOffsetMatrix = this._tileset.clippingPlaneOffsetMatrix;
// Dereference the clipping planes from the model if they are irrelevant - saves on shading
// Link/Dereference directly to avoid ownership checks.
model._clippingPlanes = (tilesetClippingPlanes.enabled && this._tile._isClipped) ? tilesetClippingPlanes : undefined;
Expand Down
Loading