From 19f3ff90babde8ec00081f0f33f152c428b41a6f Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Thu, 16 Apr 2015 15:22:22 -0400 Subject: [PATCH 01/40] Clamp billboards to ground WIP. --- Source/Scene/BillboardCollection.js | 30 +++++++++ Source/Shaders/BillboardCollectionVS.glsl | 82 ++++++++++++++++------- 2 files changed, 87 insertions(+), 25 deletions(-) diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 9a1975acc216..f0eea0c5fd67 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -15,6 +15,8 @@ define([ '../Core/IndexDatatype', '../Core/Math', '../Core/Matrix4', + '../Core/Ray', + '../Core/Rectangle', '../Renderer/BufferUsage', '../Renderer/DrawCommand', '../Renderer/ShaderSource', @@ -43,6 +45,8 @@ define([ IndexDatatype, CesiumMath, Matrix4, + Ray, + Rectangle, BufferUsage, DrawCommand, ShaderSource, @@ -1020,6 +1024,26 @@ define([ var billboards = this._billboards; var billboardsLength = billboards.length; + var globe = this._globe; + if (defined(globe)) { + var ellipsoid = globe.ellipsoid; + var surface = globe._surface; + surface.forEachRenderedTile(function(tile) { + for (var i = 0; i < billboards.length; ++i) { + var billboard = billboards[i]; + var position = billboard.position; + var level = defaultValue(billboard.level, 0.0); + var positionCartographic = ellipsoid.cartesianToCartographic(position); + if (level < tile.level && Rectangle.contains(tile.rectangle, positionCartographic)) { + var ray = new Ray(); + Cartesian3.normalize(position, ray.direction); + billboard.position = tile.data.pick(ray, undefined, false, new Cartesian3()); + billboard.level = tile.level; + } + } + }); + } + var textureAtlas = this._textureAtlas; if (!defined(textureAtlas)) { textureAtlas = this._textureAtlas = new TextureAtlas({ @@ -1218,6 +1242,9 @@ define([ if (this._shaderPixelOffsetScaleByDistance) { vs.defines.push('EYE_DISTANCE_PIXEL_OFFSET'); } + if (defined(this._globe)) { + vs.defines.push('TEST_GLOBE_DEPTH'); + } this._sp = context.replaceShaderProgram(this._sp, vs, BillboardCollectionFS, attributeLocations); this._compiledShaderRotation = this._shaderRotation; @@ -1283,6 +1310,9 @@ define([ if (this._shaderPixelOffsetScaleByDistance) { vs.defines.push('EYE_DISTANCE_PIXEL_OFFSET'); } + if (defined(this._globe)) { + vs.defines.push('TEST_GLOBE_DEPTH'); + } fs = new ShaderSource({ defines : ['RENDER_FOR_PICK'], diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index b80ec03d20c0..43257679d253 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -46,6 +46,42 @@ const float SHIFT_RIGHT3 = 1.0 / 8.0; const float SHIFT_RIGHT2 = 1.0 / 4.0; const float SHIFT_RIGHT1 = 1.0 / 2.0; +vec4 computePositionWindowCoordinates(vec4 positionEC, vec2 imageSize, float scale, vec2 direction, vec2 origin, vec2 translate, vec2 pixelOffset, vec3 alignedAxis, float rotation) +{ + vec4 positionWC = czm_eyeToWindowCoordinates(positionEC); + + vec2 halfSize = imageSize * scale * czm_resolutionScale; + halfSize *= ((direction * 2.0) - 1.0); + + positionWC.xy += (origin * abs(halfSize)); + +#if defined(ROTATION) || defined(ALIGNED_AXIS) + if (!all(equal(alignedAxis, vec3(0.0))) || rotation != 0.0) + { + float angle = rotation; + if (!all(equal(alignedAxis, vec3(0.0)))) + { + vec3 pos = positionEC.xyz + czm_encodedCameraPositionMCHigh + czm_encodedCameraPositionMCLow; + vec3 normal = normalize(cross(alignedAxis, pos)); + vec4 tangent = vec4(normalize(cross(pos, normal)), 0.0); + tangent = czm_modelViewProjection * tangent; + angle += sign(-tangent.x) * acos(tangent.y / length(tangent.xy)); + } + + float cosTheta = cos(angle); + float sinTheta = sin(angle); + mat2 rotationMatrix = mat2(cosTheta, sinTheta, -sinTheta, cosTheta); + halfSize = rotationMatrix * halfSize; + } +#endif + + positionWC.xy += halfSize; + positionWC.xy += translate; + positionWC.xy += (pixelOffset * czm_resolutionScale); + + return positionWC; +} + void main() { // Modifying this shader may also require modifications to Billboard._computeScreenSpacePosition @@ -57,6 +93,8 @@ void main() #if defined(ROTATION) || defined(ALIGNED_AXIS) float rotation = positionLowAndRotation.w; +#else + float rotation = 0.0; #endif float compressed = compressedAttribute0.x; @@ -186,38 +224,32 @@ void main() float pixelOffsetScale = getNearFarScalar(pixelOffsetScaleByDistance, lengthSq); pixelOffset *= pixelOffsetScale; #endif - - vec4 positionWC = czm_eyeToWindowCoordinates(positionEC); - - vec2 halfSize = imageSize * scale * czm_resolutionScale; - halfSize *= ((direction * 2.0) - 1.0); - positionWC.xy += (origin * abs(halfSize)); +#ifdef TEST_GLOBE_DEPTH + vec2 directions[4]; + directions[0] = vec2(0.0, 0.0); + directions[1] = vec2(0.0, 1.0); + directions[2] = vec2(1.0, 1.0); + directions[3] = vec2(1.0, 0.0); -#if defined(ROTATION) || defined(ALIGNED_AXIS) - if (!all(equal(alignedAxis, vec3(0.0))) || rotation != 0.0) + bool visible = false; + for (int i = 0; i < 4; ++i) { - float angle = rotation; - if (!all(equal(alignedAxis, vec3(0.0)))) - { - vec3 pos = positionEC.xyz + czm_encodedCameraPositionMCHigh + czm_encodedCameraPositionMCLow; - vec3 normal = normalize(cross(alignedAxis, pos)); - vec4 tangent = vec4(normalize(cross(pos, normal)), 0.0); - tangent = czm_modelViewProjection * tangent; - angle += sign(-tangent.x) * acos(tangent.y / length(tangent.xy)); + vec4 p = computePositionWindowCoordinates(positionEC, imageSize, scale, directions[i], origin, translate, pixelOffset, alignedAxis, rotation); + float d = texture2D(czm_globeDepthTexture, p.xy / czm_viewport.zw).r; + if (p.z <= d) { + visible = true; + break; } - - float cosTheta = cos(angle); - float sinTheta = sin(angle); - mat2 rotationMatrix = mat2(cosTheta, sinTheta, -sinTheta, cosTheta); - halfSize = rotationMatrix * halfSize; + } + + if (!visible) { + gl_Position = czm_projection * vec4(vec3(0.0), 1.0); + return; } #endif - positionWC.xy += halfSize; - positionWC.xy += translate; - positionWC.xy += (pixelOffset * czm_resolutionScale); - + vec4 positionWC = computePositionWindowCoordinates(positionEC, imageSize, scale, direction, origin, translate, pixelOffset, alignedAxis, rotation); gl_Position = czm_viewportOrthographic * vec4(positionWC.xy, -positionWC.z, 1.0); v_textureCoordinates = textureCoordinates; From 45265e3de4550f468008dd8e180e62f4b20391f1 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Thu, 16 Apr 2015 17:28:07 -0400 Subject: [PATCH 02/40] Hook up callbacks when loading tiles in the quadtree. Billboards on terrain WIP. --- Source/Scene/BillboardCollection.js | 37 +++++++++++------------- Source/Scene/GlobeSurfaceTileProvider.js | 6 ++++ Source/Scene/QuadtreePrimitive.js | 35 +++++++++++++++++++++- Source/Scene/QuadtreeTile.js | 26 +++++++++++++++++ 4 files changed, 83 insertions(+), 21 deletions(-) diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index f0eea0c5fd67..dba5d8766e78 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -373,6 +373,23 @@ define([ this._billboards.push(b); this._createVertexArray = true; + var globe = this._globe; + if (defined(globe) && billboard.clampToTerrain) { + var ellipsoid = globe.ellipsoid; + var surface = globe._surface; + surface.addTileLoadedCallback({ + position : ellipsoid.cartesianToCartographic(b.position), + func : function (tile) { + if (tile !== b._currentTile) { + var ray = new Ray(); + Cartesian3.normalize(b.position, ray.direction); + b.position = tile.data.pick(ray, undefined, false, new Cartesian3()); + b._currentTile = tile; + } + } + }); + } + return b; }; @@ -1024,26 +1041,6 @@ define([ var billboards = this._billboards; var billboardsLength = billboards.length; - var globe = this._globe; - if (defined(globe)) { - var ellipsoid = globe.ellipsoid; - var surface = globe._surface; - surface.forEachRenderedTile(function(tile) { - for (var i = 0; i < billboards.length; ++i) { - var billboard = billboards[i]; - var position = billboard.position; - var level = defaultValue(billboard.level, 0.0); - var positionCartographic = ellipsoid.cartesianToCartographic(position); - if (level < tile.level && Rectangle.contains(tile.rectangle, positionCartographic)) { - var ray = new Ray(); - Cartesian3.normalize(position, ray.direction); - billboard.position = tile.data.pick(ray, undefined, false, new Cartesian3()); - billboard.level = tile.level; - } - } - }); - } - var textureAtlas = this._textureAtlas; if (!defined(textureAtlas)) { textureAtlas = this._textureAtlas = new TextureAtlas({ diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 8775a2b43645..69ce446360e2 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -464,6 +464,12 @@ define([ tileSet.push(tile); + var callbacks = tile.callbacks; + var length = callbacks.length; + for (var j = 0; j < length; ++j) { + callbacks[j].func(tile); + } + var debug = this._debug; ++debug.tilesRendered; debug.texturesRendered += readyTextureCount; diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index f82d8c43f29e..685a76c8f87c 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -6,6 +6,7 @@ define([ '../Core/DeveloperError', '../Core/getTimestamp', '../Core/Queue', + '../Core/Rectangle', '../Core/Visibility', './QuadtreeOccluders', './QuadtreeTile', @@ -19,6 +20,7 @@ define([ DeveloperError, getTimestamp, Queue, + Rectangle, Visibility, QuadtreeOccluders, QuadtreeTile, @@ -90,6 +92,9 @@ define([ this._levelZeroTilesReady = false; this._loadQueueTimeSlice = 5.0; + this._callbacksAdded = []; + this._callbacksRemoved = []; + /** * Gets or sets the maximum screen-space error, in pixels, that is allowed. * A higher maximum error will render fewer tiles and improve performance, while a lower @@ -182,6 +187,14 @@ define([ } }; + QuadtreePrimitive.prototype.addTileLoadedCallback = function(callback) { + this._callbacksAdded.push(callback); + }; + + QuadtreePrimitive.prototype.removeTileLoadedCallback = function(callback) { + this._callbacksRemoved.push(callback); + }; + /** * Updates the primitive. * @@ -247,6 +260,7 @@ define([ } var i; + var j; var len; // Clear the render list. @@ -282,9 +296,28 @@ define([ var occluders = primitive._occluders; var tile; + var levelZeroTiles = primitive._levelZeroTiles; + + var callbacksAdded = primitive._callbacksAdded; + var callbacksRemoved = primitive._callbacksRemoved; + var callback; + + if (callbacksAdded.length > 0) { + for (i = 0, len = levelZeroTiles.length; i < len; ++i) { + tile = levelZeroTiles[i]; + for (j = 0; j < callbacksAdded.length; ++j) { + callback = callbacksAdded[j]; + if (Rectangle.contains(tile.rectangle, callback.position)) { + tile.callbacks.push(callback); + } + } + } + callbacksAdded.length = 0; + } else if (callbacksRemoved.length > 0) { + // TODO + } // Enqueue the root tiles that are renderable and visible. - var levelZeroTiles = primitive._levelZeroTiles; for (i = 0, len = levelZeroTiles.length; i < len; ++i) { tile = levelZeroTiles[i]; primitive._tileReplacementQueue.markTileRendered(tile); diff --git a/Source/Scene/QuadtreeTile.js b/Source/Scene/QuadtreeTile.js index 283ac5cfb264..6d5ab7f71853 100644 --- a/Source/Scene/QuadtreeTile.js +++ b/Source/Scene/QuadtreeTile.js @@ -3,11 +3,13 @@ define([ '../Core/defined', '../Core/defineProperties', '../Core/DeveloperError', + '../Core/Rectangle', './QuadtreeTileLoadState' ], function( defined, defineProperties, DeveloperError, + Rectangle, QuadtreeTileLoadState) { "use strict"; @@ -62,6 +64,8 @@ define([ // QuadtreePrimitive gets/sets this private property. this._distance = 0.0; + this._callbacks = undefined; + /** * Gets or sets the current state of the tile in the tile load pipeline. * @type {QuadtreeTileLoadState} @@ -240,6 +244,28 @@ define([ } }, + callbacks : { + get : function() { + if (!defined(this._callbacks)) { + this._callbacks = []; + + var parent = this._parent; + if (defined(parent)) { + var parentCallbacks = parent.callbacks; + var length = parentCallbacks.length; + for (var i = 0; i < length; ++i) { + var parentCallback = parentCallbacks[i]; + if (Rectangle.contains(this._rectangle, parentCallback.position)) { + this._callbacks.push(parentCallback); + } + } + } + } + + return this._callbacks; + } + }, + /** * Gets a value indicating whether or not this tile needs further loading. * This property will return true if the {@link QuadtreeTile#state} is From db403b630a8cc4fcaef1261eb17d0c32ffe0f72f Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 17 Apr 2015 13:52:57 -0400 Subject: [PATCH 03/40] Update quadtree callbacks when billboards are added or removed. --- Source/Scene/QuadtreePrimitive.js | 15 ++---- Source/Scene/QuadtreeTile.js | 81 ++++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 23 deletions(-) diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index 685a76c8f87c..3cdcff71e591 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -300,21 +300,16 @@ define([ var callbacksAdded = primitive._callbacksAdded; var callbacksRemoved = primitive._callbacksRemoved; - var callback; - if (callbacksAdded.length > 0) { + if (callbacksAdded.length > 0 || callbacksRemoved.length > 0) { for (i = 0, len = levelZeroTiles.length; i < len; ++i) { tile = levelZeroTiles[i]; - for (j = 0; j < callbacksAdded.length; ++j) { - callback = callbacksAdded[j]; - if (Rectangle.contains(tile.rectangle, callback.position)) { - tile.callbacks.push(callback); - } - } + tile._makeDirty(); + tile._updateCallbacks(callbacksAdded, callbacksRemoved); } + callbacksAdded.length = 0; - } else if (callbacksRemoved.length > 0) { - // TODO + callbacksRemoved.length = 0; } // Enqueue the root tiles that are renderable and visible. diff --git a/Source/Scene/QuadtreeTile.js b/Source/Scene/QuadtreeTile.js index 6d5ab7f71853..588b215cafaf 100644 --- a/Source/Scene/QuadtreeTile.js +++ b/Source/Scene/QuadtreeTile.js @@ -65,6 +65,7 @@ define([ this._distance = 0.0; this._callbacks = undefined; + this._dirty = false; /** * Gets or sets the current state of the tile in the tile load pipeline. @@ -133,6 +134,54 @@ define([ return result; }; + QuadtreeTile.prototype._makeDirty = function() { + var stack = [this]; + + while (stack.length > 0) { + var tile = stack.pop(); + + var children = tile._children; + if (defined(children)) { + var length = children.length; + for (var i = 0; i < length; ++i) { + var child = children[i]; + if (!child._dirty) { + stack.push(child); + } + } + } + + tile._dirty = true; + } + }; + + QuadtreeTile.prototype._updateCallbacks = function(added, removed) { + var callbacks = this.callbacks; + + var i; + var callback; + + for (i = 0; i < removed.length; ++i) { + callback = removed[i]; + for (var j = 0; j < callbacks.length; ++j) { + if (callbacks[j] === callback) { + callbacks.splice(j, 1); + break; + } + } + } + + var rectangle = this._rectangle; + for (i = 0; i < added.length; ++i) { + callback = added[i]; + if (Rectangle.contains(rectangle, callback.position)) { + callbacks.push(callback); + } + } + + this._dirty = false; + }; + defineProperties(QuadtreeTile.prototype, { /** * Gets the tiling scheme used to tile the surface. @@ -246,23 +295,29 @@ define([ callbacks : { get : function() { - if (!defined(this._callbacks)) { - this._callbacks = []; - - var parent = this._parent; - if (defined(parent)) { - var parentCallbacks = parent.callbacks; - var length = parentCallbacks.length; - for (var i = 0; i < length; ++i) { - var parentCallback = parentCallbacks[i]; - if (Rectangle.contains(this._rectangle, parentCallback.position)) { - this._callbacks.push(parentCallback); - } + var callbacks = this._callbacks; + if (!defined(callbacks)) { + callbacks = this._callbacks = []; + this._dirty = true; + } + + var parent = this._parent; + if (this._dirty && defined(parent)) { + this._callbacks.length = 0; + + var parentCallbacks = parent.callbacks; + var length = parentCallbacks.length; + for (var i = 0; i < length; ++i) { + var parentCallback = parentCallbacks[i]; + if (Rectangle.contains(this._rectangle, parentCallback.position)) { + callbacks.push(parentCallback); } } + + this._dirty = false; } - return this._callbacks; + return callbacks; } }, From b7137f515a4b9252efe7a1d2d6ac66df989eb8af Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 17 Apr 2015 14:50:09 -0400 Subject: [PATCH 04/40] Move clamp control from billboard collection to billboard. --- Source/Scene/Billboard.js | 80 +++++++++++++++++++++++++++++ Source/Scene/BillboardCollection.js | 21 -------- 2 files changed, 80 insertions(+), 21 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index 8ab451a5382b..7bbb33f5877e 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -4,6 +4,7 @@ define([ '../Core/Cartesian2', '../Core/Cartesian3', '../Core/Cartesian4', + '../Core/Cartographic', '../Core/Color', '../Core/createGuid', '../Core/defaultValue', @@ -12,6 +13,7 @@ define([ '../Core/DeveloperError', '../Core/Matrix4', '../Core/NearFarScalar', + '../Core/Ray', './HorizontalOrigin', './SceneMode', './SceneTransforms', @@ -21,6 +23,7 @@ define([ Cartesian2, Cartesian3, Cartesian4, + Cartographic, Color, createGuid, defaultValue, @@ -29,6 +32,7 @@ define([ DeveloperError, Matrix4, NearFarScalar, + Ray, HorizontalOrigin, SceneMode, SceneTransforms, @@ -98,6 +102,7 @@ define([ this._scaleByDistance = options.scaleByDistance; this._translucencyByDistance = options.translucencyByDistance; this._pixelOffsetScaleByDistance = options.pixelOffsetScaleByDistance; + this._clampToGround = defaultValue(options.clampToGround, false); this._id = options.id; this._collection = defaultValue(options.collection, billboardCollection); @@ -140,6 +145,12 @@ define([ if (defined(this._billboardCollection._textureAtlas)) { this._loadImage(); } + + this._globe = billboardCollection._globe; + this._callback = undefined; + this._currentTile = undefined; + + this._updateClamping(); }; var SHOW_INDEX = Billboard.SHOW_INDEX = 0; @@ -212,6 +223,27 @@ define([ Cartesian3.clone(value, position); Cartesian3.clone(value, this._actualPosition); + this._updateClamping(); + makeDirty(this, POSITION_INDEX); + } + } + }, + + clampToGround : { + get : function() { + return this._clampToGround; + }, + set : function(value) { + //>>includeStart('debug', pragmas.debug) + if (!defined(value)) { + throw new DeveloperError('value is required.'); + } + //>>includeEnd('debug'); + + var clampToGround = this._clampToGround; + if (value !== clampToGround) { + this._clampToGround = value; + this._updateClamping(); makeDirty(this, POSITION_INDEX); } } @@ -762,6 +794,54 @@ define([ return this._pickId; }; + function createCallback(billboard, position) { + var ray = new Ray(); + return function (tile) { + if (tile !== billboard._currentTile) { + Cartesian3.normalize(billboard.position, ray.direction); + billboard.position = tile.data.pick(ray, undefined, false, new Cartesian3()); + billboard._currentTile = tile; + } + }; + } + + Billboard.prototype._updateClamping = function() { + var globe = this._globe; + if (!defined(globe)) { + if (defined(this._clampToGround)) { + throw new DeveloperError('Clamping a billboard to the ground is not supported.'); + } + return; + } + + var ellipsoid = globe.ellipsoid; + var surface = globe._surface; + var callback = this._callback; + + if (defined(callback) && !this._clampToGround) { + surface.removeTileLoadedCallback(callback); + this._callback = undefined; + } + + if (!this._clampToGround) { + return; + } + + var position = ellipsoid.cartesianToCartographic(this._position); + if (defined(callback)) { + if (Cartographic.equals(position, callback.position)) { + return; + } + surface.removeTileLoadedCallback(callback); + } + + this._callback = { + position : position, + func : createCallback(this, position) + }; + surface.addTileLoadedCallback(this._callback); + }; + Billboard.prototype._loadImage = function() { var atlas = this._billboardCollection._textureAtlas; diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index dba5d8766e78..588af9de3b01 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -15,8 +15,6 @@ define([ '../Core/IndexDatatype', '../Core/Math', '../Core/Matrix4', - '../Core/Ray', - '../Core/Rectangle', '../Renderer/BufferUsage', '../Renderer/DrawCommand', '../Renderer/ShaderSource', @@ -45,8 +43,6 @@ define([ IndexDatatype, CesiumMath, Matrix4, - Ray, - Rectangle, BufferUsage, DrawCommand, ShaderSource, @@ -373,23 +369,6 @@ define([ this._billboards.push(b); this._createVertexArray = true; - var globe = this._globe; - if (defined(globe) && billboard.clampToTerrain) { - var ellipsoid = globe.ellipsoid; - var surface = globe._surface; - surface.addTileLoadedCallback({ - position : ellipsoid.cartesianToCartographic(b.position), - func : function (tile) { - if (tile !== b._currentTile) { - var ray = new Ray(); - Cartesian3.normalize(b.position, ray.direction); - b.position = tile.data.pick(ray, undefined, false, new Cartesian3()); - b._currentTile = tile; - } - } - }); - } - return b; }; From ac3aee2b8fb545f08e693e5ec9fbe945abd0cd67 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 17 Apr 2015 15:40:01 -0400 Subject: [PATCH 05/40] Track clamped position differently from user provided position. --- Source/Scene/Billboard.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index 7bbb33f5877e..a04f301e56ea 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -149,6 +149,7 @@ define([ this._globe = billboardCollection._globe; this._callback = undefined; this._currentTile = undefined; + this._clampedPosition = undefined; this._updateClamping(); }; @@ -799,8 +800,9 @@ define([ return function (tile) { if (tile !== billboard._currentTile) { Cartesian3.normalize(billboard.position, ray.direction); - billboard.position = tile.data.pick(ray, undefined, false, new Cartesian3()); + billboard._clampedPosition = tile.data.pick(ray, undefined, false, billboard._clampedPosition); billboard._currentTile = tile; + makeDirty(billboard, POSITION_INDEX); } }; } @@ -991,7 +993,7 @@ define([ }; Billboard.prototype._getActualPosition = function() { - return this._actualPosition; + return defined(this._callback) && defined(this._clampedPosition) ? this._clampedPosition : this._actualPosition; }; Billboard.prototype._setActualPosition = function(value) { From 529883491029347ec35471e019e19466de9b8d76 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 17 Apr 2015 17:46:21 -0400 Subject: [PATCH 06/40] Improve performance by not updating entire quadtree when adding or removing a billboard. --- Source/Scene/QuadtreePrimitive.js | 2 +- Source/Scene/QuadtreeTile.js | 98 ++++++++++++------------------- 2 files changed, 39 insertions(+), 61 deletions(-) diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index 3cdcff71e591..b36bfd514b8d 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -304,7 +304,6 @@ define([ if (callbacksAdded.length > 0 || callbacksRemoved.length > 0) { for (i = 0, len = levelZeroTiles.length; i < len; ++i) { tile = levelZeroTiles[i]; - tile._makeDirty(); tile._updateCallbacks(callbacksAdded, callbacksRemoved); } @@ -337,6 +336,7 @@ define([ ++debug.tilesVisited; primitive._tileReplacementQueue.markTileRendered(tile); + tile._updateCallbacks(); if (tile.level > debug.maxDepth) { debug.maxDepth = tile.level; diff --git a/Source/Scene/QuadtreeTile.js b/Source/Scene/QuadtreeTile.js index 588b215cafaf..86abce2606db 100644 --- a/Source/Scene/QuadtreeTile.js +++ b/Source/Scene/QuadtreeTile.js @@ -64,8 +64,8 @@ define([ // QuadtreePrimitive gets/sets this private property. this._distance = 0.0; - this._callbacks = undefined; - this._dirty = false; + this._callbacks = []; + this._dirtyValue = 0; /** * Gets or sets the current state of the tile in the tile load pipeline. @@ -134,52 +134,52 @@ define([ return result; }; - QuadtreeTile.prototype._makeDirty = function() { - var stack = [this]; - - while (stack.length > 0) { - var tile = stack.pop(); - - var children = tile._children; - if (defined(children)) { - var length = children.length; - for (var i = 0; i < length; ++i) { - var child = children[i]; - if (!child._dirty) { - stack.push(child); - } - } - } - - tile._dirty = true; - } - }; - QuadtreeTile.prototype._updateCallbacks = function(added, removed) { var callbacks = this.callbacks; var i; var callback; + var rectangle; + + if (defined(added) && defined(removed)) { + // level zero tile + for (i = 0; i < removed.length; ++i) { + callback = removed[i]; + for (var j = 0; j < callbacks.length; ++j) { + if (callbacks[j] === callback) { + callbacks.splice(j, 1); + break; + } + } + } - for (i = 0; i < removed.length; ++i) { - callback = removed[i]; - for (var j = 0; j < callbacks.length; ++j) { - if (callbacks[j] === callback) { - callbacks.splice(j, 1); - break; + rectangle = this._rectangle; + for (i = 0; i < added.length; ++i) { + callback = added[i]; + if (Rectangle.contains(rectangle, callback.position)) { + callbacks.push(callback); } } - } - var rectangle = this._rectangle; - for (i = 0; i < added.length; ++i) { - callback = added[i]; - if (Rectangle.contains(rectangle, callback.position)) { - callbacks.push(callback); + this._dirtyValue = Math.random(); + } else { + // interior or leaf tile, update from parent + var parent = this._parent; + if (defined(parent) && this._dirtyValue !== parent._dirtyValue) { + callbacks.length = 0; + + rectangle = this._rectangle; + var parentCallbacks = parent.callbacks; + for (i = 0; i < parentCallbacks.length; ++i) { + callback = parentCallbacks[i]; + if (Rectangle.contains(rectangle, callback.position)) { + callbacks.push(callback); + } + } + + this._dirtyValue = parent._dirtyValue; } } - - this._dirty = false; }; defineProperties(QuadtreeTile.prototype, { @@ -295,29 +295,7 @@ define([ callbacks : { get : function() { - var callbacks = this._callbacks; - if (!defined(callbacks)) { - callbacks = this._callbacks = []; - this._dirty = true; - } - - var parent = this._parent; - if (this._dirty && defined(parent)) { - this._callbacks.length = 0; - - var parentCallbacks = parent.callbacks; - var length = parentCallbacks.length; - for (var i = 0; i < length; ++i) { - var parentCallback = parentCallbacks[i]; - if (Rectangle.contains(this._rectangle, parentCallback.position)) { - callbacks.push(parentCallback); - } - } - - this._dirty = false; - } - - return callbacks; + return this._callbacks; } }, From 6abe6edfd50229e612bd1363c731d429caea99f0 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 20 Apr 2015 15:32:46 -0400 Subject: [PATCH 07/40] Fix clamping to billboards to ground in 2D, Columbus view and when morphing. --- Source/Scene/Billboard.js | 50 +++++++++++++++++++++++------ Source/Scene/BillboardCollection.js | 2 +- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index a04f301e56ea..c1a29acff600 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -146,10 +146,11 @@ define([ this._loadImage(); } - this._globe = billboardCollection._globe; this._callback = undefined; this._currentTile = undefined; this._clampedPosition = undefined; + this._positionChanged = false; + this._mode = undefined; this._updateClamping(); }; @@ -795,12 +796,40 @@ define([ return this._pickId; }; + var scratchRay = new Ray(); + var scratchPosition = new Cartesian3(); + var scratchCartographic = new Cartographic(); + function createCallback(billboard, position) { - var ray = new Ray(); return function (tile) { - if (tile !== billboard._currentTile) { - Cartesian3.normalize(billboard.position, ray.direction); - billboard._clampedPosition = tile.data.pick(ray, undefined, false, billboard._clampedPosition); + var scene = billboard._billboardCollection._scene; + var mode = scene.mode; + var billboardMode = billboard._mode; + var modeChanged = mode !== SceneMode.MORPHING && mode !== billboardMode; + + if (tile !== billboard._currentTile || billboard._positionChanged || modeChanged) { + if (mode === SceneMode.SCENE3D) { + Cartesian3.clone(Cartesian3.ZERO, scratchRay.origin); + Cartesian3.normalize(billboard.position, scratchRay.direction); + } else { + var projection = scene.mapProjection; + var ellipsoid = projection.ellipsoid; + + ellipsoid.cartesianToCartographic(billboard.position, scratchCartographic); + scratchCartographic.height = -1000.0; // TODO: get minimum height of entire terrain set + projection.project(scratchCartographic, scratchPosition); + Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, scratchPosition); + Cartesian3.clone(scratchPosition, scratchRay.origin); + Cartesian3.clone(Cartesian3.UNIT_X, scratchRay.direction); + } + + var position = tile.data.pick(scratchRay, scene, false, scratchPosition); + if (defined(position)) { + billboard._clampedPosition = Cartesian3.clone(position, billboard._clampedPosition); + } + + billboard._positionChanged = false; + billboard._mode = mode; billboard._currentTile = tile; makeDirty(billboard, POSITION_INDEX); } @@ -808,7 +837,7 @@ define([ } Billboard.prototype._updateClamping = function() { - var globe = this._globe; + var globe = this._billboardCollection._globe; if (!defined(globe)) { if (defined(this._clampToGround)) { throw new DeveloperError('Clamping a billboard to the ground is not supported.'); @@ -842,6 +871,7 @@ define([ func : createCallback(this, position) }; surface.addTileLoadedCallback(this._callback); + this._positionChanged = true; }; Billboard.prototype._loadImage = function() { @@ -993,7 +1023,7 @@ define([ }; Billboard.prototype._getActualPosition = function() { - return defined(this._callback) && defined(this._clampedPosition) ? this._clampedPosition : this._actualPosition; + return defined(this._callback) && defined(this._clampedPosition) && this._mode !== SceneMode.MORPHING ? this._clampedPosition : this._actualPosition; }; Billboard.prototype._setActualPosition = function(value) { @@ -1002,8 +1032,10 @@ define([ }; var tempCartesian3 = new Cartesian4(); - Billboard._computeActualPosition = function(position, frameState, modelMatrix) { - if (frameState.mode === SceneMode.SCENE3D) { + Billboard._computeActualPosition = function(billboard, position, frameState, modelMatrix) { + if (defined(billboard._callback) && defined(billboard._clampedPosition) && this._mode !== SceneMode.MORPHING) { + return billboard._clampedPosition; + } else if (frameState.mode === SceneMode.SCENE3D) { return position; } diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 588af9de3b01..31ba5c665398 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -936,7 +936,7 @@ define([ for ( var i = 0; i < length; ++i) { var billboard = billboards[i]; var position = billboard.position; - var actualPosition = Billboard._computeActualPosition(position, frameState, modelMatrix); + var actualPosition = Billboard._computeActualPosition(billboard, position, frameState, modelMatrix); if (defined(actualPosition)) { billboard._setActualPosition(actualPosition); From 83f5dc3589d98da8ad78579846ad5b3673ced828 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 20 Apr 2015 16:20:57 -0400 Subject: [PATCH 08/40] Only use one vertex texture fetch for the depth at the center of the billboard and compare against an offset position in eye coordinates. --- Source/Shaders/BillboardCollectionVS.glsl | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index 43257679d253..6de240197c95 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -226,24 +226,10 @@ void main() #endif #ifdef TEST_GLOBE_DEPTH - vec2 directions[4]; - directions[0] = vec2(0.0, 0.0); - directions[1] = vec2(0.0, 1.0); - directions[2] = vec2(1.0, 1.0); - directions[3] = vec2(1.0, 0.0); - - bool visible = false; - for (int i = 0; i < 4; ++i) - { - vec4 p = computePositionWindowCoordinates(positionEC, imageSize, scale, directions[i], origin, translate, pixelOffset, alignedAxis, rotation); - float d = texture2D(czm_globeDepthTexture, p.xy / czm_viewport.zw).r; - if (p.z <= d) { - visible = true; - break; - } - } - - if (!visible) { + vec4 offsetPosition = positionEC + vec4(0.0, 0.0, -positionEC.z * 0.05, 0.0); + vec4 wc = computePositionWindowCoordinates(offsetPosition, vec2(0.0, 0.0), scale, direction, origin, translate, pixelOffset, alignedAxis, rotation); + float d = texture2D(czm_globeDepthTexture, wc.xy / czm_viewport.zw).r; + if (wc.z > d) { gl_Position = czm_projection * vec4(vec3(0.0), 1.0); return; } From 9a76c648bc74bb9f51becd6bd8fb205a45a3be4e Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 20 Apr 2015 19:28:18 -0400 Subject: [PATCH 09/40] Throttle billboards clamped to terrain to only pick the mesh in the given time slice. --- Source/Scene/Billboard.js | 70 ++++++++++++++++------------- Source/Scene/BillboardCollection.js | 17 +++++++ 2 files changed, 56 insertions(+), 31 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index c1a29acff600..8e674e2ac310 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -800,38 +800,46 @@ define([ var scratchPosition = new Cartesian3(); var scratchCartographic = new Cartographic(); - function createCallback(billboard, position) { - return function (tile) { - var scene = billboard._billboardCollection._scene; - var mode = scene.mode; - var billboardMode = billboard._mode; - var modeChanged = mode !== SceneMode.MORPHING && mode !== billboardMode; - - if (tile !== billboard._currentTile || billboard._positionChanged || modeChanged) { - if (mode === SceneMode.SCENE3D) { - Cartesian3.clone(Cartesian3.ZERO, scratchRay.origin); - Cartesian3.normalize(billboard.position, scratchRay.direction); - } else { - var projection = scene.mapProjection; - var ellipsoid = projection.ellipsoid; - - ellipsoid.cartesianToCartographic(billboard.position, scratchCartographic); - scratchCartographic.height = -1000.0; // TODO: get minimum height of entire terrain set - projection.project(scratchCartographic, scratchPosition); - Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, scratchPosition); - Cartesian3.clone(scratchPosition, scratchRay.origin); - Cartesian3.clone(Cartesian3.UNIT_X, scratchRay.direction); - } + Billboard._clampPosition = function(billboard) { + var scene = billboard._billboardCollection._scene; + var mode = scene.mode; + var billboardMode = billboard._mode; + var modeChanged = mode !== SceneMode.MORPHING && mode !== billboardMode; + + if (billboard._newTile !== billboard._currentTile || billboard._positionChanged || modeChanged) { + if (mode === SceneMode.SCENE3D) { + Cartesian3.clone(Cartesian3.ZERO, scratchRay.origin); + Cartesian3.normalize(billboard.position, scratchRay.direction); + } else { + var projection = scene.mapProjection; + var ellipsoid = projection.ellipsoid; + + ellipsoid.cartesianToCartographic(billboard.position, scratchCartographic); + scratchCartographic.height = -1000.0; // TODO: get minimum height of entire terrain set + projection.project(scratchCartographic, scratchPosition); + Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, scratchPosition); + Cartesian3.clone(scratchPosition, scratchRay.origin); + Cartesian3.clone(Cartesian3.UNIT_X, scratchRay.direction); + } - var position = tile.data.pick(scratchRay, scene, false, scratchPosition); - if (defined(position)) { - billboard._clampedPosition = Cartesian3.clone(position, billboard._clampedPosition); - } + var position = billboard._newTile.data.pick(scratchRay, scene, false, scratchPosition); + if (defined(position)) { + billboard._clampedPosition = Cartesian3.clone(position, billboard._clampedPosition); + } - billboard._positionChanged = false; - billboard._mode = mode; - billboard._currentTile = tile; - makeDirty(billboard, POSITION_INDEX); + billboard._positionChanged = false; + billboard._mode = mode; + billboard._currentTile = billboard._newTile; + makeDirty(billboard, POSITION_INDEX); + } + }; + + function createCallback(billboard) { + return function (tile) { + billboard._newTile = tile; + var clampList = billboard._billboardCollection._clampBillboardsToTerrain; + if (clampList.indexOf(billboard) === -1) { + clampList.push(billboard); } }; } @@ -868,7 +876,7 @@ define([ this._callback = { position : position, - func : createCallback(this, position) + func : createCallback(this) }; surface.addTileLoadedCallback(this._callback); this._positionChanged = true; diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 31ba5c665398..15b273bd9f01 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -12,6 +12,7 @@ define([ '../Core/destroyObject', '../Core/DeveloperError', '../Core/EncodedCartesian3', + '../Core/getTimestamp', '../Core/IndexDatatype', '../Core/Math', '../Core/Matrix4', @@ -40,6 +41,7 @@ define([ destroyObject, DeveloperError, EncodedCartesian3, + getTimestamp, IndexDatatype, CesiumMath, Matrix4, @@ -180,6 +182,9 @@ define([ this._boundingVolume = new BoundingSphere(); this._boundingVolumeDirty = false; + this._clampBillboardsToTerrain = []; + this._clampTimeSlice = 5.0; + this._colorCommands = []; this._pickCommands = []; @@ -1015,6 +1020,18 @@ define([ * @exception {RuntimeError} image with id must be in the atlas. */ BillboardCollection.prototype.update = function(context, frameState, commandList) { + var startTime = getTimestamp(); + var timeSlice = this._clampTimeSlice; + var endTime = startTime + timeSlice; + + var clampList = this._clampBillboardsToTerrain; + while (clampList.length > 0) { + Billboard._clampPosition(clampList.shift()); + if (getTimestamp() >= endTime) { + break; + } + } + removeBillboards(this); var billboards = this._billboards; From 458351612ee01ee149e10933eaa3c5e4a1c61924 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 21 Apr 2015 13:09:52 -0400 Subject: [PATCH 10/40] Add clamp to ground option to labels. --- Source/Scene/BillboardCollection.js | 2 +- Source/Scene/Label.js | 1 + Source/Scene/LabelCollection.js | 1 + Source/Scene/PolylineCollection.js | 2 +- Source/Shaders/BillboardCollectionVS.glsl | 2 +- 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 15b273bd9f01..c46a5efbf6a4 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -183,7 +183,7 @@ define([ this._boundingVolumeDirty = false; this._clampBillboardsToTerrain = []; - this._clampTimeSlice = 5.0; + this._clampTimeSlice = 10.0; this._colorCommands = []; this._pickCommands = []; diff --git a/Source/Scene/Label.js b/Source/Scene/Label.js index 04f85c7b0e9a..da0bb43d26b2 100644 --- a/Source/Scene/Label.js +++ b/Source/Scene/Label.js @@ -86,6 +86,7 @@ define([ this._id = options.id; this._translucencyByDistance = options.translucencyByDistance; this._pixelOffsetScaleByDistance = options.pixelOffsetScaleByDistance; + this._clampToGround = defaultValue(options.clampToGround, false); this._labelCollection = labelCollection; this._glyphs = []; diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index 287bb0398801..36d5b3991a66 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -200,6 +200,7 @@ define([ billboard.image = id; billboard.translucencyByDistance = label._translucencyByDistance; billboard.pixelOffsetScaleByDistance = label._pixelOffsetScaleByDistance; + billboard.clampToGround = label._clampToGround; } } diff --git a/Source/Scene/PolylineCollection.js b/Source/Scene/PolylineCollection.js index 65c30b3ca70f..c06f5d47736d 100644 --- a/Source/Scene/PolylineCollection.js +++ b/Source/Scene/PolylineCollection.js @@ -312,7 +312,7 @@ define([ * Determines if this collection contains the specified polyline. * * @param {Polyline} polyline The polyline to check for. - * @returns {Boolean} true if this collection contains the billboard, false otherwise. + * @returns {Boolean} true if this collection contains the polyline, false otherwise. * * @see PolylineCollection#get */ diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index 6de240197c95..f5087cd52f14 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -227,7 +227,7 @@ void main() #ifdef TEST_GLOBE_DEPTH vec4 offsetPosition = positionEC + vec4(0.0, 0.0, -positionEC.z * 0.05, 0.0); - vec4 wc = computePositionWindowCoordinates(offsetPosition, vec2(0.0, 0.0), scale, direction, origin, translate, pixelOffset, alignedAxis, rotation); + vec4 wc = computePositionWindowCoordinates(offsetPosition, vec2(0.0, 0.0), scale, direction, origin, vec2(0.0), pixelOffset, alignedAxis, rotation); float d = texture2D(czm_globeDepthTexture, wc.xy / czm_viewport.zw).r; if (wc.z > d) { gl_Position = czm_projection * vec4(vec3(0.0), 1.0); From 88406235f04e8f3db843b20b6e0542e35440147f Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 21 Apr 2015 14:07:05 -0400 Subject: [PATCH 11/40] Clean up picking a terrain tile's mesh and fix billboards when created with an undefined position. --- Source/Scene/Billboard.js | 14 +++++++------- Source/Scene/BillboardCollection.js | 6 ++++-- Source/Scene/Globe.js | 4 ++-- Source/Scene/GlobeSurfaceTile.js | 13 ++++++------- Source/Scene/LabelCollection.js | 6 +++++- Source/Shaders/BillboardCollectionVS.glsl | 3 ++- 6 files changed, 26 insertions(+), 20 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index 8e674e2ac310..28f1b84d419c 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -800,9 +800,7 @@ define([ var scratchPosition = new Cartesian3(); var scratchCartographic = new Cartographic(); - Billboard._clampPosition = function(billboard) { - var scene = billboard._billboardCollection._scene; - var mode = scene.mode; + Billboard._clampPosition = function(billboard, mode, projection) { var billboardMode = billboard._mode; var modeChanged = mode !== SceneMode.MORPHING && mode !== billboardMode; @@ -811,9 +809,7 @@ define([ Cartesian3.clone(Cartesian3.ZERO, scratchRay.origin); Cartesian3.normalize(billboard.position, scratchRay.direction); } else { - var projection = scene.mapProjection; var ellipsoid = projection.ellipsoid; - ellipsoid.cartesianToCartographic(billboard.position, scratchCartographic); scratchCartographic.height = -1000.0; // TODO: get minimum height of entire terrain set projection.project(scratchCartographic, scratchPosition); @@ -822,7 +818,7 @@ define([ Cartesian3.clone(Cartesian3.UNIT_X, scratchRay.direction); } - var position = billboard._newTile.data.pick(scratchRay, scene, false, scratchPosition); + var position = billboard._newTile.data.pick(scratchRay, mode, projection, false, scratchPosition); if (defined(position)) { billboard._clampedPosition = Cartesian3.clone(position, billboard._clampedPosition); } @@ -862,11 +858,15 @@ define([ this._callback = undefined; } - if (!this._clampToGround) { + if (!this._clampToGround || !defined(this._position)) { return; } var position = ellipsoid.cartesianToCartographic(this._position); + if (!defined(position)) { + return; + } + if (defined(callback)) { if (Cartographic.equals(position, callback.position)) { return; diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index c46a5efbf6a4..3b8a585ae68c 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -134,6 +134,8 @@ define([ var BillboardCollection = function(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); + this._globe = options.globe; + this._textureAtlas = undefined; this._textureAtlasGUID = undefined; this._destroyTextureAtlas = true; @@ -183,7 +185,7 @@ define([ this._boundingVolumeDirty = false; this._clampBillboardsToTerrain = []; - this._clampTimeSlice = 10.0; + this._clampTimeSlice = 5.0; this._colorCommands = []; this._pickCommands = []; @@ -1026,7 +1028,7 @@ define([ var clampList = this._clampBillboardsToTerrain; while (clampList.length > 0) { - Billboard._clampPosition(clampList.shift()); + Billboard._clampPosition(clampList.shift(), frameState.mode, frameState.mapProjection); if (getTimestamp() >= endTime) { break; } diff --git a/Source/Scene/Globe.js b/Source/Scene/Globe.js index d4c97243abcf..4e1fb885ab6c 100644 --- a/Source/Scene/Globe.js +++ b/Source/Scene/Globe.js @@ -409,7 +409,7 @@ define([ var intersection; length = sphereIntersections.length; for (i = 0; i < length; ++i) { - intersection = sphereIntersections[i].pick(ray, scene, true, result); + intersection = sphereIntersections[i].pick(ray, scene.mode, scene.mapProjection, true, result); if (defined(intersection)) { break; } @@ -482,7 +482,7 @@ define([ var ray = scratchGetHeightRay; Cartesian3.normalize(cartesian, ray.direction); - var intersection = tile.data.pick(ray, undefined, false, scratchGetHeightIntersection); + var intersection = tile.data.pick(ray, undefined, undefined, false, scratchGetHeightIntersection); if (!defined(intersection)) { return undefined; } diff --git a/Source/Scene/GlobeSurfaceTile.js b/Source/Scene/GlobeSurfaceTile.js index ba6039493603..a9a8eb8ebc1d 100644 --- a/Source/Scene/GlobeSurfaceTile.js +++ b/Source/Scene/GlobeSurfaceTile.js @@ -170,12 +170,11 @@ define([ } }); - function getPosition(tile, scene, vertices, stride, index, result) { + function getPosition(tile, mode, projection, vertices, stride, index, result) { Cartesian3.unpack(vertices, index * stride, result); Cartesian3.add(tile.center, result, result); - if (defined(scene) && scene.mode !== SceneMode.SCENE3D) { - var projection = scene.mapProjection; + if (defined(mode) && mode !== SceneMode.SCENE3D) { var ellipsoid = projection.ellipsoid; var positionCart = ellipsoid.cartesianToCartographic(result); projection.project(positionCart, result); @@ -190,7 +189,7 @@ define([ var scratchV2 = new Cartesian3(); var scratchResult = new Cartesian3(); - GlobeSurfaceTile.prototype.pick = function(ray, scene, cullBackFaces, result) { + GlobeSurfaceTile.prototype.pick = function(ray, mode, projection, cullBackFaces, result) { var terrain = this.pickTerrain; if (!defined(terrain)) { return undefined; @@ -211,9 +210,9 @@ define([ var i1 = indices[i + 1]; var i2 = indices[i + 2]; - var v0 = getPosition(this, scene, vertices, stride, i0, scratchV0); - var v1 = getPosition(this, scene, vertices, stride, i1, scratchV1); - var v2 = getPosition(this, scene, vertices, stride, i2, scratchV2); + var v0 = getPosition(this, mode, projection, vertices, stride, i0, scratchV0); + var v1 = getPosition(this, mode, projection, vertices, stride, i1, scratchV1); + var v2 = getPosition(this, mode, projection, vertices, stride, i2, scratchV2); var intersection = IntersectionTests.rayTriangle(ray, v0, v1, v2, cullBackFaces, scratchResult); if (defined(intersection)) { diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index 36d5b3991a66..d44b294884af 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -318,9 +318,13 @@ define([ var LabelCollection = function(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); + this._globe = options.globe; + this._textureAtlas = undefined; - this._billboardCollection = new BillboardCollection(); + this._billboardCollection = new BillboardCollection({ + globe : this._globe + }); this._billboardCollection.destroyTextureAtlas = false; this._spareBillboards = []; diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index f5087cd52f14..7f599408ec32 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -229,7 +229,8 @@ void main() vec4 offsetPosition = positionEC + vec4(0.0, 0.0, -positionEC.z * 0.05, 0.0); vec4 wc = computePositionWindowCoordinates(offsetPosition, vec2(0.0, 0.0), scale, direction, origin, vec2(0.0), pixelOffset, alignedAxis, rotation); float d = texture2D(czm_globeDepthTexture, wc.xy / czm_viewport.zw).r; - if (wc.z > d) { + if (wc.z > d) + { gl_Position = czm_projection * vec4(vec3(0.0), 1.0); return; } From f1150942f379bab4a8ddfa4d6dcf41eb15504e4e Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 21 Apr 2015 15:01:25 -0400 Subject: [PATCH 12/40] Use the frame number when updating callbacks for rendered tiles instead of generating a random number. --- Source/Scene/QuadtreePrimitive.js | 5 +++-- Source/Scene/QuadtreeTile.js | 11 ++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index b36bfd514b8d..6edf8020eab0 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -300,11 +300,12 @@ define([ var callbacksAdded = primitive._callbacksAdded; var callbacksRemoved = primitive._callbacksRemoved; + var frameNumber = frameState.frameNumber; if (callbacksAdded.length > 0 || callbacksRemoved.length > 0) { for (i = 0, len = levelZeroTiles.length; i < len; ++i) { tile = levelZeroTiles[i]; - tile._updateCallbacks(callbacksAdded, callbacksRemoved); + tile._updateCallbacks(frameNumber, callbacksAdded, callbacksRemoved); } callbacksAdded.length = 0; @@ -336,7 +337,7 @@ define([ ++debug.tilesVisited; primitive._tileReplacementQueue.markTileRendered(tile); - tile._updateCallbacks(); + tile._updateCallbacks(frameNumber); if (tile.level > debug.maxDepth) { debug.maxDepth = tile.level; diff --git a/Source/Scene/QuadtreeTile.js b/Source/Scene/QuadtreeTile.js index 86abce2606db..57da2e53f048 100644 --- a/Source/Scene/QuadtreeTile.js +++ b/Source/Scene/QuadtreeTile.js @@ -65,7 +65,8 @@ define([ this._distance = 0.0; this._callbacks = []; - this._dirtyValue = 0; + this._frameUpdated = undefined; + this._frameRendered = undefined; /** * Gets or sets the current state of the tile in the tile load pipeline. @@ -134,7 +135,7 @@ define([ return result; }; - QuadtreeTile.prototype._updateCallbacks = function(added, removed) { + QuadtreeTile.prototype._updateCallbacks = function(frameNumber, added, removed) { var callbacks = this.callbacks; var i; @@ -161,11 +162,11 @@ define([ } } - this._dirtyValue = Math.random(); + this._frameUpdated = frameNumber; } else { // interior or leaf tile, update from parent var parent = this._parent; - if (defined(parent) && this._dirtyValue !== parent._dirtyValue) { + if (defined(parent) && this._frameUpdated !== parent._frameUpdated) { callbacks.length = 0; rectangle = this._rectangle; @@ -177,7 +178,7 @@ define([ } } - this._dirtyValue = parent._dirtyValue; + this._frameUpdated = parent._frameUpdated; } } }; From 27df468dc0363c5a87761e90f5466a3988fd9eb2 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 21 Apr 2015 15:54:05 -0400 Subject: [PATCH 13/40] Clamp the entire label instead of the individual billboards of the label. --- Source/Scene/Billboard.js | 71 +++++++++++++++++------------ Source/Scene/BillboardCollection.js | 4 +- Source/Scene/Label.js | 61 +++++++++++++++++++++++-- Source/Scene/LabelCollection.js | 20 +++++++- 4 files changed, 118 insertions(+), 38 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index 28f1b84d419c..a300fd64b296 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -148,7 +148,7 @@ define([ this._callback = undefined; this._currentTile = undefined; - this._clampedPosition = undefined; + this._actualClampedPosition = undefined; this._positionChanged = false; this._mode = undefined; @@ -781,6 +781,16 @@ define([ get : function() { return this._imageIndex !== -1; } + }, + + _clampedPosition : { + get : function() { + return this._actualClampedPosition; + }, + set : function(value) { + this._actualClampedPosition = Cartesian3.clone(value, this._actualClampedPosition); + makeDirty(this, POSITION_INDEX); + } } }); @@ -800,17 +810,15 @@ define([ var scratchPosition = new Cartesian3(); var scratchCartographic = new Cartographic(); - Billboard._clampPosition = function(billboard, mode, projection) { - var billboardMode = billboard._mode; - var modeChanged = mode !== SceneMode.MORPHING && mode !== billboardMode; - - if (billboard._newTile !== billboard._currentTile || billboard._positionChanged || modeChanged) { + Billboard._clampPosition = function(object, mode, projection, markObjectDirty) { + var modeChanged = mode !== SceneMode.MORPHING && mode !== object._mode; + if (object._newTile !== object._currentTile || object._positionChanged || modeChanged) { if (mode === SceneMode.SCENE3D) { Cartesian3.clone(Cartesian3.ZERO, scratchRay.origin); - Cartesian3.normalize(billboard.position, scratchRay.direction); + Cartesian3.normalize(object.position, scratchRay.direction); } else { var ellipsoid = projection.ellipsoid; - ellipsoid.cartesianToCartographic(billboard.position, scratchCartographic); + ellipsoid.cartesianToCartographic(object.position, scratchCartographic); scratchCartographic.height = -1000.0; // TODO: get minimum height of entire terrain set projection.project(scratchCartographic, scratchPosition); Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, scratchPosition); @@ -818,32 +826,35 @@ define([ Cartesian3.clone(Cartesian3.UNIT_X, scratchRay.direction); } - var position = billboard._newTile.data.pick(scratchRay, mode, projection, false, scratchPosition); + var position = object._newTile.data.pick(scratchRay, mode, projection, false, scratchPosition); if (defined(position)) { - billboard._clampedPosition = Cartesian3.clone(position, billboard._clampedPosition); + object._clampedPosition = Cartesian3.clone(position, object._clampedPosition); } - billboard._positionChanged = false; - billboard._mode = mode; - billboard._currentTile = billboard._newTile; - makeDirty(billboard, POSITION_INDEX); + object._positionChanged = false; + object._mode = mode; + object._currentTile = object._newTile; } }; - function createCallback(billboard) { + function createCallback(collection, object) { return function (tile) { - billboard._newTile = tile; - var clampList = billboard._billboardCollection._clampBillboardsToTerrain; - if (clampList.indexOf(billboard) === -1) { - clampList.push(billboard); + object._newTile = tile; + var clampList = collection._clampToTerrainList; + if (clampList.indexOf(object) === -1) { + clampList.push(object); } }; } Billboard.prototype._updateClamping = function() { - var globe = this._billboardCollection._globe; + Billboard._updateClamping(this._billboardCollection, this); + }; + + Billboard._updateClamping = function(collection, object) { + var globe = collection._globe; if (!defined(globe)) { - if (defined(this._clampToGround)) { + if (defined(object._clampToGround)) { throw new DeveloperError('Clamping a billboard to the ground is not supported.'); } return; @@ -851,18 +862,18 @@ define([ var ellipsoid = globe.ellipsoid; var surface = globe._surface; - var callback = this._callback; + var callback = object._callback; - if (defined(callback) && !this._clampToGround) { + if (defined(callback) && !object._clampToGround) { surface.removeTileLoadedCallback(callback); - this._callback = undefined; + object._callback = undefined; } - if (!this._clampToGround || !defined(this._position)) { + if (!object._clampToGround || !defined(object._position)) { return; } - var position = ellipsoid.cartesianToCartographic(this._position); + var position = ellipsoid.cartesianToCartographic(object._position); if (!defined(position)) { return; } @@ -874,12 +885,12 @@ define([ surface.removeTileLoadedCallback(callback); } - this._callback = { + object._callback = { position : position, - func : createCallback(this) + func : createCallback(collection, object) }; - surface.addTileLoadedCallback(this._callback); - this._positionChanged = true; + surface.addTileLoadedCallback(object._callback); + object._positionChanged = true; }; Billboard.prototype._loadImage = function() { diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 3b8a585ae68c..d80e913e7f12 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -184,7 +184,7 @@ define([ this._boundingVolume = new BoundingSphere(); this._boundingVolumeDirty = false; - this._clampBillboardsToTerrain = []; + this._clampToTerrainList = []; this._clampTimeSlice = 5.0; this._colorCommands = []; @@ -1026,7 +1026,7 @@ define([ var timeSlice = this._clampTimeSlice; var endTime = startTime + timeSlice; - var clampList = this._clampBillboardsToTerrain; + var clampList = this._clampToTerrainList; while (clampList.length > 0) { Billboard._clampPosition(clampList.shift(), frameState.mode, frameState.mapProjection); if (getTimestamp() >= endTime) { diff --git a/Source/Scene/Label.js b/Source/Scene/Label.js index da0bb43d26b2..cad87527a522 100644 --- a/Source/Scene/Label.js +++ b/Source/Scene/Label.js @@ -93,6 +93,14 @@ define([ this._rebindAllGlyphs = true; this._repositionAllGlyphs = true; + + this._callback = undefined; + this._currentTile = undefined; + this._actualClampedPosition = undefined; + this._positionChanged = false; + this._mode = undefined; + + this._updateClamping(); }; defineProperties(Label.prototype, { @@ -147,17 +155,39 @@ define([ if (!Cartesian3.equals(position, value)) { Cartesian3.clone(value, position); - var glyphs = this._glyphs; - for (var i = 0, len = glyphs.length; i < len; i++) { - var glyph = glyphs[i]; - if (defined(glyph.billboard)) { - glyph.billboard.position = value; + if (!this._clampToGround) { + var glyphs = this._glyphs; + for (var i = 0, len = glyphs.length; i < len; i++) { + var glyph = glyphs[i]; + if (defined(glyph.billboard)) { + glyph.billboard.position = value; + } } + } else { + this._updateClamping(); } } } }, + clampToGround : { + get : function() { + return this._clampToGround; + }, + set : function(value) { + //>>includeStart('debug', pragmas.debug); + if (!defined(value)) { + throw new DeveloperError('value is required.'); + } + //>>includeEnd('debug'); + + if (value !== this._clampToGround) { + this._clamptoGround = value; + this._updateClamping(); + } + } + }, + /** * Gets or sets the text of this label. * @memberof Label.prototype @@ -628,9 +658,30 @@ define([ } } } + }, + + _clampedPosition : { + get : function() { + return this._actualClampedPosition; + }, + set : function(value) { + this._actualClampedPosition = Cartesian3.clone(value, this._actualClampedPosition); + + var glyphs = this._glyphs; + for (var i = 0, len = glyphs.length; i < len; i++) { + var glyph = glyphs[i]; + if (defined(glyph.billboard)) { + glyph.billboard.position = value; + } + } + } } }); + Label.prototype._updateClamping = function() { + Billboard._updateClamping(this._labelCollection, this); + }; + /** * Computes the screen-space position of the label's origin, taking into account eye and pixel offsets. * The screen space origin is the top, left corner of the canvas; x increases from diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index d44b294884af..840c7f49893c 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -6,8 +6,10 @@ define([ '../Core/defineProperties', '../Core/destroyObject', '../Core/DeveloperError', + '../Core/getTimestamp', '../Core/Matrix4', '../Core/writeTextToCanvas', + './Billboard', './BillboardCollection', './HorizontalOrigin', './Label', @@ -21,8 +23,10 @@ define([ defineProperties, destroyObject, DeveloperError, + getTimestamp, Matrix4, writeTextToCanvas, + Billboard, BillboardCollection, HorizontalOrigin, Label, @@ -200,7 +204,6 @@ define([ billboard.image = id; billboard.translucencyByDistance = label._translucencyByDistance; billboard.pixelOffsetScaleByDistance = label._pixelOffsetScaleByDistance; - billboard.clampToGround = label._clampToGround; } } @@ -334,6 +337,9 @@ define([ this._totalGlyphCount = 0; this._resolutionScale = undefined; + this._clampToTerrainList = []; + this._clampTimeSlice = 5.0; + /** * The 4x4 transformation matrix that transforms each label in this collection from model to world coordinates. * When this is the identity matrix, the labels are drawn in world coordinates, i.e., Earth's WGS84 coordinates. @@ -558,6 +564,18 @@ define([ * @private */ LabelCollection.prototype.update = function(context, frameState, commandList) { + var startTime = getTimestamp(); + var timeSlice = this._clampTimeSlice; + var endTime = startTime + timeSlice; + + var clampList = this._clampToTerrainList; + while (clampList.length > 0) { + Billboard._clampPosition(clampList.shift(), frameState.mode, frameState.mapProjection); + if (getTimestamp() >= endTime) { + break; + } + } + var billboardCollection = this._billboardCollection; billboardCollection.modelMatrix = this.modelMatrix; From 8ce9101aca632982cac0f133b0b56c8586f47010 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 21 Apr 2015 16:20:14 -0400 Subject: [PATCH 14/40] Check the last frame rendered and only use callbacks when a tile transitions from not rendered to rendered. Update time slices. --- Source/Scene/BillboardCollection.js | 2 +- Source/Scene/GlobeSurfaceTileProvider.js | 11 +++++++---- Source/Scene/LabelCollection.js | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index d80e913e7f12..03786e117940 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -185,7 +185,7 @@ define([ this._boundingVolumeDirty = false; this._clampToTerrainList = []; - this._clampTimeSlice = 5.0; + this._clampTimeSlice = 1.0; this._colorCommands = []; this._pickCommands = []; diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 69ce446360e2..9dedcbd8fc8a 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -464,11 +464,14 @@ define([ tileSet.push(tile); - var callbacks = tile.callbacks; - var length = callbacks.length; - for (var j = 0; j < length; ++j) { - callbacks[j].func(tile); + if (tile._frameRendered !== frameState.frameNumber - 1) { + var callbacks = tile.callbacks; + var length = callbacks.length; + for (var j = 0; j < length; ++j) { + callbacks[j].func(tile); + } } + tile._frameRendered = frameState.frameNumber; var debug = this._debug; ++debug.tilesRendered; diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index 840c7f49893c..b8e733624596 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -338,7 +338,7 @@ define([ this._resolutionScale = undefined; this._clampToTerrainList = []; - this._clampTimeSlice = 5.0; + this._clampTimeSlice = 1.0; /** * The 4x4 transformation matrix that transforms each label in this collection from model to world coordinates. From 0acc7029b302ccb20d1a7738add63619dc858237 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Wed, 22 Apr 2015 14:42:44 -0400 Subject: [PATCH 15/40] Improve performance. Associate data with the quadtree that will update when we walk the tree. Add an event to the quadtree that fires when a tile is queued for rendering. --- Source/Scene/Billboard.js | 36 +++++++----------- Source/Scene/BillboardCollection.js | 47 ++++++++++++++++++++---- Source/Scene/GlobeSurfaceTileProvider.js | 9 ----- Source/Scene/Label.js | 2 +- Source/Scene/LabelCollection.js | 47 +++++++++++++++++++++--- Source/Scene/QuadtreePrimitive.js | 38 ++++++++++++------- Source/Scene/QuadtreeTile.js | 38 +++++++++---------- 7 files changed, 138 insertions(+), 79 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index a300fd64b296..405973327236 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -146,7 +146,7 @@ define([ this._loadImage(); } - this._callback = undefined; + this._customData = undefined; this._currentTile = undefined; this._actualClampedPosition = undefined; this._positionChanged = false; @@ -837,16 +837,6 @@ define([ } }; - function createCallback(collection, object) { - return function (tile) { - object._newTile = tile; - var clampList = collection._clampToTerrainList; - if (clampList.indexOf(object) === -1) { - clampList.push(object); - } - }; - } - Billboard.prototype._updateClamping = function() { Billboard._updateClamping(this._billboardCollection, this); }; @@ -862,11 +852,11 @@ define([ var ellipsoid = globe.ellipsoid; var surface = globe._surface; - var callback = object._callback; + var customData = object._customData; - if (defined(callback) && !object._clampToGround) { - surface.removeTileLoadedCallback(callback); - object._callback = undefined; + if (defined(customData) && !object._clampToGround) { + surface.removeTileCustomData(customData); + object._customData = undefined; } if (!object._clampToGround || !defined(object._position)) { @@ -878,18 +868,18 @@ define([ return; } - if (defined(callback)) { - if (Cartographic.equals(position, callback.position)) { + if (defined(customData)) { + if (Cartographic.equals(position, customData.position)) { return; } - surface.removeTileLoadedCallback(callback); + surface.removeTileCustomData(customData); } - object._callback = { + object._customData = { position : position, - func : createCallback(collection, object) + object : object }; - surface.addTileLoadedCallback(object._callback); + surface.addTileCustomData(object._customData); object._positionChanged = true; }; @@ -1042,7 +1032,7 @@ define([ }; Billboard.prototype._getActualPosition = function() { - return defined(this._callback) && defined(this._clampedPosition) && this._mode !== SceneMode.MORPHING ? this._clampedPosition : this._actualPosition; + return defined(this._customData) && defined(this._clampedPosition) && this._mode !== SceneMode.MORPHING ? this._clampedPosition : this._actualPosition; }; Billboard.prototype._setActualPosition = function(value) { @@ -1052,7 +1042,7 @@ define([ var tempCartesian3 = new Cartesian4(); Billboard._computeActualPosition = function(billboard, position, frameState, modelMatrix) { - if (defined(billboard._callback) && defined(billboard._clampedPosition) && this._mode !== SceneMode.MORPHING) { + if (defined(billboard._customData) && defined(billboard._clampedPosition) && this._mode !== SceneMode.MORPHING) { return billboard._clampedPosition; } else if (frameState.mode === SceneMode.SCENE3D) { return position; diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 03786e117940..81ac35cf2dd5 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -184,8 +184,9 @@ define([ this._boundingVolume = new BoundingSphere(); this._boundingVolumeDirty = false; - this._clampToTerrainList = []; + this._renderedTileList = []; this._clampTimeSlice = 1.0; + this._lastTileIndex = 0; this._colorCommands = []; this._pickCommands = []; @@ -262,6 +263,15 @@ define([ return that._textureAtlas.texture; } }; + + if (defined(this._globe)) { + this._globe._surface.tileRenderedEvent.addEventListener(function(tile) { + var tileList = that._renderedTileList; + if (tileList.indexOf(tile) === -1) { + tileList.push(tile); + } + }); + } }; defineProperties(BillboardCollection.prototype, { @@ -1022,15 +1032,39 @@ define([ * @exception {RuntimeError} image with id must be in the atlas. */ BillboardCollection.prototype.update = function(context, frameState, commandList) { + var i; + var j; + var startTime = getTimestamp(); var timeSlice = this._clampTimeSlice; var endTime = startTime + timeSlice; - var clampList = this._clampToTerrainList; - while (clampList.length > 0) { - Billboard._clampPosition(clampList.shift(), frameState.mode, frameState.mapProjection); - if (getTimestamp() >= endTime) { + var tileList = this._renderedTileList; + while (tileList.length > 0) { + var tile = tileList[0]; + var customData = tile.customData; + var customDataLength = customData.length; + + var timeSliceMax = false; + for (i = this._lastTileIndex; i < customDataLength; ++i) { + var data = customData[i]; + var object = data.object; + if (defined(object) && object instanceof Billboard) { + object._newTile = tile; + Billboard._clampPosition(object, frameState.mode, frameState.mapProjection); + if (getTimestamp() >= endTime) { + timeSliceMax = true; + break; + } + } + } + + if (timeSliceMax) { + this._lastTileIndex = i; break; + } else { + this._lastTileIndex = 0; + tileList.shift(); } } @@ -1090,7 +1124,7 @@ define([ vafWriters = this._vaf.writers; // Rewrite entire buffer if billboards were added or removed. - for (var i = 0; i < billboardsLength; ++i) { + for (i = 0; i < billboardsLength; ++i) { var billboard = this._billboards[i]; billboard._dirty = false; // In case it needed an update. writeBillboard(this, context, textureAtlasCoordinates, vafWriters, billboard); @@ -1196,7 +1230,6 @@ define([ var va; var vaLength; var command; - var j; var vs; var fs; diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 9dedcbd8fc8a..8775a2b43645 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -464,15 +464,6 @@ define([ tileSet.push(tile); - if (tile._frameRendered !== frameState.frameNumber - 1) { - var callbacks = tile.callbacks; - var length = callbacks.length; - for (var j = 0; j < length; ++j) { - callbacks[j].func(tile); - } - } - tile._frameRendered = frameState.frameNumber; - var debug = this._debug; ++debug.tilesRendered; debug.texturesRendered += readyTextureCount; diff --git a/Source/Scene/Label.js b/Source/Scene/Label.js index cad87527a522..5ef44f12de13 100644 --- a/Source/Scene/Label.js +++ b/Source/Scene/Label.js @@ -94,7 +94,7 @@ define([ this._rebindAllGlyphs = true; this._repositionAllGlyphs = true; - this._callback = undefined; + this._customData = undefined; this._currentTile = undefined; this._actualClampedPosition = undefined; this._positionChanged = false; diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index b8e733624596..5bd4e0a4d9a1 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -337,8 +337,9 @@ define([ this._totalGlyphCount = 0; this._resolutionScale = undefined; - this._clampToTerrainList = []; + this._renderedTileList = []; this._clampTimeSlice = 1.0; + this._lastTileIndex = 0; /** * The 4x4 transformation matrix that transforms each label in this collection from model to world coordinates. @@ -382,6 +383,16 @@ define([ * @default false */ this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false); + + if (defined(this._globe)) { + var that = this; + this._globe._surface.tileRenderedEvent.addEventListener(function(tile) { + var tileList = that._renderedTileList; + if (tileList.indexOf(tile) === -1) { + tileList.push(tile); + } + }); + } }; defineProperties(LabelCollection.prototype, { @@ -564,15 +575,38 @@ define([ * @private */ LabelCollection.prototype.update = function(context, frameState, commandList) { + var i; + var startTime = getTimestamp(); var timeSlice = this._clampTimeSlice; var endTime = startTime + timeSlice; - var clampList = this._clampToTerrainList; - while (clampList.length > 0) { - Billboard._clampPosition(clampList.shift(), frameState.mode, frameState.mapProjection); - if (getTimestamp() >= endTime) { + var tileList = this._renderedTileList; + while (tileList.length > 0) { + var tile = tileList[0]; + var customData = tile.customData; + var customDataLength = customData.length; + + var timeSliceMax = false; + for (i = this._lastTileIndex; i < customDataLength; ++i) { + var data = customData[i]; + var object = data.object; + if (defined(object) && object instanceof Label) { + object._newTile = tile; + Billboard._clampPosition(object, frameState.mode, frameState.mapProjection); + if (getTimestamp() >= endTime) { + timeSliceMax = true; + break; + } + } + } + + if (timeSliceMax) { + this._lastTileIndex = i; break; + } else { + this._lastTileIndex = 0; + tileList.shift(); } } @@ -600,7 +634,8 @@ define([ labelsToUpdate = this._labelsToUpdate; } - for (var i = 0, len = labelsToUpdate.length; i < len; ++i) { + var len = labelsToUpdate.length; + for (i = 0; i < len; ++i) { var label = labelsToUpdate[i]; if (label.isDestroyed()) { continue; diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index 6edf8020eab0..a65df9ce421a 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -4,6 +4,7 @@ define([ '../Core/defined', '../Core/defineProperties', '../Core/DeveloperError', + '../Core/Event', '../Core/getTimestamp', '../Core/Queue', '../Core/Rectangle', @@ -18,6 +19,7 @@ define([ defined, defineProperties, DeveloperError, + Event, getTimestamp, Queue, Rectangle, @@ -92,8 +94,8 @@ define([ this._levelZeroTilesReady = false; this._loadQueueTimeSlice = 5.0; - this._callbacksAdded = []; - this._callbacksRemoved = []; + this._customDataAdded = []; + this._customDataRemoved = []; /** * Gets or sets the maximum screen-space error, in pixels, that is allowed. @@ -114,6 +116,8 @@ define([ */ this.tileCacheSize = defaultValue(options.tileCacheSize, 100); + this.tileRenderedEvent = new Event(); + this._occluders = new QuadtreeOccluders({ ellipsoid : ellipsoid }); @@ -187,12 +191,12 @@ define([ } }; - QuadtreePrimitive.prototype.addTileLoadedCallback = function(callback) { - this._callbacksAdded.push(callback); + QuadtreePrimitive.prototype.addTileCustomData = function(customData) { + this._customDataAdded.push(customData); }; - QuadtreePrimitive.prototype.removeTileLoadedCallback = function(callback) { - this._callbacksRemoved.push(callback); + QuadtreePrimitive.prototype.removeTileCustomData = function(customData) { + this._customDataRemoved.push(customData); }; /** @@ -298,18 +302,18 @@ define([ var tile; var levelZeroTiles = primitive._levelZeroTiles; - var callbacksAdded = primitive._callbacksAdded; - var callbacksRemoved = primitive._callbacksRemoved; + var customDataAdded = primitive._customDataAdded; + var customDataRemoved = primitive._customDataRemoved; var frameNumber = frameState.frameNumber; - if (callbacksAdded.length > 0 || callbacksRemoved.length > 0) { + if (customDataAdded.length > 0 || customDataRemoved.length > 0) { for (i = 0, len = levelZeroTiles.length; i < len; ++i) { tile = levelZeroTiles[i]; - tile._updateCallbacks(frameNumber, callbacksAdded, callbacksRemoved); + tile._updateCustomData(frameNumber, customDataAdded, customDataRemoved); } - callbacksAdded.length = 0; - callbacksRemoved.length = 0; + customDataAdded.length = 0; + customDataRemoved.length = 0; } // Enqueue the root tiles that are renderable and visible. @@ -337,7 +341,7 @@ define([ ++debug.tilesVisited; primitive._tileReplacementQueue.markTileRendered(tile); - tile._updateCallbacks(frameNumber); + tile._updateCustomData(frameNumber); if (tile.level > debug.maxDepth) { debug.maxDepth = tile.level; @@ -490,7 +494,13 @@ define([ tilesToRender.sort(tileDistanceSortFunction); for (var i = 0, len = tilesToRender.length; i < len; ++i) { - tileProvider.showTileThisFrame(tilesToRender[i], context, frameState, commandList); + var tile = tilesToRender[i]; + tileProvider.showTileThisFrame(tile, context, frameState, commandList); + + if (tile._frameRendered !== frameState.frameNumber - 1) { + primitive.tileRenderedEvent.raiseEvent(tile); + } + tile._frameRendered = frameState.frameNumber; } } diff --git a/Source/Scene/QuadtreeTile.js b/Source/Scene/QuadtreeTile.js index 57da2e53f048..eade6322eb78 100644 --- a/Source/Scene/QuadtreeTile.js +++ b/Source/Scene/QuadtreeTile.js @@ -64,7 +64,7 @@ define([ // QuadtreePrimitive gets/sets this private property. this._distance = 0.0; - this._callbacks = []; + this._customData = []; this._frameUpdated = undefined; this._frameRendered = undefined; @@ -135,20 +135,20 @@ define([ return result; }; - QuadtreeTile.prototype._updateCallbacks = function(frameNumber, added, removed) { - var callbacks = this.callbacks; + QuadtreeTile.prototype._updateCustomData = function(frameNumber, added, removed) { + var customData = this.customData; var i; - var callback; + var data; var rectangle; if (defined(added) && defined(removed)) { // level zero tile for (i = 0; i < removed.length; ++i) { - callback = removed[i]; - for (var j = 0; j < callbacks.length; ++j) { - if (callbacks[j] === callback) { - callbacks.splice(j, 1); + data = removed[i]; + for (var j = 0; j < customData.length; ++j) { + if (customData[j] === data) { + customData.splice(j, 1); break; } } @@ -156,9 +156,9 @@ define([ rectangle = this._rectangle; for (i = 0; i < added.length; ++i) { - callback = added[i]; - if (Rectangle.contains(rectangle, callback.position)) { - callbacks.push(callback); + data = added[i]; + if (Rectangle.contains(rectangle, data.position)) { + customData.push(data); } } @@ -167,14 +167,14 @@ define([ // interior or leaf tile, update from parent var parent = this._parent; if (defined(parent) && this._frameUpdated !== parent._frameUpdated) { - callbacks.length = 0; + customData.length = 0; rectangle = this._rectangle; - var parentCallbacks = parent.callbacks; - for (i = 0; i < parentCallbacks.length; ++i) { - callback = parentCallbacks[i]; - if (Rectangle.contains(rectangle, callback.position)) { - callbacks.push(callback); + var parentCustomData = parent.customData; + for (i = 0; i < parentCustomData.length; ++i) { + data = parentCustomData[i]; + if (Rectangle.contains(rectangle, data.position)) { + customData.push(data); } } @@ -294,9 +294,9 @@ define([ } }, - callbacks : { + customData : { get : function() { - return this._callbacks; + return this._customData; } }, From fefe9444f83045ec188ba4a0f37f7c9274e7a00b Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Wed, 22 Apr 2015 20:04:13 -0400 Subject: [PATCH 16/40] Change clampToGround boolean to heightReference with enum that can be none, clamp to ground or relative to ground. Clean up modifications to quadtree when destroying a billboard or label. --- Source/Scene/Billboard.js | 39 ++++++++++++++++------- Source/Scene/BillboardCollection.js | 7 +++- Source/Scene/HeightReference.js | 15 +++++++++ Source/Scene/Label.js | 15 +++++---- Source/Scene/LabelCollection.js | 17 +++++++++- Source/Shaders/BillboardCollectionVS.glsl | 5 ++- 6 files changed, 78 insertions(+), 20 deletions(-) create mode 100644 Source/Scene/HeightReference.js diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index 405973327236..c1a5a2f0d44c 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -14,6 +14,7 @@ define([ '../Core/Matrix4', '../Core/NearFarScalar', '../Core/Ray', + './HeightReference', './HorizontalOrigin', './SceneMode', './SceneTransforms', @@ -33,6 +34,7 @@ define([ Matrix4, NearFarScalar, Ray, + HeightReference, HorizontalOrigin, SceneMode, SceneTransforms, @@ -102,7 +104,7 @@ define([ this._scaleByDistance = options.scaleByDistance; this._translucencyByDistance = options.translucencyByDistance; this._pixelOffsetScaleByDistance = options.pixelOffsetScaleByDistance; - this._clampToGround = defaultValue(options.clampToGround, false); + this._heightReference = defaultValue(options.heightReference, HeightReference.NONE); this._id = options.id; this._collection = defaultValue(options.collection, billboardCollection); @@ -148,6 +150,7 @@ define([ this._customData = undefined; this._currentTile = undefined; + this._newTile = undefined; this._actualClampedPosition = undefined; this._positionChanged = false; this._mode = undefined; @@ -231,9 +234,9 @@ define([ } }, - clampToGround : { + heightReference : { get : function() { - return this._clampToGround; + return this._heightReference; }, set : function(value) { //>>includeStart('debug', pragmas.debug) @@ -242,9 +245,9 @@ define([ } //>>includeEnd('debug'); - var clampToGround = this._clampToGround; - if (value !== clampToGround) { - this._clampToGround = value; + var heightReference = this._heightReference; + if (value !== heightReference) { + this._heightReference = value; this._updateClamping(); makeDirty(this, POSITION_INDEX); } @@ -812,12 +815,13 @@ define([ Billboard._clampPosition = function(object, mode, projection, markObjectDirty) { var modeChanged = mode !== SceneMode.MORPHING && mode !== object._mode; + var ellipsoid = projection.ellipsoid; + if (object._newTile !== object._currentTile || object._positionChanged || modeChanged) { if (mode === SceneMode.SCENE3D) { Cartesian3.clone(Cartesian3.ZERO, scratchRay.origin); Cartesian3.normalize(object.position, scratchRay.direction); } else { - var ellipsoid = projection.ellipsoid; ellipsoid.cartesianToCartographic(object.position, scratchCartographic); scratchCartographic.height = -1000.0; // TODO: get minimum height of entire terrain set projection.project(scratchCartographic, scratchPosition); @@ -828,6 +832,11 @@ define([ var position = object._newTile.data.pick(scratchRay, mode, projection, false, scratchPosition); if (defined(position)) { + if (object._heightReference === HeightReference.RELATIVE_TO_GROUND) { + var clampedCart = ellipsoid.cartesianToCartographic(position, scratchCartographic); + clampedCart.height += object._customData.position.height; + ellipsoid.cartographicToCartesian(clampedCart, position); + } object._clampedPosition = Cartesian3.clone(position, object._clampedPosition); } @@ -844,8 +853,8 @@ define([ Billboard._updateClamping = function(collection, object) { var globe = collection._globe; if (!defined(globe)) { - if (defined(object._clampToGround)) { - throw new DeveloperError('Clamping a billboard to the ground is not supported.'); + if (object._heightReference !== HeightReference.NONE) { + throw new DeveloperError('Height reference is not supported.'); } return; } @@ -854,12 +863,12 @@ define([ var surface = globe._surface; var customData = object._customData; - if (defined(customData) && !object._clampToGround) { + if (defined(customData) && object._heightReference === HeightReference.NONE) { surface.removeTileCustomData(customData); object._customData = undefined; } - if (!object._clampToGround || !defined(object._position)) { + if (object._heightReference === HeightReference.NONE || !defined(object._position)) { return; } @@ -1155,6 +1164,14 @@ define([ }; Billboard.prototype._destroy = function() { + if (defined(this._customData)) { + this._billboardCollection._globe._surface.removeTileCustomData(this._customData); + this._customData = undefined; + } + + this._currentTile = undefined; + this._newTile = undefined; + this.image = undefined; this._pickId = this._pickId && this._pickId.destroy(); this._billboardCollection = undefined; diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 81ac35cf2dd5..417abb95a73e 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -264,8 +264,9 @@ define([ } }; + this._removeEventFunc = undefined; if (defined(this._globe)) { - this._globe._surface.tileRenderedEvent.addEventListener(function(tile) { + this._removeEventFunc = this._globe._surface.tileRenderedEvent.addEventListener(function(tile) { var tileList = that._renderedTileList; if (tileList.indexOf(tile) === -1) { tileList.push(tile); @@ -1419,6 +1420,10 @@ define([ this._vaf = this._vaf && this._vaf.destroy(); this._destroyBillboards(); + if (defined(this._removeEventFunc)) { + this._removeEventFunc(); + } + return destroyObject(this); }; diff --git a/Source/Scene/HeightReference.js b/Source/Scene/HeightReference.js new file mode 100644 index 000000000000..42681ead89fd --- /dev/null +++ b/Source/Scene/HeightReference.js @@ -0,0 +1,15 @@ +/*global define*/ +define([ + '../Core/freezeObject' + ], function( + freezeObject) { + "use strict"; + + var HeightReference = { + NONE : 0, + CLAMP_TO_GROUND : 1, + RELATIVE_TO_GROUND : 2 + }; + + return freezeObject(HeightReference); +}); diff --git a/Source/Scene/Label.js b/Source/Scene/Label.js index 5ef44f12de13..0151fe54e995 100644 --- a/Source/Scene/Label.js +++ b/Source/Scene/Label.js @@ -9,6 +9,7 @@ define([ '../Core/DeveloperError', '../Core/NearFarScalar', './Billboard', + './HeightReference', './HorizontalOrigin', './LabelStyle', './VerticalOrigin' @@ -22,6 +23,7 @@ define([ DeveloperError, NearFarScalar, Billboard, + HeightReference, HorizontalOrigin, LabelStyle, VerticalOrigin) { @@ -86,7 +88,7 @@ define([ this._id = options.id; this._translucencyByDistance = options.translucencyByDistance; this._pixelOffsetScaleByDistance = options.pixelOffsetScaleByDistance; - this._clampToGround = defaultValue(options.clampToGround, false); + this._heightReference = defaultValue(options.heightReference, HeightReference.NONE); this._labelCollection = labelCollection; this._glyphs = []; @@ -96,6 +98,7 @@ define([ this._customData = undefined; this._currentTile = undefined; + this._newTile = undefined; this._actualClampedPosition = undefined; this._positionChanged = false; this._mode = undefined; @@ -155,7 +158,7 @@ define([ if (!Cartesian3.equals(position, value)) { Cartesian3.clone(value, position); - if (!this._clampToGround) { + if (this._heightReference === HeightReference.NONE) { var glyphs = this._glyphs; for (var i = 0, len = glyphs.length; i < len; i++) { var glyph = glyphs[i]; @@ -170,9 +173,9 @@ define([ } }, - clampToGround : { + heightReference : { get : function() { - return this._clampToGround; + return this._heightReference; }, set : function(value) { //>>includeStart('debug', pragmas.debug); @@ -181,8 +184,8 @@ define([ } //>>includeEnd('debug'); - if (value !== this._clampToGround) { - this._clamptoGround = value; + if (value !== this._heightReference) { + this._heightReference = value; this._updateClamping(); } } diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index 5bd4e0a4d9a1..e1d0d4691d07 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -272,6 +272,15 @@ define([ unbindGlyph(labelCollection, glyphs[i]); } label._labelCollection = undefined; + + if (defined(label._customData)) { + labelCollection._globe._surface.removeTileCustomData(label._customData); + label._customData = undefined; + } + + label._currentTile = undefined; + label._newTile = undefined; + destroyObject(label); } @@ -384,9 +393,10 @@ define([ */ this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false); + this._removeEventFunc = undefined; if (defined(this._globe)) { var that = this; - this._globe._surface.tileRenderedEvent.addEventListener(function(tile) { + this._removeEventFunc = this._globe._surface.tileRenderedEvent.addEventListener(function(tile) { var tileList = that._renderedTileList; if (tileList.indexOf(tile) === -1) { tileList.push(tile); @@ -696,6 +706,11 @@ define([ this.removeAll(); this._billboardCollection = this._billboardCollection.destroy(); this._textureAtlas = this._textureAtlas && this._textureAtlas.destroy(); + + if (defined(this._removeEventFunc)) { + this._removeEventFunc(); + } + return destroyObject(this); }; diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index 7f599408ec32..747c7de38c4f 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -226,7 +226,10 @@ void main() #endif #ifdef TEST_GLOBE_DEPTH - vec4 offsetPosition = positionEC + vec4(0.0, 0.0, -positionEC.z * 0.05, 0.0); + //float piece = step(3000.0, -positionEC.z); + //float offsetZ = (1.0 - piece) * -positionEC.z * 0.005; + float offsetZ = -positionEC.z * 0.005; + vec4 offsetPosition = positionEC + vec4(0.0, 0.0, offsetZ, 0.0); vec4 wc = computePositionWindowCoordinates(offsetPosition, vec2(0.0, 0.0), scale, direction, origin, vec2(0.0), pixelOffset, alignedAxis, rotation); float d = texture2D(czm_globeDepthTexture, wc.xy / czm_viewport.zw).r; if (wc.z > d) From 1bdde11d52cb9b55faf068a60f1fe151973034c5 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 24 Apr 2015 17:51:44 -0400 Subject: [PATCH 17/40] Change method for determining billboard visibility. --- Source/Shaders/BillboardCollectionVS.glsl | 28 +++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index 747c7de38c4f..49981f3cfa83 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -226,13 +226,27 @@ void main() #endif #ifdef TEST_GLOBE_DEPTH - //float piece = step(3000.0, -positionEC.z); - //float offsetZ = (1.0 - piece) * -positionEC.z * 0.005; - float offsetZ = -positionEC.z * 0.005; - vec4 offsetPosition = positionEC + vec4(0.0, 0.0, offsetZ, 0.0); - vec4 wc = computePositionWindowCoordinates(offsetPosition, vec2(0.0, 0.0), scale, direction, origin, vec2(0.0), pixelOffset, alignedAxis, rotation); - float d = texture2D(czm_globeDepthTexture, wc.xy / czm_viewport.zw).r; - if (wc.z > d) + vec2 directions[4]; + directions[0] = vec2(0.0, 0.0); + directions[1] = vec2(0.0, 1.0); + directions[2] = vec2(1.0, 0.0); + directions[3] = vec2(1.0, 1.0); + + vec2 invSize = 1.0 / czm_viewport.zw; + + bool visible = false; + for (int i = 0; i < 4; ++i) + { + vec4 wc = computePositionWindowCoordinates(positionEC, imageSize, scale, directions[i], origin, vec2(0.0), pixelOffset, alignedAxis, rotation); + float d = texture2D(czm_globeDepthTexture, wc.xy * invSize).r; + if (wc.z < d) + { + visible = true; + break; + } + } + + if (!visible) { gl_Position = czm_projection * vec4(vec3(0.0), 1.0); return; From e70d14009ac64e32c4771536d38207c6d9fa97a7 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 24 Apr 2015 17:59:27 -0400 Subject: [PATCH 18/40] Add Sandcastle example clamping billboards to the ground. --- .../development/BillboardClampToGround.html | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 Apps/Sandcastle/gallery/development/BillboardClampToGround.html diff --git a/Apps/Sandcastle/gallery/development/BillboardClampToGround.html b/Apps/Sandcastle/gallery/development/BillboardClampToGround.html new file mode 100644 index 000000000000..2eaf158d3954 --- /dev/null +++ b/Apps/Sandcastle/gallery/development/BillboardClampToGround.html @@ -0,0 +1,73 @@ + + + + + + + + + Cesium Demo + + + + + + +
+

Loading...

+
+
+
+
+
+
+ + + From 55cc7d35f2c34546a3445fb4f88d6c28e997d266 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 28 Apr 2015 14:12:17 -0400 Subject: [PATCH 19/40] Add attribute to billboards to compute label visibility. --- Source/Scene/Billboard.js | 18 ++++++++++++++- Source/Scene/BillboardCollection.js | 28 +++++++++++++++++++++-- Source/Scene/LabelCollection.js | 7 ++++++ Source/Shaders/BillboardCollectionVS.glsl | 4 +++- 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index c1a5a2f0d44c..f2cd7f3baf1f 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -105,6 +105,7 @@ define([ this._translucencyByDistance = options.translucencyByDistance; this._pixelOffsetScaleByDistance = options.pixelOffsetScaleByDistance; this._heightReference = defaultValue(options.heightReference, HeightReference.NONE); + this._maxImageSize = new Cartesian2(); // used by labels this._id = options.id; this._collection = defaultValue(options.collection, billboardCollection); @@ -172,7 +173,8 @@ define([ var SCALE_BY_DISTANCE_INDEX = Billboard.SCALE_BY_DISTANCE_INDEX = 11; var TRANSLUCENCY_BY_DISTANCE_INDEX = Billboard.TRANSLUCENCY_BY_DISTANCE_INDEX = 12; var PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX = Billboard.PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX = 13; - Billboard.NUMBER_OF_PROPERTIES = 14; + var MAX_SIZE_INDEX = Billboard.MAX_SIZE_INDEX = 14; + Billboard.NUMBER_OF_PROPERTIES = 15; function makeDirty(billboard, propertyChanged) { var billboardCollection = billboard._billboardCollection; @@ -1040,6 +1042,20 @@ define([ } }; + Billboard.prototype._setMaxImageSize = function(value) { + //>>includeStart('debug', pragmas.debug); + if (!defined(value)) { + throw new DeveloperError('value is required.'); + } + //>>includeEnd('debug'); + + var maxSize = this._maxImageSize; + if (!Cartesian2.equals(maxSize, value)) { + Cartesian2.clone(value, maxSize); + makeDirty(this, MAX_SIZE_INDEX); + } + }; + Billboard.prototype._getActualPosition = function() { return defined(this._customData) && defined(this._clampedPosition) && this._mode !== SceneMode.MORPHING ? this._clampedPosition : this._actualPosition; }; diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 417abb95a73e..3a176de09cd4 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -73,6 +73,7 @@ define([ var SCALE_BY_DISTANCE_INDEX = Billboard.SCALE_BY_DISTANCE_INDEX; var TRANSLUCENCY_BY_DISTANCE_INDEX = Billboard.TRANSLUCENCY_BY_DISTANCE_INDEX; var PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX = Billboard.PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX; + var MAX_SIZE_INDEX = Billboard.MAX_SIZE_INDEX; var NUMBER_OF_PROPERTIES = Billboard.NUMBER_OF_PROPERTIES; var attributeLocations = { @@ -83,7 +84,8 @@ define([ compressedAttribute2 : 4, // image height, color, pick color, 2 bytes free eyeOffset : 5, scaleByDistance : 6, - pixelOffsetScaleByDistance : 7 + pixelOffsetScaleByDistance : 7, + maxSize : 8 }; /** @@ -254,7 +256,8 @@ define([ BufferUsage.STATIC_DRAW, // ALIGNED_AXIS_INDEX BufferUsage.STATIC_DRAW, // SCALE_BY_DISTANCE_INDEX BufferUsage.STATIC_DRAW, // TRANSLUCENCY_BY_DISTANCE_INDEX - BufferUsage.STATIC_DRAW // PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX + BufferUsage.STATIC_DRAW, // PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX + BufferUsage.STATIC_DRAW // PIXEL_MAX_SIZE_INDEX ]; var that = this; @@ -609,6 +612,11 @@ define([ componentsPerAttribute : 4, componentDatatype : ComponentDatatype.FLOAT, usage : buffersUsage[PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX] + }, { + index : attributeLocations.maxSize, + componentsPerAttribute : 2, + componentDatatype : ComponentDatatype.FLOAT, + usage : buffersUsage[MAX_SIZE_INDEX] }], 4 * numberOfBillboards); // 4 vertices per billboard } @@ -931,6 +939,17 @@ define([ writer(i + 3, near, nearValue, far, farValue); } + function writeMaxSize(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) { + var i = billboard._index * 4; + var maxSize = billboard._maxImageSize; + + var writer = vafWriters[attributeLocations.maxSize]; + writer(i + 0, maxSize.x, maxSize.y); + writer(i + 1, maxSize.x, maxSize.y); + writer(i + 2, maxSize.x, maxSize.y); + writer(i + 3, maxSize.x, maxSize.y); + } + function writeBillboard(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) { writePositionScaleAndRotation(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard); writeCompressedAttrib0(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard); @@ -939,6 +958,7 @@ define([ writeEyeOffset(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard); writeScaleByDistance(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard); writePixelOffsetScaleByDistance(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard); + writeMaxSize(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard); } function recomputeActualPositions(billboardCollection, billboards, length, frameState, modelMatrix, recomputeBoundingVolume) { @@ -1169,6 +1189,10 @@ define([ writers.push(writePixelOffsetScaleByDistance); } + if (properties[MAX_SIZE_INDEX]) { + writers.push(writeMaxSize); + } + vafWriters = this._vaf.writers; if ((billboardsToUpdateLength / billboardsLength) > 0.1) { diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index e1d0d4691d07..3fafaa32df27 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -214,6 +214,7 @@ define([ // reusable Cartesian2 instance var glyphPixelOffset = new Cartesian2(); + var maxSize = new Cartesian2(); function repositionAllGlyphs(label, resolutionScale) { var glyphs = label._glyphs; @@ -221,6 +222,7 @@ define([ var dimensions; var totalWidth = 0; var maxHeight = 0; + var maxWidth = 0; var glyphIndex = 0; var glyphLength = glyphs.length; @@ -229,6 +231,7 @@ define([ dimensions = glyph.dimensions; totalWidth += dimensions.computedWidth; maxHeight = Math.max(maxHeight, dimensions.height); + maxWidth = Math.max(maxWidth, dimensions.computedWidth); } var scale = label._scale; @@ -243,6 +246,9 @@ define([ glyphPixelOffset.x = widthOffset * resolutionScale; glyphPixelOffset.y = 0; + maxSize.x = maxWidth; + maxSize.y = maxHeight; + var verticalOrigin = label._verticalOrigin; for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) { glyph = glyphs[glyphIndex]; @@ -260,6 +266,7 @@ define([ if (defined(glyph.billboard)) { glyph.billboard._setTranslate(glyphPixelOffset); + glyph.billboard._setMaxImageSize(maxSize); } glyphPixelOffset.x += dimensions.computedWidth * scale * resolutionScale; diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index 49981f3cfa83..7b3c869a5637 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -6,6 +6,7 @@ attribute vec4 compressedAttribute2; // image height, color, pick color, attribute vec3 eyeOffset; // eye offset in meters attribute vec4 scaleByDistance; // near, nearScale, far, farScale attribute vec4 pixelOffsetScaleByDistance; // near, nearScale, far, farScale +attribute vec2 maxSize; varying vec2 v_textureCoordinates; @@ -233,11 +234,12 @@ void main() directions[3] = vec2(1.0, 1.0); vec2 invSize = 1.0 / czm_viewport.zw; + vec2 size = all(equal(vec2(0.0), maxSize)) ? imageSize : maxSize; bool visible = false; for (int i = 0; i < 4; ++i) { - vec4 wc = computePositionWindowCoordinates(positionEC, imageSize, scale, directions[i], origin, vec2(0.0), pixelOffset, alignedAxis, rotation); + vec4 wc = computePositionWindowCoordinates(positionEC, size, scale, directions[i], vec2(0.0, 0.0), vec2(0.0), pixelOffset, alignedAxis, rotation); float d = texture2D(czm_globeDepthTexture, wc.xy * invSize).r; if (wc.z < d) { From 0ae305a719eb1a707e3921ca2c2f407a2c362bb7 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 28 Apr 2015 14:59:45 -0400 Subject: [PATCH 20/40] Only update billboard position on terrain loaded. --- Source/Scene/Billboard.js | 15 ++++++--------- Source/Scene/BillboardCollection.js | 5 ++--- Source/Scene/LabelCollection.js | 2 +- Source/Scene/QuadtreePrimitive.js | 6 ++++++ 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index f2cd7f3baf1f..e4c255e16160 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -150,8 +150,7 @@ define([ } this._customData = undefined; - this._currentTile = undefined; - this._newTile = undefined; + this._level = 0; this._actualClampedPosition = undefined; this._positionChanged = false; this._mode = undefined; @@ -815,11 +814,12 @@ define([ var scratchPosition = new Cartesian3(); var scratchCartographic = new Cartographic(); - Billboard._clampPosition = function(object, mode, projection, markObjectDirty) { + Billboard._clampPosition = function(object, tile, mode, projection) { var modeChanged = mode !== SceneMode.MORPHING && mode !== object._mode; var ellipsoid = projection.ellipsoid; + var level = tile.level; - if (object._newTile !== object._currentTile || object._positionChanged || modeChanged) { + if (level > object._level || object._positionChanged || modeChanged) { if (mode === SceneMode.SCENE3D) { Cartesian3.clone(Cartesian3.ZERO, scratchRay.origin); Cartesian3.normalize(object.position, scratchRay.direction); @@ -832,7 +832,7 @@ define([ Cartesian3.clone(Cartesian3.UNIT_X, scratchRay.direction); } - var position = object._newTile.data.pick(scratchRay, mode, projection, false, scratchPosition); + var position = tile.data.pick(scratchRay, mode, projection, false, scratchPosition); if (defined(position)) { if (object._heightReference === HeightReference.RELATIVE_TO_GROUND) { var clampedCart = ellipsoid.cartesianToCartographic(position, scratchCartographic); @@ -844,7 +844,7 @@ define([ object._positionChanged = false; object._mode = mode; - object._currentTile = object._newTile; + object._level = level; } }; @@ -1185,9 +1185,6 @@ define([ this._customData = undefined; } - this._currentTile = undefined; - this._newTile = undefined; - this.image = undefined; this._pickId = this._pickId && this._pickId.destroy(); this._billboardCollection = undefined; diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 3a176de09cd4..c1a77ece3f4d 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -269,7 +269,7 @@ define([ this._removeEventFunc = undefined; if (defined(this._globe)) { - this._removeEventFunc = this._globe._surface.tileRenderedEvent.addEventListener(function(tile) { + this._removeEventFunc = this._globe._surface.tileLoadedEvent.addEventListener(function(tile) { var tileList = that._renderedTileList; if (tileList.indexOf(tile) === -1) { tileList.push(tile); @@ -1071,8 +1071,7 @@ define([ var data = customData[i]; var object = data.object; if (defined(object) && object instanceof Billboard) { - object._newTile = tile; - Billboard._clampPosition(object, frameState.mode, frameState.mapProjection); + Billboard._clampPosition(object, tile, frameState.mode, frameState.mapProjection); if (getTimestamp() >= endTime) { timeSliceMax = true; break; diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index 3fafaa32df27..31b7e0748f11 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -403,7 +403,7 @@ define([ this._removeEventFunc = undefined; if (defined(this._globe)) { var that = this; - this._removeEventFunc = this._globe._surface.tileRenderedEvent.addEventListener(function(tile) { + this._removeEventFunc = this._globe._surface.tileLoadedEvent.addEventListener(function(tile) { var tileList = that._renderedTileList; if (tileList.indexOf(tile) === -1) { tileList.push(tile); diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index a65df9ce421a..de2d0f69effc 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -117,6 +117,7 @@ define([ this.tileCacheSize = defaultValue(options.tileCacheSize, 100); this.tileRenderedEvent = new Event(); + this.tileLoadedEvent = new Event(); this._occluders = new QuadtreeOccluders({ ellipsoid : ellipsoid @@ -477,6 +478,11 @@ define([ var tile = tileLoadQueue[i]; primitive._tileReplacementQueue.markTileRendered(tile); tileProvider.loadTile(context, frameState, tile); + + if (tile.state === QuadtreeTileLoadState.DONE) { + primitive.tileLoadedEvent.raiseEvent(tile); + } + if (getTimestamp() >= endTime) { break; } From b25eac780396e928dabee513dc9edc087920316b Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 28 Apr 2015 16:31:24 -0400 Subject: [PATCH 21/40] Remove updating the billboard on tile load. Update the position on tile render only if the level is greater than the billboard level. --- Source/Scene/BillboardCollection.js | 2 +- Source/Scene/LabelCollection.js | 2 +- Source/Scene/QuadtreePrimitive.js | 6 --- Source/Shaders/BillboardCollectionVS.glsl | 51 ++++++++++++----------- 4 files changed, 29 insertions(+), 32 deletions(-) diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index c1a77ece3f4d..b2ef4b9b1d15 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -269,7 +269,7 @@ define([ this._removeEventFunc = undefined; if (defined(this._globe)) { - this._removeEventFunc = this._globe._surface.tileLoadedEvent.addEventListener(function(tile) { + this._removeEventFunc = this._globe._surface.tileRenderedEvent.addEventListener(function(tile) { var tileList = that._renderedTileList; if (tileList.indexOf(tile) === -1) { tileList.push(tile); diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index 31b7e0748f11..3fafaa32df27 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -403,7 +403,7 @@ define([ this._removeEventFunc = undefined; if (defined(this._globe)) { var that = this; - this._removeEventFunc = this._globe._surface.tileLoadedEvent.addEventListener(function(tile) { + this._removeEventFunc = this._globe._surface.tileRenderedEvent.addEventListener(function(tile) { var tileList = that._renderedTileList; if (tileList.indexOf(tile) === -1) { tileList.push(tile); diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index de2d0f69effc..a65df9ce421a 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -117,7 +117,6 @@ define([ this.tileCacheSize = defaultValue(options.tileCacheSize, 100); this.tileRenderedEvent = new Event(); - this.tileLoadedEvent = new Event(); this._occluders = new QuadtreeOccluders({ ellipsoid : ellipsoid @@ -478,11 +477,6 @@ define([ var tile = tileLoadQueue[i]; primitive._tileReplacementQueue.markTileRendered(tile); tileProvider.loadTile(context, frameState, tile); - - if (tile.state === QuadtreeTileLoadState.DONE) { - primitive.tileLoadedEvent.raiseEvent(tile); - } - if (getTimestamp() >= endTime) { break; } diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index 7b3c869a5637..93489ea4b27c 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -227,31 +227,34 @@ void main() #endif #ifdef TEST_GLOBE_DEPTH - vec2 directions[4]; - directions[0] = vec2(0.0, 0.0); - directions[1] = vec2(0.0, 1.0); - directions[2] = vec2(1.0, 0.0); - directions[3] = vec2(1.0, 1.0); - - vec2 invSize = 1.0 / czm_viewport.zw; - vec2 size = all(equal(vec2(0.0), maxSize)) ? imageSize : maxSize; - - bool visible = false; - for (int i = 0; i < 4; ++i) - { - vec4 wc = computePositionWindowCoordinates(positionEC, size, scale, directions[i], vec2(0.0, 0.0), vec2(0.0), pixelOffset, alignedAxis, rotation); - float d = texture2D(czm_globeDepthTexture, wc.xy * invSize).r; - if (wc.z < d) - { - visible = true; - break; - } - } - - if (!visible) + if (-positionEC.z < 70000.0) { - gl_Position = czm_projection * vec4(vec3(0.0), 1.0); - return; + vec2 directions[4]; + directions[0] = vec2(0.0, 0.0); + directions[1] = vec2(0.0, 1.0); + directions[2] = vec2(1.0, 0.0); + directions[3] = vec2(1.0, 1.0); + + vec2 invSize = 1.0 / czm_viewport.zw; + vec2 size = all(equal(vec2(0.0), maxSize)) ? imageSize : maxSize; + + bool visible = false; + for (int i = 0; i < 4; ++i) + { + vec4 wc = computePositionWindowCoordinates(positionEC, size, scale, directions[i], vec2(0.0, 0.0), vec2(0.0), pixelOffset, alignedAxis, rotation); + float d = texture2D(czm_globeDepthTexture, wc.xy * invSize).r; + if (wc.z < d) + { + visible = true; + break; + } + } + + if (!visible) + { + gl_Position = czm_projection * vec4(vec3(0.0), 1.0); + return; + } } #endif From 8d3377c6538abd4d6d760a83b947e5af497817e8 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 28 Apr 2015 19:47:32 -0400 Subject: [PATCH 22/40] Fix updating height reference and changine position. Fixed columbus view. --- Source/Scene/Billboard.js | 37 ++++++++++++---- Source/Shaders/BillboardCollectionVS.glsl | 51 +++++++++++------------ 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index e4c255e16160..1c23095bb53f 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -152,7 +152,6 @@ define([ this._customData = undefined; this._level = 0; this._actualClampedPosition = undefined; - this._positionChanged = false; this._mode = undefined; this._updateClamping(); @@ -815,11 +814,11 @@ define([ var scratchCartographic = new Cartographic(); Billboard._clampPosition = function(object, tile, mode, projection) { - var modeChanged = mode !== SceneMode.MORPHING && mode !== object._mode; + var modeChanged = object._mode !== mode; var ellipsoid = projection.ellipsoid; var level = tile.level; - if (level > object._level || object._positionChanged || modeChanged) { + if (level > object._level || modeChanged) { if (mode === SceneMode.SCENE3D) { Cartesian3.clone(Cartesian3.ZERO, scratchRay.origin); Cartesian3.normalize(object.position, scratchRay.direction); @@ -842,8 +841,8 @@ define([ object._clampedPosition = Cartesian3.clone(position, object._clampedPosition); } - object._positionChanged = false; object._mode = mode; + object._projection = projection; object._level = level; } }; @@ -865,9 +864,12 @@ define([ var surface = globe._surface; var customData = object._customData; + var mode = object._mode = defaultValue(object._mode, SceneMode.SCENE3D); + if (defined(customData) && object._heightReference === HeightReference.NONE) { surface.removeTileCustomData(customData); object._customData = undefined; + object._clampedPosition = undefined; } if (object._heightReference === HeightReference.NONE || !defined(object._position)) { @@ -880,9 +882,6 @@ define([ } if (defined(customData)) { - if (Cartographic.equals(position, customData.position)) { - return; - } surface.removeTileCustomData(customData); } @@ -891,7 +890,20 @@ define([ object : object }; surface.addTileCustomData(object._customData); - object._positionChanged = true; + + var height = globe.getHeight(position); + if (defined(height)) { + var clampedCart = Cartographic.clone(position, scratchCartographic); + clampedCart.height = object._heightReference === HeightReference.RELATIVE_TO_GROUND ? height + position.height : height; + + if (mode === SceneMode.SCENE3D) { + object._clampedPosition = ellipsoid.cartographicToCartesian(clampedCart, object._clampedPosition); + } else if (defined(object._projection)) { + object._projection.project(clampedCart, scratchPosition); + object._clampedPosition = Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, object._clampedPosition); + } + + } }; Billboard.prototype._loadImage = function() { @@ -1061,13 +1073,20 @@ define([ }; Billboard.prototype._setActualPosition = function(value) { - Cartesian3.clone(value, this._actualPosition); + if (!(defined(this._customData) && defined(this._clampedPosition) && this._mode !== SceneMode.MORPHING)) { + Cartesian3.clone(value, this._actualPosition); + } makeDirty(this, POSITION_INDEX); }; var tempCartesian3 = new Cartesian4(); Billboard._computeActualPosition = function(billboard, position, frameState, modelMatrix) { if (defined(billboard._customData) && defined(billboard._clampedPosition) && this._mode !== SceneMode.MORPHING) { + if (frameState.mode !== this._mode) { + billboard._mode = frameState.mode; + billboard._projection = frameState.mapProjection; + billboard._updateClamping(); + } return billboard._clampedPosition; } else if (frameState.mode === SceneMode.SCENE3D) { return position; diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index 93489ea4b27c..7b3c869a5637 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -227,34 +227,31 @@ void main() #endif #ifdef TEST_GLOBE_DEPTH - if (-positionEC.z < 70000.0) + vec2 directions[4]; + directions[0] = vec2(0.0, 0.0); + directions[1] = vec2(0.0, 1.0); + directions[2] = vec2(1.0, 0.0); + directions[3] = vec2(1.0, 1.0); + + vec2 invSize = 1.0 / czm_viewport.zw; + vec2 size = all(equal(vec2(0.0), maxSize)) ? imageSize : maxSize; + + bool visible = false; + for (int i = 0; i < 4; ++i) + { + vec4 wc = computePositionWindowCoordinates(positionEC, size, scale, directions[i], vec2(0.0, 0.0), vec2(0.0), pixelOffset, alignedAxis, rotation); + float d = texture2D(czm_globeDepthTexture, wc.xy * invSize).r; + if (wc.z < d) + { + visible = true; + break; + } + } + + if (!visible) { - vec2 directions[4]; - directions[0] = vec2(0.0, 0.0); - directions[1] = vec2(0.0, 1.0); - directions[2] = vec2(1.0, 0.0); - directions[3] = vec2(1.0, 1.0); - - vec2 invSize = 1.0 / czm_viewport.zw; - vec2 size = all(equal(vec2(0.0), maxSize)) ? imageSize : maxSize; - - bool visible = false; - for (int i = 0; i < 4; ++i) - { - vec4 wc = computePositionWindowCoordinates(positionEC, size, scale, directions[i], vec2(0.0, 0.0), vec2(0.0), pixelOffset, alignedAxis, rotation); - float d = texture2D(czm_globeDepthTexture, wc.xy * invSize).r; - if (wc.z < d) - { - visible = true; - break; - } - } - - if (!visible) - { - gl_Position = czm_projection * vec4(vec3(0.0), 1.0); - return; - } + gl_Position = czm_projection * vec4(vec3(0.0), 1.0); + return; } #endif From ae61e7abacf9077068c44dbd60e9c614bceec4ba Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 28 Apr 2015 20:13:50 -0400 Subject: [PATCH 23/40] Update Sandcastle example. --- .../development/BillboardClampToGround.html | 101 +++++++++++++++--- Source/Shaders/BillboardCollectionVS.glsl | 51 ++++----- 2 files changed, 115 insertions(+), 37 deletions(-) diff --git a/Apps/Sandcastle/gallery/development/BillboardClampToGround.html b/Apps/Sandcastle/gallery/development/BillboardClampToGround.html index 2eaf158d3954..93836efa2a6c 100644 --- a/Apps/Sandcastle/gallery/development/BillboardClampToGround.html +++ b/Apps/Sandcastle/gallery/development/BillboardClampToGround.html @@ -35,12 +35,9 @@ var viewer = new Cesium.Viewer('cesiumContainer'); var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider({ - url : '//assets.agi.com/stk-terrain/world', - requestWaterMask : true, - requestVertexNormals : true + url : '//assets.agi.com/stk-terrain/world' }); viewer.terrainProvider = cesiumTerrainProviderMeshes; - viewer.scene.globe.depthTestAgainstTerrain = false; var ellipsoid = viewer.scene.globe.ellipsoid; @@ -48,17 +45,95 @@ globe : viewer.scene.globe })); -billboardCollection.add({ - position : ellipsoid.cartographicToCartesian(new Cesium.Cartographic(-1.385205433269729, 0.6777926580888163)), - image : '../images/facility.gif', - heightReference : Cesium.HeightReference.CLAMP_TO_GROUND +// everest +//var centerLatitude = Cesium.Math.toRadians(27.988257); +//var centerLongitude = Cesium.Math.toRadians(86.925145); + +// seneca +var centerLongitude = -1.385205433269729; +var centerLatitude = 0.6777926580888163; + +var gridWidth = Math.floor(Math.random() * 100.0); +var gridHeight = Math.floor(Math.random() * 100.0); +var rectangleHalfSize = 0.0005; + +var e = new Cesium.Rectangle(centerLongitude - rectangleHalfSize, centerLatitude - rectangleHalfSize, centerLongitude + rectangleHalfSize, centerLatitude + rectangleHalfSize); + +for (var y = 0; y < gridHeight; ++y) { + for (var x = 0; x < gridWidth; ++x) { + var longitude = Cesium.Math.lerp(e.west, e.east, x / (gridWidth - 1)); + var latitude = Cesium.Math.lerp(e.south, e.north, y / (gridHeight - 1)); + var position = new Cesium.Cartographic(longitude, latitude); + + billboardCollection.add({ + position : ellipsoid.cartographicToCartesian(position), + image : '../images/facility.gif', + scale : 0.7, + heightReference : Cesium.HeightReference.CLAMP_TO_GROUND + }); + } +} + +var billboard; + +Sandcastle.addToolbarButton('Add billboard', function() { + if (!Cesium.defined(billboard)) { + billboard = billboardCollection.add({ + position : ellipsoid.cartographicToCartesian(new Cesium.Cartographic(centerLongitude, centerLatitude, 1000.0)), + image : '../images/Cesium_Logo_overlay.png', + scale : 0.7, + heightReference : Cesium.HeightReference.RELATIVE_TO_GROUND + }); + } }); -var camera = viewer.camera; -camera.position = new Cesium.Cartesian3(917846.4341998018, -4889990.680688238, 3978635.235478647); -camera.direction = new Cesium.Cartesian3(0.70656899850878, 0.33817652508595303, -0.6216083077204182); -camera.right = Cesium.Cartesian3.cross(camera.direction, ellipsoid.geodeticSurfaceNormal(camera.position), new Cesium.Cartesian3()); -camera.up = Cesium.Cartesian3.cross(camera.right, camera.direction, new Cesium.Cartesian3()); +Sandcastle.addToolbarButton('Remove billboard', function() { + if (Cesium.defined(billboard)) { + billboardCollection.remove(billboard); + billboard = undefined; + } +}); + +Sandcastle.addToolbarMenu([ { + text : 'Relative to ground', + onselect : function() { + if (Cesium.defined(billboard)) { + billboard.heightReference = Cesium.HeightReference.RELATIVE_TO_GROUND; + } + } +}, { + text : 'Clamp to ground', + onselect : function() { + if (Cesium.defined(billboard)) { + billboard.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND; + } + } +}, { + text : 'None', + onselect : function() { + if (Cesium.defined(billboard)) { + billboard.heightReference = Cesium.HeightReference.NONE; + } + } +}]); + +var lonGran = 0.00005; + +Sandcastle.addToolbarButton('Increase longitude', function() { + if (Cesium.defined(billboard)) { + var cartographic = ellipsoid.cartesianToCartographic(billboard.position); + cartographic.longitude += lonGran; + billboard.position = ellipsoid.cartographicToCartesian(cartographic); + } +}); + +Sandcastle.addToolbarButton('Decrease longitude', function() { + if (Cesium.defined(billboard)) { + var cartographic = ellipsoid.cartesianToCartographic(billboard.position); + cartographic.longitude -= lonGran; + billboard.position = ellipsoid.cartographicToCartesian(cartographic); + } +}); //Sandcastle_End Sandcastle.finishedLoading(); diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index 7b3c869a5637..93489ea4b27c 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -227,31 +227,34 @@ void main() #endif #ifdef TEST_GLOBE_DEPTH - vec2 directions[4]; - directions[0] = vec2(0.0, 0.0); - directions[1] = vec2(0.0, 1.0); - directions[2] = vec2(1.0, 0.0); - directions[3] = vec2(1.0, 1.0); - - vec2 invSize = 1.0 / czm_viewport.zw; - vec2 size = all(equal(vec2(0.0), maxSize)) ? imageSize : maxSize; - - bool visible = false; - for (int i = 0; i < 4; ++i) - { - vec4 wc = computePositionWindowCoordinates(positionEC, size, scale, directions[i], vec2(0.0, 0.0), vec2(0.0), pixelOffset, alignedAxis, rotation); - float d = texture2D(czm_globeDepthTexture, wc.xy * invSize).r; - if (wc.z < d) - { - visible = true; - break; - } - } - - if (!visible) + if (-positionEC.z < 70000.0) { - gl_Position = czm_projection * vec4(vec3(0.0), 1.0); - return; + vec2 directions[4]; + directions[0] = vec2(0.0, 0.0); + directions[1] = vec2(0.0, 1.0); + directions[2] = vec2(1.0, 0.0); + directions[3] = vec2(1.0, 1.0); + + vec2 invSize = 1.0 / czm_viewport.zw; + vec2 size = all(equal(vec2(0.0), maxSize)) ? imageSize : maxSize; + + bool visible = false; + for (int i = 0; i < 4; ++i) + { + vec4 wc = computePositionWindowCoordinates(positionEC, size, scale, directions[i], vec2(0.0, 0.0), vec2(0.0), pixelOffset, alignedAxis, rotation); + float d = texture2D(czm_globeDepthTexture, wc.xy * invSize).r; + if (wc.z < d) + { + visible = true; + break; + } + } + + if (!visible) + { + gl_Position = czm_projection * vec4(vec3(0.0), 1.0); + return; + } } #endif From b94190269aa76551668f24a98a3d8be31e61858e Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Wed, 29 Apr 2015 13:08:08 -0400 Subject: [PATCH 24/40] Some updates base don review. --- Source/Scene/Billboard.js | 1 - Source/Scene/BillboardCollection.js | 42 ++++++++++++----------- Source/Scene/LabelCollection.js | 27 ++++++++------- Source/Shaders/BillboardCollectionVS.glsl | 2 +- 4 files changed, 38 insertions(+), 34 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index 1c23095bb53f..97410b6adcb3 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -902,7 +902,6 @@ define([ object._projection.project(clampedCart, scratchPosition); object._clampedPosition = Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, object._clampedPosition); } - } }; diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index b2ef4b9b1d15..ca7079164683 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -1042,32 +1042,20 @@ define([ boundingVolume.radius += size + offset; } - /** - * Called when {@link Viewer} or {@link CesiumWidget} render the scene to - * get the draw commands needed to render this primitive. - *

- * Do not call this function directly. This is documented just to - * list the exceptions that may be propagated when the scene is rendered: - *

- * - * @exception {RuntimeError} image with id must be in the atlas. - */ - BillboardCollection.prototype.update = function(context, frameState, commandList) { - var i; - var j; - + function updateClampedBillboards(collection, frameState) { + // Unified time slicing tasks: https://github.com/AnalyticalGraphicsInc/cesium/issues/2655 var startTime = getTimestamp(); - var timeSlice = this._clampTimeSlice; + var timeSlice = collection._clampTimeSlice; var endTime = startTime + timeSlice; - var tileList = this._renderedTileList; + var tileList = collection._renderedTileList; while (tileList.length > 0) { var tile = tileList[0]; var customData = tile.customData; var customDataLength = customData.length; var timeSliceMax = false; - for (i = this._lastTileIndex; i < customDataLength; ++i) { + for (var i = collection._lastTileIndex; i < customDataLength; ++i) { var data = customData[i]; var object = data.object; if (defined(object) && object instanceof Billboard) { @@ -1080,14 +1068,27 @@ define([ } if (timeSliceMax) { - this._lastTileIndex = i; + collection._lastTileIndex = i; break; } else { - this._lastTileIndex = 0; + collection._lastTileIndex = 0; tileList.shift(); } } + } + /** + * Called when {@link Viewer} or {@link CesiumWidget} render the scene to + * get the draw commands needed to render this primitive. + *

+ * Do not call this function directly. This is documented just to + * list the exceptions that may be propagated when the scene is rendered: + *

+ * + * @exception {RuntimeError} image with id must be in the atlas. + */ + BillboardCollection.prototype.update = function(context, frameState, commandList) { + updateClampedBillboards(this, frameState); removeBillboards(this); var billboards = this._billboards; @@ -1144,7 +1145,7 @@ define([ vafWriters = this._vaf.writers; // Rewrite entire buffer if billboards were added or removed. - for (i = 0; i < billboardsLength; ++i) { + for (var i = 0; i < billboardsLength; ++i) { var billboard = this._billboards[i]; billboard._dirty = false; // In case it needed an update. writeBillboard(this, context, textureAtlasCoordinates, vafWriters, billboard); @@ -1256,6 +1257,7 @@ define([ var command; var vs; var fs; + var j; if (pass.render) { var colorList = this._colorCommands; diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index 3fafaa32df27..6243da8c9db1 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -588,24 +588,20 @@ define([ return this._labels[index]; }; - /** - * @private - */ - LabelCollection.prototype.update = function(context, frameState, commandList) { - var i; - + function updateClampedLabels(collection, frameState) { + // Unified time slicing tasks: https://github.com/AnalyticalGraphicsInc/cesium/issues/2655 var startTime = getTimestamp(); - var timeSlice = this._clampTimeSlice; + var timeSlice = collection._clampTimeSlice; var endTime = startTime + timeSlice; - var tileList = this._renderedTileList; + var tileList = collection._renderedTileList; while (tileList.length > 0) { var tile = tileList[0]; var customData = tile.customData; var customDataLength = customData.length; var timeSliceMax = false; - for (i = this._lastTileIndex; i < customDataLength; ++i) { + for (var i = collection._lastTileIndex; i < customDataLength; ++i) { var data = customData[i]; var object = data.object; if (defined(object) && object instanceof Label) { @@ -619,13 +615,20 @@ define([ } if (timeSliceMax) { - this._lastTileIndex = i; + collection._lastTileIndex = i; break; } else { - this._lastTileIndex = 0; + collection._lastTileIndex = 0; tileList.shift(); } } + } + + /** + * @private + */ + LabelCollection.prototype.update = function(context, frameState, commandList) { + updateClampedLabels(this, frameState); var billboardCollection = this._billboardCollection; @@ -652,7 +655,7 @@ define([ } var len = labelsToUpdate.length; - for (i = 0; i < len; ++i) { + for (var i = 0; i < len; ++i) { var label = labelsToUpdate[i]; if (label.isDestroyed()) { continue; diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index 93489ea4b27c..f701ad3992d1 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -252,7 +252,7 @@ void main() if (!visible) { - gl_Position = czm_projection * vec4(vec3(0.0), 1.0); + gl_Position = czm_projection[3]; return; } } From 2b5ae8029905e64fbcd9b4df3ec6299e68173eca Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Wed, 29 Apr 2015 13:59:39 -0400 Subject: [PATCH 25/40] Rename maxSize to ownerSize. Update labels and other changes based on review. --- Source/Scene/Billboard.js | 25 +++++++------ Source/Scene/BillboardCollection.js | 45 +++++++++++++---------- Source/Scene/Label.js | 4 +- Source/Scene/LabelCollection.js | 21 +++++------ Source/Shaders/BillboardCollectionVS.glsl | 4 +- 5 files changed, 52 insertions(+), 47 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index e698a03765b1..ac5ba68b8571 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -105,7 +105,7 @@ define([ this._translucencyByDistance = options.translucencyByDistance; this._pixelOffsetScaleByDistance = options.pixelOffsetScaleByDistance; this._heightReference = defaultValue(options.heightReference, HeightReference.NONE); - this._maxImageSize = new Cartesian2(); // used by labels + this._ownerSize = new Cartesian2(); // used by labels this._id = options.id; this._collection = defaultValue(options.collection, billboardCollection); @@ -171,7 +171,7 @@ define([ var SCALE_BY_DISTANCE_INDEX = Billboard.SCALE_BY_DISTANCE_INDEX = 11; var TRANSLUCENCY_BY_DISTANCE_INDEX = Billboard.TRANSLUCENCY_BY_DISTANCE_INDEX = 12; var PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX = Billboard.PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX = 13; - var MAX_SIZE_INDEX = Billboard.MAX_SIZE_INDEX = 14; + var OWNER_SIZE_INDEX = Billboard.OWNER_SIZE_INDEX = 14; Billboard.NUMBER_OF_PROPERTIES = 15; function makeDirty(billboard, propertyChanged) { @@ -824,7 +824,9 @@ define([ Cartesian3.normalize(object.position, scratchRay.direction); } else { ellipsoid.cartesianToCartographic(object.position, scratchCartographic); - scratchCartographic.height = -1000.0; // TODO: get minimum height of entire terrain set + + // minimum height for the terrain set, need to get this information from the terrain provider + scratchCartographic.height = -11500.0; projection.project(scratchCartographic, scratchPosition); Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, scratchPosition); Cartesian3.clone(scratchPosition, scratchRay.origin); @@ -852,14 +854,15 @@ define([ }; Billboard._updateClamping = function(collection, object) { - var globe = collection._globe; - if (!defined(globe)) { + var scene = collection._scene; + if (!defined(scene)) { if (object._heightReference !== HeightReference.NONE) { throw new DeveloperError('Height reference is not supported.'); } return; } + var globe = scene.globe; var ellipsoid = globe.ellipsoid; var surface = globe._surface; var customData = object._customData; @@ -1053,17 +1056,17 @@ define([ } }; - Billboard.prototype._setMaxImageSize = function(value) { + Billboard.prototype._setOwnerSize = function(value) { //>>includeStart('debug', pragmas.debug); if (!defined(value)) { throw new DeveloperError('value is required.'); } //>>includeEnd('debug'); - var maxSize = this._maxImageSize; - if (!Cartesian2.equals(maxSize, value)) { - Cartesian2.clone(value, maxSize); - makeDirty(this, MAX_SIZE_INDEX); + var size = this._ownerSize; + if (!Cartesian2.equals(size, value)) { + Cartesian2.clone(value, size); + makeDirty(this, OWNER_SIZE_INDEX); } }; @@ -1204,7 +1207,7 @@ define([ Billboard.prototype._destroy = function() { if (defined(this._customData)) { - this._billboardCollection._globe._surface.removeTileCustomData(this._customData); + this._billboardCollection._scene.globe._surface.removeTileCustomData(this._customData); this._customData = undefined; } diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index b008f320f404..222a9f155ed5 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -73,7 +73,7 @@ define([ var SCALE_BY_DISTANCE_INDEX = Billboard.SCALE_BY_DISTANCE_INDEX; var TRANSLUCENCY_BY_DISTANCE_INDEX = Billboard.TRANSLUCENCY_BY_DISTANCE_INDEX; var PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX = Billboard.PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX; - var MAX_SIZE_INDEX = Billboard.MAX_SIZE_INDEX; + var OWNER_SIZE_INDEX = Billboard.OWNER_SIZE_INDEX; var NUMBER_OF_PROPERTIES = Billboard.NUMBER_OF_PROPERTIES; var attributeLocations = { @@ -85,7 +85,7 @@ define([ eyeOffset : 5, scaleByDistance : 6, pixelOffsetScaleByDistance : 7, - maxSize : 8 + ownerSize : 8 }; /** @@ -136,7 +136,7 @@ define([ var BillboardCollection = function(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - this._globe = options.globe; + this._scene = options.scene; this._textureAtlas = undefined; this._textureAtlasGUID = undefined; @@ -257,7 +257,7 @@ define([ BufferUsage.STATIC_DRAW, // SCALE_BY_DISTANCE_INDEX BufferUsage.STATIC_DRAW, // TRANSLUCENCY_BY_DISTANCE_INDEX BufferUsage.STATIC_DRAW, // PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX - BufferUsage.STATIC_DRAW // PIXEL_MAX_SIZE_INDEX + BufferUsage.STATIC_DRAW // OWNER_SIZE_INDEX ]; var that = this; @@ -268,8 +268,8 @@ define([ }; this._removeEventFunc = undefined; - if (defined(this._globe)) { - this._removeEventFunc = this._globe._surface.tileRenderedEvent.addEventListener(function(tile) { + if (defined(this._scene)) { + this._removeEventFunc = this._scene.globe._surface.tileRenderedEvent.addEventListener(function(tile) { var tileList = that._renderedTileList; if (tileList.indexOf(tile) === -1) { tileList.push(tile); @@ -622,10 +622,10 @@ define([ componentDatatype : ComponentDatatype.FLOAT, usage : buffersUsage[PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX] }, { - index : attributeLocations.maxSize, + index : attributeLocations.ownerSize, componentsPerAttribute : 2, componentDatatype : ComponentDatatype.FLOAT, - usage : buffersUsage[MAX_SIZE_INDEX] + usage : buffersUsage[OWNER_SIZE_INDEX] }], 4 * numberOfBillboards); // 4 vertices per billboard } @@ -948,15 +948,15 @@ define([ writer(i + 3, near, nearValue, far, farValue); } - function writeMaxSize(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) { + function writeOwnerSize(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) { var i = billboard._index * 4; - var maxSize = billboard._maxImageSize; + var size = billboard._ownerSize; - var writer = vafWriters[attributeLocations.maxSize]; - writer(i + 0, maxSize.x, maxSize.y); - writer(i + 1, maxSize.x, maxSize.y); - writer(i + 2, maxSize.x, maxSize.y); - writer(i + 3, maxSize.x, maxSize.y); + var writer = vafWriters[attributeLocations.ownerSize]; + writer(i + 0, size.x, size.y); + writer(i + 1, size.x, size.y); + writer(i + 2, size.x, size.y); + writer(i + 3, size.x, size.y); } function writeBillboard(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) { @@ -967,7 +967,7 @@ define([ writeEyeOffset(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard); writeScaleByDistance(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard); writePixelOffsetScaleByDistance(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard); - writeMaxSize(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard); + writeOwnerSize(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard); } function recomputeActualPositions(billboardCollection, billboards, length, frameState, modelMatrix, recomputeBoundingVolume) { @@ -1099,6 +1099,11 @@ define([ * @exception {RuntimeError} image with id must be in the atlas. */ BillboardCollection.prototype.update = function(context, frameState, commandList) { + var scene = this._scene; + if (defined(scene) && (!scene._globeDepth.supported || context.maximumVertexTextureImageUnits === 0)) { + throw new DeveloperError('Bilboards with a height reference are not supported.'); + } + updateClampedBillboards(this, frameState); removeBillboards(this); @@ -1201,8 +1206,8 @@ define([ writers.push(writePixelOffsetScaleByDistance); } - if (properties[MAX_SIZE_INDEX]) { - writers.push(writeMaxSize); + if (properties[OWNER_SIZE_INDEX]) { + writers.push(writeOwnerSize); } var numWriters = writers.length; @@ -1309,7 +1314,7 @@ define([ if (this._shaderPixelOffsetScaleByDistance) { vs.defines.push('EYE_DISTANCE_PIXEL_OFFSET'); } - if (defined(this._globe)) { + if (defined(this._scene)) { vs.defines.push('TEST_GLOBE_DEPTH'); } @@ -1377,7 +1382,7 @@ define([ if (this._shaderPixelOffsetScaleByDistance) { vs.defines.push('EYE_DISTANCE_PIXEL_OFFSET'); } - if (defined(this._globe)) { + if (defined(this._scene)) { vs.defines.push('TEST_GLOBE_DEPTH'); } diff --git a/Source/Scene/Label.js b/Source/Scene/Label.js index efd18e873d13..8e495bf94566 100644 --- a/Source/Scene/Label.js +++ b/Source/Scene/Label.js @@ -97,10 +97,8 @@ define([ this._repositionAllGlyphs = true; this._customData = undefined; - this._currentTile = undefined; - this._newTile = undefined; + this._level = 0; this._actualClampedPosition = undefined; - this._positionChanged = false; this._mode = undefined; this._updateClamping(); diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index 6243da8c9db1..f1a13bacd408 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -214,7 +214,7 @@ define([ // reusable Cartesian2 instance var glyphPixelOffset = new Cartesian2(); - var maxSize = new Cartesian2(); + var ownerSize = new Cartesian2(); function repositionAllGlyphs(label, resolutionScale) { var glyphs = label._glyphs; @@ -246,8 +246,8 @@ define([ glyphPixelOffset.x = widthOffset * resolutionScale; glyphPixelOffset.y = 0; - maxSize.x = maxWidth; - maxSize.y = maxHeight; + ownerSize.x = maxWidth; + ownerSize.y = maxHeight; var verticalOrigin = label._verticalOrigin; for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) { @@ -266,7 +266,7 @@ define([ if (defined(glyph.billboard)) { glyph.billboard._setTranslate(glyphPixelOffset); - glyph.billboard._setMaxImageSize(maxSize); + glyph.billboard._setOwnerSize(ownerSize); } glyphPixelOffset.x += dimensions.computedWidth * scale * resolutionScale; @@ -281,7 +281,7 @@ define([ label._labelCollection = undefined; if (defined(label._customData)) { - labelCollection._globe._surface.removeTileCustomData(label._customData); + labelCollection._scene.globe._surface.removeTileCustomData(label._customData); label._customData = undefined; } @@ -337,12 +337,12 @@ define([ var LabelCollection = function(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - this._globe = options.globe; + this._scene = options.scene; this._textureAtlas = undefined; this._billboardCollection = new BillboardCollection({ - globe : this._globe + scene : this._scene }); this._billboardCollection.destroyTextureAtlas = false; @@ -401,9 +401,9 @@ define([ this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false); this._removeEventFunc = undefined; - if (defined(this._globe)) { + if (defined(this._scene)) { var that = this; - this._removeEventFunc = this._globe._surface.tileRenderedEvent.addEventListener(function(tile) { + this._removeEventFunc = this._scene.globe._surface.tileRenderedEvent.addEventListener(function(tile) { var tileList = that._renderedTileList; if (tileList.indexOf(tile) === -1) { tileList.push(tile); @@ -605,8 +605,7 @@ define([ var data = customData[i]; var object = data.object; if (defined(object) && object instanceof Label) { - object._newTile = tile; - Billboard._clampPosition(object, frameState.mode, frameState.mapProjection); + Billboard._clampPosition(object, tile, frameState.mode, frameState.mapProjection); if (getTimestamp() >= endTime) { timeSliceMax = true; break; diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index f701ad3992d1..adda5e5e5d36 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -6,7 +6,7 @@ attribute vec4 compressedAttribute2; // image height, color, pick color, attribute vec3 eyeOffset; // eye offset in meters attribute vec4 scaleByDistance; // near, nearScale, far, farScale attribute vec4 pixelOffsetScaleByDistance; // near, nearScale, far, farScale -attribute vec2 maxSize; +attribute vec2 ownerSize; varying vec2 v_textureCoordinates; @@ -236,7 +236,7 @@ void main() directions[3] = vec2(1.0, 1.0); vec2 invSize = 1.0 / czm_viewport.zw; - vec2 size = all(equal(vec2(0.0), maxSize)) ? imageSize : maxSize; + vec2 size = all(equal(vec2(0.0), ownerSize)) ? imageSize : ownerSize; bool visible = false; for (int i = 0; i < 4; ++i) From 220f3b26a8b208395a27bc194afd05d34bd97698 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Wed, 29 Apr 2015 14:22:33 -0400 Subject: [PATCH 26/40] More renames and updates based on review. --- Source/Scene/BillboardCollection.js | 11 ++++------- Source/Scene/LabelCollection.js | 11 ++++------- Source/Scene/QuadtreePrimitive.js | 4 ++-- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 222a9f155ed5..49b0da39325a 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -186,7 +186,7 @@ define([ this._boundingVolume = new BoundingSphere(); this._boundingVolumeDirty = false; - this._renderedTileList = []; + this._newlyVisibleTileList = []; this._clampTimeSlice = 1.0; this._lastTileIndex = 0; @@ -269,11 +269,8 @@ define([ this._removeEventFunc = undefined; if (defined(this._scene)) { - this._removeEventFunc = this._scene.globe._surface.tileRenderedEvent.addEventListener(function(tile) { - var tileList = that._renderedTileList; - if (tileList.indexOf(tile) === -1) { - tileList.push(tile); - } + this._removeEventFunc = this._scene.globe._surface.tileVisibleEvent.addEventListener(function(tile) { + that._newlyVisibleTileList.push(tile); }); } }; @@ -1057,7 +1054,7 @@ define([ var timeSlice = collection._clampTimeSlice; var endTime = startTime + timeSlice; - var tileList = collection._renderedTileList; + var tileList = collection._newlyVisibleTileList; while (tileList.length > 0) { var tile = tileList[0]; var customData = tile.customData; diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index f1a13bacd408..e3e77df697a6 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -353,7 +353,7 @@ define([ this._totalGlyphCount = 0; this._resolutionScale = undefined; - this._renderedTileList = []; + this._newlyVisibleTileList = []; this._clampTimeSlice = 1.0; this._lastTileIndex = 0; @@ -403,11 +403,8 @@ define([ this._removeEventFunc = undefined; if (defined(this._scene)) { var that = this; - this._removeEventFunc = this._scene.globe._surface.tileRenderedEvent.addEventListener(function(tile) { - var tileList = that._renderedTileList; - if (tileList.indexOf(tile) === -1) { - tileList.push(tile); - } + this._removeEventFunc = this._scene.globe._surface.tileVisibleEvent.addEventListener(function(tile) { + that._newlyVisibleTileList.push(tile); }); } }; @@ -594,7 +591,7 @@ define([ var timeSlice = collection._clampTimeSlice; var endTime = startTime + timeSlice; - var tileList = collection._renderedTileList; + var tileList = collection._newlyVisibleTileList; while (tileList.length > 0) { var tile = tileList[0]; var customData = tile.customData; diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index 39e92b33d47b..0da7104282eb 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -116,7 +116,7 @@ define([ */ this.tileCacheSize = defaultValue(options.tileCacheSize, 100); - this.tileRenderedEvent = new Event(); + this.tileVisibleEvent = new Event(); this._occluders = new QuadtreeOccluders({ ellipsoid : ellipsoid @@ -498,7 +498,7 @@ define([ tileProvider.showTileThisFrame(tile, context, frameState, commandList); if (tile._frameRendered !== frameState.frameNumber - 1) { - primitive.tileRenderedEvent.raiseEvent(tile); + primitive.tileVisibleEvent.raiseEvent(tile); } tile._frameRendered = frameState.frameNumber; } From 2ff3d437e089b28121a6ed629d3b563087359e66 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Wed, 29 Apr 2015 15:03:40 -0400 Subject: [PATCH 27/40] Add doc. --- Source/Scene/Billboard.js | 12 ++++++++++++ Source/Scene/BillboardCollection.js | 1 + Source/Scene/HeightReference.js | 23 +++++++++++++++++++++++ Source/Scene/Label.js | 11 +++++++++++ Source/Scene/LabelCollection.js | 1 + Source/Scene/QuadtreePrimitive.js | 19 +++++++++++++++++++ Source/Scene/QuadtreeTile.js | 5 +++++ 7 files changed, 72 insertions(+) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index ac5ba68b8571..8f072d94551c 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -234,6 +234,12 @@ define([ } }, + /** + * Gets or sets the height reference of this billboard. + * @memberof Billboard.prototype + * @type {HeightReference} + * @default HeightReference.NONE + */ heightReference : { get : function() { return this._heightReference; @@ -786,6 +792,12 @@ define([ } }, + /** + * Keeps track of the position of the billboard based on the height reference. + * @memberof Billboard.prototype + * @type {Cartesian3} + * @private + */ _clampedPosition : { get : function() { return this._actualClampedPosition; diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index 49b0da39325a..d078394bde8c 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -107,6 +107,7 @@ define([ * @param {Object} [options] Object with the following properties: * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms each billboard from model to world coordinates. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown. + * @param {Scene} [options.scene] Must be passed in for billboards that use the height reference property or will be depth tested against the globe. * * @performance For best performance, prefer a few collections, each with many billboards, to * many collections with only a few billboards each. Organize collections so that billboards diff --git a/Source/Scene/HeightReference.js b/Source/Scene/HeightReference.js index 42681ead89fd..50522c3a2143 100644 --- a/Source/Scene/HeightReference.js +++ b/Source/Scene/HeightReference.js @@ -5,9 +5,32 @@ define([ freezeObject) { "use strict"; + /** + * Represents the position relative to the terrain. + * + * @namespace + * @alias HeightReference + */ var HeightReference = { + /** + * The position is absolute. + * @type {Number} + * @constant + */ NONE : 0, + + /** + * The position is clamped to the terrain. + * @type {Number} + * @constant + */ CLAMP_TO_GROUND : 1, + + /** + * The position height is the height above the terrain. + * @type {Number} + * @constant + */ RELATIVE_TO_GROUND : 2 }; diff --git a/Source/Scene/Label.js b/Source/Scene/Label.js index 8e495bf94566..4ef4b06cc9be 100644 --- a/Source/Scene/Label.js +++ b/Source/Scene/Label.js @@ -171,6 +171,11 @@ define([ } }, + /** + * Gets or sets the height reference of this billboard. + * @memberof Label.prototype + * @type {HeightReference} + */ heightReference : { get : function() { return this._heightReference; @@ -661,6 +666,12 @@ define([ } }, + /** + * Keeps track of the position of the label based on the height reference. + * @memberof Label.prototype + * @type {Cartesian3} + * @private + */ _clampedPosition : { get : function() { return this._actualClampedPosition; diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index e3e77df697a6..073fbd1f9d1d 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -309,6 +309,7 @@ define([ * @param {Object} [options] Object with the following properties: * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms each label from model to world coordinates. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown. + * @param {Scene} [options.scene] Must be passed in for labels that use the height reference property or will be depth tested against the globe. * * @performance For best performance, prefer a few collections, each with many labels, to * many collections with only a few labels each. Avoid having collections where some diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index 0da7104282eb..d7205c297e29 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -116,6 +116,11 @@ define([ */ this.tileCacheSize = defaultValue(options.tileCacheSize, 100); + /** + * An event that is raised when a tile becomes visible. The argument to the event listener + * is the visible tile. + * @type {Event} + */ this.tileVisibleEvent = new Event(); this._occluders = new QuadtreeOccluders({ @@ -191,10 +196,24 @@ define([ } }; + /** + * Associate data with the tiles of the quadtree. The custom data must have a Cartographic position property. + * The position will be used to associate the data with the individual tiles of the quadtree. If the position + * is in the tile's rectangle, the custom data will be added to the tile. + * + * @param {Object} customData The object literal with a Cartographic position property and any other custom properties. + */ QuadtreePrimitive.prototype.addTileCustomData = function(customData) { this._customDataAdded.push(customData); }; + /** + * Removes custom data from the tiles quadtree. + * + * @param {Object} customData The data to be removed. + * + * @see QuadtreePrimitive.addTileCustomData + */ QuadtreePrimitive.prototype.removeTileCustomData = function(customData) { this._customDataRemoved.push(customData); }; diff --git a/Source/Scene/QuadtreeTile.js b/Source/Scene/QuadtreeTile.js index a08e516e92cc..009299c4b3a7 100644 --- a/Source/Scene/QuadtreeTile.js +++ b/Source/Scene/QuadtreeTile.js @@ -294,6 +294,11 @@ define([ } }, + /** + * An array of objects associated with this tile. See QuadtreePrimitive.addTileCustomData. + * @memberof QuadtreeTile.prototype + * @type {Array} + */ customData : { get : function() { return this._customData; From 6c722f99ea92e5ea0cbdceb4d93edb81cbc800a4 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Wed, 29 Apr 2015 15:34:12 -0400 Subject: [PATCH 28/40] Update computing screen space position for billboards and labels. --- Source/Scene/Billboard.js | 4 +++- Source/Scene/Label.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index 8f072d94551c..219a521f9980 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -1184,7 +1184,9 @@ define([ Cartesian2.add(scratchPixelOffset, this._translate, scratchPixelOffset); var modelMatrix = billboardCollection.modelMatrix; - var windowCoordinates = Billboard._computeScreenSpacePosition(modelMatrix, this._actualPosition, + var actualPosition = this._getActualPosition(); + + var windowCoordinates = Billboard._computeScreenSpacePosition(modelMatrix, actualPosition, this._eyeOffset, scratchPixelOffset, scene, result); windowCoordinates.y = scene.canvas.clientHeight - windowCoordinates.y; return windowCoordinates; diff --git a/Source/Scene/Label.js b/Source/Scene/Label.js index 4ef4b06cc9be..6541d637a50c 100644 --- a/Source/Scene/Label.js +++ b/Source/Scene/Label.js @@ -722,7 +722,7 @@ define([ var labelCollection = this._labelCollection; var modelMatrix = labelCollection.modelMatrix; - var actualPosition = Billboard._computeActualPosition(this._position, scene.frameState, modelMatrix); + var actualPosition = Billboard._computeActualPosition(this, this._position, scene.frameState, modelMatrix); var windowCoordinates = Billboard._computeScreenSpacePosition(modelMatrix, actualPosition, this._eyeOffset, this._pixelOffset, scene, result); From 9b1f56144e1aa21751813d0282c4ecf64bd9eae2 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 1 May 2015 14:46:52 -0400 Subject: [PATCH 29/40] Move time slicing code from the billboard/label collection to the quadtree primitive. Billboard/label only requests for an updated height at a position. --- Source/Scene/Billboard.js | 90 ++++---------- Source/Scene/BillboardCollection.js | 51 -------- Source/Scene/LabelCollection.js | 53 -------- Source/Scene/QuadtreePrimitive.js | 141 +++++++++++++++++----- Source/Scene/QuadtreeTile.js | 4 +- Source/Shaders/BillboardCollectionVS.glsl | 2 +- 6 files changed, 136 insertions(+), 205 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index 219a521f9980..a3f1845dcf31 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -149,10 +149,9 @@ define([ this._loadImage(); } - this._customData = undefined; - this._level = 0; this._actualClampedPosition = undefined; - this._mode = undefined; + this._removeCallbackFunc = undefined; + this._mode = SceneMode.SCENE3D; this._updateClamping(); }; @@ -821,50 +820,13 @@ define([ return this._pickId; }; - var scratchRay = new Ray(); - var scratchPosition = new Cartesian3(); - var scratchCartographic = new Cartographic(); - - Billboard._clampPosition = function(object, tile, mode, projection) { - var modeChanged = object._mode !== mode; - var ellipsoid = projection.ellipsoid; - var level = tile.level; - - if (level > object._level || modeChanged) { - if (mode === SceneMode.SCENE3D) { - Cartesian3.clone(Cartesian3.ZERO, scratchRay.origin); - Cartesian3.normalize(object.position, scratchRay.direction); - } else { - ellipsoid.cartesianToCartographic(object.position, scratchCartographic); - - // minimum height for the terrain set, need to get this information from the terrain provider - scratchCartographic.height = -11500.0; - projection.project(scratchCartographic, scratchPosition); - Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, scratchPosition); - Cartesian3.clone(scratchPosition, scratchRay.origin); - Cartesian3.clone(Cartesian3.UNIT_X, scratchRay.direction); - } - - var position = tile.data.pick(scratchRay, mode, projection, false, scratchPosition); - if (defined(position)) { - if (object._heightReference === HeightReference.RELATIVE_TO_GROUND) { - var clampedCart = ellipsoid.cartesianToCartographic(position, scratchCartographic); - clampedCart.height += object._customData.position.height; - ellipsoid.cartographicToCartesian(clampedCart, position); - } - object._clampedPosition = Cartesian3.clone(position, object._clampedPosition); - } - - object._mode = mode; - object._projection = projection; - object._level = level; - } - }; - Billboard.prototype._updateClamping = function() { Billboard._updateClamping(this._billboardCollection, this); }; + var scratchCartographic = new Cartographic(); + var scratchPosition = new Cartesian3(); + Billboard._updateClamping = function(collection, object) { var scene = collection._scene; if (!defined(scene)) { @@ -877,13 +839,10 @@ define([ var globe = scene.globe; var ellipsoid = globe.ellipsoid; var surface = globe._surface; - var customData = object._customData; - var mode = object._mode = defaultValue(object._mode, SceneMode.SCENE3D); - - if (defined(customData) && object._heightReference === HeightReference.NONE) { - surface.removeTileCustomData(customData); - object._customData = undefined; + if (object._heightReference === HeightReference.NONE && defined(object._removeCallbackFunc)) { + object._removeCallbackFunc(); + object._removeCallbackFunc = undefined; object._clampedPosition = undefined; } @@ -896,27 +855,24 @@ define([ return; } - if (defined(customData)) { - surface.removeTileCustomData(customData); + if (defined(object._removeCallbackFunc)) { + object._removeCallbackFunc(); } - object._customData = { - position : position, - object : object + var updateFunction = function(position) { + if (object._heightReference === HeightReference.RELATIVE_TO_GROUND) { + var clampedCart = ellipsoid.cartesianToCartographic(position, scratchCartographic); + clampedCart.height += object._customData.position.height; + ellipsoid.cartographicToCartesian(clampedCart, position); + } + object._clampedPosition = Cartesian3.clone(position, object._clampedPosition); }; - surface.addTileCustomData(object._customData); + + object._removeCallbackFunc = surface.updateHeight(position, updateFunction); var height = globe.getHeight(position); if (defined(height)) { - var clampedCart = Cartographic.clone(position, scratchCartographic); - clampedCart.height = object._heightReference === HeightReference.RELATIVE_TO_GROUND ? height + position.height : height; - - if (mode === SceneMode.SCENE3D) { - object._clampedPosition = ellipsoid.cartographicToCartesian(clampedCart, object._clampedPosition); - } else if (defined(object._projection)) { - object._projection.project(clampedCart, scratchPosition); - object._clampedPosition = Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, object._clampedPosition); - } + updateFunction(height); } }; @@ -1083,11 +1039,11 @@ define([ }; Billboard.prototype._getActualPosition = function() { - return defined(this._customData) && defined(this._clampedPosition) && this._mode !== SceneMode.MORPHING ? this._clampedPosition : this._actualPosition; + return defined(this._clampedPosition) && this._mode !== SceneMode.MORPHING ? this._clampedPosition : this._actualPosition; }; Billboard.prototype._setActualPosition = function(value) { - if (!(defined(this._customData) && defined(this._clampedPosition) && this._mode !== SceneMode.MORPHING)) { + if (!(defined(this._clampedPosition) && this._mode !== SceneMode.MORPHING)) { Cartesian3.clone(value, this._actualPosition); } makeDirty(this, POSITION_INDEX); @@ -1095,7 +1051,7 @@ define([ var tempCartesian3 = new Cartesian4(); Billboard._computeActualPosition = function(billboard, position, frameState, modelMatrix) { - if (defined(billboard._customData) && defined(billboard._clampedPosition) && this._mode !== SceneMode.MORPHING) { + if (defined(billboard._clampedPosition) && this._mode !== SceneMode.MORPHING) { if (frameState.mode !== this._mode) { billboard._mode = frameState.mode; billboard._projection = frameState.mapProjection; diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index d078394bde8c..b72d1b92ded3 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -187,10 +187,6 @@ define([ this._boundingVolume = new BoundingSphere(); this._boundingVolumeDirty = false; - this._newlyVisibleTileList = []; - this._clampTimeSlice = 1.0; - this._lastTileIndex = 0; - this._colorCommands = []; this._pickCommands = []; @@ -267,13 +263,6 @@ define([ return that._textureAtlas.texture; } }; - - this._removeEventFunc = undefined; - if (defined(this._scene)) { - this._removeEventFunc = this._scene.globe._surface.tileVisibleEvent.addEventListener(function(tile) { - that._newlyVisibleTileList.push(tile); - }); - } }; defineProperties(BillboardCollection.prototype, { @@ -1049,41 +1038,6 @@ define([ boundingVolume.radius += size + offset; } - function updateClampedBillboards(collection, frameState) { - // Unified time slicing tasks: https://github.com/AnalyticalGraphicsInc/cesium/issues/2655 - var startTime = getTimestamp(); - var timeSlice = collection._clampTimeSlice; - var endTime = startTime + timeSlice; - - var tileList = collection._newlyVisibleTileList; - while (tileList.length > 0) { - var tile = tileList[0]; - var customData = tile.customData; - var customDataLength = customData.length; - - var timeSliceMax = false; - for (var i = collection._lastTileIndex; i < customDataLength; ++i) { - var data = customData[i]; - var object = data.object; - if (defined(object) && object instanceof Billboard) { - Billboard._clampPosition(object, tile, frameState.mode, frameState.mapProjection); - if (getTimestamp() >= endTime) { - timeSliceMax = true; - break; - } - } - } - - if (timeSliceMax) { - collection._lastTileIndex = i; - break; - } else { - collection._lastTileIndex = 0; - tileList.shift(); - } - } - } - var scratchWriterArray = []; /** @@ -1102,7 +1056,6 @@ define([ throw new DeveloperError('Bilboards with a height reference are not supported.'); } - updateClampedBillboards(this, frameState); removeBillboards(this); var billboards = this._billboards; @@ -1461,10 +1414,6 @@ define([ this._vaf = this._vaf && this._vaf.destroy(); destroyBillboards(this._billboards); - if (defined(this._removeEventFunc)) { - this._removeEventFunc(); - } - return destroyObject(this); }; diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index 073fbd1f9d1d..181c4bbb8f05 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -354,10 +354,6 @@ define([ this._totalGlyphCount = 0; this._resolutionScale = undefined; - this._newlyVisibleTileList = []; - this._clampTimeSlice = 1.0; - this._lastTileIndex = 0; - /** * The 4x4 transformation matrix that transforms each label in this collection from model to world coordinates. * When this is the identity matrix, the labels are drawn in world coordinates, i.e., Earth's WGS84 coordinates. @@ -400,14 +396,6 @@ define([ * @default false */ this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false); - - this._removeEventFunc = undefined; - if (defined(this._scene)) { - var that = this; - this._removeEventFunc = this._scene.globe._surface.tileVisibleEvent.addEventListener(function(tile) { - that._newlyVisibleTileList.push(tile); - }); - } }; defineProperties(LabelCollection.prototype, { @@ -586,47 +574,10 @@ define([ return this._labels[index]; }; - function updateClampedLabels(collection, frameState) { - // Unified time slicing tasks: https://github.com/AnalyticalGraphicsInc/cesium/issues/2655 - var startTime = getTimestamp(); - var timeSlice = collection._clampTimeSlice; - var endTime = startTime + timeSlice; - - var tileList = collection._newlyVisibleTileList; - while (tileList.length > 0) { - var tile = tileList[0]; - var customData = tile.customData; - var customDataLength = customData.length; - - var timeSliceMax = false; - for (var i = collection._lastTileIndex; i < customDataLength; ++i) { - var data = customData[i]; - var object = data.object; - if (defined(object) && object instanceof Label) { - Billboard._clampPosition(object, tile, frameState.mode, frameState.mapProjection); - if (getTimestamp() >= endTime) { - timeSliceMax = true; - break; - } - } - } - - if (timeSliceMax) { - collection._lastTileIndex = i; - break; - } else { - collection._lastTileIndex = 0; - tileList.shift(); - } - } - } - /** * @private */ LabelCollection.prototype.update = function(context, frameState, commandList) { - updateClampedLabels(this, frameState); - var billboardCollection = this._billboardCollection; billboardCollection.modelMatrix = this.modelMatrix; @@ -714,10 +665,6 @@ define([ this._billboardCollection = this._billboardCollection.destroy(); this._textureAtlas = this._textureAtlas && this._textureAtlas.destroy(); - if (defined(this._removeEventFunc)) { - this._removeEventFunc(); - } - return destroyObject(this); }; diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index d7205c297e29..af5f77af29fe 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -1,5 +1,7 @@ /*global define*/ define([ + '../Core/Cartesian3', + '../Core/Cartographic', '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', @@ -7,6 +9,7 @@ define([ '../Core/Event', '../Core/getTimestamp', '../Core/Queue', + '../Core/Ray', '../Core/Rectangle', '../Core/Visibility', './QuadtreeOccluders', @@ -15,6 +18,8 @@ define([ './SceneMode', './TileReplacementQueue' ], function( + Cartesian3, + Cartographic, defaultValue, defined, defineProperties, @@ -22,6 +27,7 @@ define([ Event, getTimestamp, Queue, + Ray, Rectangle, Visibility, QuadtreeOccluders, @@ -94,8 +100,12 @@ define([ this._levelZeroTilesReady = false; this._loadQueueTimeSlice = 5.0; - this._customDataAdded = []; - this._customDataRemoved = []; + this._addHeightCallbacks = []; + this._removeHeightCallbacks = []; + + this._tileToUpdateHeights = []; + this._lastTileIndex = 0; + this._updateHeightsTimeSlice = 2.0; /** * Gets or sets the maximum screen-space error, in pixels, that is allowed. @@ -116,13 +126,6 @@ define([ */ this.tileCacheSize = defaultValue(options.tileCacheSize, 100); - /** - * An event that is raised when a tile becomes visible. The argument to the event listener - * is the visible tile. - * @type {Event} - */ - this.tileVisibleEvent = new Event(); - this._occluders = new QuadtreeOccluders({ ellipsoid : ellipsoid }); @@ -196,26 +199,20 @@ define([ } }; - /** - * Associate data with the tiles of the quadtree. The custom data must have a Cartographic position property. - * The position will be used to associate the data with the individual tiles of the quadtree. If the position - * is in the tile's rectangle, the custom data will be added to the tile. - * - * @param {Object} customData The object literal with a Cartographic position property and any other custom properties. - */ - QuadtreePrimitive.prototype.addTileCustomData = function(customData) { - this._customDataAdded.push(customData); - }; + QuadtreePrimitive.prototype.updateHeight = function(cartographic, callback) { + var primitive = this; + var object = { + position : undefined, + positionCartographic : cartographic, + level : 0, + callback : callback, + removeFunc : function() { + primitive._removeHeightCallbacks.push(this); + } + }; - /** - * Removes custom data from the tiles quadtree. - * - * @param {Object} customData The data to be removed. - * - * @see QuadtreePrimitive.addTileCustomData - */ - QuadtreePrimitive.prototype.removeTileCustomData = function(customData) { - this._customDataRemoved.push(customData); + primitive._addHeightCallbacks.push(object); + return object.removeFunc; }; /** @@ -321,8 +318,8 @@ define([ var tile; var levelZeroTiles = primitive._levelZeroTiles; - var customDataAdded = primitive._customDataAdded; - var customDataRemoved = primitive._customDataRemoved; + var customDataAdded = primitive._addHeightCallbacks; + var customDataRemoved = primitive._removeHeightCallbacks; var frameNumber = frameState.frameNumber; if (customDataAdded.length > 0 || customDataRemoved.length > 0) { @@ -502,6 +499,85 @@ define([ } } + var scratchRay = new Ray(); + var scratchCartographic = new Cartographic(); + var scratchPosition = new Cartesian3(); + + function updateHeights(primitive, frameState) { + var tilesToUpdateHeights = primitive._tileToUpdateHeights; + + var startTime = getTimestamp(); + var timeSlice = primitive._updateHeightsTimeSlice; + var endTime = startTime + timeSlice; + + var mode = frameState.mode; + var projection = frameState.mapProjection; + var ellipsoid = projection.ellipsoid; + + while (tilesToUpdateHeights.length > 0) { + var tile = tilesToUpdateHeights[0]; + var customData = tile.customData; + var customDataLength = customData.length; + + var timeSliceMax = false; + for (var i = primitive._lastTileIndex; i < customDataLength; ++i) { + var data = customData[i]; + + if (tile.level > data.level) { + if (!defined(data.position)) { + data.position = ellipsoid.cartographicToCartesian(data.positionCartographic); + } + + if (mode === SceneMode.SCENE3D) { + Cartesian3.clone(Cartesian3.ZERO, scratchRay.origin); + Cartesian3.normalize(data.position, scratchRay.direction); + } else { + Cartographic.clone(data.positionCartographic, scratchCartographic); + + // minimum height for the terrain set, need to get this information from the terrain provider + scratchCartographic.height = -11500.0; + projection.project(scratchCartographic, scratchPosition); + Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, scratchPosition); + Cartesian3.clone(scratchPosition, scratchRay.origin); + Cartesian3.clone(Cartesian3.UNIT_X, scratchRay.direction); + } + + var position = tile.data.pick(scratchRay, mode, projection, false, scratchPosition); + if (defined(position)) { + data.callback(position); + } + + data.level = tile.level; + } /*else if (tile.level === data.level) { + var children = tile.children; + var childrenLength = children.length; + + var upsampledOnly = true; + for (var j = 0; j < childrenLength; ++j) { + upsampledOnly = upsampledOnly && children[j].upsampledFromParent; + } + + if (upsampledOnly) { + data.removeFunc(); + } + }*/ + + if (getTimestamp() >= endTime) { + timeSliceMax = true; + break; + } + } + + if (timeSliceMax) { + primitive._lastTileIndex = i; + break; + } else { + primitive._lastTileIndex = 0; + tilesToUpdateHeights.shift(); + } + } + } + function tileDistanceSortFunction(a, b) { return a._distance - b._distance; } @@ -509,6 +585,7 @@ define([ function createRenderCommandsForSelectedTiles(primitive, context, frameState, commandList) { var tileProvider = primitive._tileProvider; var tilesToRender = primitive._tilesToRender; + var tilesToUpdateHeights = primitive._tileToUpdateHeights; tilesToRender.sort(tileDistanceSortFunction); @@ -517,10 +594,12 @@ define([ tileProvider.showTileThisFrame(tile, context, frameState, commandList); if (tile._frameRendered !== frameState.frameNumber - 1) { - primitive.tileVisibleEvent.raiseEvent(tile); + tilesToUpdateHeights.push(tile); } tile._frameRendered = frameState.frameNumber; } + + updateHeights(primitive, frameState); } return QuadtreePrimitive; diff --git a/Source/Scene/QuadtreeTile.js b/Source/Scene/QuadtreeTile.js index 009299c4b3a7..6f5e852801b0 100644 --- a/Source/Scene/QuadtreeTile.js +++ b/Source/Scene/QuadtreeTile.js @@ -157,7 +157,7 @@ define([ rectangle = this._rectangle; for (i = 0; i < added.length; ++i) { data = added[i]; - if (Rectangle.contains(rectangle, data.position)) { + if (Rectangle.contains(rectangle, data.positionCartographic)) { customData.push(data); } } @@ -173,7 +173,7 @@ define([ var parentCustomData = parent.customData; for (i = 0; i < parentCustomData.length; ++i) { data = parentCustomData[i]; - if (Rectangle.contains(rectangle, data.position)) { + if (Rectangle.contains(rectangle, data.positionCartographic)) { customData.push(data); } } diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index adda5e5e5d36..ff424ed1af6b 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -227,7 +227,7 @@ void main() #endif #ifdef TEST_GLOBE_DEPTH - if (-positionEC.z < 70000.0) + if (-positionEC.z < 50000.0) { vec2 directions[4]; directions[0] = vec2(0.0, 0.0); From 0b2a63a742bf0a60dc392a4915e652cb2efe3063 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 1 May 2015 17:36:07 -0400 Subject: [PATCH 30/40] Stop updating billboards/labels when the height for the lowest level terrain tile has been picked. Fix initial guess at height. Fix height relative to ground. --- Source/Scene/Billboard.js | 14 ++++++++------ Source/Scene/QuadtreePrimitive.js | 19 +++++++++++++------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index a3f1845dcf31..499f72441bd3 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -859,20 +859,22 @@ define([ object._removeCallbackFunc(); } - var updateFunction = function(position) { + var updateFunction = function(clampedPosition) { if (object._heightReference === HeightReference.RELATIVE_TO_GROUND) { - var clampedCart = ellipsoid.cartesianToCartographic(position, scratchCartographic); - clampedCart.height += object._customData.position.height; - ellipsoid.cartographicToCartesian(clampedCart, position); + var clampedCart = ellipsoid.cartesianToCartographic(clampedPosition, scratchCartographic); + clampedCart.height += position.height; + ellipsoid.cartographicToCartesian(clampedCart, clampedPosition); } - object._clampedPosition = Cartesian3.clone(position, object._clampedPosition); + object._clampedPosition = Cartesian3.clone(clampedPosition, object._clampedPosition); }; object._removeCallbackFunc = surface.updateHeight(position, updateFunction); var height = globe.getHeight(position); if (defined(height)) { - updateFunction(height); + Cartographic.clone(position, scratchCartographic); + scratchCartographic.height = height; + updateFunction(ellipsoid.cartographicToCartesian(scratchCartographic, scratchPosition)); } }; diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index af5f77af29fe..a6bbc94b8a2e 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -505,6 +505,7 @@ define([ function updateHeights(primitive, frameState) { var tilesToUpdateHeights = primitive._tileToUpdateHeights; + var terrainProvider = primitive._tileProvider.terrainProvider; var startTime = getTimestamp(); var timeSlice = primitive._updateHeightsTimeSlice; @@ -548,19 +549,25 @@ define([ } data.level = tile.level; - } /*else if (tile.level === data.level) { + } else if (tile.level === data.level) { var children = tile.children; var childrenLength = children.length; - var upsampledOnly = true; + var child; for (var j = 0; j < childrenLength; ++j) { - upsampledOnly = upsampledOnly && children[j].upsampledFromParent; + child = children[j]; + if (Rectangle.contains(child.rectangle, data.positionCartographic)) { + break; + } } - if (upsampledOnly) { - data.removeFunc(); + var tileDataAvailable = terrainProvider.getTileDataAvailable(child.x, child.y, child.level); + if ((defined(tileDataAvailable) && !tileDataAvailable) || + (defined(parent) && defined(parent.data) && defined(parent.data.terrainData) && + !parent.data.terrainData.isChildAvailable(parent.x, parent.y, child.x, child.y))) { + data.removeFunc(); } - }*/ + } if (getTimestamp() >= endTime) { timeSliceMax = true; From 26d6ad591de109c16a06416692557df86f481499 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 4 May 2015 14:17:14 -0400 Subject: [PATCH 31/40] Fix updating billboard/label height reference and position. --- Source/Scene/QuadtreePrimitive.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index a6bbc94b8a2e..adecf1f1cbf8 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -205,10 +205,11 @@ define([ position : undefined, positionCartographic : cartographic, level : 0, - callback : callback, - removeFunc : function() { - primitive._removeHeightCallbacks.push(this); - } + callback : callback + }; + + object.removeFunc = function() { + primitive._removeHeightCallbacks.push(object); }; primitive._addHeightCallbacks.push(object); From d9061fb9c847beadeba03c16f0b09c27931def03 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 4 May 2015 14:56:43 -0400 Subject: [PATCH 32/40] Rename from review. --- Source/Scene/Billboard.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index 499f72441bd3..2f3946eba395 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -827,10 +827,10 @@ define([ var scratchCartographic = new Cartographic(); var scratchPosition = new Cartesian3(); - Billboard._updateClamping = function(collection, object) { + Billboard._updateClamping = function(collection, owner) { var scene = collection._scene; if (!defined(scene)) { - if (object._heightReference !== HeightReference.NONE) { + if (owner._heightReference !== HeightReference.NONE) { throw new DeveloperError('Height reference is not supported.'); } return; @@ -840,35 +840,35 @@ define([ var ellipsoid = globe.ellipsoid; var surface = globe._surface; - if (object._heightReference === HeightReference.NONE && defined(object._removeCallbackFunc)) { - object._removeCallbackFunc(); - object._removeCallbackFunc = undefined; - object._clampedPosition = undefined; + if (owner._heightReference === HeightReference.NONE && defined(owner._removeCallbackFunc)) { + owner._removeCallbackFunc(); + owner._removeCallbackFunc = undefined; + owner._clampedPosition = undefined; } - if (object._heightReference === HeightReference.NONE || !defined(object._position)) { + if (owner._heightReference === HeightReference.NONE || !defined(owner._position)) { return; } - var position = ellipsoid.cartesianToCartographic(object._position); + var position = ellipsoid.cartesianToCartographic(owner._position); if (!defined(position)) { return; } - if (defined(object._removeCallbackFunc)) { - object._removeCallbackFunc(); + if (defined(owner._removeCallbackFunc)) { + owner._removeCallbackFunc(); } var updateFunction = function(clampedPosition) { - if (object._heightReference === HeightReference.RELATIVE_TO_GROUND) { + if (owner._heightReference === HeightReference.RELATIVE_TO_GROUND) { var clampedCart = ellipsoid.cartesianToCartographic(clampedPosition, scratchCartographic); clampedCart.height += position.height; ellipsoid.cartographicToCartesian(clampedCart, clampedPosition); } - object._clampedPosition = Cartesian3.clone(clampedPosition, object._clampedPosition); + owner._clampedPosition = Cartesian3.clone(clampedPosition, owner._clampedPosition); }; - object._removeCallbackFunc = surface.updateHeight(position, updateFunction); + owner._removeCallbackFunc = surface.updateHeight(position, updateFunction); var height = globe.getHeight(position); if (defined(height)) { From fb7901e78ff9bc759fb2b8d2e362621415440b85 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 4 May 2015 14:59:07 -0400 Subject: [PATCH 33/40] Update Sandcastle example. --- .../development/BillboardClampToGround.html | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Apps/Sandcastle/gallery/development/BillboardClampToGround.html b/Apps/Sandcastle/gallery/development/BillboardClampToGround.html index 93836efa2a6c..3feab2e187ae 100644 --- a/Apps/Sandcastle/gallery/development/BillboardClampToGround.html +++ b/Apps/Sandcastle/gallery/development/BillboardClampToGround.html @@ -5,7 +5,7 @@ - + Cesium Demo @@ -42,9 +42,15 @@ var ellipsoid = viewer.scene.globe.ellipsoid; var billboardCollection = viewer.scene.primitives.add(new Cesium.BillboardCollection({ - globe : viewer.scene.globe + scene : viewer.scene })); +/* +var labelCollection = viewer.scene.primitives.add(new Cesium.LabelCollection({ + scene : viewer.scene +})); +*/ + // everest //var centerLatitude = Cesium.Math.toRadians(27.988257); //var centerLongitude = Cesium.Math.toRadians(86.925145); @@ -68,9 +74,13 @@ billboardCollection.add({ position : ellipsoid.cartographicToCartesian(position), image : '../images/facility.gif', - scale : 0.7, heightReference : Cesium.HeightReference.CLAMP_TO_GROUND }); + //labelCollection.add({ + // text : 'Label', + // position : ellipsoid.cartographicToCartesian(position), + // heightReference : Cesium.HeightReference.CLAMP_TO_GROUND + //}); } } From 344619da1845107bf0db1f12a9c709f79ac60d56 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 4 May 2015 16:01:15 -0400 Subject: [PATCH 34/40] Update doc. --- .../gallery/development/BillboardClampToGround.html | 2 +- Source/Scene/QuadtreePrimitive.js | 8 ++++++++ Source/Scene/QuadtreeTile.js | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Apps/Sandcastle/gallery/development/BillboardClampToGround.html b/Apps/Sandcastle/gallery/development/BillboardClampToGround.html index 3feab2e187ae..b3db0abd654e 100644 --- a/Apps/Sandcastle/gallery/development/BillboardClampToGround.html +++ b/Apps/Sandcastle/gallery/development/BillboardClampToGround.html @@ -4,7 +4,7 @@ - + Cesium Demo diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index adecf1f1cbf8..e98126b5bf49 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -199,6 +199,14 @@ define([ } }; + /** + * Calls the callback when a new tile is rendered that contains the given cartographic. The only parameter + * is the cartesian position on the tile. + * + * @param {Cartographic} cartographic The cartographic position. + * @param {Function} callback The function to be called when a new tile is loaded containing cartographic. + * @returns {Function} The function to remove this callback from the quadtree. + */ QuadtreePrimitive.prototype.updateHeight = function(cartographic, callback) { var primitive = this; var object = { diff --git a/Source/Scene/QuadtreeTile.js b/Source/Scene/QuadtreeTile.js index 6f5e852801b0..abc1e0231c66 100644 --- a/Source/Scene/QuadtreeTile.js +++ b/Source/Scene/QuadtreeTile.js @@ -295,7 +295,7 @@ define([ }, /** - * An array of objects associated with this tile. See QuadtreePrimitive.addTileCustomData. + * An array of objects associated with this tile. * @memberof QuadtreeTile.prototype * @type {Array} */ From f68c78b3164111ca1f7f743f3fd6ee9d3bfb59ba Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 4 May 2015 16:12:51 -0400 Subject: [PATCH 35/40] Improve update performance. --- Source/Scene/QuadtreePrimitive.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index e98126b5bf49..f02374472e6a 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -525,7 +525,11 @@ define([ var ellipsoid = projection.ellipsoid; while (tilesToUpdateHeights.length > 0) { - var tile = tilesToUpdateHeights[0]; + var tile = tilesToUpdateHeights[tilesToUpdateHeights.length - 1]; + if (tile !== primitive._lastTileUpdated) { + primitive._lastTileIndex = 0; + } + var customData = tile.customData; var customDataLength = customData.length; @@ -585,11 +589,11 @@ define([ } if (timeSliceMax) { + primitive._lastTileUpdated = tile; primitive._lastTileIndex = i; break; } else { - primitive._lastTileIndex = 0; - tilesToUpdateHeights.shift(); + tilesToUpdateHeights.pop(); } } } From 1770da49a9983b6aaf1d7a6485a46f2bb9e10e6d Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 4 May 2015 16:24:11 -0400 Subject: [PATCH 36/40] Update labels/billboards when the terrain provider changes. --- Source/Scene/QuadtreePrimitive.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index f02374472e6a..6879c8b2f787 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -161,6 +161,16 @@ define([ var levelZeroTiles = this._levelZeroTiles; if (defined(levelZeroTiles)) { for (var i = 0; i < levelZeroTiles.length; ++i) { + var tile = levelZeroTiles[i]; + var customData = tile.customData; + var customDataLength = customData.length; + + for (var j = 0; j < customDataLength; ++j) { + var data = customData[j]; + data.level = 0; + this._addHeightCallbacks.push(data); + } + levelZeroTiles[i].freeResources(); } } From 9f7f1ab1ad69901c4ac2cdf2becda3ce48771a51 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 5 May 2015 15:23:04 -0400 Subject: [PATCH 37/40] Fix ciolumbus view. Clean up requires. --- Source/Scene/Billboard.js | 39 +++++++++++++++++++---------- Source/Scene/BillboardCollection.js | 2 -- Source/Scene/Label.js | 3 +-- Source/Scene/LabelCollection.js | 12 ++------- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/Source/Scene/Billboard.js b/Source/Scene/Billboard.js index 2f3946eba395..cbfe9e34b7e9 100644 --- a/Source/Scene/Billboard.js +++ b/Source/Scene/Billboard.js @@ -13,7 +13,6 @@ define([ '../Core/DeveloperError', '../Core/Matrix4', '../Core/NearFarScalar', - '../Core/Ray', './HeightReference', './HorizontalOrigin', './SceneMode', @@ -33,7 +32,6 @@ define([ DeveloperError, Matrix4, NearFarScalar, - Ray, HeightReference, HorizontalOrigin, SceneMode, @@ -840,7 +838,13 @@ define([ var ellipsoid = globe.ellipsoid; var surface = globe._surface; - if (owner._heightReference === HeightReference.NONE && defined(owner._removeCallbackFunc)) { + var mode = scene.frameState.mode; + var projection = scene.frameState.mapProjection; + + var modeChanged = mode !== owner._mode; + owner._mode = mode; + + if ((owner._heightReference === HeightReference.NONE || modeChanged) && defined(owner._removeCallbackFunc)) { owner._removeCallbackFunc(); owner._removeCallbackFunc = undefined; owner._clampedPosition = undefined; @@ -861,9 +865,13 @@ define([ var updateFunction = function(clampedPosition) { if (owner._heightReference === HeightReference.RELATIVE_TO_GROUND) { - var clampedCart = ellipsoid.cartesianToCartographic(clampedPosition, scratchCartographic); - clampedCart.height += position.height; - ellipsoid.cartographicToCartesian(clampedCart, clampedPosition); + if (owner._mode === SceneMode.SCENE3D) { + var clampedCart = ellipsoid.cartesianToCartographic(clampedPosition, scratchCartographic); + clampedCart.height += position.height; + ellipsoid.cartographicToCartesian(clampedCart, clampedPosition); + } else { + clampedPosition.x += position.height; + } } owner._clampedPosition = Cartesian3.clone(clampedPosition, owner._clampedPosition); }; @@ -874,7 +882,14 @@ define([ if (defined(height)) { Cartographic.clone(position, scratchCartographic); scratchCartographic.height = height; - updateFunction(ellipsoid.cartographicToCartesian(scratchCartographic, scratchPosition)); + if (owner._mode === SceneMode.SCENE3D) { + ellipsoid.cartographicToCartesian(scratchCartographic, scratchPosition); + } else { + projection.project(scratchCartographic, scratchPosition); + Cartesian3.fromElements(scratchPosition.z, scratchPosition.x, scratchPosition.y, scratchPosition); + } + + updateFunction(scratchPosition); } }; @@ -1041,11 +1056,11 @@ define([ }; Billboard.prototype._getActualPosition = function() { - return defined(this._clampedPosition) && this._mode !== SceneMode.MORPHING ? this._clampedPosition : this._actualPosition; + return defined(this._clampedPosition) ? this._clampedPosition : this._actualPosition; }; Billboard.prototype._setActualPosition = function(value) { - if (!(defined(this._clampedPosition) && this._mode !== SceneMode.MORPHING)) { + if (!(defined(this._clampedPosition))) { Cartesian3.clone(value, this._actualPosition); } makeDirty(this, POSITION_INDEX); @@ -1053,10 +1068,8 @@ define([ var tempCartesian3 = new Cartesian4(); Billboard._computeActualPosition = function(billboard, position, frameState, modelMatrix) { - if (defined(billboard._clampedPosition) && this._mode !== SceneMode.MORPHING) { - if (frameState.mode !== this._mode) { - billboard._mode = frameState.mode; - billboard._projection = frameState.mapProjection; + if (defined(billboard._clampedPosition)) { + if (frameState.mode !== billboard._mode) { billboard._updateClamping(); } return billboard._clampedPosition; diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js index b72d1b92ded3..012bc535564a 100644 --- a/Source/Scene/BillboardCollection.js +++ b/Source/Scene/BillboardCollection.js @@ -12,7 +12,6 @@ define([ '../Core/destroyObject', '../Core/DeveloperError', '../Core/EncodedCartesian3', - '../Core/getTimestamp', '../Core/IndexDatatype', '../Core/Math', '../Core/Matrix4', @@ -41,7 +40,6 @@ define([ destroyObject, DeveloperError, EncodedCartesian3, - getTimestamp, IndexDatatype, CesiumMath, Matrix4, diff --git a/Source/Scene/Label.js b/Source/Scene/Label.js index 6541d637a50c..ef165523f0b9 100644 --- a/Source/Scene/Label.js +++ b/Source/Scene/Label.js @@ -96,9 +96,8 @@ define([ this._rebindAllGlyphs = true; this._repositionAllGlyphs = true; - this._customData = undefined; - this._level = 0; this._actualClampedPosition = undefined; + this._removeCallbackFunc = undefined; this._mode = undefined; this._updateClamping(); diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index 181c4bbb8f05..cd708e1da525 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -6,10 +6,8 @@ define([ '../Core/defineProperties', '../Core/destroyObject', '../Core/DeveloperError', - '../Core/getTimestamp', '../Core/Matrix4', '../Core/writeTextToCanvas', - './Billboard', './BillboardCollection', './HorizontalOrigin', './Label', @@ -23,10 +21,8 @@ define([ defineProperties, destroyObject, DeveloperError, - getTimestamp, Matrix4, writeTextToCanvas, - Billboard, BillboardCollection, HorizontalOrigin, Label, @@ -280,14 +276,10 @@ define([ } label._labelCollection = undefined; - if (defined(label._customData)) { - labelCollection._scene.globe._surface.removeTileCustomData(label._customData); - label._customData = undefined; + if (defined(label._removeCallbackFunc)) { + label._removeCallbackFunc(); } - label._currentTile = undefined; - label._newTile = undefined; - destroyObject(label); } From 58980dc0e4ca36afeffc7422c5f7ca4a3a7185b1 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 5 May 2015 16:40:59 -0400 Subject: [PATCH 38/40] Re-add eye z offset. --- Source/Shaders/BillboardCollectionVS.glsl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Shaders/BillboardCollectionVS.glsl b/Source/Shaders/BillboardCollectionVS.glsl index ff424ed1af6b..868a389ad6a0 100644 --- a/Source/Shaders/BillboardCollectionVS.glsl +++ b/Source/Shaders/BillboardCollectionVS.glsl @@ -229,6 +229,9 @@ void main() #ifdef TEST_GLOBE_DEPTH if (-positionEC.z < 50000.0) { + vec4 offsetPosition = positionEC; + offsetPosition.z *= 0.99; + vec2 directions[4]; directions[0] = vec2(0.0, 0.0); directions[1] = vec2(0.0, 1.0); @@ -241,7 +244,7 @@ void main() bool visible = false; for (int i = 0; i < 4; ++i) { - vec4 wc = computePositionWindowCoordinates(positionEC, size, scale, directions[i], vec2(0.0, 0.0), vec2(0.0), pixelOffset, alignedAxis, rotation); + vec4 wc = computePositionWindowCoordinates(offsetPosition, size, scale, directions[i], vec2(0.0, 0.0), vec2(0.0), pixelOffset, alignedAxis, rotation); float d = texture2D(czm_globeDepthTexture, wc.xy * invSize).r; if (wc.z < d) { From 3b7c13b277cbf569a7ff04b850b375d4587c7919 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Wed, 6 May 2015 21:34:42 -0400 Subject: [PATCH 39/40] Add tests for billboards/labels with height references and for the quadtree primitive update height callbacks. --- Source/Scene/QuadtreePrimitive.js | 2 +- Specs/Scene/BillboardCollectionSpec.js | 154 +++++++++++++++++++++++++ Specs/Scene/LabelCollectionSpec.js | 153 ++++++++++++++++++++++++ Specs/Scene/QuadtreePrimitiveSpec.js | 87 ++++++++++++++ 4 files changed, 395 insertions(+), 1 deletion(-) diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index 6879c8b2f787..6a7b67d8adeb 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -222,7 +222,7 @@ define([ var object = { position : undefined, positionCartographic : cartographic, - level : 0, + level : -1, callback : callback }; diff --git a/Specs/Scene/BillboardCollectionSpec.js b/Specs/Scene/BillboardCollectionSpec.js index 97c8f506719c..5b05901041aa 100644 --- a/Specs/Scene/BillboardCollectionSpec.js +++ b/Specs/Scene/BillboardCollectionSpec.js @@ -6,9 +6,11 @@ defineSuite([ 'Core/Cartesian2', 'Core/Cartesian3', 'Core/Color', + 'Core/Ellipsoid', 'Core/loadImage', 'Core/Math', 'Core/NearFarScalar', + 'Scene/HeightReference', 'Scene/HorizontalOrigin', 'Scene/OrthographicFrustum', 'Scene/TextureAtlas', @@ -23,9 +25,11 @@ defineSuite([ Cartesian2, Cartesian3, Color, + Ellipsoid, loadImage, CesiumMath, NearFarScalar, + HeightReference, HorizontalOrigin, OrthographicFrustum, TextureAtlas, @@ -39,6 +43,8 @@ defineSuite([ var scene; var camera; var billboards; + var heightReferenceSupported; + var billboardsWithHeight; var greenImage; var blueImage; @@ -49,6 +55,8 @@ defineSuite([ scene = createScene(); camera = scene.camera; + heightReferenceSupported = scene._globeDepth.supported && scene.context.maximumVertexTextureImageUnits > 0; + return when.join( loadImage('./Data/Images/Green.png').then(function(result) { greenImage = result; @@ -70,11 +78,20 @@ defineSuite([ beforeEach(function() { scene.morphTo3D(0); + camera.position = new Cartesian3(10.0, 0.0, 0.0); camera.direction = Cartesian3.negate(Cartesian3.UNIT_X, new Cartesian3()); camera.up = Cartesian3.clone(Cartesian3.UNIT_Z); + billboards = new BillboardCollection(); scene.primitives.add(billboards); + + if (heightReferenceSupported) { + billboardsWithHeight = new BillboardCollection({ + scene : scene + }); + scene.primitives.add(billboardsWithHeight); + } }); afterEach(function() { @@ -104,6 +121,7 @@ defineSuite([ expect(b.width).not.toBeDefined(); expect(b.height).not.toBeDefined(); expect(b.id).not.toBeDefined(); + expect(b.heightReference).toEqual(HeightReference.NONE); }); it('can add and remove before first update.', function() { @@ -1412,4 +1430,140 @@ defineSuite([ return deferred.promise; }); + + describe('height referenced billboards', function() { + function createMockGlobe() { + var globe = { + callback : undefined, + removedCallback : false, + ellipsoid : Ellipsoid.WGS84, + update : function() {}, + getHeight : function() { + return 0.0; + }, + _surface : {}, + destroy : function() {} + }; + + globe._surface.updateHeight = function(position, callback) { + globe.callback = callback; + return function() { + globe.removedCallback = true; + globe.callback = undefined; + }; + }; + + return globe; + } + + it('explicitly constructs a billboard with height reference', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var b = billboardsWithHeight.add({ + heightReference : HeightReference.CLAMP_TO_GROUND + }); + + expect(b.heightReference).toEqual(HeightReference.CLAMP_TO_GROUND); + }); + + it('set billboard height reference property', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var b = billboardsWithHeight.add(); + b.heightReference = HeightReference.CLAMP_TO_GROUND; + + expect(b.heightReference).toEqual(HeightReference.CLAMP_TO_GROUND); + }); + + it('creating with a height reference creates a height update callback', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var b = billboardsWithHeight.add({ + heightReference : HeightReference.CLAMP_TO_GROUND, + position : Cartesian3.fromDegrees(-72.0, 40.0) + }); + expect(scene.globe.callback).toBeDefined(); + }); + + it('set height reference property creates a height update callback', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var b = billboardsWithHeight.add({ + position : Cartesian3.fromDegrees(-72.0, 40.0) + }); + b.heightReference = HeightReference.CLAMP_TO_GROUND; + expect(scene.globe.callback).toBeDefined(); + }); + + it('updates the callback when the height reference changes', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var b = billboardsWithHeight.add({ + heightReference : HeightReference.CLAMP_TO_GROUND, + position : Cartesian3.fromDegrees(-72.0, 40.0) + }); + expect(scene.globe.callback).toBeDefined(); + + b.heightReference = HeightReference.RELATIVE_TO_GROUND; + expect(scene.globe.removedCallback).toEqual(true); + expect(scene.globe.callback).toBeDefined(); + + scene.globe.removedCallback = false; + b.heightReference = HeightReference.NONE; + expect(scene.globe.removedCallback).toEqual(true); + expect(scene.globe.callback).not.toBeDefined(); + }); + + it('changing the position updates the callback', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var b = billboardsWithHeight.add({ + heightReference : HeightReference.CLAMP_TO_GROUND, + position : Cartesian3.fromDegrees(-72.0, 40.0) + }); + expect(scene.globe.callback).toBeDefined(); + + b.position = Cartesian3.fromDegrees(-73.0, 40.0); + expect(scene.globe.removedCallback).toEqual(true); + expect(scene.globe.callback).toBeDefined(); + }); + + it('callback updates the position', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var b = billboardsWithHeight.add({ + heightReference : HeightReference.CLAMP_TO_GROUND, + position : Cartesian3.fromDegrees(-72.0, 40.0) + }); + expect(scene.globe.callback).toBeDefined(); + + var cartographic = scene.globe.ellipsoid.cartesianToCartographic(b._clampedPosition); + expect(cartographic.height).toEqual(0.0); + + scene.globe.callback(Cartesian3.fromDegrees(-72.0, 40.0, 100.0)); + cartographic = scene.globe.ellipsoid.cartesianToCartographic(b._clampedPosition); + expect(cartographic.height).toEqualEpsilon(100.0, CesiumMath.EPSILON9); + }); + }); }, 'WebGL'); diff --git a/Specs/Scene/LabelCollectionSpec.js b/Specs/Scene/LabelCollectionSpec.js index 934c83baa84a..68364d02dd15 100644 --- a/Specs/Scene/LabelCollectionSpec.js +++ b/Specs/Scene/LabelCollectionSpec.js @@ -5,8 +5,10 @@ defineSuite([ 'Core/Cartesian2', 'Core/Cartesian3', 'Core/Color', + 'Core/Ellipsoid', 'Core/Math', 'Core/NearFarScalar', + 'Scene/HeightReference', 'Scene/HorizontalOrigin', 'Scene/LabelStyle', 'Scene/OrthographicFrustum', @@ -18,8 +20,10 @@ defineSuite([ Cartesian2, Cartesian3, Color, + Ellipsoid, CesiumMath, NearFarScalar, + HeightReference, HorizontalOrigin, LabelStyle, OrthographicFrustum, @@ -33,10 +37,14 @@ defineSuite([ var scene; var camera; var labels; + var heightReferenceSupported; + var labelsWithHeight; beforeAll(function() { scene = createScene(); camera = scene.camera; + + heightReferenceSupported = scene._globeDepth.supported && scene.context.maximumVertexTextureImageUnits > 0; }); afterAll(function() { @@ -45,11 +53,20 @@ defineSuite([ beforeEach(function() { scene.morphTo3D(0); + camera.position = new Cartesian3(10.0, 0.0, 0.0); camera.direction = Cartesian3.negate(Cartesian3.UNIT_X, new Cartesian3()); camera.up = Cartesian3.clone(Cartesian3.UNIT_Z); + labels = new LabelCollection(); scene.primitives.add(labels); + + if (heightReferenceSupported) { + labelsWithHeight = new LabelCollection({ + scene : scene + }); + scene.primitives.add(labelsWithHeight); + } }); afterEach(function() { @@ -1617,4 +1634,140 @@ defineSuite([ expect(textureAtlas.isDestroyed()).toBe(true); }); + describe('height referenced labels', function() { + function createMockGlobe() { + var globe = { + callback : undefined, + removedCallback : false, + ellipsoid : Ellipsoid.WGS84, + update : function() {}, + getHeight : function() { + return 0.0; + }, + _surface : {}, + destroy : function() {} + }; + + globe._surface.updateHeight = function(position, callback) { + globe.callback = callback; + return function() { + globe.removedCallback = true; + globe.callback = undefined; + }; + }; + + return globe; + } + + it('explicitly constructs a label with height reference', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var l = labelsWithHeight.add({ + heightReference : HeightReference.CLAMP_TO_GROUND + }); + + expect(l.heightReference).toEqual(HeightReference.CLAMP_TO_GROUND); + }); + + it('set label height reference property', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var l = labelsWithHeight.add(); + l.heightReference = HeightReference.CLAMP_TO_GROUND; + + expect(l.heightReference).toEqual(HeightReference.CLAMP_TO_GROUND); + }); + + it('creating with a height reference creates a height update callback', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var l = labelsWithHeight.add({ + heightReference : HeightReference.CLAMP_TO_GROUND, + position : Cartesian3.fromDegrees(-72.0, 40.0) + }); + expect(scene.globe.callback).toBeDefined(); + }); + + it('set height reference property creates a height update callback', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var l = labelsWithHeight.add({ + position : Cartesian3.fromDegrees(-72.0, 40.0) + }); + l.heightReference = HeightReference.CLAMP_TO_GROUND; + expect(scene.globe.callback).toBeDefined(); + }); + + it('updates the callback when the height reference changes', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var l = labelsWithHeight.add({ + heightReference : HeightReference.CLAMP_TO_GROUND, + position : Cartesian3.fromDegrees(-72.0, 40.0) + }); + expect(scene.globe.callback).toBeDefined(); + + l.heightReference = HeightReference.RELATIVE_TO_GROUND; + expect(scene.globe.removedCallback).toEqual(true); + expect(scene.globe.callback).toBeDefined(); + + scene.globe.removedCallback = false; + l.heightReference = HeightReference.NONE; + expect(scene.globe.removedCallback).toEqual(true); + expect(scene.globe.callback).not.toBeDefined(); + }); + + it('changing the position updates the callback', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var l = labelsWithHeight.add({ + heightReference : HeightReference.CLAMP_TO_GROUND, + position : Cartesian3.fromDegrees(-72.0, 40.0) + }); + expect(scene.globe.callback).toBeDefined(); + + l.position = Cartesian3.fromDegrees(-73.0, 40.0); + expect(scene.globe.removedCallback).toEqual(true); + expect(scene.globe.callback).toBeDefined(); + }); + + it('callback updates the position', function() { + if (!heightReferenceSupported) { + return; + } + + scene.globe = createMockGlobe(); + var l = labelsWithHeight.add({ + heightReference : HeightReference.CLAMP_TO_GROUND, + position : Cartesian3.fromDegrees(-72.0, 40.0) + }); + expect(scene.globe.callback).toBeDefined(); + + var cartographic = scene.globe.ellipsoid.cartesianToCartographic(l._clampedPosition); + expect(cartographic.height).toEqual(0.0); + + scene.globe.callback(Cartesian3.fromDegrees(-72.0, 40.0, 100.0)); + cartographic = scene.globe.ellipsoid.cartesianToCartographic(l._clampedPosition); + expect(cartographic.height).toEqualEpsilon(100.0, CesiumMath.EPSILON9); + }); + }); + }, 'WebGL'); \ No newline at end of file diff --git a/Specs/Scene/QuadtreePrimitiveSpec.js b/Specs/Scene/QuadtreePrimitiveSpec.js index dcee05216c89..3787fd46b6fd 100644 --- a/Specs/Scene/QuadtreePrimitiveSpec.js +++ b/Specs/Scene/QuadtreePrimitiveSpec.js @@ -1,6 +1,8 @@ /*global defineSuite*/ defineSuite([ 'Scene/QuadtreePrimitive', + 'Core/Cartesian3', + 'Core/Cartographic', 'Core/defineProperties', 'Core/GeographicTilingScheme', 'Core/Visibility', @@ -9,6 +11,8 @@ defineSuite([ 'Specs/createFrameState' ], function( QuadtreePrimitive, + Cartesian3, + Cartographic, defineProperties, GeographicTilingScheme, Visibility, @@ -158,4 +162,87 @@ defineSuite([ expect(tile.state).not.toBe(QuadtreeTileLoadState.START); }); }); + + it('add and remove callbacks to tiles', function() { + var tileProvider = createSpyTileProvider(); + tileProvider.getReady.and.returnValue(true); + tileProvider.computeTileVisibility.and.returnValue(Visibility.FULL); + tileProvider.computeDistanceToTile.and.returnValue(1e-15); + + // Load the root tiles. + tileProvider.loadTile.and.callFake(function(context, frameState, tile) { + tile.state = QuadtreeTileLoadState.DONE; + tile.renderable = true; + }); + + var quadtree = new QuadtreePrimitive({ + tileProvider : tileProvider + }); + + var removeFunc = quadtree.updateHeight(Cartographic.fromDegrees(-72.0, 40.0), function(position) {}); + + quadtree.update(context, frameState, []); + + var addedCallback = false; + quadtree.forEachLoadedTile(function (tile) { + addedCallback = addedCallback || tile.customData.length > 0; + }); + + expect(addedCallback).toEqual(true); + + removeFunc(); + quadtree.update(context, frameState, []); + + var removedCallback = true; + quadtree.forEachLoadedTile(function (tile) { + removedCallback = removedCallback && tile.customData.length === 0; + }); + + expect(removedCallback).toEqual(true); + }); + + it('updates heights', function() { + var tileProvider = createSpyTileProvider(); + tileProvider.getReady.and.returnValue(true); + tileProvider.computeTileVisibility.and.returnValue(Visibility.FULL); + tileProvider.computeDistanceToTile.and.returnValue(1e-15); + + tileProvider.terrainProvider = { + getTileDataAvailable : function() { + return true; + } + }; + + // Load the root tiles. + tileProvider.loadTile.and.callFake(function(context, frameState, tile) { + tile.state = QuadtreeTileLoadState.DONE; + tile.renderable = true; + }); + + var quadtree = new QuadtreePrimitive({ + tileProvider : tileProvider + }); + + var position = Cartesian3.clone(Cartesian3.ZERO); + var updatedPosition = Cartesian3.clone(Cartesian3.UNIT_X); + + quadtree.updateHeight(Cartographic.fromDegrees(-72.0, 40.0), function(p) { + Cartesian3.clone(p, position); + }); + + quadtree.update(context, frameState, []); + expect(position).toEqual(Cartesian3.ZERO); + + quadtree.forEachLoadedTile(function (tile) { + tile.data = { + pick : function() { + return updatedPosition; + } + }; + }); + + quadtree.update(context, frameState, []); + + expect(position).toEqual(updatedPosition); + }); }); \ No newline at end of file From 9fff44c2aa735e53f153d2a88a9e94ab3cc5a5a6 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Wed, 6 May 2015 22:25:29 -0400 Subject: [PATCH 40/40] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 0dc284704372..9cf5ce0688dc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,7 @@ Change Log ### 1.10 - 2015-06-01 * Breaking changes * +* Added `Billboard.heightReference` and `Label.heightReference` to clamp billboards and labels to terrain. * Added new `PointPrimitive` and `PointPrimitiveCollection`, which are faster and use less memory than billboards with circles. * Changed `Entity.point` back-end graphics to use the new `PointPrimitive` instead of billboards. No change to the `Entity.point` API. * Upgraded Autolinker from version 0.15.2 to 0.17.1.