Skip to content

Commit

Permalink
Merge pull request #7034 from OmarShehata/clipping-planes-matrix-fix
Browse files Browse the repository at this point in the history
Fix clipping planes for tiles with RTC and/or no transforms
  • Loading branch information
lilleyse authored Sep 21, 2018
2 parents 5352b53 + 79a49e0 commit b73152b
Show file tree
Hide file tree
Showing 17 changed files with 175 additions and 51 deletions.
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);
} 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 support for glTF extension [KHR_materials_pbrSpecularGlossiness](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness) [#7006](https://github.com/AnalyticalGraphicsInc/cesium/pull/7006).
* Added support for glTF extension [KHR_materials_unlit](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit) [#6977](https://github.com/AnalyticalGraphicsInc/cesium/pull/6977).
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

0 comments on commit b73152b

Please sign in to comment.