From 0317622bd94679860c586d85beb09ab893327452 Mon Sep 17 00:00:00 2001 From: Kangning Li Date: Tue, 30 Jan 2018 09:59:09 -0500 Subject: [PATCH 01/72] proof-of-concept oct32 normals and in-shader transform for clipping planes by texture --- Apps/Sandcastle/gallery/clipping circle.html | 167 +++++++++++++++++ Source/Core/ClippingPlaneCollection.js | 169 ++++++++++++++---- Source/Scene/Model.js | 80 ++++++--- .../Builtin/Constants/maxClippingPlanes.glsl | 2 +- .../discardIfClippedWithIntersect.glsl | 10 +- .../Functions/discardIfClippedWithUnion.glsl | 8 +- .../getClippingPlaneFromTexture.glsl | 28 +++ .../Shaders/Builtin/Functions/octDecode.glsl | 10 +- 8 files changed, 401 insertions(+), 73 deletions(-) create mode 100644 Apps/Sandcastle/gallery/clipping circle.html create mode 100644 Source/Shaders/Builtin/Functions/getClippingPlaneFromTexture.glsl diff --git a/Apps/Sandcastle/gallery/clipping circle.html b/Apps/Sandcastle/gallery/clipping circle.html new file mode 100644 index 000000000000..efe777c08ead --- /dev/null +++ b/Apps/Sandcastle/gallery/clipping circle.html @@ -0,0 +1,167 @@ + + + + + + + + + Cesium Demo + + + + + + +
+

Loading...

