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

Tileset traversal with clipping planes #5966

Merged
merged 11 commits into from
Nov 21, 2017
44 changes: 26 additions & 18 deletions Apps/Sandcastle/gallery/Clipping Planes.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,25 +44,26 @@
<tr>
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm seeing a crash when zooming into the BIM tileset.
error

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is fixed in the next branch.

<td>x</td>
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 tileset doesn't seem to show up for me, even after playing around with the sliders.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Noted, but I think it will be easier to fix this in the next branch as I have added easier ways to handle this.

<td>
<input type="range" min="-100" max="100" step="1" data-bind="value: xOffset, valueUpdate: 'input'">
<input type="range" min="-150" max="150" step="1" data-bind="value: xOffset, valueUpdate: 'input'">
<input type="text" size="2" data-bind="value: xOffset">
</td>
</tr>
<tr>
<td>y</td>
<td>
<input type="range" min="-100" max="100" step="1" data-bind="value: yOffset, valueUpdate: 'input'">
<input type="range" min="-150" max="150" step="1" data-bind="value: yOffset, valueUpdate: 'input'">
<input type="text" size="2" data-bind="value: yOffset">
</td>
</tr>
<tr>
<td>z</td>
<td>
<input type="range" min="-100" max="100" step="1" data-bind="value: zOffset, valueUpdate: 'input'">
<input type="range" min="-150" max="150" step="1" data-bind="value: zOffset, valueUpdate: 'input'">
<input type="text" size="2" data-bind="value: zOffset">
</td>
</tr>
</tbody></table>
<input type="checkbox" value="false" data-bind="checked: debugBoundingVolumesEnabled, valueUpdate: 'input'"> Show debug <code>boundingVolume</code>
</div>

<script id="cesium_sandcastle_script">
Expand All @@ -72,15 +73,25 @@
var viewer = new Cesium.Viewer('cesiumContainer');

var defaultClippingPlanes = [
new Cesium.Plane(new Cesium.Cartesian3(-1, 0, 0), 0.0),
new Cesium.Plane(new Cesium.Cartesian3(0, -1, 0), 100.0),
new Cesium.Plane(new Cesium.Cartesian3(0, 0, 1), 100.0)
new Cesium.Plane(new Cesium.Cartesian3(1, 0, 0), 0.0),
new Cesium.Plane(new Cesium.Cartesian3(0, 1, 0), -100.0),
new Cesium.Plane(new Cesium.Cartesian3(0, 0, -1), -100.0)
];

function loadTileset (url) {
var viewModel = {
exampleType : 'BIM',
exampleTypes : ['BIM', 'Model', 'Point Cloud'],
xOffset : 0.0,
yOffset: -100.0,
zOffset: -100.0,
debugBoundingVolumesEnabled: false
};

var tileset;
function loadTileset (url, offeset) {
reset();

var tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
url : url
}));

Expand All @@ -92,6 +103,7 @@
throw(error);
});

tileset.debugShowBoundingVolume = viewModel.debugBoundingVolumesEnabled;
tileset.clippingPlanes = defaultClippingPlanes;
return tileset.clippingPlanes;
}
Expand Down Expand Up @@ -131,14 +143,6 @@
var clippingPlanes = loadTileset(bimUrl);

// Track and create the bindings for the view model

var viewModel = {
exampleType : 'BIM',
exampleTypes : ['BIM', 'Model', 'Point Cloud'],
xOffset : 0.0,
yOffset: 100.0,
zOffset: 100.0
};
var toolbar = document.getElementById('toolbar');
Cesium.knockout.track(viewModel);
Cesium.knockout.applyBindings(viewModel, toolbar);
Expand All @@ -155,6 +159,10 @@
clippingPlanes[2].distance = parseFloat(newValue);
});

Cesium.knockout.getObservable(viewModel, 'debugBoundingVolumesEnabled').subscribe(function(newValue) {
tileset.debugShowBoundingVolume = newValue;
});

