diff --git a/CHANGES.md b/CHANGES.md index 5f6648d972ac..50c2b920ad6f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,7 @@ Change Log ========== ### 1.31 - 2017-03-01 - +* Added support to `DebugCameraPrimitive` to draw multifrustum planes. The attribute `debugShowFrustumPlanes` of `Scene` and `frustumPlanes` of `CesiumInspector` toggles this. `FrameState` has been augmented to include `frustumSplits` which is a `Number[]` of the near/far planes of the camera frustums. * Enable rendering `GroundPrimitives` on hardware without the `EXT_frag_depth` extension; however, this could cause artifacts for certain viewing angles. * Added compressed texture support. [#4758](https://github.com/AnalyticalGraphicsInc/cesium/pull/4758) * glTF models and imagery layers can now reference [KTX](https://www.khronos.org/opengles/sdk/tools/KTX/) textures and textures compressed with [crunch](https://github.com/BinomialLLC/crunch). diff --git a/Source/Scene/DebugCameraPrimitive.js b/Source/Scene/DebugCameraPrimitive.js index ffcf283e6cf1..c282852684cd 100644 --- a/Source/Scene/DebugCameraPrimitive.js +++ b/Source/Scene/DebugCameraPrimitive.js @@ -92,24 +92,20 @@ define([ this._planesPrimitive = undefined; } - var frustumCornersNDC = new Array(8); - frustumCornersNDC[0] = new Cartesian4(-1.0, -1.0, -1.0, 1.0); - frustumCornersNDC[1] = new Cartesian4(1.0, -1.0, -1.0, 1.0); - frustumCornersNDC[2] = new Cartesian4(1.0, 1.0, -1.0, 1.0); - frustumCornersNDC[3] = new Cartesian4(-1.0, 1.0, -1.0, 1.0); - frustumCornersNDC[4] = new Cartesian4(-1.0, -1.0, 1.0, 1.0); - frustumCornersNDC[5] = new Cartesian4(1.0, -1.0, 1.0, 1.0); - frustumCornersNDC[6] = new Cartesian4(1.0, 1.0, 1.0, 1.0); - frustumCornersNDC[7] = new Cartesian4(-1.0, 1.0, 1.0, 1.0); + var frustumCornersNDC = new Array(4); + frustumCornersNDC[0] = new Cartesian4(-1.0, -1.0, 1.0, 1.0); + frustumCornersNDC[1] = new Cartesian4(1.0, -1.0, 1.0, 1.0); + frustumCornersNDC[2] = new Cartesian4(1.0, 1.0, 1.0, 1.0); + frustumCornersNDC[3] = new Cartesian4(-1.0, 1.0, 1.0, 1.0); var scratchMatrix = new Matrix4(); - var scratchFrustumCorners = new Array(8); - for (var i = 0; i < 8; ++i) { + var scratchFrustumCorners = new Array(4); + for (var i = 0; i < 4; ++i) { scratchFrustumCorners[i] = new Cartesian4(); } var scratchColor = new Color(); - + var scratchSplits = [1.0, 100000.0]; /** * @private */ @@ -130,14 +126,34 @@ define([ var viewProjection = Matrix4.multiply(projection, view, scratchMatrix); var inverseViewProjection = Matrix4.inverse(viewProjection, scratchMatrix); - var positions = new Float64Array(8 * 3); - for (var i = 0; i < 8; ++i) { - var corner = Cartesian4.clone(frustumCornersNDC[i], scratchFrustumCorners[i]); - Matrix4.multiplyByVector(inverseViewProjection, corner, corner); - Cartesian3.divideByScalar(corner, corner.w, corner); // Handle the perspective divide - positions[i * 3] = corner.x; - positions[i * 3 + 1] = corner.y; - positions[i * 3 + 2] = corner.z; + var frustumSplits = frameState.frustumSplits; + var numFrustums = frustumSplits.length - 1; + if (numFrustums <= 0) { + frustumSplits = scratchSplits; // Use near and far planes if no splits created + frustumSplits[0] = this._camera.frustum.near; + frustumSplits[1] = this._camera.frustum.far; + numFrustums = 1; + } + + var positions = new Float64Array(3 * 4 * (numFrustums + 1)); + var f; + for (f = 0; f < numFrustums + 1; ++f) { + for (var i = 0; i < 4; ++i) { + var corner = Cartesian4.clone(frustumCornersNDC[i], scratchFrustumCorners[i]); + + Matrix4.multiplyByVector(inverseViewProjection, corner, corner); + Cartesian3.divideByScalar(corner, corner.w, corner); // Handle the perspective divide + Cartesian3.subtract(corner, this._camera.positionWC, corner); + Cartesian3.normalize(corner, corner); + + var fac = Cartesian3.dot(this._camera.directionWC, corner); + Cartesian3.multiplyByScalar(corner, frustumSplits[f] / fac, corner); + Cartesian3.add(corner, this._camera.positionWC, corner); + + positions[12 * f + i * 3] = corner.x; + positions[12 * f + i * 3 + 1] = corner.y; + positions[12 * f + i * 3 + 2] = corner.z; + } } var boundingSphere = new BoundingSphere.fromVertices(positions); @@ -149,8 +165,38 @@ define([ values : positions }); + var offset, index; + // Create the outline primitive - var outlineIndices = new Uint16Array([0,1,1,2,2,3,3,0,0,4,4,7,7,3,7,6,6,2,2,1,1,5,5,4,5,6]); + var outlineIndices = new Uint16Array(8 * (2 * numFrustums + 1)); + // Build the far planes + for (f = 0; f < numFrustums + 1; ++f) { + offset = f * 8; + index = f * 4; + + outlineIndices[offset] = index; + outlineIndices[offset + 1] = index + 1; + outlineIndices[offset + 2] = index + 1; + outlineIndices[offset + 3] = index + 2; + outlineIndices[offset + 4] = index + 2; + outlineIndices[offset + 5] = index + 3; + outlineIndices[offset + 6] = index + 3; + outlineIndices[offset + 7] = index; + } + // Build the sides of the frustums + for (f = 0; f < numFrustums; ++f) { + offset = (numFrustums + 1 + f) * 8; + index = f * 4; + + outlineIndices[offset] = index; + outlineIndices[offset + 1] = index + 4; + outlineIndices[offset + 2] = index + 1; + outlineIndices[offset + 3] = index + 5; + outlineIndices[offset + 4] = index + 2; + outlineIndices[offset + 5] = index + 6; + outlineIndices[offset + 6] = index + 3; + outlineIndices[offset + 7] = index + 7; + } this._outlinePrimitive = new Primitive({ geometryInstances : new GeometryInstance({ @@ -174,7 +220,52 @@ define([ }); // Create the planes primitive - var planesIndices = new Uint16Array([4,5,6,4,6,7,5,1,2,5,2,6,7,6,2,7,2,3,0,1,5,0,5,4,0,4,7,0,7,3,1,0,3,1,3,2]); + var planesIndices = new Uint16Array(6 * (5 * numFrustums + 1)); + // Build the far planes + for (f = 0; f < numFrustums + 1; ++f) { + offset = f * 6; + index = f * 4; + + planesIndices[offset] = index; + planesIndices[offset + 1] = index + 1; + planesIndices[offset + 2] = index + 2; + planesIndices[offset + 3] = index; + planesIndices[offset + 4] = index + 2; + planesIndices[offset + 5] = index + 3; + } + // Build the sides of the frustums + for (f = 0; f < numFrustums; ++f) { + offset = (numFrustums + 1 + 4 * f) * 6; + index = f * 4; + + planesIndices[offset] = index + 4; + planesIndices[offset + 1] = index; + planesIndices[offset + 2] = index + 3; + planesIndices[offset + 3] = index + 4; + planesIndices[offset + 4] = index + 3; + planesIndices[offset + 5] = index + 7; + + planesIndices[offset + 6] = index + 4; + planesIndices[offset + 7] = index; + planesIndices[offset + 8] = index + 1; + planesIndices[offset + 9] = index + 4; + planesIndices[offset + 10] = index + 1; + planesIndices[offset + 11] = index + 5; + + planesIndices[offset + 12] = index + 7; + planesIndices[offset + 13] = index + 3; + planesIndices[offset + 14] = index + 2; + planesIndices[offset + 15] = index + 7; + planesIndices[offset + 16] = index + 2; + planesIndices[offset + 17] = index + 6; + + planesIndices[offset + 18] = index + 6; + planesIndices[offset + 19] = index + 2; + planesIndices[offset + 20] = index + 1; + planesIndices[offset + 21] = index + 6; + planesIndices[offset + 22] = index + 1; + planesIndices[offset + 23] = index + 5; + } this._planesPrimitive = new Primitive({ geometryInstances : new GeometryInstance({ diff --git a/Source/Scene/FrameState.js b/Source/Scene/FrameState.js index b29b83806062..f28094fd9c7b 100644 --- a/Source/Scene/FrameState.js +++ b/Source/Scene/FrameState.js @@ -235,6 +235,13 @@ define([ * @default 0.0 */ this.imagerySplitPosition = 0.0; + + /** + * Distances to the near and far planes of the camera frustums + * @type {Number[]} + * @default [] + */ + this.frustumSplits = []; } /** diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js index 8ebad9dda2d4..261ccb8c2c43 100644 --- a/Source/Scene/Scene.js +++ b/Source/Scene/Scene.js @@ -42,6 +42,7 @@ define([ './Camera', './CreditDisplay', './CullingVolume', + './DebugCameraPrimitive', './DepthPlane', './DeviceOrientationCameraController', './Fog', @@ -109,6 +110,7 @@ define([ Camera, CreditDisplay, CullingVolume, + DebugCameraPrimitive, DepthPlane, DeviceOrientationCameraController, Fog, @@ -515,6 +517,20 @@ define([ */ this.debugShowDepthFrustum = 1; + /** + * This property is for debugging only; it is not for production use. + *
+ * When true
, draws outlines to show the boundaries of the camera frustums
+ *
true
, enables Fast Approximate Anti-aliasing even when order independent translucency
* is unsupported.
@@ -1442,6 +1458,15 @@ define([
updateFrustums(near, far, farToNearRatio, numFrustums, frustumCommandsList, is2D, scene.nearToFarDistance2D);
createPotentiallyVisibleSet(scene);
}
+
+ var frustumSplits = frameState.frustumSplits;
+ frustumSplits.length = numFrustums + 1;
+ for (var j = 0; j < numFrustums; ++j) {
+ frustumSplits[j] = frustumCommandsList[j].near;
+ if (j === numFrustums - 1) {
+ frustumSplits[j + 1] = frustumCommandsList[j].far;
+ }
+ }
}
function getAttributeLocations(shaderProgram) {
@@ -2202,6 +2227,25 @@ define([
}
}
+ function updateDebugFrustumPlanes(scene) {
+ var frameState = scene._frameState;
+ if (scene.debugShowFrustumPlanes !== scene._debugShowFrustumPlanes) {
+ if (scene.debugShowFrustumPlanes) {
+ scene._debugFrustumPlanes = new DebugCameraPrimitive({
+ camera: scene.camera,
+ updateOnChange: false
+ });
+ } else {
+ scene._debugFrustumPlanes = scene._debugFrustumPlanes && scene._debugFrustumPlanes.destroy();
+ }
+ scene._debugShowFrustumPlanes = scene.debugShowFrustumPlanes;
+ }
+
+ if (defined(scene._debugFrustumPlanes)) {
+ scene._debugFrustumPlanes.update(frameState);
+ }
+ }
+
function updateShadowMaps(scene) {
var frameState = scene._frameState;
var shadowMaps = frameState.shadowMaps;
@@ -2253,6 +2297,7 @@ define([
scene._groundPrimitives.update(frameState);
scene._primitives.update(frameState);
+ updateDebugFrustumPlanes(scene);
updateShadowMaps(scene);
if (scene._globe) {
@@ -2908,6 +2953,7 @@ define([
this._sunPostProcess = this._sunPostProcess && this._sunPostProcess.destroy();
this._depthPlane = this._depthPlane && this._depthPlane.destroy();
this._transitioner.destroy();
+ this._debugFrustumPlanes = this._debugFrustumPlanes && this._debugFrustumPlanes.destroy();
if (defined(this._globeDepth)) {
this._globeDepth.destroy();
diff --git a/Source/Widgets/CesiumInspector/CesiumInspector.js b/Source/Widgets/CesiumInspector/CesiumInspector.js
index 923ead6b0980..ec0864d7daf6 100644
--- a/Source/Widgets/CesiumInspector/CesiumInspector.js
+++ b/Source/Widgets/CesiumInspector/CesiumInspector.js
@@ -80,6 +80,7 @@ define([
generalSection.className = 'cesium-cesiumInspector-section';
generalSection.setAttribute('data-bind', 'css: {"cesium-cesiumInspector-show" : generalVisible, "cesium-cesiumInspector-hide" : !generalVisible}');
panel.appendChild(generalSection);
+
var debugShowFrustums = document.createElement('div');
generalSection.appendChild(debugShowFrustums);
var frustumStats = document.createElement('div');
@@ -92,6 +93,14 @@ define([
debugShowFrustums.appendChild(document.createTextNode('Show Frustums'));
debugShowFrustums.appendChild(frustumStats);
+ var debugShowFrustumPlanes = document.createElement('div');
+ generalSection.appendChild(debugShowFrustumPlanes);
+ var frustumPlanesCheckbox = document.createElement('input');
+ frustumPlanesCheckbox.type = 'checkbox';
+ frustumPlanesCheckbox.setAttribute('data-bind', 'checked: frustumPlanes');
+ debugShowFrustumPlanes.appendChild(frustumPlanesCheckbox);
+ debugShowFrustumPlanes.appendChild(document.createTextNode('Show Frustum Planes'));
+
var performanceDisplay = document.createElement('div');
generalSection.appendChild(performanceDisplay);
var pdCheckbox = document.createElement('input');
diff --git a/Source/Widgets/CesiumInspector/CesiumInspectorViewModel.js b/Source/Widgets/CesiumInspector/CesiumInspectorViewModel.js
index 8eb93556173a..f5e5b55330ac 100644
--- a/Source/Widgets/CesiumInspector/CesiumInspectorViewModel.js
+++ b/Source/Widgets/CesiumInspector/CesiumInspectorViewModel.js
@@ -107,6 +107,13 @@ define([
*/
this.frustums = false;
+ /**
+ * Gets or sets the show frustum planes state. This property is observable.
+ * @type {Boolean}
+ * @default false
+ */
+ this.frustumPlanes = false;
+
/**
* Gets or sets the show performance display state. This property is observable.
* @type {Boolean}
@@ -305,6 +312,7 @@ define([
knockout.track(this, [
'frustums',
+ 'frustumPlanes',
'performance',
'shaderCacheText',
'primitiveBoundingSphere',
@@ -351,6 +359,10 @@ define([
that._scene.debugShowFrustums = val;
});
+ this._frustumPlanesSubscription = knockout.getObservable(this, 'frustumPlanes').subscribe(function(val) {
+ that._scene.debugShowFrustumPlanes = val;
+ });
+
this._performanceSubscription = knockout.getObservable(this, 'performance').subscribe(function(val) {
if (val) {
that._performanceDisplay = new PerformanceDisplay({
@@ -940,6 +952,7 @@ define([
CesiumInspectorViewModel.prototype.destroy = function() {
this._eventHandler.destroy();
this._frustumsSubscription.dispose();
+ this._frustumPlanesSubscription.dispose();
this._performanceSubscription.dispose();
this._primitiveBoundingSphereSubscription.dispose();
this._primitiveReferenceFrameSubscription.dispose();