+
+ + + diff --git a/Source/Core/ClippingPlaneCollection.js b/Source/Core/ClippingPlaneCollection.js index e2d9e44f5837..5d6122e43fb8 100644 --- a/Source/Core/ClippingPlaneCollection.js +++ b/Source/Core/ClippingPlaneCollection.js @@ -1,6 +1,9 @@ define([ + './AttributeCompression', + './Cartesian2', './Cartesian3', './Cartesian4', + './Math', './Check', './Color', './defaultValue', @@ -9,10 +12,20 @@ define([ './DeveloperError', './Intersect', './Matrix4', - './Plane' + './PixelFormat', + './Plane', + '../Renderer/PixelDatatype', + '../Renderer/Sampler', + '../Renderer/Texture', + '../Renderer/TextureMagnificationFilter', + '../Renderer/TextureMinificationFilter', + '../Renderer/TextureWrap' ], function( + AttributeCompression, + Cartesian2, Cartesian3, Cartesian4, + CesiumMath, Check, Color, defaultValue, @@ -21,7 +34,14 @@ define([ DeveloperError, Intersect, Matrix4, - Plane) { + PixelFormat, + Plane, + PixelDatatype, + Sampler, + Texture, + TextureMagnificationFilter, + TextureMinificationFilter, + TextureWrap) { 'use strict'; /** @@ -82,9 +102,18 @@ define([ */ this.edgeWidth = defaultValue(options.edgeWidth, 0.0); + /** + * Range for inflating the normalized distances in the clipping plane texture + * + * @type {Cartesian2} + */ + this.distanceRange = new Cartesian2(); + this._testIntersection = undefined; this._unionClippingRegions = undefined; this.unionClippingRegions = defaultValue(options.unionClippingRegions, false); + + this._rgbaUbytePixels = new Uint8Array(ClippingPlaneCollection.TEXTURE_WIDTH * ClippingPlaneCollection.TEXTURE_WIDTH * 4); } function unionIntersectFunction(value) { @@ -235,50 +264,96 @@ define([ this._planes = []; }; - var scratchPlane = new Plane(Cartesian3.UNIT_X, 0.0); - var scratchMatrix = new Matrix4(); + // See Aras Pranckevičius' post Encoding Floats to RGBA + // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ + var floatEncode = new Cartesian4(1.0, 255.0, 65025.0, 16581375.0); + function packNormalizedFloat(float, result) { + Cartesian4.multiplyByScalar(floatEncode, float, result); + result.x = result.x - Math.floor(result.x); + result.y = result.y - Math.floor(result.y); + result.z = result.z - Math.floor(result.z); + result.w = result.w - Math.floor(result.w); + + result.x -= result.y / 255.0; + result.y -= result.z / 255.0; + result.z -= result.w / 255.0; + + return result; + } + + var encodingScratch = new Cartesian4(); + function insertFloat(uint8Buffer, float, byteIndex) { + packNormalizedFloat(float, encodingScratch); + uint8Buffer[byteIndex] = encodingScratch.x * 255; + uint8Buffer[byteIndex + 1] = encodingScratch.y * 255; + uint8Buffer[byteIndex + 2] = encodingScratch.z * 255; + uint8Buffer[byteIndex + 3] = encodingScratch.w * 255; + } + + var octEncodeScratch = new Cartesian2(); + var rightShift = 1.0 / 256; /** - * Applies the transformations to each plane and packs it into an array. + * Encodes a normalized vector into 4 SNORM values in the range [0-255] following the 'oct' encoding. + */ + function oct32EncodeNormal(vector, result) { + AttributeCompression.octEncodeInRange(vector, 65535, octEncodeScratch); + result.x = octEncodeScratch.x * rightShift; + result.y = octEncodeScratch.x; + result.z = octEncodeScratch.y * rightShift; + result.w = octEncodeScratch.y; + return result; + } + + var oct32EncodeScratch = new Cartesian4(); + /** + * Applies the transformations to each plane and packs it into a typed array for transfer to a texture. * @private * - * @param {Matrix4} viewMatrix The 4x4 matrix to transform the plane into eyespace. - * @param {Cartesian4[]} [array] The array into which the planes will be packed. - * @returns {Cartesian4[]} The array of packed planes. + * @returns {Uint8Array} Typed Array representing the clipping planes packed to a RGBA Uint8 texture. */ - ClippingPlaneCollection.prototype.transformAndPackPlanes = function(viewMatrix, array) { - //>>includeStart('debug', pragmas.debug); - Check.typeOf.object('viewMatrix', viewMatrix); - //>>includeEnd('debug'); + ClippingPlaneCollection.prototype.transformAndPackPlanes = function() { + var rgbaUbytePixels = this._rgbaUbytePixels; var planes = this._planes; var length = planes.length; + var distances = new Array(length); - var index = 0; - if (!defined(array)) { - array = new Array(length); - } else { - index = array.length; - array.length = length; - } - + // Transform all planes, recording the directions in the typed array and computing the range for the planes + var distanceMin = Number.POSITIVE_INFINITY; + var distanceMax = Number.NEGATIVE_INFINITY; var i; - for (i = index; i < length; ++i) { - array[i] = new Cartesian4(); - } - - var transform = Matrix4.multiply(viewMatrix, this.modelMatrix, scratchMatrix); - for (i = 0; i < length; ++i) { var plane = planes[i]; - var packedPlane = array[i]; - Plane.transform(plane, transform, scratchPlane); + var byteIndex = i * 8; + + var oct32Normal = oct32EncodeNormal(plane.normal, oct32EncodeScratch); + rgbaUbytePixels[byteIndex] = oct32Normal.x; + rgbaUbytePixels[byteIndex + 1] = oct32Normal.y; + rgbaUbytePixels[byteIndex + 2] = oct32Normal.z; + rgbaUbytePixels[byteIndex + 3] = oct32Normal.w; - Cartesian3.clone(scratchPlane.normal, packedPlane); - packedPlane.w = scratchPlane.distance; + var distance = plane.distance; + distanceMin = Math.min(distance, distanceMin); + distanceMax = Math.max(distance, distanceMax); + distances[i] = distance; } - return array; + // expand distance range a little bit to prevent packing 1s + distanceMax += (distanceMax - distanceMin) * CesiumMath.EPSILON3; + + // Normalize all the distances to the range and record them in the typed array. + var distanceRange = this.distanceRange; + distanceRange.x = distanceMin; + distanceRange.y = distanceMax; + var distanceRangeSize = distanceMax - distanceMin; + for (i = 0; i < length; ++i) { + var normalizedDistance = (distances[i] - distanceMin) / distanceRangeSize; + var byteIndex = i * 8 + 4; + insertFloat(rgbaUbytePixels, normalizedDistance, byteIndex); + } + + return rgbaUbytePixels; }; /** @@ -317,6 +392,8 @@ define([ return result; }; + var scratchMatrix = new Matrix4(); + var scratchPlane = new Plane(Cartesian3.UNIT_X, 0.0); /** * Determines the type intersection with the planes of this ClippingPlaneCollection instance and the specified {@link BoundingVolume}. * @private @@ -365,10 +442,38 @@ define([ /** * The maximum number of supported clipping planes. * + * @see maxClippingPlanes.glsl + * @type {number} + * @constant + */ + ClippingPlaneCollection.MAX_CLIPPING_PLANES = 128; + + /** + * The pixel width of a square, power-of-two RGBA UNSIGNED_BYTE texture + * with enough pixels to support MAX_CLIPPING_PLANES. + * + * A plane is a float in [0, 1) packed to RGBA and an Oct32 quantized normal, so 8 bits or 2 pixels in RGBA + * * @type {number} * @constant */ - ClippingPlaneCollection.MAX_CLIPPING_PLANES = 6; + ClippingPlaneCollection.TEXTURE_WIDTH = CesiumMath.nextPowerOfTwo(Math.ceil(Math.sqrt(ClippingPlaneCollection.MAX_CLIPPING_PLANES * 2))); + + ClippingPlaneCollection.getTextureParameters = function(context) { + return { + context : context, + width : ClippingPlaneCollection.TEXTURE_WIDTH, + height : ClippingPlaneCollection.TEXTURE_WIDTH, + pixelFormat : PixelFormat.RGBA, + pixelDatatype : PixelDatatype.UNSIGNED_BYTE, + sampler : new Sampler({ + wrapS : TextureWrap.CLAMP_TO_EDGE, + wrapT : TextureWrap.CLAMP_TO_EDGE, + minificationFilter : TextureMinificationFilter.NEAREST, + magnificationFilter : TextureMagnificationFilter.NEAREST + }) + } + } return ClippingPlaneCollection; }); diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index 59678a227458..5a316c97f144 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -5,6 +5,7 @@ define([ '../Core/Cartesian4', '../Core/Cartographic', '../Core/clone', + '../Core/ClippingPlaneCollection', '../Core/Color', '../Core/combine', '../Core/defaultValue', @@ -82,6 +83,7 @@ define([ Cartesian4, Cartographic, clone, + ClippingPlaneCollection, Color, combine, defaultValue, @@ -706,7 +708,7 @@ define([ this._rtcCenter3D = undefined; // in world coordinates this._rtcCenter2D = undefined; // in projected world coordinates - this._packedClippingPlanes = []; + this._packedClippingPlanes = undefined; // texture of clipping planes } defineProperties(Model.prototype, { @@ -3319,31 +3321,49 @@ define([ function createClippingPlanesLengthFunction(model) { return function() { - return model._packedClippingPlanes.length; + var clippingPlanes = model.clippingPlanes; + if (!defined(clippingPlanes)) { + return 0; + } + return clippingPlanes.length; }; } - function createClippingPlanesUnionRegionsFunction(model) { + var scratchClippingPlaneMatrix = new Matrix4(); + function createClippingPlanesMatrixFunction(model) { return function() { var clippingPlanes = model.clippingPlanes; if (!defined(clippingPlanes)) { - return false; + return Matrix4.IDENTITY; } - - return clippingPlanes.unionClippingRegions; + return Matrix4.multiply(model._modelViewMatrix, clippingPlanes.modelMatrix, scratchClippingPlaneMatrix) }; } function createClippingPlanesFunction(model) { + return function() { + return model._packedClippingPlanes; + }; + } + + function createClippingPlanesRangeFunction(model) { return function() { var clippingPlanes = model.clippingPlanes; - var packedPlanes = model._packedClippingPlanes; + if (!defined(clippingPlanes)) { + return Cartesian2.ZERO; + } + return clippingPlanes.distanceRange; + }; + } - if (defined(clippingPlanes) && clippingPlanes.enabled) { - clippingPlanes.transformAndPackPlanes(model._modelViewMatrix, packedPlanes); + function createClippingPlanesUnionRegionsFunction(model) { + return function() { + var clippingPlanes = model.clippingPlanes; + if (!defined(clippingPlanes)) { + return false; } - return packedPlanes; + return clippingPlanes.unionClippingRegions; }; } @@ -3457,8 +3477,10 @@ define([ gltf_colorBlend : createColorBlendFunction(model), gltf_clippingPlanesLength: createClippingPlanesLengthFunction(model), gltf_clippingPlanesUnionRegions: createClippingPlanesUnionRegionsFunction(model), - gltf_clippingPlanes: createClippingPlanesFunction(model, context), - gltf_clippingPlanesEdgeStyle: createClippingPlanesEdgeStyleFunction(model) + gltf_clippingPlanes: createClippingPlanesFunction(model), + gltf_clippingPlanesRange: createClippingPlanesRangeFunction(model), + gltf_clippingPlanesEdgeStyle: createClippingPlanesEdgeStyleFunction(model), + gltf_clippingPlanesMatrix: createClippingPlanesMatrixFunction(model) }); // Allow callback to modify the uniformMap @@ -3751,6 +3773,8 @@ define([ createUniformMaps(model, context); // using glTF materials/techniques createRuntimeNodes(model, context, scene3DOnly); // using glTF scene + + model._packedClippingPlanes = new Texture(ClippingPlaneCollection.getTextureParameters(context)); } /////////////////////////////////////////////////////////////////////////// @@ -4255,10 +4279,13 @@ define([ function modifyShaderForClippingPlanes(shader) { shader = ShaderSource.replaceMain(shader, 'gltf_clip_main'); shader += + '#define PLANES_TEXTURE_WIDTH ' + ClippingPlaneCollection.TEXTURE_WIDTH + '\n' + 'uniform int gltf_clippingPlanesLength; \n' + 'uniform bool gltf_clippingPlanesUnionRegions; \n' + - 'uniform vec4 gltf_clippingPlanes[czm_maxClippingPlanes]; \n' + + 'uniform sampler2D gltf_clippingPlanes; \n' + + 'uniform vec2 gltf_clippingPlanesRange; \n' + 'uniform vec4 gltf_clippingPlanesEdgeStyle; \n' + + 'uniform mat4 gltf_clippingPlanesMatrix; \n' + 'void main() \n' + '{ \n' + ' gltf_clip_main(); \n' + @@ -4267,11 +4294,11 @@ define([ ' float clipDistance; \n' + ' if (gltf_clippingPlanesUnionRegions) \n' + ' { \n' + - ' clipDistance = czm_discardIfClippedWithUnion(gltf_clippingPlanes, gltf_clippingPlanesLength); \n' + + ' clipDistance = czm_discardIfClippedWithUnion(gltf_clippingPlanes, gltf_clippingPlanesLength, gltf_clippingPlanesRange, PLANES_TEXTURE_WIDTH, gltf_clippingPlanesMatrix); \n' + ' } \n' + ' else \n' + ' { \n' + - ' clipDistance = czm_discardIfClippedWithIntersect(gltf_clippingPlanes, gltf_clippingPlanesLength); \n' + + ' clipDistance = czm_discardIfClippedWithIntersect(gltf_clippingPlanes, gltf_clippingPlanesLength, gltf_clippingPlanesRange, PLANES_TEXTURE_WIDTH, gltf_clippingPlanesMatrix); \n' + ' } \n' + ' \n' + ' vec4 clippingPlanesEdgeColor = vec4(1.0); \n' + @@ -4279,7 +4306,7 @@ define([ ' float clippingPlanesEdgeWidth = gltf_clippingPlanesEdgeStyle.a; \n' + ' if (clipDistance > 0.0 && clipDistance < clippingPlanesEdgeWidth) \n' + ' { \n' + - ' gl_FragColor = clippingPlanesEdgeColor; \n' + + ' gl_FragColor = clippingPlanesEdgeColor;\n' + ' } \n' + ' } \n' + '} \n'; @@ -4311,19 +4338,12 @@ define([ function updateClippingPlanes(model) { var clippingPlanes = model.clippingPlanes; - var length = 0; if (defined(clippingPlanes) && clippingPlanes.enabled) { - length = clippingPlanes.length; - } - - var packedPlanes = model._packedClippingPlanes; - var packedLength = packedPlanes.length; - if (packedLength !== length) { - packedPlanes.length = length; - - for (var i = packedLength; i < length; ++i) { - packedPlanes[i] = new Cartesian4(); - } + model._packedClippingPlanes.copyFrom({ + width : ClippingPlaneCollection.TEXTURE_WIDTH, + height : ClippingPlaneCollection.TEXTURE_WIDTH, + arrayBufferView : clippingPlanes.transformAndPackPlanes() + }); } } @@ -4796,7 +4816,7 @@ define([ updateShadows(this); updateColor(this, frameState); updateSilhouette(this, frameState); - updateClippingPlanes(this, frameState); + updateClippingPlanes(this); } if (justLoaded) { @@ -4934,6 +4954,8 @@ define([ releaseCachedGltf(this); + this._packedClippingPlanes.destroy(); + return destroyObject(this); }; diff --git a/Source/Shaders/Builtin/Constants/maxClippingPlanes.glsl b/Source/Shaders/Builtin/Constants/maxClippingPlanes.glsl index 30c377df1668..f09ae838587d 100644 --- a/Source/Shaders/Builtin/Constants/maxClippingPlanes.glsl +++ b/Source/Shaders/Builtin/Constants/maxClippingPlanes.glsl @@ -5,4 +5,4 @@ * @glslConstant * @see czm_clipPlanes */ -const int czm_maxClippingPlanes = 6; +const int czm_maxClippingPlanes = 128; diff --git a/Source/Shaders/Builtin/Functions/discardIfClippedWithIntersect.glsl b/Source/Shaders/Builtin/Functions/discardIfClippedWithIntersect.glsl index 987dd8d354c8..36146573cbec 100644 --- a/Source/Shaders/Builtin/Functions/discardIfClippedWithIntersect.glsl +++ b/Source/Shaders/Builtin/Functions/discardIfClippedWithIntersect.glsl @@ -9,7 +9,7 @@ * @param {int} clippingPlanesLength The number of planes in the array of clipping planes. * @returns {float} The distance away from a clipped fragment, in eyespace */ -float czm_discardIfClippedWithIntersect(vec4 clippingPlanes[czm_maxClippingPlanes], int clippingPlanesLength) +float czm_discardIfClippedWithIntersect(sampler2D clippingPlanes, int clippingPlanesLength, vec2 range, int textureWidth, mat4 clippingPlanesMatrix) { if (clippingPlanesLength > 0) { @@ -27,8 +27,12 @@ float czm_discardIfClippedWithIntersect(vec4 clippingPlanes[czm_maxClippingPlane break; } - clipNormal = clippingPlanes[i].xyz; - clipPosition = -clippingPlanes[i].w * clipNormal; + vec4 clippingPlane = czm_getClippingPlaneFromTexture(clippingPlanes, range, i, textureWidth, clippingPlanesMatrix); + //clipNormal = normalize((czm_modelView * vec4(0.99999999995, 0.000009999999999833334, 0, 0.0)).xyz); + clipNormal = clippingPlane.xyz; + + //clipPosition = -range.x * clipNormal; + clipPosition = -clippingPlane.w * clipNormal; float amount = dot(clipNormal, (position.xyz - clipPosition)) / pixelWidth; clipAmount = max(amount, clipAmount); diff --git a/Source/Shaders/Builtin/Functions/discardIfClippedWithUnion.glsl b/Source/Shaders/Builtin/Functions/discardIfClippedWithUnion.glsl index ae6110f8346f..367d54cb3dd6 100644 --- a/Source/Shaders/Builtin/Functions/discardIfClippedWithUnion.glsl +++ b/Source/Shaders/Builtin/Functions/discardIfClippedWithUnion.glsl @@ -9,7 +9,7 @@ * @param {int} clippingPlanesLength The number of planes in the array of clipping planes. * @returns {float} The distance away from a clipped fragment, in eyespace */ -float czm_discardIfClippedWithUnion(vec4 clippingPlanes[czm_maxClippingPlanes], int clippingPlanesLength) +float czm_discardIfClippedWithUnion(sampler2D clippingPlanes, int clippingPlanesLength, vec2 range, int textureWidth, mat4 clippingPlanesMatrix) { if (clippingPlanesLength > 0) { @@ -26,8 +26,10 @@ float czm_discardIfClippedWithUnion(vec4 clippingPlanes[czm_maxClippingPlanes], break; } - clipNormal = clippingPlanes[i].xyz; - clipPosition = -clippingPlanes[i].w * clipNormal; + vec4 clippingPlane = czm_getClippingPlaneFromTexture(clippingPlanes, range, i, textureWidth, clippingPlanesMatrix); + + clipNormal = clippingPlane.xyz; + clipPosition = -clippingPlane.w * clipNormal; float amount = dot(clipNormal, (position.xyz - clipPosition)) / pixelWidth; clipAmount = max(amount, clipAmount); diff --git a/Source/Shaders/Builtin/Functions/getClippingPlaneFromTexture.glsl b/Source/Shaders/Builtin/Functions/getClippingPlaneFromTexture.glsl new file mode 100644 index 000000000000..54cb1efc32e6 --- /dev/null +++ b/Source/Shaders/Builtin/Functions/getClippingPlaneFromTexture.glsl @@ -0,0 +1,28 @@ +vec4 transformPlane(mat4 transform, vec4 clippingPlane) { + vec3 transformedDirection = normalize((transform * vec4(clippingPlane.xyz, 0.0)).xyz); + vec3 transformedPosition = (transform * vec4(clippingPlane.xyz * -clippingPlane.w, 1.0)).xyz; + vec4 transformedPlane; + transformedPlane.xyz = transformedDirection; + transformedPlane.w = -dot(transformedDirection, transformedPosition); + return transformedPlane; +} + +vec4 czm_getClippingPlaneFromTexture(sampler2D packedClippingPlanes, vec2 range, int clippingPlaneNumber, int textureWidth, mat4 transform) +{ + int clippingPlaneStartIndex = clippingPlaneNumber * 2; // clipping planes are two pixels each + int pixY = clippingPlaneStartIndex / textureWidth; + int pixX = clippingPlaneStartIndex - (pixY * textureWidth); + pixY = textureWidth - pixY; // flipped relative to texture + float pixelWidth = 1.0 / float(textureWidth); + float u = (float(pixX) + 0.5) * pixelWidth; // sample from center of pixel + float v = (float(pixY) - 0.5) * pixelWidth; + + vec4 oct32 = texture2D(packedClippingPlanes, vec2(u, v)) * 255.0; + vec2 oct = vec2(oct32.x * 256.0 + oct32.y, oct32.z * 256.0 + oct32.w); + + vec4 plane; + plane.xyz = czm_octDecode(oct, 65535.0); + plane.w = czm_unpackDepth(texture2D(packedClippingPlanes, vec2(u + pixelWidth, v))) * (range.y - range.x) + range.x; + + return transformPlane(transform, plane); +} diff --git a/Source/Shaders/Builtin/Functions/octDecode.glsl b/Source/Shaders/Builtin/Functions/octDecode.glsl index ce4df362da12..98b2736f706a 100644 --- a/Source/Shaders/Builtin/Functions/octDecode.glsl +++ b/Source/Shaders/Builtin/Functions/octDecode.glsl @@ -28,7 +28,7 @@ * Decodes a unit-length vector in 'oct' encoding to a normalized 3-component Cartesian vector. * The 'oct' encoding is described in "A Survey of Efficient Representations of Independent Unit Vectors", * Cigolle et al 2014: http://jcgt.org/published/0003/02/01/ - * + * * @name czm_octDecode * @param {vec2} encoded The oct-encoded, unit-length vector * @returns {vec3} The decoded and normalized vector @@ -42,7 +42,7 @@ * Decodes a unit-length vector in 'oct' encoding packed into a floating-point number to a normalized 3-component Cartesian vector. * The 'oct' encoding is described in "A Survey of Efficient Representations of Independent Unit Vectors", * Cigolle et al 2014: http://jcgt.org/published/0003/02/01/ - * + * * @name czm_octDecode * @param {float} encoded The oct-encoded, unit-length vector * @returns {vec3} The decoded and normalized vector @@ -54,12 +54,12 @@ float y = (temp - x) * 256.0; return czm_octDecode(vec2(x, y)); } - + /** * Decodes three unit-length vectors in 'oct' encoding packed into two floating-point numbers to normalized 3-component Cartesian vectors. * The 'oct' encoding is described in "A Survey of Efficient Representations of Independent Unit Vectors", * Cigolle et al 2014: http://jcgt.org/published/0003/02/01/ - * + * * @name czm_octDecode * @param {vec2} encoded The packed oct-encoded, unit-length vectors. * @param {vec3} vector1 One decoded and normalized vector. @@ -80,4 +80,4 @@ vector2 = czm_octDecode(encodedFloat2); vector3 = czm_octDecode(vec2(x, y)); } - + From 44a266295134b88c3d3dadf0d1bba3ece61d2136 Mon Sep 17 00:00:00 2001 From: Kangning Li Date: Thu, 1 Feb 2018 16:51:22 -0500 Subject: [PATCH 02/72] proof-of-concept for sharing ClippingPlaneCollections over b3dm tilesets and update-as-needed --- Apps/Sandcastle/gallery/clipping circle.html | 223 ++++++++++-------- Source/Core/ClippingPlaneCollection.js | 179 ++++++++++++-- Source/Scene/Batched3DModel3DTileContent.js | 15 +- Source/Scene/Cesium3DTileset.js | 19 ++ Source/Scene/Model.js | 26 +- .../Builtin/Constants/maxClippingPlanes.glsl | 2 +- 6 files changed, 320 insertions(+), 144 deletions(-) diff --git a/Apps/Sandcastle/gallery/clipping circle.html b/Apps/Sandcastle/gallery/clipping circle.html index efe777c08ead..3f3d2b549048 100644 --- a/Apps/Sandcastle/gallery/clipping circle.html +++ b/Apps/Sandcastle/gallery/clipping circle.html @@ -24,7 +24,18 @@

Loading...

-
+
+ + + + + +
Spiral Size + + +
+ +
+ + + + + +
+

Loading...

+
+ + + + From f4a12860f4c5880456c1538209f1d61a1c11877f Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Sat, 10 Mar 2018 13:27:25 -0500 Subject: [PATCH 68/72] Update Sandcastle tags, thumbnail, and CHANGES.md --- Apps/Sandcastle/gallery/Multi-part CZML.html | 4 ++-- Apps/Sandcastle/gallery/Multi-part CZML.jpg | Bin 0 -> 17633 bytes CHANGES.md | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 Apps/Sandcastle/gallery/Multi-part CZML.jpg diff --git a/Apps/Sandcastle/gallery/Multi-part CZML.html b/Apps/Sandcastle/gallery/Multi-part CZML.html index cc5d642fed5a..373a1ddb2441 100644 --- a/Apps/Sandcastle/gallery/Multi-part CZML.html +++ b/Apps/Sandcastle/gallery/Multi-part CZML.html @@ -4,8 +4,8 @@ - - + + Cesium Demo diff --git a/Apps/Sandcastle/gallery/Multi-part CZML.jpg b/Apps/Sandcastle/gallery/Multi-part CZML.jpg new file mode 100644 index 0000000000000000000000000000000000000000..edecb392ff3988e3e260fc740a2f1e808e06d15c GIT binary patch literal 17633 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 J5GVcu|Jf4ZK1Tom literal 0 HcmV?d00001 diff --git a/CHANGES.md b/CHANGES.md index 538530a211a1..9bbaa229c836 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,14 +13,13 @@ Change Log * Removed the 6-clipping-plane limit. * Added support for Internet Explorer. * Added a `ClippingPlane` object to be used with `ClippingPlaneCollection`. +* Updated `WebMapServiceImageryProvider` so it can take an srs or crs string to pass to the resource query parameters based on the WMS version. [#6223](https://github.com/AnalyticalGraphicsInc/cesium/issues/6223) +* Added a multi-part CZML example to Sandcastle. [#6320](https://github.com/AnalyticalGraphicsInc/cesium/pull/6320) ##### Fixes :wrench: * Fixed support of glTF-supplied tangent vectors. [#6302](https://github.com/AnalyticalGraphicsInc/cesium/pull/6302) * Fixed improper zoom during model load failure. [#6305](https://github.com/AnalyticalGraphicsInc/cesium/pull/6305) -#### Additions :tada: -* Updated `WebMapServiceImageryProvider` so it can take an srs or crs string to pass to the resource query parameters based on the WMS version. [#6223](https://github.com/AnalyticalGraphicsInc/cesium/issues/6223) - ### 1.43 - 2018-03-01 ##### Major Announcements :loudspeaker: From cc6cc9a9ea7d245be521910f1eccc559eff278cc Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Sat, 10 Mar 2018 13:43:35 -0500 Subject: [PATCH 69/72] Tweak comment, remove unused variable. --- Apps/Sandcastle/gallery/Multi-part CZML.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Apps/Sandcastle/gallery/Multi-part CZML.html b/Apps/Sandcastle/gallery/Multi-part CZML.html index 373a1ddb2441..87623ab4787c 100644 --- a/Apps/Sandcastle/gallery/Multi-part CZML.html +++ b/Apps/Sandcastle/gallery/Multi-part CZML.html @@ -96,12 +96,12 @@ var timeOffset = Cesium.JulianDate.secondsDifference(clock.currentTime, clock.startTime); // Filter the list of parts to just the ones that need loading right now. - var partToLoad = partsToLoad.filter(function(part) { + // Then, process each part that needs loading. + partsToLoad.filter(function(part) { return (!part.requested) && (timeOffset >= part.range[0] - preloadTimeInSeconds) && (timeOffset <= part.range[1]); }).forEach(function(part) { - // Process each part that needs loading. processPart(part); }); }); From 4dec77f6351199afe7491926a81fb8249e4d4094 Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Sat, 10 Mar 2018 15:28:52 -0500 Subject: [PATCH 70/72] Replace billboard with 3D model. --- Apps/SampleData/MultipartVehicle_part1.czml | 39 +++++++------------- Apps/Sandcastle/gallery/Multi-part CZML.html | 13 +++---- 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/Apps/SampleData/MultipartVehicle_part1.czml b/Apps/SampleData/MultipartVehicle_part1.czml index 0c9de17919b3..46fa36d22f68 100644 --- a/Apps/SampleData/MultipartVehicle_part1.czml +++ b/Apps/SampleData/MultipartVehicle_part1.czml @@ -6,28 +6,6 @@ { "id":"Vehicle", "availability":"2012-08-04T16:00:00Z/2012-08-04T17:04:54.9962195740191Z", - "billboard":{ - "eyeOffset":{ - "cartesian":[ - 0.0,0.0,0.0 - ] - }, - "horizontalOrigin":"CENTER", - "image":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEISURBVEhLvVXBDYQwDOuojHKj8LhBbpTbpBCEkZsmIVTXq1RVQGrHiWlLmTTqPiZBlyLgy/KSZQ5JSHDQ/mCYCsC8106kDU0AdwRnvYZArWRcAl0dcYJq1hWCb3hBrumbDAVMwAC82WoRvgMnVMDBnB0nYZFTbE6BBvdUGqVqCbjBIk3PyFFR/NU7EKzru+qZsau3ryPwwCRLKYOzutZuCL6fUmWeJGzNzL/RxAMrUmASSCkkAayk2IxPlwhAAYGpsiHQjbLccfdOY5gKkCXAMi7SscAwbQpAnKyctWyUZ6z8ja3OGMepwD8asz+9FnSvbhU8uVOHFIwQsI3/p0CfhuqCSQuxLqsN6mu8SS+N42MAAAAASUVORK5CYII=", - "pixelOffset":{ - "cartesian2":[ - 0.0,0.0 - ] - }, - "scale":0.8333333333333334, - "show":[ - { - "interval":"2012-08-04T16:00:00Z/2012-08-04T18:00:00Z", - "boolean":true - } - ], - "verticalOrigin":"BOTTOM" - }, "label":{ "fillColor":[ { @@ -38,7 +16,7 @@ } ], "font":"bold 10pt Segoe UI Semibold", - "horizontalOrigin":"LEFT", + "horizontalOrigin":"CENTER", "outlineColor":{ "rgba":[ 0,0,0,255 @@ -46,7 +24,7 @@ }, "pixelOffset":{ "cartesian2":[ - 10.0,0.0 + 0.0,20.0 ] }, "scale":1.0, @@ -57,9 +35,20 @@ } ], "style":"FILL", - "text":"Vehicle", + "text":"Test Vehicle", "verticalOrigin":"CENTER" }, + "model":{ + "gltf":"models/CesiumMilkTruck/CesiumMilkTruck.glb", + "minimumPixelSize":100, + "maximumScale":50 + }, + "orientation" : { + "velocityReference": "#position" + }, + "viewFrom": { + "cartesian": [ -2080, -1715, 779 ] + }, "path":{ "material":{ "solidColor":{ diff --git a/Apps/Sandcastle/gallery/Multi-part CZML.html b/Apps/Sandcastle/gallery/Multi-part CZML.html index 87623ab4787c..d33a7bf6a730 100644 --- a/Apps/Sandcastle/gallery/Multi-part CZML.html +++ b/Apps/Sandcastle/gallery/Multi-part CZML.html @@ -81,6 +81,11 @@ dataSource.process(czmlPath + part.url).then(function() { part.loaded = true; updateStatusDisplay(); + + // Follow the vehicle with the camera. + if (!viewer.trackedEntity) { + viewer.trackedEntity = dataSource.entities.getById('Vehicle'); + } }); } @@ -106,14 +111,6 @@ }); }); -// Set the initial camera view. -viewer.scene.camera.setView({ - destination: Cesium.Cartesian3.fromDegrees(-116.52, 35.02, 95000), - orientation: { - heading: 6 - } -}); - // Add a reset button, for convenience. Sandcastle.addToolbarButton('Reset demo', function() { // Put things back to the starting position. From e7f60e8d7377072a03914d8bdcb4305c2ec6e12e Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Sat, 10 Mar 2018 15:45:34 -0500 Subject: [PATCH 71/72] Add a multi-part custom CZML property. --- Apps/SampleData/MultipartVehicle_part1.czml | 9 +++++++++ Apps/SampleData/MultipartVehicle_part2.czml | 8 ++++++++ Apps/SampleData/MultipartVehicle_part3.czml | 8 ++++++++ Apps/Sandcastle/gallery/Multi-part CZML.html | 17 ++++++++++++++++- 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/Apps/SampleData/MultipartVehicle_part1.czml b/Apps/SampleData/MultipartVehicle_part1.czml index 46fa36d22f68..c9f1d359fd37 100644 --- a/Apps/SampleData/MultipartVehicle_part1.czml +++ b/Apps/SampleData/MultipartVehicle_part1.czml @@ -49,6 +49,15 @@ "viewFrom": { "cartesian": [ -2080, -1715, 779 ] }, + "properties" : { + "fuel_remaining" : { + "epoch":"2012-08-04T16:00:00Z", + "number": [ + 0, 22.5, + 1500, 21.2 + ] + } + }, "path":{ "material":{ "solidColor":{ diff --git a/Apps/SampleData/MultipartVehicle_part2.czml b/Apps/SampleData/MultipartVehicle_part2.czml index 2d6ae6332a65..a1a7f69045b5 100644 --- a/Apps/SampleData/MultipartVehicle_part2.czml +++ b/Apps/SampleData/MultipartVehicle_part2.czml @@ -5,6 +5,14 @@ }, { "id":"Vehicle", + "properties" : { + "fuel_remaining" : { + "epoch":"2012-08-04T16:00:00Z", + "number": [ + 3000, 19.9 + ] + } + }, "position":{ "interpolationAlgorithm":"LAGRANGE", "interpolationDegree":1, diff --git a/Apps/SampleData/MultipartVehicle_part3.czml b/Apps/SampleData/MultipartVehicle_part3.czml index b139a9cab37b..610d6cb8ea15 100644 --- a/Apps/SampleData/MultipartVehicle_part3.czml +++ b/Apps/SampleData/MultipartVehicle_part3.czml @@ -5,6 +5,14 @@ }, { "id":"Vehicle", + "properties" : { + "fuel_remaining" : { + "epoch":"2012-08-04T16:00:00Z", + "number": [ + 4500, 18.6 + ] + } + }, "position":{ "interpolationAlgorithm":"LAGRANGE", "interpolationDegree":1, diff --git a/Apps/Sandcastle/gallery/Multi-part CZML.html b/Apps/Sandcastle/gallery/Multi-part CZML.html index d33a7bf6a730..68b80c6b1fa2 100644 --- a/Apps/Sandcastle/gallery/Multi-part CZML.html +++ b/Apps/Sandcastle/gallery/Multi-part CZML.html @@ -35,7 +35,9 @@ }); var statusDisplay = document.createElement('div'); +var fuelDisplay = document.createElement('div'); var czmlPath = '../../SampleData/'; +var vehicleEntity; // Add a blank CzmlDataSource to hold our multi-part entity/entities. var dataSource = new Cesium.CzmlDataSource(); @@ -84,7 +86,7 @@ // Follow the vehicle with the camera. if (!viewer.trackedEntity) { - viewer.trackedEntity = dataSource.entities.getById('Vehicle'); + viewer.trackedEntity = vehicleEntity = dataSource.entities.getById('Vehicle'); } }); } @@ -109,6 +111,13 @@ }).forEach(function(part) { processPart(part); }); + + if (vehicleEntity) { + var fuel = vehicleEntity.properties.fuel_remaining.getValue(clock.currentTime); + if (Cesium.defined(fuel)) { + fuelDisplay.textContent = 'Fuel: ' + fuel.toFixed(2) + ' gal'; + } + } }); // Add a reset button, for convenience. @@ -130,6 +139,12 @@ statusDisplay.style.background = 'rgba(42, 42, 42, 0.7)'; statusDisplay.style.padding = '5px 10px'; document.getElementById('toolbar').appendChild(statusDisplay); + +// Show a multi-part custom property being read from CZML. +fuelDisplay.style.background = 'rgba(42, 42, 42, 0.7)'; +fuelDisplay.style.padding = '5px 10px'; +fuelDisplay.style.marginTop = '5px'; +document.getElementById('toolbar').appendChild(fuelDisplay); //Sandcastle_End Sandcastle.finishedLoading(); } From ed3fad2abf374555209acf8bb9e95d5936fd02f6 Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Sat, 10 Mar 2018 15:52:55 -0500 Subject: [PATCH 72/72] Update thumbnail. --- Apps/Sandcastle/gallery/Multi-part CZML.jpg | Bin 17633 -> 17375 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Apps/Sandcastle/gallery/Multi-part CZML.jpg b/Apps/Sandcastle/gallery/Multi-part CZML.jpg index edecb392ff3988e3e260fc740a2f1e808e06d15c..f02df208e50cd406c7ccca68b7f16681ffbe7d16 100644 GIT binary patch literal 17375 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 J5GVcu|Jf4ZK1Tom