Cesium.knockout.getObservable(viewModel, 'exampleType').subscribe(
function(newValue) {
if (newValue === 'BIM') {
Expand All @@ -173,8 +181,8 @@

if (Cesium.defined(viewModel)) {
viewModel.xOffset = 0.0;
viewModel.yOffset = 100.0;
viewModel.zOffset = 100.0;
viewModel.yOffset = -100.0;
viewModel.zOffset = -100.0;
}
}

Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Change Log
* Fixed removing multiple event listeners within event callbacks. [#5827](https://github.com/AnalyticalGraphicsInc/cesium/issues/5827)
* Running `buildApps` now creates a built version of Sandcastle which uses the built version of Cesium for better performance.
* Added `clippingPlanes` property to models and 3D Tilesets, which specify an array of planes to clip the object. [TODO]()
* Added `Plane.transformPlane` function to apply a transformation to a plane. [TODO]()
* Fixed a tileset traversal bug when the `skipLevelOfDetail` optimization is off. [#5869](https://github.com/AnalyticalGraphicsInc/cesium/issues/5869)

### 1.37 - 2017-09-01
Expand Down
61 changes: 38 additions & 23 deletions Source/Core/Plane.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
define([
'./Cartesian3',
'./Check',
'./defined',
'./DeveloperError',
'./freezeObject',
'./Math'
'./Math',
'./Matrix4'
], function(
Cartesian3,
Check,
defined,
DeveloperError,
freezeObject,
CesiumMath) {
CesiumMath,
Matrix4
) {
'use strict';

/**
Expand Down Expand Up @@ -39,15 +44,11 @@ define([
*/
function Plane(normal, distance) {
//>>includeStart('debug', pragmas.debug);
if (!defined(normal)) {
throw new DeveloperError('normal is required.');
}
Check.typeOf.object('normal', normal);
if (!CesiumMath.equalsEpsilon(Cartesian3.magnitude(normal), 1.0, CesiumMath.EPSILON6)) {
throw new DeveloperError('normal must be normalized.');
}
if (!defined(distance)) {
throw new DeveloperError('distance is required.');
}
Check.typeOf.number('distance', distance);
//>>includeEnd('debug');

/**
Expand Down Expand Up @@ -86,12 +87,8 @@ define([
*/
Plane.fromPointNormal = function(point, normal, result) {
//>>includeStart('debug', pragmas.debug);
if (!defined(point)) {
throw new DeveloperError('point is required.');
}
if (!defined(normal)) {
throw new DeveloperError('normal is required.');
}
Check.typeOf.object('point', point);
Check.typeOf.object('normal', normal);
if (!CesiumMath.equalsEpsilon(Cartesian3.magnitude(normal), 1.0, CesiumMath.EPSILON6)) {
throw new DeveloperError('normal must be normalized.');
}
Expand Down Expand Up @@ -120,9 +117,7 @@ define([
*/
Plane.fromCartesian4 = function(coefficients, result) {
//>>includeStart('debug', pragmas.debug);
if (!defined(coefficients)) {
throw new DeveloperError('coefficients is required.');
}
Check.typeOf.object('coefficients', coefficients);
//>>includeEnd('debug');

var normal = Cartesian3.fromCartesian4(coefficients, scratchNormal);
Expand Down Expand Up @@ -155,17 +150,37 @@ define([
*/
Plane.getPointDistance = function(plane, point) {
//>>includeStart('debug', pragmas.debug);
if (!defined(plane)) {
throw new DeveloperError('plane is required.');
}
if (!defined(point)) {
throw new DeveloperError('point is required.');
}
Check.typeOf.object('plane', plane);
Check.typeOf.object('point', point);
//>>includeEnd('debug');

return Cartesian3.dot(plane.normal, point) + plane.distance;
};

var scratchPosition = new Cartesian3();
/**
* Transforms the plane by the given transformation matrix.
*
* @param {Plane} plane The plane.
* @param {Matrix4} transform The transformation matrix.
* @param {Plane} [result] The object into which to store the result.
* @returns {Plane} The plane transformed by the given transformation matrix.
*/
Plane.transformPlane = function(plane, transform, result) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Make sure to write tests for this once you start writing tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also since this is a new thing it should be added to CHANGES.md, unless this is better off private.

Copy link
Contributor

Choose a reason for hiding this comment

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

Just name this transform since Plane is the class name?

//>>includeStart('debug', pragmas.debug);
Check.typeOf.object('plane', plane);
Check.typeOf.object('transform', transform);
//>>includeEnd('debug');
Copy link
Contributor

Choose a reason for hiding this comment

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

Everything in this file should move over to the Check syntax.


Matrix4.multiplyByPointAsVector(transform, plane.normal, scratchNormal);
Cartesian3.normalize(scratchNormal, scratchNormal);

Cartesian3.multiplyByScalar(plane.normal, plane.distance, scratchPosition);
Matrix4.multiplyByPoint(transform, scratchPosition, scratchPosition);

return Plane.fromPointNormal(scratchPosition, scratchNormal, result);
};

/**
* A constant initialized to the XY plane passing through the origin, with normal in positive Z.
*
Expand Down
31 changes: 31 additions & 0 deletions Source/Scene/Cesium3DTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ define([
'../Core/BoundingSphere',
'../Core/Cartesian3',
'../Core/Color',
'../Core/CullingVolume',
'../Core/defaultValue',
'../Core/defined',
'../Core/defineProperties',
Expand All @@ -14,6 +15,7 @@ define([
'../Core/loadArrayBuffer',
'../Core/Matrix3',
'../Core/Matrix4',
'../Core/Plane',
'../Core/Rectangle',
'../Core/Request',
'../Core/RequestScheduler',
Expand All @@ -35,6 +37,7 @@ define([
BoundingSphere,
Cartesian3,
Color,
CullingVolume,
defaultValue,
defined,
defineProperties,
Expand All @@ -47,6 +50,7 @@ define([
loadArrayBuffer,
Matrix3,
Matrix4,
Plane,
Rectangle,
Request,
RequestScheduler,
Expand Down Expand Up @@ -735,6 +739,23 @@ define([
return frameState.mode !== SceneMode.SCENE3D ? tile._contentBoundingVolume2D : tile._contentBoundingVolume;
}


var scratchPlane = new Plane(Cartesian3.UNIT_X, 0.0);
function checkTileClipped(tile, boundingVolume) {
var planes = tile._tileset.clippingPlanes;
var length = planes.length;
for (var i = 0; i < length; ++i) {
var plane = planes[i];
Plane.transformPlane(plane, tile._tileset._root.computedTransform, scratchPlane);
Copy link
Contributor

Choose a reason for hiding this comment

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

Outside of the loop:

var rootTransform = tile._tileset._root.computedTransform;

if (boundingVolume.intersectPlane(scratchPlane) === Intersect.OUTSIDE) {
return true;
}
}

return false;
}


/**
* Determines whether the tile's bounding volume intersects the culling volume.
*
Expand All @@ -747,6 +768,11 @@ define([
Cesium3DTile.prototype.visibility = function(frameState, parentVisibilityPlaneMask) {
var cullingVolume = frameState.cullingVolume;
var boundingVolume = getBoundingVolume(this, frameState);

if (checkTileClipped(this, boundingVolume)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Part of this optimization is to use the original shader when the tile is not clipped. Does this PR do that?

return CullingVolume.MASK_OUTSIDE;
}

return cullingVolume.computeVisibilityWithPlaneMask(boundingVolume, parentVisibilityPlaneMask);
};

Expand All @@ -770,6 +796,11 @@ define([
// tile's (not the content's) bounding volume intersects the culling volume?
var cullingVolume = frameState.cullingVolume;
var boundingVolume = getContentBoundingVolume(this, frameState);

if (checkTileClipped(this, boundingVolume)) {
return Intersect.OUTSIDE;
}

return cullingVolume.computeVisibility(boundingVolume);
};

Expand Down
14 changes: 8 additions & 6 deletions Source/Scene/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ define([
'../Core/Matrix3',
'../Core/Matrix4',
'../Core/PixelFormat',
'../Core/Plane',
'../Core/PrimitiveType',
'../Core/Quaternion',
'../Core/Queue',
Expand Down Expand Up @@ -108,6 +109,7 @@ define([
Matrix3,
Matrix4,
PixelFormat,
Plane,
PrimitiveType,
Quaternion,
Queue,
Expand Down Expand Up @@ -3312,7 +3314,7 @@ define([
};
}

var scratchCartesian = new Cartesian3();
var scratchPlane = new Plane(Cartesian3.UNIT_X, 0.0);
var scratchMatrix = new Matrix4();

function createClippingPlanesFunction(model, context) {
Copy link
Contributor

Choose a reason for hiding this comment

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

context isn't used any more.

Expand All @@ -3327,11 +3329,11 @@ define([
for (var i = 0; i < length; ++i) {
var plane = planes[i];
var packedPlane = packedPlanes[i];
Matrix4.multiplyByPointAsVector(scratchMatrix, plane.normal, packedPlane);
Cartesian3.normalize(packedPlane, packedPlane);
Cartesian3.multiplyByScalar(plane.normal, plane.distance, scratchCartesian);
Matrix4.multiplyByPoint(scratchMatrix, scratchCartesian, scratchCartesian);
packedPlane.w = Cartesian3.dot(packedPlane, scratchCartesian);

Plane.transformPlane(plane, scratchMatrix, scratchPlane);

Cartesian3.clone(scratchPlane.normal, packedPlane);
packedPlane.w = scratchPlane.distance;
}
return packedPlanes;
};
Expand Down
16 changes: 10 additions & 6 deletions Source/Scene/PointCloud3DTileContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ define([
'../Core/Matrix3',
'../Core/Matrix4',
'../Core/oneTimeWarning',
'../Core/Plane',
'../Core/PrimitiveType',
'../Core/RuntimeError',
'../Core/Transforms',
Expand Down Expand Up @@ -50,6 +51,7 @@ define([
Matrix3,
Matrix4,
oneTimeWarning,
Plane,
PrimitiveType,
RuntimeError,
Transforms,
Expand Down Expand Up @@ -514,8 +516,8 @@ define([
}
}

var scratchCartesian = new Cartesian3();

var scratchPlane = new Plane(Cartesian3.UNIT_X, 0.0);
var scratchMatrix = new Matrix4();
var uniformMap = {
u_pointSizeAndTilesetTime : function() {
scratchPointSizeAndTilesetTime.x = content._pointSize;
Expand All @@ -532,17 +534,19 @@ define([
return content._tileset.clippingPlanes.length;
},
u_clippingPlanes : function() {
Matrix4.multiply(context.uniformState.view3D, content._modelMatrix, scratchMatrix);

var planes = content._tileset.clippingPlanes;
var length = planes.length;
var packedPlanes = content._packedClippingPlanes;
for (var i = 0; i < length; ++i) {
var plane = planes[i];
var packedPlane = packedPlanes[i];

Matrix3.multiplyByVector(context.uniformState.normal, plane.normal, packedPlane);
Cartesian3.multiplyByScalar(plane.normal, plane.distance, scratchCartesian);
Matrix4.multiplyByPoint(context.uniformState.modelView3D, scratchCartesian, scratchCartesian);
packedPlane.w = Cartesian3.dot(packedPlane, scratchCartesian);
Plane.transformPlane(plane, scratchMatrix, scratchPlane);

Cartesian3.clone(scratchPlane.normal, packedPlane);
packedPlane.w = scratchPlane.distance;
}
return packedPlanes;
}
Expand Down
Loading