-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Clipping planes for models, tilesets, point clouds #5913
Changes from 11 commits
05a4387
5d0d22e
cb685e4
5512b11
ff35a7d
c3945d1
9252ad5
2b342c0
7a56927
1513f0c
d25a825
8642cf7
f843aa3
d9a2c56
bb4c63f
5be9ef6
973ae3a
7d6cba2
1c101a8
b01ffa9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <!-- Use Chrome Frame in IE --> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> | ||
<meta name="description" content="User-defined clipping planes applied to a batched 3D Tileset, point cloud, and model."> | ||
<meta name="cesium-sandcastle-labels" content="Showcases, 3D Tiles"> | ||
<title>Cesium Demo</title> | ||
<script type="text/javascript" src="../Sandcastle-header.js"></script> | ||
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.20/require.js"></script> | ||
<script type="text/javascript"> | ||
require.config({ | ||
baseUrl : '../../../Source', | ||
waitSeconds : 60 | ||
}); | ||
</script> | ||
</head> | ||
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html"> | ||
<style> | ||
@import url(../templates/bucket.css); | ||
#toolbar { | ||
background: rgba(42, 42, 42, 0.8); | ||
padding: 4px; | ||
border-radius: 4px; | ||
} | ||
#toolbar input { | ||
vertical-align: middle; | ||
padding-top: 2px; | ||
padding-bottom: 2px; | ||
} | ||
#toolbar .header { | ||
font-weight: bold; | ||
} | ||
</style> | ||
<div id="cesiumContainer" class="fullSize"></div> | ||
<div id="loadingOverlay"><h1>Loading...</h1></div> | ||
<div id="toolbar"> | ||
<table><tbody> | ||
<tr> | ||
<td>Type</td> | ||
<td><select data-bind="options: exampleTypes, value: exampleType"></select></td> | ||
</tr> | ||
<tr> | ||
<td>x</td> | ||
<td> | ||
<input type="range" min="-100" max="100" step="1" data-bind="value: xOffset, valueUpdate: 'input'"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reset x, y, and z when a new model is selected. After playing around with the BIM tileset I switched to the airplane and couldn't see it because the values were just too big. It might even be good to limit the range of these values per-model. The sliders are too shifty for the airplane model. Or just scale up the airplane if that's easier. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So setting the scale on the model causes the clipping planes to behave differently- It will not be relative to the model anymore and move around when the camera changes position. But only when the model is set to a scale other than 1. Do you know why that might be? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The scale component of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead I inverted, muliplied by scale, and inverted back. Is that ok? |
||
<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="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="text" size="2" data-bind="value: zOffset"> | ||
</td> | ||
</tr> | ||
</tbody></table> | ||
</div> | ||
|
||
<script id="cesium_sandcastle_script"> | ||
function startup(Cesium) { | ||
'use strict'; | ||
//Sandcastle_Begin | ||
var viewer = new Cesium.Viewer('cesiumContainer'); | ||
|
||
var defaultClippingPlanes = [ | ||
new Cesium.Plane(Cesium.Cartesian3.UNIT_X, 0), | ||
new Cesium.Plane(Cesium.Cartesian3.UNIT_Y, 0), | ||
new Cesium.Plane(Cesium.Cartesian3.UNIT_Z, 0) | ||
]; | ||
|
||
function loadTileset (url) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Throughout, no space before |
||
viewer.entities.removeAll(); | ||
viewer.scene.primitives.removeAll(); | ||
|
||
var tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ | ||
url : url | ||
})); | ||
|
||
tileset.readyPromise.then(function() { | ||
var boundingSphere = tileset.boundingSphere; | ||
viewer.camera.viewBoundingSphere(boundingSphere, new Cesium.HeadingPitchRange(0.5, -0.2, boundingSphere.radius * 4.0)); | ||
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY); | ||
}).otherwise(function(error) { | ||
throw(error); | ||
}); | ||
|
||
tileset.clippingPlanes = defaultClippingPlanes; | ||
return tileset.clippingPlanes; | ||
} | ||
|
||
function loadModel (url) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is an awkward design to have the In |
||
viewer.entities.removeAll(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also need to call To keep is simple, these cleanup lines can go in their own function called from within |
||
viewer.scene.primitives.removeAll(); | ||
|
||
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, 1.0); | ||
var heading = Cesium.Math.toRadians(135); | ||
var pitch = 0; | ||
var roll = 0; | ||
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll); | ||
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr); | ||
|
||
var entity = viewer.entities.add({ | ||
name : url, | ||
position : position, | ||
orientation : orientation, | ||
model : { | ||
uri : url | ||
} | ||
}); | ||
|
||
viewer.trackedEntity = entity; | ||
|
||
entity.model.clippingPlanes = defaultClippingPlanes; | ||
return entity.model.clippingPlanes.getValue(); | ||
} | ||
|
||
// Power Plant design model provided by Bentley Systems | ||
var bimUrl = 'https://beta.cesium.com/api/assets/1459?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIzNjUyM2I5Yy01YmRhLTQ0MjktOGI0Zi02MDdmYzBjMmY0MjYiLCJpZCI6NDQsImFzc2V0cyI6WzE0NTldLCJpYXQiOjE0OTkyNjQ3ODF9.SW_rwY-ic0TwQBeiweXNqFyywoxnnUBtcVjeCmDGef4'; | ||
var pointCloudUrl = 'https://beta.cesium.com/api/assets/1460?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyMzk2YzJiOS1jZGFmLTRlZmYtYmQ4MS00NTA3NjEwMzViZTkiLCJpZCI6NDQsImFzc2V0cyI6WzE0NjBdLCJpYXQiOjE0OTkyNjQ3NTV9.oWjvN52CRQ-dk3xtvD4e8ZnOHZhoWSpJLlw115mbQJM'; | ||
var modelUrl = '../../SampleData/models/CesiumAir/Cesium_Air.glb'; | ||
|
||
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: 0.0, | ||
zOffset: 0.0 | ||
}; | ||
var toolbar = document.getElementById('toolbar'); | ||
Cesium.knockout.track(viewModel); | ||
Cesium.knockout.applyBindings(viewModel, toolbar); | ||
|
||
Cesium.knockout.getObservable(viewModel, 'xOffset').subscribe(function(newValue) { | ||
clippingPlanes[0].distance = parseFloat(newValue); | ||
}); | ||
|
||
Cesium.knockout.getObservable(viewModel, 'yOffset').subscribe(function(newValue) { | ||
clippingPlanes[1].distance = parseFloat(newValue); | ||
}); | ||
|
||
Cesium.knockout.getObservable(viewModel, 'zOffset').subscribe(function(newValue) { | ||
clippingPlanes[2].distance = parseFloat(newValue); | ||
}); | ||
|
||
Cesium.knockout.getObservable(viewModel, 'exampleType').subscribe( | ||
function(newValue) { | ||
if (newValue === 'BIM') { | ||
clippingPlanes = loadTileset(bimUrl); | ||
} else if (newValue === 'Point Cloud') { | ||
clippingPlanes = loadTileset(pointCloudUrl); | ||
} else { | ||
clippingPlanes = loadModel(modelUrl); | ||
} | ||
} | ||
); | ||
|
||
//Sandcastle_End | ||
Sandcastle.finishedLoading(); | ||
} | ||
if (typeof Cesium !== "undefined") { | ||
startup(Cesium); | ||
} else if (typeof require === "function") { | ||
require(["Cesium"], startup); | ||
} | ||
</script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ Change Log | |
* Fixed a 3D Tiles point cloud bug causing a stray point to appear at the center of the screen on certain hardware. [#5599](https://github.com/AnalyticalGraphicsInc/cesium/issues/5599) | ||
* 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]() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Put this in a new There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Explicitly name the Cesium classes. |
||
* Fixed a tileset traversal bug when the `skipLevelOfDetail` optimization is off. [#5869](https://github.com/AnalyticalGraphicsInc/cesium/issues/5869) | ||
|
||
### 1.37 - 2017-09-01 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,7 @@ define([ | |
* @param {Property} [options.color=Color.WHITE] A Property specifying the {@link Color} that blends with the model's rendered color. | ||
* @param {Property} [options.colorBlendMode=ColorBlendMode.HIGHLIGHT] An enum Property specifying how the color blends with the model. | ||
* @param {Property} [options.colorBlendAmount=0.5] A numeric Property specifying the color strength when the <code>colorBlendMode</code> is <code>MIX</code>. A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with any value in-between resulting in a mix of the two. | ||
* @param {Property} [options.clippingPlanes=[]] A property specifying an array of {@link Plane} used to clip the model. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is currently limited to 6 planes, right? Document that here and throughout. |
||
* | ||
* @see {@link http://cesiumjs.org/2014/03/03/Cesium-3D-Models-Tutorial/|3D Models Tutorial} | ||
* @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=3D%20Models.html|Cesium Sandcastle 3D Models Demo} | ||
|
@@ -91,6 +92,8 @@ define([ | |
this._colorBlendModeSubscription = undefined; | ||
this._colorBlendAmount = undefined; | ||
this._colorBlendAmountSubscription = undefined; | ||
this._clippingPlanes = undefined; | ||
this._clippingPlanesSubscription = undefined; | ||
this._definitionChanged = new Event(); | ||
|
||
this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT)); | ||
|
@@ -242,7 +245,15 @@ define([ | |
* @type {Property} | ||
* @default 0.5 | ||
*/ | ||
colorBlendAmount : createPropertyDescriptor('colorBlendAmount') | ||
colorBlendAmount : createPropertyDescriptor('colorBlendAmount'), | ||
|
||
/** | ||
* A property specifying an array of {@link Plane} used to clip the model. | ||
* @memberof ModelGraphics.prototype | ||
* @type {Property} | ||
* @default [] | ||
*/ | ||
clippingPlanes: createPropertyDescriptor('clippingPlanes') | ||
}); | ||
|
||
/** | ||
|
@@ -271,6 +282,7 @@ define([ | |
result.color = this.color; | ||
result.colorBlendMode = this.colorBlendMode; | ||
result.colorBlendAmount = this.colorBlendAmount; | ||
result.clippingPlanes = this.clippingPlanes; | ||
|
||
return result; | ||
}; | ||
|
@@ -303,6 +315,7 @@ define([ | |
this.color = defaultValue(this.color, source.color); | ||
this.colorBlendMode = defaultValue(this.colorBlendMode, source.colorBlendMode); | ||
this.colorBlendAmount = defaultValue(this.colorBlendAmount, source.colorBlendAmount); | ||
this.clippingPlanes = defaultValue(this.clippingPlanes, source.clippingPlanes); | ||
|
||
var sourceNodeTransformations = source.nodeTransformations; | ||
if (defined(sourceNodeTransformations)) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,6 +40,7 @@ define([ | |
var defaultColor = Color.WHITE; | ||
var defaultColorBlendMode = ColorBlendMode.HIGHLIGHT; | ||
var defaultColorBlendAmount = 0.5; | ||
var defaultClippingPlanes = []; | ||
|
||
var modelMatrixScratch = new Matrix4(); | ||
var nodeMatrixScratch = new Matrix4(); | ||
|
@@ -152,6 +153,7 @@ define([ | |
model.color = Property.getValueOrDefault(modelGraphics._color, time, defaultColor, model._color); | ||
model.colorBlendMode = Property.getValueOrDefault(modelGraphics._colorBlendMode, time, defaultColorBlendMode); | ||
model.colorBlendAmount = Property.getValueOrDefault(modelGraphics._colorBlendAmount, time, defaultColorBlendAmount); | ||
model.clippingPlanes = Property.getValueOrDefault(modelGraphics._clippingPlanes, time, defaultClippingPlanes); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make sure to double-check that everything works correctly when two models are added that use different clipping planes. It seems like it should be fine. |
||
|
||
if (model.ready) { | ||
var runAnimations = Property.getValueOrDefault(modelGraphics._runAnimations, time, true); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,6 +105,7 @@ define([ | |
* @param {Number} [options.skipLevels=1] When <code>skipLevelOfDetail</code> is <code>true</code>, a constant defining the minimum number of levels to skip when loading tiles. When it is 0, no levels are skipped. Used in conjunction with <code>skipScreenSpaceErrorFactor</code> to determine which tiles to load. | ||
* @param {Boolean} [options.immediatelyLoadDesiredLevelOfDetail=false] When <code>skipLevelOfDetail</code> is <code>true</code>, only tiles that meet the maximum screen space error will ever be downloaded. Skipping factors are ignored and just the desired tiles are loaded. | ||
* @param {Boolean} [options.loadSiblings=false] When <code>skipLevelOfDetail</code> is <code>true</code>, determines whether siblings of visible tiles are always downloaded during traversal. | ||
* @param {Plane[]} [options.clippingPlanes=[]] An array of {@link Plane} used to clip the tileset. | ||
* @param {Boolean} [options.debugFreezeFrame=false] For debugging only. Determines if only the tiles from last frame should be used for rendering. | ||
* @param {Boolean} [options.debugColorizeTiles=false] For debugging only. When true, assigns a random color to each tile. | ||
* @param {Boolean} [options.debugWireframe=false] For debugging only. When true, render's each tile's content as a wireframe. | ||
|
@@ -522,6 +523,14 @@ define([ | |
*/ | ||
this.loadSiblings = defaultValue(options.loadSiblings, false); | ||
|
||
/** | ||
* An array of {@link Plane} used to clip the tileset. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here and throughout the reference doc should provide a tad more context: what does it mean to "clip" the tileset? |
||
* | ||
* @type {Plane[]} | ||
* @default [] | ||
*/ | ||
this.clippingPlanes = defaultValue(options.clippingPlanes, []); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor, but here and below we usually would not use However, couldn't If not, please make sure that we throw a |
||
|
||
/** | ||
* This property is for debugging only; it is not optimized for production use. | ||
* <p> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -339,6 +339,7 @@ define([ | |
* @param {Number} [options.colorBlendAmount=0.5] Value used to determine the color strength when the <code>colorBlendMode</code> is <code>MIX</code>. A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with any value in-between resulting in a mix of the two. | ||
* @param {Color} [options.silhouetteColor=Color.RED] The silhouette color. If more than 256 models have silhouettes enabled, there is a small chance that overlapping models will have minor artifacts. | ||
* @param {Number} [options.silhouetteSize=0.0] The size of the silhouette in pixels. | ||
* @param {Plane[]} [options.clippingPlanes=[]] An array of {@link Plane} used to clip the model. | ||
* | ||
* @exception {DeveloperError} bgltf is not a valid Binary glTF file. | ||
* @exception {DeveloperError} Only glTF Binary version 1 is supported. | ||
|
@@ -576,6 +577,15 @@ define([ | |
*/ | ||
this.colorBlendAmount = defaultValue(options.colorBlendAmount, 0.5); | ||
|
||
/** | ||
* An array of {@link Plane} used to clip the model. | ||
* | ||
* @type {Plane[]} | ||
* | ||
* @default [] | ||
*/ | ||
this.clippingPlanes = defaultValue(options.clippingPlanes, []); | ||
|
||
/** | ||
* This property is for debugging only; it is not for production use nor is it optimized. | ||
* <p> | ||
|
@@ -2096,9 +2106,10 @@ define([ | |
|
||
var premultipliedAlpha = hasPremultipliedAlpha(model); | ||
var blendFS = modifyShaderForColor(fs, premultipliedAlpha); | ||
var clippingFS = modifyShaderForClippingPlanes(blendFS); | ||
|
||
var drawVS = modifyShader(vs, id, model._vertexShaderLoaded); | ||
var drawFS = modifyShader(blendFS, id, model._fragmentShaderLoaded); | ||
var drawFS = modifyShader(clippingFS, id, model._fragmentShaderLoaded); | ||
|
||
model._rendererResources.programs[id] = ShaderProgram.fromCache({ | ||
context : context, | ||
|
@@ -3293,6 +3304,32 @@ define([ | |
}; | ||
} | ||
|
||
function createClippingPlanesLengthFunction(model) { | ||
return function() { | ||
return model.clippingPlanes.length; | ||
}; | ||
} | ||
|
||
var scratchCartesian = new Cartesian3(); | ||
var scratchPlane = new Cartesian4(); | ||
|
||
function createClippingPlanesFunction(model, context) { | ||
return function() { | ||
var planes = model.clippingPlanes; | ||
var length = planes.length; | ||
var packedPlanes = new Array(length); | ||
for (var i = 0; i < length; ++i) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably be limited to 6. Check what happens if you have more than 6 clipping planes, there may be an error in setting the uniform. |
||
var plane = planes[i]; | ||
Matrix3.multiplyByVector(context.uniformState.normal, plane.normal, scratchPlane); | ||
Cartesian3.multiplyByScalar(plane.normal, plane.distance, scratchCartesian); | ||
Matrix4.multiplyByPoint(context.uniformState.modelView3D, scratchCartesian, scratchCartesian); | ||
scratchPlane.w = Cartesian3.dot(scratchPlane, scratchCartesian); | ||
packedPlanes[i] = scratchPlane.clone(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One last thing - instead of allocating the |
||
} | ||
return packedPlanes; | ||
}; | ||
} | ||
|
||
function createColorBlendFunction(model) { | ||
return function() { | ||
return ColorBlendMode.getColorBlend(model.colorBlendMode, model.colorBlendAmount); | ||
|
@@ -3387,7 +3424,9 @@ define([ | |
|
||
uniformMap = combine(uniformMap, { | ||
gltf_color : createColorFunction(model), | ||
gltf_colorBlend : createColorBlendFunction(model) | ||
gltf_colorBlend : createColorBlendFunction(model), | ||
gltf_clippingPlanesLength: createClippingPlanesLengthFunction(model), | ||
gltf_clippingPlanes: createClippingPlanesFunction(model, context) | ||
}); | ||
|
||
// Allow callback to modify the uniformMap | ||
|
@@ -4181,6 +4220,20 @@ define([ | |
} | ||
} | ||
|
||
function modifyShaderForClippingPlanes(shader) { | ||
shader = ShaderSource.replaceMain(shader, 'gltf_clip_main'); | ||
shader += | ||
'uniform int gltf_clippingPlanesLength; \n' + | ||
'uniform vec4 gltf_clippingPlanes[czm_maxClippingPlanes]; \n' + | ||
'void main() \n' + | ||
'{ \n' + | ||
' gltf_clip_main(); \n' + | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The clipping planes code should not be run if there are no clipping planes. Put an if in here that checks |
||
' czm_clipPlanes(gltf_clippingPlanes, gltf_clippingPlanesLength); \n' + | ||
'} \n'; | ||
|
||
return shader; | ||
} | ||
|
||
function updateSilhouette(model, frameState) { | ||
// Generate silhouette commands when the silhouette size is greater than 0.0 and the alpha is greater than 0.0 | ||
// There are two silhouette commands: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an image for the demo.