From 108ce2d201b70a3cb5fc672163dc9cbfe9cf23e7 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 16 Sep 2016 16:05:10 -0400 Subject: [PATCH 01/12] Add batch table and hook it up to polyline collection. Polylines are still a WIP. --- Source/Scene/BatchTable.js | 313 +++++++++++++++++++++++++++++ Source/Scene/Polyline.js | 6 +- Source/Scene/PolylineCollection.js | 150 +++++++++----- Source/Shaders/PolylineVS.glsl | 18 +- 4 files changed, 425 insertions(+), 62 deletions(-) create mode 100644 Source/Scene/BatchTable.js diff --git a/Source/Scene/BatchTable.js b/Source/Scene/BatchTable.js new file mode 100644 index 000000000000..f402665a4473 --- /dev/null +++ b/Source/Scene/BatchTable.js @@ -0,0 +1,313 @@ +/*global define*/ +define([ + '../Core/Cartesian2', + '../Core/Cartesian3', + '../Core/Cartesian4', + '../Core/combine', + '../Core/ComponentDatatype', + '../Core/defined', + '../Core/destroyObject', + '../Core/DeveloperError', + '../Core/PixelFormat', + '../Core/RuntimeError', + '../Renderer/ContextLimits', + '../Renderer/PixelDatatype', + '../Renderer/Sampler', + '../Renderer/Texture', + '../Renderer/TextureMagnificationFilter', + '../Renderer/TextureMinificationFilter' + ], function( + Cartesian2, + Cartesian3, + Cartesian4, + combine, + ComponentDatatype, + defined, + destroyObject, + DeveloperError, + PixelFormat, + RuntimeError, + ContextLimits, + PixelDatatype, + Sampler, + Texture, + TextureMagnificationFilter, + TextureMinificationFilter) { + 'use strict'; + + function BatchTable(attributes, numberOfInstances) { + //>>includeStart('debug', pragmas.debug); + if (!defined(attributes)) { + throw new DeveloperError('attributes is required'); + } + if (!defined(numberOfInstances)) { + throw new DeveloperError('numberOfInstances is required'); + } + //>>includeEnd('debug'); + + this._attributes = attributes; + this._numberOfInstances = numberOfInstances; + + var pixelDatatype = getDatatype(attributes); + + var numberOfAttributes = attributes.length; + var maxNumberOfInstancesPerRow = Math.floor(ContextLimits.maximumTextureSize / numberOfAttributes); + + var instancesPerWidth = Math.min(numberOfInstances, maxNumberOfInstancesPerRow); + var width = numberOfAttributes * instancesPerWidth; + var height = Math.ceil(numberOfInstances / instancesPerWidth); + + var stepX = 1.0 / width; + var centerX = stepX * 0.5; + var stepY = 1.0 / height; + var centerY = stepY * 0.5; + + this._textureDimensions = new Cartesian2(width, height); + this._textureStep = new Cartesian4(stepX, centerX, stepY, centerY); + this._pixelDatatype = pixelDatatype; + this._texture = undefined; + + var batchLength = width * height * 4; + this._batchValues = pixelDatatype === PixelDatatype.FLOAT ? new Float32Array(batchLength) : new Uint8Array(batchLength); + this._batchValuesDirty = false; + } + + function getDatatype(attributes) { + var foundFloatDatatype = false; + var length = attributes.length; + for (var i = 0; i < length; ++i) { + if (attributes[i].componentDatatype !== ComponentDatatype.UNSIGNED_BYTE) { + foundFloatDatatype = true; + } + } + return foundFloatDatatype ? PixelDatatype.FLOAT : PixelDatatype.UNSIGNED_BYTE; + } + + function getEntryType(attributes, attributeIndex) { + var componentsPerAttribute = attributes[attributeIndex].componentsPerAttribute; + if (componentsPerAttribute === 2) { + return Cartesian2; + } else if (componentsPerAttribute === 3) { + return Cartesian3; + } else if (componentsPerAttribute === 4) { + return Cartesian4; + } + return Number; + } + + var scratchgetEntryCartesian4 = new Cartesian4(); + + BatchTable.prototype.getEntry = function(instanceIndex, attributeIndex, result) { + //>>includeStart('debug', pragmas.debug); + if (instanceIndex < 0 || instanceIndex >= this._numberOfInstances) { + throw new DeveloperError('instanceIndex is out of range.'); + } + if (attributeIndex < 0 || attributeIndex >= this._attributes.length) { + throw new DeveloperError('attributeIndex is out of range'); + } + //>>includeEnd('debug'); + + var attributes = this._attributes; + var index = 4 * attributes.length * instanceIndex + 4 * attributeIndex; + var value = Cartesian4.unpack(this._batchValues, index, scratchgetEntryCartesian4); + + var entryType = getEntryType(attributes, attributeIndex); + if (defined(entryType.fromCartesian4)) { + return entryType.fromCartesian4(value, result); + } else if (defined(entryType.clone)) { + return entryType.clone(value, result); + } + + return value.x; + }; + + var setEntryScratchValues = [undefined, undefined, new Cartesian2(), new Cartesian3(), new Cartesian4()]; + var setEntryScratchCartesian4 = new Cartesian4(); + + BatchTable.prototype.setEntry = function(instanceIndex, attributeIndex, value) { + //>>includeStart('debug', pragmas.debug); + if (instanceIndex < 0 || instanceIndex >= this._numberOfInstances) { + throw new DeveloperError('instanceIndex is out of range.'); + } + if (attributeIndex < 0 || attributeIndex >= this._attributes.length) { + throw new DeveloperError('attributeIndex is out of range'); + } + //>>includeEnd('debug'); + + var attributes = this._attributes; + var result = setEntryScratchValues[attributes[attributeIndex].componentsPerAttribute]; + var currentEntry = this.getEntry(instanceIndex, attributeIndex, result); + var entryType = getEntryType(this._attributes, attributeIndex); + var entriesEqual = defined(entryType.equals) ? entryType.equals(currentEntry, value) : currentEntry === value; + if (entriesEqual) { + return; + } + + var entryValue = setEntryScratchCartesian4; + entryValue.x = defined(value.x) ? value.x : value; + entryValue.y = defined(value.y) ? value.y : 0.0; + entryValue.z = defined(value.z) ? value.z : 0.0; + entryValue.w = defined(value.w) ? value.w : 0.0; + + var index = 4 * attributes.length * instanceIndex + 4 * attributeIndex; + Cartesian4.pack(entryValue, this._batchValues, index); + + this._batchValuesDirty = true; + }; + + function createTexture(batchTable, context) { + var dimensions = batchTable._textureDimensions; + batchTable._texture = new Texture({ + context : context, + pixelFormat : PixelFormat.RGBA, + pixelDatatype : batchTable._pixelDatatype, + width : dimensions.x, + height : dimensions.y, + sampler : new Sampler({ + minificationFilter : TextureMinificationFilter.NEAREST, + magnificationFilter : TextureMagnificationFilter.NEAREST + }) + }); + } + + function updateTexture(batchTable) { + var dimensions = batchTable._textureDimensions; + batchTable._texture.copyFrom({ + width : dimensions.x, + height : dimensions.y, + arrayBufferView : batchTable._batchValues + }); + } + + BatchTable.prototype.update = function(frameState) { + var context = frameState.context; + if (this._pixelDatatype === PixelDatatype.FLOAT && !context.floatingPointTexture) { + // TODO: We could probably pack the floats to RGBA unsigned bytes but that would add a lot CPU and memory overhead. + throw new RuntimeError('The floating point texture extension is required but not supported.'); + } + + if (defined(this._texture) && !this._batchValuesDirty) { + return; + } + + this._batchValuesDirty = false; + + if (!defined(this._texture)) { + createTexture(this, context); + } + updateTexture(this); + }; + + BatchTable.prototype.getUniformMapCallback = function() { + var that = this; + return function(uniformMap) { + var batchUniformMap = { + batchTexture : function() { + return that._texture; + }, + batchTextureDimensions : function() { + return that._textureDimensions; + }, + batchTextureStep : function() { + return that._textureStep; + } + }; + + return combine(uniformMap, batchUniformMap); + }; + }; + + function getGlslComputeSt(batchTable) { + var numberOfAttributes = batchTable._attributes.length; + + // GLSL batchId is zero-based: [0, numberOfInstances - 1] + if (batchTable._textureDimensions.y === 1) { + return 'uniform vec4 batchTextureStep; \n' + + 'vec2 computeSt(float batchId) \n' + + '{ \n' + + ' float stepX = batchTextureStep.x; \n' + + ' float centerX = batchTextureStep.y; \n' + + ' float numberOfAttributes = float('+ numberOfAttributes + '); \n' + + ' return vec2(centerX + (batchId * numberOfAttributes * stepX), 0.5); \n' + + '} \n'; + } + + return 'uniform vec4 batchTextureStep; \n' + + 'uniform vec2 batchTextureDimensions; \n' + + 'vec2 computeSt(float batchId) \n' + + '{ \n' + + ' float stepX = batchTextureStep.x; \n' + + ' float centerX = batchTextureStep.y; \n' + + ' float stepY = batchTextureStep.z; \n' + + ' float centerY = batchTextureStep.w; \n' + + ' float numberOfAttributes = float('+ numberOfAttributes + '); \n' + + ' float xId = mod(batchId * numberOfAttributes, batchTextureDimensions.x); \n' + + ' float yId = floor(batchId * numberOfAttributes / batchTextureDimensions.x); \n' + + ' return vec2(centerX + (xId * stepX), 1.0 - (centerY + (yId * stepY))); \n' + + '} \n'; + } + + function getComponentType(componentsPerAttribute) { + if (componentsPerAttribute === 1) { + return 'float'; + } + return 'vec' + componentsPerAttribute; + } + + function getComponentSwizzle(componentsPerAttribute) { + if (componentsPerAttribute === 1) { + return '.x'; + } else if (componentsPerAttribute === 2) { + return '.xy'; + } else if (componentsPerAttribute === 3) { + return '.xyz'; + } + return ''; + } + + function getGlslAttributeFunction(batchTable, attributeIndex) { + var attributes = batchTable._attributes; + var attribute = attributes[attributeIndex]; + var componentsPerAttribute = attribute.componentsPerAttribute; + var functionName = attribute.functionName; + var functionReturnType = getComponentType(componentsPerAttribute); + var functionReturnValue = getComponentSwizzle(componentsPerAttribute); + + return functionReturnType + ' ' + functionName + '(float batchId) \n' + + '{ \n' + + ' vec2 st = computeSt(batchId); \n' + + ' st.x += batchTextureStep.x * float(' + attributeIndex + '); \n' + + ' vec4 value = texture2D(batchTexture, st); \n' + + ' return value' + functionReturnValue + '; \n' + + '} \n'; + } + + BatchTable.prototype.getVertexShaderCallback = function() { + var batchTableShader = 'uniform sampler2D batchTexture; \n'; + batchTableShader += getGlslComputeSt(this) + '\n'; + + var attributes = this._attributes; + var length = attributes.length; + for (var i = 0; i < length; ++i) { + batchTableShader += getGlslAttributeFunction(this, i); + } + + return function(source) { + var mainIndex = source.indexOf('void main'); + var beforeMain = source.substring(0, mainIndex); + var afterMain = source.substring(mainIndex); + return beforeMain + '\n' + batchTableShader + '\n' + afterMain; + }; + }; + + BatchTable.prototype.isDestroyed = function() { + return false; + }; + + BatchTable.prototype.destroy = function() { + this._texture = this._texture && this._texture.destroy(); + return destroyObject(this); + }; + + return BatchTable; +}); \ No newline at end of file diff --git a/Source/Scene/Polyline.js b/Source/Scene/Polyline.js index 7e2032296b99..3e9e747429a2 100644 --- a/Source/Scene/Polyline.js +++ b/Source/Scene/Polyline.js @@ -93,9 +93,9 @@ define([ this._boundingVolume2D = new BoundingSphere(); // modified in PolylineCollection } - var SHOW_INDEX = Polyline.SHOW_INDEX = 0; - var WIDTH_INDEX = Polyline.WIDTH_INDEX = 1; - var POSITION_INDEX = Polyline.POSITION_INDEX = 2; + var POSITION_INDEX = Polyline.POSITION_INDEX = 0; + var SHOW_INDEX = Polyline.SHOW_INDEX = 1; + var WIDTH_INDEX = Polyline.WIDTH_INDEX = 2; var MATERIAL_INDEX = Polyline.MATERIAL_INDEX = 3; var POSITION_SIZE_INDEX = Polyline.POSITION_SIZE_INDEX = 4; var NUMBER_OF_PROPERTIES = Polyline.NUMBER_OF_PROPERTIES = 5; diff --git a/Source/Scene/PolylineCollection.js b/Source/Scene/PolylineCollection.js index b6efa5504bbc..42fcca12ce0d 100644 --- a/Source/Scene/PolylineCollection.js +++ b/Source/Scene/PolylineCollection.js @@ -1,6 +1,7 @@ /*global define*/ define([ '../Core/BoundingSphere', + '../Core/Cartesian2', '../Core/Cartesian3', '../Core/Cartesian4', '../Core/Cartographic', @@ -27,6 +28,7 @@ define([ '../Shaders/PolylineCommon', '../Shaders/PolylineFS', '../Shaders/PolylineVS', + './BatchTable', './BlendingState', './Material', './Pass', @@ -34,6 +36,7 @@ define([ './SceneMode' ], function( BoundingSphere, + Cartesian2, Cartesian3, Cartesian4, Cartographic, @@ -60,6 +63,7 @@ define([ PolylineCommon, PolylineFS, PolylineVS, + BatchTable, BlendingState, Material, Pass, @@ -77,7 +81,7 @@ define([ var NUMBER_OF_PROPERTIES = Polyline.NUMBER_OF_PROPERTIES; var attributeLocations = { - texCoordExpandWidthAndShow : 0, + texCoordAndExpand : 0, position3DHigh : 1, position3DLow : 2, position2DHigh : 3, @@ -90,7 +94,7 @@ define([ nextPosition3DLow : 10, nextPosition2DHigh : 11, nextPosition2DLow : 12, - pickColor : 13 + batchTableIndex : 13 }; /** @@ -184,11 +188,7 @@ define([ this._polylineBuckets = {}; // The buffer usage for each attribute is determined based on the usage of the attribute over time. - this._buffersUsage = [ - {bufferUsage: BufferUsage.STATIC_DRAW, frameCount:0}, // SHOW_INDEX - {bufferUsage: BufferUsage.STATIC_DRAW, frameCount:0}, // WIDTH_INDEX - {bufferUsage: BufferUsage.STATIC_DRAW, frameCount:0} // POSITION_INDEX - ]; + this._buffersUsage = [{bufferUsage: BufferUsage.STATIC_DRAW, frameCount:0}]; // POSITION_INDEX this._mode = undefined; @@ -197,6 +197,9 @@ define([ this._positionBuffer = undefined; this._pickColorBuffer = undefined; this._texCoordExpandWidthAndShowBuffer = undefined; + + this._batchTable = undefined; + this._createBatchTable = false; } defineProperties(PolylineCollection.prototype, { @@ -248,6 +251,7 @@ define([ p._index = this._polylines.length; this._polylines.push(p); this._createVertexArray = true; + this._createBatchTable = true; return p; }; @@ -280,6 +284,7 @@ define([ this._polylines[polyline._index] = undefined; // Removed later this._polylinesRemoved = true; this._createVertexArray = true; + this._createBatchTable = true; if (defined(polyline._bucket)) { var bucket = polyline._bucket; bucket.shaderProgram = bucket.shaderProgram && bucket.shaderProgram.destroy(); @@ -369,6 +374,25 @@ define([ return this._polylines[index]; }; + function createBatchTable(collection, context) { + if (defined(collection._batchTable)) { + collection._batchTable.destroy(); + } + + var attributes = [{ + functionName : 'batchTable_getWidthAndShow', + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + componentsPerAttribute : 2 + }, { + functionName : 'batchTable_getPickColor', + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + componentsPerAttribute : 4, + normalize : true + }]; + + collection._batchTable = new BatchTable(attributes, collection._polylines.length); + } + /** * @private */ @@ -386,6 +410,11 @@ define([ var polyline; var properties = this._propertiesChanged; + if (this._createBatchTable) { + createBatchTable(this, context); + this._createBatchTable = false; + } + if (this._createVertexArray || computeNewBuffersUsage(this)) { createVertexArrays(this, context, projection); } else if (this._polylinesUpdated) { @@ -461,6 +490,8 @@ define([ }); } + this._batchTable.update(frameState); + if (pass.render) { var colorList = this._colorCommands; createCommandLists(this, frameState, colorList, modelMatrix, true); @@ -486,6 +517,9 @@ define([ var vertexArrays = polylineCollection._vertexArrays; var debugShowBoundingVolume = polylineCollection.debugShowBoundingVolume; + var batchTable = polylineCollection._batchTable; + var uniformCallback = batchTable.getUniformMapCallback(); + var length = vertexArrays.length; for ( var m = 0; m < length; ++m) { var va = vertexArrays[m]; @@ -531,7 +565,7 @@ define([ command.pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE; command.debugShowBoundingVolume = renderPass ? debugShowBoundingVolume : false; - command.uniformMap = currentMaterial._uniforms; + command.uniformMap = uniformCallback(currentMaterial._uniforms); command.count = count; command.offset = offset; @@ -598,7 +632,7 @@ define([ command.pass = currentMaterial.isTranslucent() ? Pass.TRANSLUCENT : Pass.OPAQUE; command.debugShowBoundingVolume = renderPass ? debugShowBoundingVolume : false; - command.uniformMap = currentMaterial._uniforms; + command.uniformMap = uniformCallback(currentMaterial._uniforms); command.count = count; command.offset = offset; @@ -654,6 +688,8 @@ define([ }; function computeNewBuffersUsage(collection) { + return false; + var buffersUsage = collection._buffersUsage; var usageChanged = false; @@ -695,6 +731,8 @@ define([ var totalIndices = [[]]; var indices = totalIndices[0]; + var batchTable = collection._batchTable; + //used to determine the vertexBuffer offset if the indicesArray goes over 64k. //if it's the same polyline while it goes over 64k, the offset needs to backtrack componentsPerAttribute * componentDatatype bytes //so that the polyline looks contiguous. @@ -709,7 +747,7 @@ define([ for (x in polylineBuckets) { if (polylineBuckets.hasOwnProperty(x)) { bucket = polylineBuckets[x]; - bucket.updateShader(context); + bucket.updateShader(context, batchTable); totalLength += bucket.lengthOfPositions; } } @@ -718,17 +756,18 @@ define([ var mode = collection._mode; var positionArray = new Float32Array(6 * totalLength * 3); - var pickColorArray = new Uint8Array(totalLength * 4); - var texCoordExpandWidthAndShowArray = new Float32Array(totalLength * 4); + var texCoordAndExpandArray = new Float32Array(totalLength * 3); + var batchTableIndexArray = new Float32Array(totalLength); var position3DArray; var positionIndex = 0; var colorIndex = 0; - var texCoordExpandWidthAndShowIndex = 0; + var texCoordAndExpandIndex = 0; + var batchTableIndex = 0; for (x in polylineBuckets) { if (polylineBuckets.hasOwnProperty(x)) { bucket = polylineBuckets[x]; - bucket.write(positionArray, pickColorArray, texCoordExpandWidthAndShowArray, positionIndex, colorIndex, texCoordExpandWidthAndShowIndex, context, projection); + bucket.write(positionArray, texCoordAndExpandArray, batchTableIndexArray, positionIndex, colorIndex, texCoordAndExpandIndex, batchTableIndex, batchTable, context, projection); if (mode === SceneMode.MORPHING) { if (!defined(position3DArray)) { @@ -740,15 +779,15 @@ define([ var bucketLength = bucket.lengthOfPositions; positionIndex += 6 * bucketLength * 3; colorIndex += bucketLength * 4; - texCoordExpandWidthAndShowIndex += bucketLength * 4; + texCoordAndExpandIndex += bucketLength * 3; + batchTableIndex += bucketLength; offset = bucket.updateIndices(totalIndices, vertexBufferOffset, vertexArrayBuckets, offset); } } var positionBufferUsage = collection._buffersUsage[POSITION_INDEX].bufferUsage; - var showBufferUsage = collection._buffersUsage[SHOW_INDEX].bufferUsage; - var widthBufferUsage = collection._buffersUsage[WIDTH_INDEX].bufferUsage; - var texCoordExpandWidthAndShowBufferUsage = (showBufferUsage === BufferUsage.STREAM_DRAW || widthBufferUsage === BufferUsage.STREAM_DRAW) ? BufferUsage.STREAM_DRAW : BufferUsage.STATIC_DRAW; + var texCoordAndExpandBufferUsage = BufferUsage.STATIC_DRAW; + var batchTableIndexBufferUsage = BufferUsage.STATIC_DRAW; collection._positionBuffer = Buffer.createVertexBuffer({ context : context, @@ -763,20 +802,20 @@ define([ usage : positionBufferUsage }); } - collection._pickColorBuffer = Buffer.createVertexBuffer({ + collection._texCoordAndExpandBuffer = Buffer.createVertexBuffer({ context : context, - typedArray : pickColorArray, - usage : BufferUsage.STATIC_DRAW + typedArray : texCoordAndExpandArray, + usage : texCoordAndExpandBufferUsage }); - collection._texCoordExpandWidthAndShowBuffer = Buffer.createVertexBuffer({ + collection._batchTableIndexBuffer = Buffer.createVertexBuffer({ context : context, - typedArray : texCoordExpandWidthAndShowArray, - usage : texCoordExpandWidthAndShowBufferUsage + typedArray : batchTableIndexArray, + usage : batchTableIndexBufferUsage }); - var pickColorSizeInBytes = 4 * Uint8Array.BYTES_PER_ELEMENT; var positionSizeInBytes = 3 * Float32Array.BYTES_PER_ELEMENT; - var texCoordExpandWidthAndShowSizeInBytes = 4 * Float32Array.BYTES_PER_ELEMENT; + var texCoordAndExpandSizeInBytes = 3 * Float32Array.BYTES_PER_ELEMENT; + var batchTableIndexSizeInBytes = 3 * Float32Array.BYTES_PER_ELEMENT; var vbo = 0; var numberOfIndicesArrays = totalIndices.length; @@ -800,8 +839,8 @@ define([ var prevPositionLowOffset = positionSizeInBytes + prevPositionHighOffset; var nextPositionHighOffset = positionSizeInBytes + prevPositionLowOffset; var nextPositionLowOffset = positionSizeInBytes + nextPositionHighOffset; - var vertexPickColorBufferOffset = k * (pickColorSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) - vbo * pickColorSizeInBytes; - var vertexTexCoordExpandWidthAndShowBufferOffset = k * (texCoordExpandWidthAndShowSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) - vbo * texCoordExpandWidthAndShowSizeInBytes; + var vertexTexCoordAndExpandBufferOffset = k * (texCoordAndExpandSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) - vbo * texCoordAndExpandSizeInBytes; + var vertexBatchTableIndexBufferOffset = k * (batchTableIndexSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) - vbo * batchTableIndexSizeInBytes; var attributes = [{ index : attributeLocations.position3DHigh, @@ -876,18 +915,17 @@ define([ offsetInBytes : nextPositionLowOffset, strideInBytes : 6 * positionSizeInBytes }, { - index : attributeLocations.texCoordExpandWidthAndShow, - componentsPerAttribute : 4, + index : attributeLocations.texCoordAndExpand, + componentsPerAttribute : 3, componentDatatype : ComponentDatatype.FLOAT, - vertexBuffer : collection._texCoordExpandWidthAndShowBuffer, - offsetInBytes : vertexTexCoordExpandWidthAndShowBufferOffset + vertexBuffer : collection._texCoordAndExpandBuffer, + offsetInBytes : vertexTexCoordAndExpandBufferOffset }, { - index : attributeLocations.pickColor, - componentsPerAttribute : 4, - componentDatatype : ComponentDatatype.UNSIGNED_BYTE, - vertexBuffer : collection._pickColorBuffer, - offsetInBytes : vertexPickColorBufferOffset, - normalize : true + index : attributeLocations.batchTableIndex, + componentsPerAttribute : 1, + componentDatatype : ComponentDatatype.FLOAT, + vertexBuffer : collection._batchTableIndexBuffer, + offsetInBytes : vertexBatchTableIndexBufferOffset }]; var buffer3D; @@ -1058,6 +1096,7 @@ define([ this.mode = mode; this.modelMatrix = modelMatrix; } + PolylineBucket.prototype.addPolyline = function(p) { var polylines = this.polylines; polylines.push(p); @@ -1066,13 +1105,14 @@ define([ p._bucket = this; }; - PolylineBucket.prototype.updateShader = function(context) { + PolylineBucket.prototype.updateShader = function(context, batchTable) { if (defined(this.shaderProgram)) { return; } + var vsSource = batchTable.getVertexShaderCallback()(PolylineVS); var vs = new ShaderSource({ - sources : [PolylineCommon, PolylineVS] + sources : [PolylineCommon, vsSource] }); var fs = new ShaderSource({ sources : [this.material.shaderSource, PolylineFS] @@ -1124,7 +1164,7 @@ define([ var scratchWriteNextPosition = new Cartesian3(); var scratchWriteVector = new Cartesian3(); - PolylineBucket.prototype.write = function(positionArray, pickColorArray, texCoordExpandWidthAndShowArray, positionIndex, colorIndex, texCoordExpandWidthAndShowIndex, context, projection) { + PolylineBucket.prototype.write = function(positionArray, texCoordAndExpand, batchTableIndexArray, positionIndex, colorIndex, texCoordAndExpandIndex, batchTableIndex, batchTable, context, projection) { var mode = this.mode; var maxLon = projection.ellipsoid.maximumRadius * CesiumMath.PI; @@ -1134,6 +1174,7 @@ define([ var polyline = polylines[i]; var width = polyline.width; var show = polyline.show && width > 0.0; + var polylineBatchIndex = polyline._index; var segments = this.getSegments(polyline, projection); var positions = segments.positions; var lengths = segments.lengths; @@ -1212,22 +1253,27 @@ define([ EncodedCartesian3.writeElements(scratchWritePrevPosition, positionArray, positionIndex + 6); EncodedCartesian3.writeElements(scratchWriteNextPosition, positionArray, positionIndex + 12); - pickColorArray[colorIndex] = Color.floatToByte(pickColor.red); - pickColorArray[colorIndex + 1] = Color.floatToByte(pickColor.green); - pickColorArray[colorIndex + 2] = Color.floatToByte(pickColor.blue); - pickColorArray[colorIndex + 3] = Color.floatToByte(pickColor.alpha); - var direction = (k - 2 < 0) ? -1.0 : 1.0; - texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex] = j / (positionsLength - 1); // s tex coord - texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex + 1] = 2 * (k % 2) - 1; // expand direction - texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex + 2] = direction * width; - texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex + 3] = show; + texCoordAndExpand[texCoordAndExpandIndex] = j / (positionsLength - 1); // s tex coord + texCoordAndExpand[texCoordAndExpandIndex + 1] = 2 * (k % 2) - 1; // expand direction + texCoordAndExpand[texCoordAndExpandIndex + 2] = direction; + + batchTableIndexArray[batchTableIndex++] = polylineBatchIndex; positionIndex += 6 * 3; - colorIndex += 4; - texCoordExpandWidthAndShowIndex += 4; + texCoordAndExpandIndex += 3; } } + + // TODO: add support for color from the batch table + var colorCartesian = new Cartesian4(); + colorCartesian.x = Color.floatToByte(pickColor.red); + colorCartesian.y = Color.floatToByte(pickColor.green); + colorCartesian.z = Color.floatToByte(pickColor.blue); + colorCartesian.w = Color.floatToByte(pickColor.alpha); + + batchTable.setEntry(polylineBatchIndex, 0, new Cartesian2(width, show ? 1.0 : 0.0)); + batchTable.setEntry(polylineBatchIndex, 1, colorCartesian); } }; diff --git a/Source/Shaders/PolylineVS.glsl b/Source/Shaders/PolylineVS.glsl index 50c6b9d2e8e3..2aa1d268ece8 100644 --- a/Source/Shaders/PolylineVS.glsl +++ b/Source/Shaders/PolylineVS.glsl @@ -10,8 +10,8 @@ attribute vec3 nextPosition3DHigh; attribute vec3 nextPosition3DLow; attribute vec3 nextPosition2DHigh; attribute vec3 nextPosition2DLow; -attribute vec4 texCoordExpandWidthAndShow; -attribute vec4 pickColor; +attribute vec4 texCoordAndExpand; +attribute float batchTableIndex; varying vec2 v_st; varying float v_width; @@ -19,11 +19,15 @@ varying vec4 czm_pickColor; void main() { - float texCoord = texCoordExpandWidthAndShow.x; - float expandDir = texCoordExpandWidthAndShow.y; - float width = abs(texCoordExpandWidthAndShow.z) + 0.5; - bool usePrev = texCoordExpandWidthAndShow.z < 0.0; - float show = texCoordExpandWidthAndShow.w; + float texCoord = texCoordAndExpand.x; + float expandDir = texCoordAndExpand.y; + bool usePrev = texCoordAndExpand.z < 0.0; + + vec2 widthAndShow = batchTable_getWidthAndShow(batchTableIndex); + float width = widthAndShow.x * 255.0; + float show = widthAndShow.y * 255.0; + + vec4 pickColor = batchTable_getPickColor(batchTableIndex); vec4 p, prev, next; if (czm_morphTime == 1.0) From 74f4417ec3f80c04dba8f4956242a9f8263677bb Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 16 Sep 2016 16:16:29 -0400 Subject: [PATCH 02/12] Add normalize option for unsigned byte data. --- Source/Scene/BatchTable.js | 23 ++++++++++++++++------- Source/Shaders/PolylineVS.glsl | 4 ++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Source/Scene/BatchTable.js b/Source/Scene/BatchTable.js index f402665a4473..ed9ab728b1d8 100644 --- a/Source/Scene/BatchTable.js +++ b/Source/Scene/BatchTable.js @@ -273,13 +273,22 @@ define([ var functionReturnType = getComponentType(componentsPerAttribute); var functionReturnValue = getComponentSwizzle(componentsPerAttribute); - return functionReturnType + ' ' + functionName + '(float batchId) \n' + - '{ \n' + - ' vec2 st = computeSt(batchId); \n' + - ' st.x += batchTextureStep.x * float(' + attributeIndex + '); \n' + - ' vec4 value = texture2D(batchTexture, st); \n' + - ' return value' + functionReturnValue + '; \n' + - '} \n'; + var glslFunction = + functionReturnType + ' ' + functionName + '(float batchId) \n' + + '{ \n' + + ' vec2 st = computeSt(batchId); \n' + + ' st.x += batchTextureStep.x * float(' + attributeIndex + '); \n' + + ' vec4 textureValue = texture2D(batchTexture, st); \n' + + ' ' + functionReturnType + ' value = textureValue' + functionReturnValue + '; \n'; + + if (batchTable._pixelDatatype === PixelDatatype.UNSIGNED_BYTE && !attribute.normalize) { + glslFunction += 'value *= 255.0; \n'; + } + + glslFunction += + ' return value; \n' + + '} \n'; + return glslFunction; } BatchTable.prototype.getVertexShaderCallback = function() { diff --git a/Source/Shaders/PolylineVS.glsl b/Source/Shaders/PolylineVS.glsl index 2aa1d268ece8..18b3749e6dc0 100644 --- a/Source/Shaders/PolylineVS.glsl +++ b/Source/Shaders/PolylineVS.glsl @@ -24,8 +24,8 @@ void main() bool usePrev = texCoordAndExpand.z < 0.0; vec2 widthAndShow = batchTable_getWidthAndShow(batchTableIndex); - float width = widthAndShow.x * 255.0; - float show = widthAndShow.y * 255.0; + float width = widthAndShow.x; + float show = widthAndShow.y; vec4 pickColor = batchTable_getPickColor(batchTableIndex); From 17186638a32a8c87ec0d3c6eaf34294264785d63 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 16 Sep 2016 16:54:13 -0400 Subject: [PATCH 03/12] Properly update changed polyline width of show properties. Fix buffer usage changed code. --- Source/Scene/PolylineCollection.js | 88 ++++++++++++------------------ 1 file changed, 34 insertions(+), 54 deletions(-) diff --git a/Source/Scene/PolylineCollection.js b/Source/Scene/PolylineCollection.js index 42fcca12ce0d..85d63d754304 100644 --- a/Source/Scene/PolylineCollection.js +++ b/Source/Scene/PolylineCollection.js @@ -187,16 +187,16 @@ define([ this._polylines = []; this._polylineBuckets = {}; - // The buffer usage for each attribute is determined based on the usage of the attribute over time. - this._buffersUsage = [{bufferUsage: BufferUsage.STATIC_DRAW, frameCount:0}]; // POSITION_INDEX + // The buffer usage is determined based on the usage of the attribute over time. + this._positionBufferUsage = { bufferUsage : BufferUsage.STATIC_DRAW, frameCount : 0 }; this._mode = undefined; this._polylinesToUpdate = []; this._vertexArrays = []; this._positionBuffer = undefined; - this._pickColorBuffer = undefined; - this._texCoordExpandWidthAndShowBuffer = undefined; + this._texCoordAndExpandBuffer = undefined; + this._batchTableIndexBuffer = undefined; this._batchTable = undefined; this._createBatchTable = false; @@ -374,7 +374,7 @@ define([ return this._polylines[index]; }; - function createBatchTable(collection, context) { + function createBatchTable(collection) { if (defined(collection._batchTable)) { collection._batchTable.destroy(); } @@ -396,7 +396,7 @@ define([ /** * @private */ - PolylineCollection.prototype.update = function(frameState, commandList) { + PolylineCollection.prototype.update = function(frameState) { removePolylines(this); if (this._polylines.length === 0) { @@ -429,7 +429,7 @@ define([ } // if a polyline's positions size changes, we need to recreate the vertex arrays and vertex buffers because the indices will be different. - // if a polyline's material changes, we need to recreate the VAOs and VBOs because they will be batched differenty. + // if a polyline's material changes, we need to recreate the VAOs and VBOs because they will be batched differently. if (properties[POSITION_SIZE_INDEX] || properties[MATERIAL_INDEX]) { createVertexArrays(this, context, projection); } else { @@ -440,17 +440,22 @@ define([ properties = polyline._propertiesChanged; var bucket = polyline._bucket; var index = 0; - for ( var x in polylineBuckets) { + for (var x in polylineBuckets) { if (polylineBuckets.hasOwnProperty(x)) { if (polylineBuckets[x] === bucket) { - if (properties[POSITION_INDEX] || properties[SHOW_INDEX] || properties[WIDTH_INDEX]) { - bucket.writeUpdate(index, polyline, this._positionBuffer, this._texCoordExpandWidthAndShowBuffer, projection); + if (properties[POSITION_INDEX]) { + bucket.writeUpdate(index, polyline, this._positionBuffer, projection); } break; } index += polylineBuckets[x].lengthOfPositions; } } + + if (properties[SHOW_INDEX] || properties[WIDTH_INDEX]) { + this._batchTable.setEntry(polyline._index, 0, new Cartesian2(polyline._width, polyline._show)); + } + polyline._clean(); } } @@ -688,34 +693,28 @@ define([ }; function computeNewBuffersUsage(collection) { - return false; - - var buffersUsage = collection._buffersUsage; var usageChanged = false; - var properties = collection._propertiesChanged; - //subtract 2 from NUMBER_OF_PROPERTIES because we don't care about POSITION_SIZE_INDEX or MATERIAL_INDEX property change. - for ( var k = 0; k < NUMBER_OF_PROPERTIES - 2; ++k) { - var bufferUsage = buffersUsage[k]; - if (properties[k]) { - if (bufferUsage.bufferUsage !== BufferUsage.STREAM_DRAW) { + var bufferUsage = collection._positionBufferUsage; + if (properties[POSITION_INDEX]) { + if (bufferUsage.bufferUsage !== BufferUsage.STREAM_DRAW) { + usageChanged = true; + bufferUsage.bufferUsage = BufferUsage.STREAM_DRAW; + bufferUsage.frameCount = 100; + } else { + bufferUsage.frameCount = 100; + } + } else { + if (bufferUsage.bufferUsage !== BufferUsage.STATIC_DRAW) { + if (bufferUsage.frameCount === 0) { usageChanged = true; - bufferUsage.bufferUsage = BufferUsage.STREAM_DRAW; - bufferUsage.frameCount = 100; + bufferUsage.bufferUsage = BufferUsage.STATIC_DRAW; } else { - bufferUsage.frameCount = 100; - } - } else { - if (bufferUsage.bufferUsage !== BufferUsage.STATIC_DRAW) { - if (bufferUsage.frameCount === 0) { - usageChanged = true; - bufferUsage.bufferUsage = BufferUsage.STATIC_DRAW; - } else { - bufferUsage.frameCount--; - } + bufferUsage.frameCount--; } } } + return usageChanged; } @@ -785,7 +784,7 @@ define([ } } - var positionBufferUsage = collection._buffersUsage[POSITION_INDEX].bufferUsage; + var positionBufferUsage = collection._positionBufferUsage.bufferUsage; var texCoordAndExpandBufferUsage = BufferUsage.STATIC_DRAW; var batchTableIndexBufferUsage = BufferUsage.STATIC_DRAW; @@ -1265,7 +1264,7 @@ define([ } } - // TODO: add support for color from the batch table + // TODO: add support for color from the batch table? var colorCartesian = new Cartesian4(); colorCartesian.x = Color.floatToByte(pickColor.red); colorCartesian.y = Color.floatToByte(pickColor.green); @@ -1500,9 +1499,8 @@ define([ }; var scratchPositionsArray; - var scratchTexCoordArray; - PolylineBucket.prototype.writeUpdate = function(index, polyline, positionBuffer, texCoordExpandWidthAndShowBuffer, projection) { + PolylineBucket.prototype.writeUpdate = function(index, polyline, positionBuffer, projection) { var mode = this.mode; var maxLon = projection.ellipsoid.maximumRadius * CesiumMath.PI; @@ -1511,32 +1509,23 @@ define([ index += this.getPolylineStartIndex(polyline); var positionArray = scratchPositionsArray; - var texCoordExpandWidthAndShowArray = scratchTexCoordArray; - var positionsArrayLength = 6 * positionsLength * 3; if (!defined(positionArray) || positionArray.length < positionsArrayLength) { positionArray = scratchPositionsArray = new Float32Array(positionsArrayLength); - texCoordExpandWidthAndShowArray = scratchTexCoordArray = new Float32Array(positionsLength * 4); } else if (positionArray.length > positionsArrayLength) { positionArray = new Float32Array(positionArray.buffer, 0, positionsArrayLength); - texCoordExpandWidthAndShowArray = new Float32Array(texCoordExpandWidthAndShowArray.buffer, 0, positionsLength * 4); } - var positionIndex = 0; - var texCoordExpandWidthAndShowIndex = 0; - var segments = this.getSegments(polyline, projection); var positions = segments.positions; var lengths = segments.lengths; + var positionIndex = 0; var segmentIndex = 0; var count = 0; var position; - var width = polyline.width; - var show = polyline.show && width > 0.0; - positionsLength = positions.length; for ( var i = 0; i < positionsLength; ++i) { if (i === 0) { @@ -1604,20 +1593,11 @@ define([ EncodedCartesian3.writeElements(scratchWritePosition, positionArray, positionIndex); EncodedCartesian3.writeElements(scratchWritePrevPosition, positionArray, positionIndex + 6); EncodedCartesian3.writeElements(scratchWriteNextPosition, positionArray, positionIndex + 12); - - var direction = (j - 2 < 0) ? -1.0 : 1.0; - texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex] = i / (positionsLength - 1); // s tex coord - texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex + 1] = 2 * (j % 2) - 1; // expand direction - texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex + 2] = direction * width; - texCoordExpandWidthAndShowArray[texCoordExpandWidthAndShowIndex + 3] = show; - positionIndex += 6 * 3; - texCoordExpandWidthAndShowIndex += 4; } } positionBuffer.copyFromArrayView(positionArray, 6 * 3 * Float32Array.BYTES_PER_ELEMENT * index); - texCoordExpandWidthAndShowBuffer.copyFromArrayView(texCoordExpandWidthAndShowArray, 4 * Float32Array.BYTES_PER_ELEMENT * index); } }; From 013409095da08fbccfd56c5a0f154f853a14186b Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 16 Sep 2016 17:11:21 -0400 Subject: [PATCH 04/12] Minor cleanup. --- Source/Scene/PolylineCollection.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Source/Scene/PolylineCollection.js b/Source/Scene/PolylineCollection.js index 85d63d754304..3b73500eaeb8 100644 --- a/Source/Scene/PolylineCollection.js +++ b/Source/Scene/PolylineCollection.js @@ -689,6 +689,7 @@ define([ destroyVertexArrays(this); releaseShaders(this); destroyPolylines(this); + this._batchTable = this._batchTable && this._batchTable.destroy(); return destroyObject(this); }; @@ -1162,6 +1163,8 @@ define([ var scratchWritePrevPosition = new Cartesian3(); var scratchWriteNextPosition = new Cartesian3(); var scratchWriteVector = new Cartesian3(); + var scratchPickColorCartesian = new Cartesian4(); + var scratchWidthShowCartesian = new Cartesian2(); PolylineBucket.prototype.write = function(positionArray, texCoordAndExpand, batchTableIndexArray, positionIndex, colorIndex, texCoordAndExpandIndex, batchTableIndex, batchTable, context, projection) { var mode = this.mode; @@ -1265,13 +1268,17 @@ define([ } // TODO: add support for color from the batch table? - var colorCartesian = new Cartesian4(); + var colorCartesian = scratchPickColorCartesian; colorCartesian.x = Color.floatToByte(pickColor.red); colorCartesian.y = Color.floatToByte(pickColor.green); colorCartesian.z = Color.floatToByte(pickColor.blue); colorCartesian.w = Color.floatToByte(pickColor.alpha); - batchTable.setEntry(polylineBatchIndex, 0, new Cartesian2(width, show ? 1.0 : 0.0)); + var widthShowCartesian = scratchWidthShowCartesian; + widthShowCartesian.x = width; + widthShowCartesian.y = show ? 1.0 : 0.0; + + batchTable.setEntry(polylineBatchIndex, 0, widthShowCartesian); batchTable.setEntry(polylineBatchIndex, 1, colorCartesian); } }; From 66abc5a4a5c683c958a4d5f45bb59cd81d4c0e9b Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 16 Sep 2016 17:26:29 -0400 Subject: [PATCH 05/12] Pack the batch index with the texture coordinates and expand direction attribute which brings polylines down to 13 vertex attributes. Fix failing test. --- Source/Scene/PolylineCollection.js | 66 +++++++++++------------------- Source/Shaders/PolylineVS.glsl | 10 ++--- 2 files changed, 28 insertions(+), 48 deletions(-) diff --git a/Source/Scene/PolylineCollection.js b/Source/Scene/PolylineCollection.js index 3b73500eaeb8..cca1e4d26566 100644 --- a/Source/Scene/PolylineCollection.js +++ b/Source/Scene/PolylineCollection.js @@ -81,7 +81,7 @@ define([ var NUMBER_OF_PROPERTIES = Polyline.NUMBER_OF_PROPERTIES; var attributeLocations = { - texCoordAndExpand : 0, + texCoordExpandAndBatchIndex : 0, position3DHigh : 1, position3DLow : 2, position2DHigh : 3, @@ -93,8 +93,7 @@ define([ nextPosition3DHigh : 9, nextPosition3DLow : 10, nextPosition2DHigh : 11, - nextPosition2DLow : 12, - batchTableIndex : 13 + nextPosition2DLow : 12 }; /** @@ -195,8 +194,7 @@ define([ this._polylinesToUpdate = []; this._vertexArrays = []; this._positionBuffer = undefined; - this._texCoordAndExpandBuffer = undefined; - this._batchTableIndexBuffer = undefined; + this._texCoordExpandAndBatchIndexBuffer = undefined; this._batchTable = undefined; this._createBatchTable = false; @@ -756,18 +754,16 @@ define([ var mode = collection._mode; var positionArray = new Float32Array(6 * totalLength * 3); - var texCoordAndExpandArray = new Float32Array(totalLength * 3); - var batchTableIndexArray = new Float32Array(totalLength); + var texCoordExpandAndBatchIndexArray = new Float32Array(totalLength * 4); var position3DArray; var positionIndex = 0; var colorIndex = 0; - var texCoordAndExpandIndex = 0; - var batchTableIndex = 0; + var texCoordExpandAndBatchIndexIndex = 0; for (x in polylineBuckets) { if (polylineBuckets.hasOwnProperty(x)) { bucket = polylineBuckets[x]; - bucket.write(positionArray, texCoordAndExpandArray, batchTableIndexArray, positionIndex, colorIndex, texCoordAndExpandIndex, batchTableIndex, batchTable, context, projection); + bucket.write(positionArray, texCoordExpandAndBatchIndexArray, positionIndex, colorIndex, texCoordExpandAndBatchIndexIndex, batchTable, context, projection); if (mode === SceneMode.MORPHING) { if (!defined(position3DArray)) { @@ -779,15 +775,13 @@ define([ var bucketLength = bucket.lengthOfPositions; positionIndex += 6 * bucketLength * 3; colorIndex += bucketLength * 4; - texCoordAndExpandIndex += bucketLength * 3; - batchTableIndex += bucketLength; + texCoordExpandAndBatchIndexIndex += bucketLength * 4; offset = bucket.updateIndices(totalIndices, vertexBufferOffset, vertexArrayBuckets, offset); } } var positionBufferUsage = collection._positionBufferUsage.bufferUsage; - var texCoordAndExpandBufferUsage = BufferUsage.STATIC_DRAW; - var batchTableIndexBufferUsage = BufferUsage.STATIC_DRAW; + var texCoordExpandAndBatchIndexBufferUsage = BufferUsage.STATIC_DRAW; collection._positionBuffer = Buffer.createVertexBuffer({ context : context, @@ -802,20 +796,14 @@ define([ usage : positionBufferUsage }); } - collection._texCoordAndExpandBuffer = Buffer.createVertexBuffer({ + collection._texCoordExpandAndBatchIndexBuffer = Buffer.createVertexBuffer({ context : context, - typedArray : texCoordAndExpandArray, - usage : texCoordAndExpandBufferUsage - }); - collection._batchTableIndexBuffer = Buffer.createVertexBuffer({ - context : context, - typedArray : batchTableIndexArray, - usage : batchTableIndexBufferUsage + typedArray : texCoordExpandAndBatchIndexArray, + usage : texCoordExpandAndBatchIndexBufferUsage }); var positionSizeInBytes = 3 * Float32Array.BYTES_PER_ELEMENT; - var texCoordAndExpandSizeInBytes = 3 * Float32Array.BYTES_PER_ELEMENT; - var batchTableIndexSizeInBytes = 3 * Float32Array.BYTES_PER_ELEMENT; + var texCoordExpandAndBatchIndexSizeInBytes = 4 * Float32Array.BYTES_PER_ELEMENT; var vbo = 0; var numberOfIndicesArrays = totalIndices.length; @@ -839,8 +827,7 @@ define([ var prevPositionLowOffset = positionSizeInBytes + prevPositionHighOffset; var nextPositionHighOffset = positionSizeInBytes + prevPositionLowOffset; var nextPositionLowOffset = positionSizeInBytes + nextPositionHighOffset; - var vertexTexCoordAndExpandBufferOffset = k * (texCoordAndExpandSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) - vbo * texCoordAndExpandSizeInBytes; - var vertexBatchTableIndexBufferOffset = k * (batchTableIndexSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) - vbo * batchTableIndexSizeInBytes; + var vertexTexCoordExpandAndBatchIndexBufferOffset = k * (texCoordExpandAndBatchIndexSizeInBytes * CesiumMath.SIXTY_FOUR_KILOBYTES) - vbo * texCoordExpandAndBatchIndexSizeInBytes; var attributes = [{ index : attributeLocations.position3DHigh, @@ -915,17 +902,11 @@ define([ offsetInBytes : nextPositionLowOffset, strideInBytes : 6 * positionSizeInBytes }, { - index : attributeLocations.texCoordAndExpand, - componentsPerAttribute : 3, - componentDatatype : ComponentDatatype.FLOAT, - vertexBuffer : collection._texCoordAndExpandBuffer, - offsetInBytes : vertexTexCoordAndExpandBufferOffset - }, { - index : attributeLocations.batchTableIndex, - componentsPerAttribute : 1, + index : attributeLocations.texCoordExpandAndBatchIndex, + componentsPerAttribute : 4, componentDatatype : ComponentDatatype.FLOAT, - vertexBuffer : collection._batchTableIndexBuffer, - offsetInBytes : vertexBatchTableIndexBufferOffset + vertexBuffer : collection._texCoordExpandAndBatchIndexBuffer, + offsetInBytes : vertexTexCoordExpandAndBatchIndexBufferOffset }]; var buffer3D; @@ -1166,7 +1147,7 @@ define([ var scratchPickColorCartesian = new Cartesian4(); var scratchWidthShowCartesian = new Cartesian2(); - PolylineBucket.prototype.write = function(positionArray, texCoordAndExpand, batchTableIndexArray, positionIndex, colorIndex, texCoordAndExpandIndex, batchTableIndex, batchTable, context, projection) { + PolylineBucket.prototype.write = function(positionArray, texCoordExpandAndBatchIndexArray, positionIndex, colorIndex, texCoordExpandAndBatchIndexIndex, batchTable, context, projection) { var mode = this.mode; var maxLon = projection.ellipsoid.maximumRadius * CesiumMath.PI; @@ -1256,14 +1237,13 @@ define([ EncodedCartesian3.writeElements(scratchWriteNextPosition, positionArray, positionIndex + 12); var direction = (k - 2 < 0) ? -1.0 : 1.0; - texCoordAndExpand[texCoordAndExpandIndex] = j / (positionsLength - 1); // s tex coord - texCoordAndExpand[texCoordAndExpandIndex + 1] = 2 * (k % 2) - 1; // expand direction - texCoordAndExpand[texCoordAndExpandIndex + 2] = direction; - - batchTableIndexArray[batchTableIndex++] = polylineBatchIndex; + texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex] = j / (positionsLength - 1); // s tex coord + texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex + 1] = 2 * (k % 2) - 1; // expand direction + texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex + 2] = direction; + texCoordExpandAndBatchIndexArray[texCoordExpandAndBatchIndexIndex + 3] = polylineBatchIndex; positionIndex += 6 * 3; - texCoordAndExpandIndex += 3; + texCoordExpandAndBatchIndexIndex += 4; } } diff --git a/Source/Shaders/PolylineVS.glsl b/Source/Shaders/PolylineVS.glsl index 18b3749e6dc0..67b0bfffb2da 100644 --- a/Source/Shaders/PolylineVS.glsl +++ b/Source/Shaders/PolylineVS.glsl @@ -10,8 +10,7 @@ attribute vec3 nextPosition3DHigh; attribute vec3 nextPosition3DLow; attribute vec3 nextPosition2DHigh; attribute vec3 nextPosition2DLow; -attribute vec4 texCoordAndExpand; -attribute float batchTableIndex; +attribute vec4 texCoordExpandAndBatchIndex; varying vec2 v_st; varying float v_width; @@ -19,9 +18,10 @@ varying vec4 czm_pickColor; void main() { - float texCoord = texCoordAndExpand.x; - float expandDir = texCoordAndExpand.y; - bool usePrev = texCoordAndExpand.z < 0.0; + float texCoord = texCoordExpandAndBatchIndex.x; + float expandDir = texCoordExpandAndBatchIndex.y; + bool usePrev = texCoordExpandAndBatchIndex.z < 0.0; + float batchTableIndex = texCoordExpandAndBatchIndex.w; vec2 widthAndShow = batchTable_getWidthAndShow(batchTableIndex); float width = widthAndShow.x; From ea6422cfbf35800c11cd1a54de9b4e5fcd08880f Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 16 Sep 2016 17:34:23 -0400 Subject: [PATCH 06/12] Fix width with pixel size 1. --- Source/Shaders/PolylineVS.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Shaders/PolylineVS.glsl b/Source/Shaders/PolylineVS.glsl index 67b0bfffb2da..06eaf8caf73f 100644 --- a/Source/Shaders/PolylineVS.glsl +++ b/Source/Shaders/PolylineVS.glsl @@ -24,7 +24,7 @@ void main() float batchTableIndex = texCoordExpandAndBatchIndex.w; vec2 widthAndShow = batchTable_getWidthAndShow(batchTableIndex); - float width = widthAndShow.x; + float width = widthAndShow.x + 0.5; float show = widthAndShow.y; vec4 pickColor = batchTable_getPickColor(batchTableIndex); From a6b81784e8f35232fee6dff8313e44b6a79289c3 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 19 Sep 2016 15:12:32 -0400 Subject: [PATCH 07/12] Add batch table tests. --- Source/Scene/BatchTable.js | 19 +++ Specs/Scene/BatchTableSpec.js | 211 ++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 Specs/Scene/BatchTableSpec.js diff --git a/Source/Scene/BatchTable.js b/Source/Scene/BatchTable.js index ed9ab728b1d8..fd5650bfd9f2 100644 --- a/Source/Scene/BatchTable.js +++ b/Source/Scene/BatchTable.js @@ -6,6 +6,7 @@ define([ '../Core/combine', '../Core/ComponentDatatype', '../Core/defined', + '../Core/defineProperties', '../Core/destroyObject', '../Core/DeveloperError', '../Core/PixelFormat', @@ -23,6 +24,7 @@ define([ combine, ComponentDatatype, defined, + defineProperties, destroyObject, DeveloperError, PixelFormat, @@ -72,6 +74,20 @@ define([ this._batchValuesDirty = false; } + defineProperties(BatchTable.prototype, { + attributes : { + get : function() { + return this._attributes; + } + }, + + numberOfInstances : { + get : function () { + return this._numberOfInstances; + } + } + }); + function getDatatype(attributes) { var foundFloatDatatype = false; var length = attributes.length; @@ -132,6 +148,9 @@ define([ if (attributeIndex < 0 || attributeIndex >= this._attributes.length) { throw new DeveloperError('attributeIndex is out of range'); } + if (!defined(value)) { + throw new DeveloperError('value is required.'); + } //>>includeEnd('debug'); var attributes = this._attributes; diff --git a/Specs/Scene/BatchTableSpec.js b/Specs/Scene/BatchTableSpec.js new file mode 100644 index 000000000000..e0c050fc8f52 --- /dev/null +++ b/Specs/Scene/BatchTableSpec.js @@ -0,0 +1,211 @@ +/*global defineSuite*/ +defineSuite([ + 'Scene/BatchTable', + 'Core/Cartesian4', + 'Core/ComponentDatatype', + 'Renderer/PixelDatatype', + 'Renderer/Texture', + 'Specs/createScene' +], function( + BatchTable, + Cartesian4, + ComponentDatatype, + PixelDatatype, + Texture, + createScene) { + 'use strict'; + + var unsignedByteAttributes = [{ + functionName : 'batchTable_getShow', + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + componentsPerAttribute : 1 + }, { + functionName : 'batchTable_getPickColor', + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + componentsPerAttribute : 4, + normalize : true + }]; + + var floatAttributes = [{ + functionName : 'batchTable_getShow', + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + componentsPerAttribute : 1 + }, { + functionName : 'batchTable_getCenter', + componentDatatype : ComponentDatatype.FLOAT, + componentsPerAttribute : 3 + }]; + + var batchTable; + var scene; + + beforeAll(function() { + scene = createScene(); + }); + + afterAll(function() { + scene.destroyForSpecs(); + }); + + afterEach(function() { + batchTable = batchTable && !batchTable.isDestroyed() && batchTable.destroy(); + }); + + it('constructor', function() { + batchTable = new BatchTable(unsignedByteAttributes, 2); + expect(batchTable.attributes).toBe(unsignedByteAttributes); + expect(batchTable.numberOfInstances).toEqual(2); + }); + + it('constructior throws without attributes', function() { + expect(function() { + batchTable = new BatchTable(undefined, 5); + }).toThrowDeveloperError(); + }); + + it('constructor throws without number of instances', function() { + expect(function() { + batchTable = new BatchTable(unsignedByteAttributes, undefined); + }).toThrowDeveloperError(); + }); + + it('sets and gets entries in the table', function() { + batchTable = new BatchTable(unsignedByteAttributes, 5); + + var i; + var color = new Cartesian4(0, 1, 2, 3); + + for (i = 0; i < batchTable.numberOfInstances; ++i) { + batchTable.setEntry(i, 0, 1); + batchTable.setEntry(i, 1, color); + } + + for (i = 0; i < batchTable.numberOfInstances; ++i) { + expect(batchTable.getEntry(3, 0)).toEqual(1); + expect(batchTable.getEntry(3, 1)).toEqual(color); + } + + color = new Cartesian4(4, 5, 6, 7); + batchTable.setEntry(3, 0, 0); + batchTable.setEntry(3, 1, color); + expect(batchTable.getEntry(3, 0)).toEqual(0); + expect(batchTable.getEntry(3, 1)).toEqual(color); + }); + + it('gets with result parameter', function() { + batchTable = new BatchTable(unsignedByteAttributes, 5); + var color = new Cartesian4(0, 1, 2, 3); + batchTable.setEntry(0, 1, color); + + var result = new Cartesian4(); + var returndValue = batchTable.getEntry(0, 1, result); + expect(returndValue).toBe(result); + expect(result).toEqual(color); + }); + + it('get entry throws when instance index is out of range', function() { + batchTable = new BatchTable(unsignedByteAttributes, 5); + expect(function() { + batchTable.getEntry(-1, 0); + }).toThrowDeveloperError(); + expect(function() { + batchTable.getEntry(100, 0); + }).toThrowDeveloperError(); + }); + + it('get entry throws when attribute index is out of range', function() { + batchTable = new BatchTable(unsignedByteAttributes, 5); + expect(function() { + batchTable.getEntry(0, -1); + }).toThrowDeveloperError(); + expect(function() { + batchTable.getEntry(0, 100); + }).toThrowDeveloperError(); + }); + + it('set entry throws when instance index is out of range', function() { + batchTable = new BatchTable(unsignedByteAttributes, 5); + expect(function() { + batchTable.setEntry(-1, 0, 0); + }).toThrowDeveloperError(); + expect(function() { + batchTable.setEntry(100, 0, 1); + }).toThrowDeveloperError(); + }); + + it('set entry throws when attribute index is out of range', function() { + batchTable = new BatchTable(unsignedByteAttributes, 5); + expect(function() { + batchTable.setEntry(0, -1, 1); + }).toThrowDeveloperError(); + expect(function() { + batchTable.setEntry(0, 100, 1); + }).toThrowDeveloperError(); + }); + + it('set entry throws when value is undefined', function() { + batchTable = new BatchTable(unsignedByteAttributes, 5); + expect(function() { + batchTable.setEntry(0, 0, undefined); + }).toThrowDeveloperError(); + }); + + it('creates a uniform callback with unsigned byte texture', function() { + batchTable = new BatchTable(unsignedByteAttributes, 5); + batchTable.update(scene.frameState); + + var uniforms = batchTable.getUniformMapCallback()({}); + expect(uniforms.batchTexture).toBeDefined(); + expect(uniforms.batchTexture()).toBeInstanceOf(Texture); + expect(uniforms.batchTexture().pixelDatatype).toEqual(PixelDatatype.UNSIGNED_BYTE); + expect(uniforms.batchTextureDimensions).toBeDefined(); + expect(uniforms.batchTextureDimensions().x).toBeGreaterThan(0); + expect(uniforms.batchTextureDimensions().y).toBeGreaterThan(0); + expect(uniforms.batchTextureStep).toBeDefined(); + expect(uniforms.batchTextureStep().x).toBeGreaterThan(0); + expect(uniforms.batchTextureStep().y).toBeGreaterThan(0); + expect(uniforms.batchTextureStep().z).toBeGreaterThan(0); + expect(uniforms.batchTextureStep().w).toBeGreaterThan(0); + }); + + it('creates a uniform callback with unsigned byte texture', function() { + batchTable = new BatchTable(floatAttributes, 5); + + if (scene.context.floatingPointTexture) { + batchTable.update(scene.frameState); + + var uniforms = batchTable.getUniformMapCallback()({}); + expect(uniforms.batchTexture).toBeDefined(); + expect(uniforms.batchTexture()).toBeInstanceOf(Texture); + expect(uniforms.batchTexture().pixelDatatype).toEqual(PixelDatatype.FLOAT); + expect(uniforms.batchTextureDimensions).toBeDefined(); + expect(uniforms.batchTextureDimensions().x).toBeGreaterThan(0); + expect(uniforms.batchTextureDimensions().y).toBeGreaterThan(0); + expect(uniforms.batchTextureStep).toBeDefined(); + expect(uniforms.batchTextureStep().x).toBeGreaterThan(0); + expect(uniforms.batchTextureStep().y).toBeGreaterThan(0); + expect(uniforms.batchTextureStep().z).toBeGreaterThan(0); + expect(uniforms.batchTextureStep().w).toBeGreaterThan(0); + } else { + expect(function() { + batchTable.update(scene.frameState); + }).toThrowRuntimeError(); + } + }); + + it('create shader functions', function() { + batchTable = new BatchTable(unsignedByteAttributes, 5); + + var shader = 'void main() { gl_Position = vec4(0.0); }'; + var modifiedShader = batchTable.getVertexShaderCallback()(shader); + expect(modifiedShader.indexOf(batchTable.attributes[0].functionName)).not.toEqual(-1); + expect(modifiedShader.indexOf(batchTable.attributes[1].functionName)).not.toEqual(-1); + }); + + it('isDestroyed', function() { + batchTable = new BatchTable(unsignedByteAttributes, 5); + expect(batchTable.isDestroyed()).toEqual(false); + batchTable.destroy(); + expect(batchTable.isDestroyed()).toEqual(true); + }); +}); \ No newline at end of file From 87b01fab6f98f04ab8f438d25fb01f60bc84753f Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 19 Sep 2016 15:46:38 -0400 Subject: [PATCH 08/12] Add doc. --- Source/Scene/BatchTable.js | 136 ++++++++++++++++++++++++++++++++++++- 1 file changed, 135 insertions(+), 1 deletion(-) diff --git a/Source/Scene/BatchTable.js b/Source/Scene/BatchTable.js index fd5650bfd9f2..a96459a5a4c8 100644 --- a/Source/Scene/BatchTable.js +++ b/Source/Scene/BatchTable.js @@ -37,6 +37,52 @@ define([ TextureMinificationFilter) { 'use strict'; + /** + * Creates a texture to look up per instance attributes for batched primitives. For example, store each primitive's pick color in the texture. + * + * @alias BatchTable + * @constructor + * @private + * + * @param {Object[]} attributes An array of objects describing a per instance attribute. Each object contains a datatype, components per attributes, whether it is normalized and a function name + * to retrieve the value in the vertex shader. + * @param {Number} numberOfInstances The number of instances in a batch table. + * + * @example + * // create the batch table + * var attributes = [{ + * functionName : 'getShow()', + * componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + * componentsPerAttribute : 1 + * }, { + * functionName : 'getPickColor', + * componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + * componentsPerAttribute : 4, + * normalize : true + * }]; + * var batchTable = new BatchTable(attributes, 5); + * + * // when creating the draw commands, update the uniform map and the vertex shader + * vertexShaderSource = batchTable.getVertexShaderCallback()(vertexShaderSource); + * var shaderProgram = ShaderProgram.fromCache({ + * // ... + * vertexShaderSource : vertexShaderSource, + * }); + * + * drawCommand.shaderProgram = shaderProgram; + * drawCommand.uniformMap = batchTable.getUniformMapCallback()(uniformMap); + * + * // use the attribute function names in the shader to retrieve the instance values + * // ... + * attribute float batchId; + * + * void main() { + * // ... + * float show = getShow(batchId); + * vec3 pickColor = getPickColor(batchId); + * // ... + * } + */ function BatchTable(attributes, numberOfInstances) { //>>includeStart('debug', pragmas.debug); if (!defined(attributes)) { @@ -75,12 +121,23 @@ define([ } defineProperties(BatchTable.prototype, { + /** + * The attribute descriptions. + * @memberOf BatchTable.prototype + * @type {Object[]} + * @readonly + */ attributes : { get : function() { return this._attributes; } }, - + /** + * The number of instances. + * @memberOf BatchTable.prototype + * @type {Number} + * @readonly + */ numberOfInstances : { get : function () { return this._numberOfInstances; @@ -113,6 +170,17 @@ define([ var scratchgetEntryCartesian4 = new Cartesian4(); + /** + * Gets the value of an entry in the table. + * + * @param {Number} instanceIndex The index of the instance. + * @param {Number} attributeIndex The index of the attribute. + * @param {undefined|Cartesian2|Cartesian3|Cartesian4} [result] The object onto which to store the result. The type is dependent on the attribute's number of components. + * @returns {Number|Cartesian2|Cartesian3|Cartesian4} The attribute value stored for the instance. + * + * @exception {DeveloperError} instanceIndex is out of range. + * @exception {DeveloperError} attributeIndex is out of range. + */ BatchTable.prototype.getEntry = function(instanceIndex, attributeIndex, result) { //>>includeStart('debug', pragmas.debug); if (instanceIndex < 0 || instanceIndex >= this._numberOfInstances) { @@ -140,6 +208,16 @@ define([ var setEntryScratchValues = [undefined, undefined, new Cartesian2(), new Cartesian3(), new Cartesian4()]; var setEntryScratchCartesian4 = new Cartesian4(); + /** + * Sets the value of an entry in the table. + * + * @param {Number} instanceIndex The index of the instance. + * @param {Number} attributeIndex The index of the attribute. + * @param {Number|Cartesian2|Cartesian3|Cartesian4} value The value to be stored in the table. The type of value will depend on the number of components of the attribute. + * + * @exception {DeveloperError} instanceIndex is out of range. + * @exception {DeveloperError} attributeIndex is out of range. + */ BatchTable.prototype.setEntry = function(instanceIndex, attributeIndex, value) { //>>includeStart('debug', pragmas.debug); if (instanceIndex < 0 || instanceIndex >= this._numberOfInstances) { @@ -198,6 +276,12 @@ define([ }); } + /** + * Creates/updates the batch table texture. + * @param {FrameState} frameState The frame state. + * + * @exception {RuntimeError} The floating point texture extension is required but not supported. + */ BatchTable.prototype.update = function(frameState) { var context = frameState.context; if (this._pixelDatatype === PixelDatatype.FLOAT && !context.floatingPointTexture) { @@ -217,6 +301,11 @@ define([ updateTexture(this); }; + /** + * Gets a function that will update a uniform map to contain values for looking up values in the batch table. + * + * @returns {BatchTable~updateUniformMapCallback} A callback for updating uniform maps. + */ BatchTable.prototype.getUniformMapCallback = function() { var that = this; return function(uniformMap) { @@ -310,6 +399,11 @@ define([ return glslFunction; } + /** + * Gets a function that will update a vertex shader to contain functions for looking up values in the batch table. + * + * @returns {BatchTable~updateVertexShaderSourceCallback} A callback for updating a vertex shader source. + */ BatchTable.prototype.getVertexShaderCallback = function() { var batchTableShader = 'uniform sampler2D batchTexture; \n'; batchTableShader += getGlslComputeSt(this) + '\n'; @@ -328,14 +422,54 @@ define([ }; }; + /** + * Returns true if this object was destroyed; otherwise, false. + *

+ * If this object was destroyed, it should not be used; calling any function other than + * isDestroyed will result in a {@link DeveloperError} exception. + * + * @returns {Boolean} true if this object was destroyed; otherwise, false. + * + * @see BatchTable#destroy + */ BatchTable.prototype.isDestroyed = function() { return false; }; + /** + * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic + * release of WebGL resources, instead of relying on the garbage collector to destroy this object. + *

+ * Once an object is destroyed, it should not be used; calling any function other than + * isDestroyed will result in a {@link DeveloperError} exception. Therefore, + * assign the return value (undefined) to the object as done in the example. + * + * @returns {undefined} + * + * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called. + * + * @see BatchTable#isDestroyed + */ BatchTable.prototype.destroy = function() { this._texture = this._texture && this._texture.destroy(); return destroyObject(this); }; + /** + * A callback for updating uniform maps. + * @callback BatchTable~updateUniformMapCallback + * + * @param {Object} uniformMap The uniform map. + * @returns {Object} The new uniform map with properties for retrieving values from the batch table. + */ + + /** + * A callback for updating a vertex shader source. + * @callback BatchTable~updateVertexShaderSourceCallback + * + * @param {String} vertexShaderSource The vertex shader source. + * @returns {String} The new vertex shader source with the functions for retrieving batch table values injected. + */ + return BatchTable; }); \ No newline at end of file From dc1966b11e8506641f4c01b543d277122042b612 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Mon, 19 Sep 2016 15:47:41 -0400 Subject: [PATCH 09/12] Tag tests as requiring WebGL. --- Specs/Scene/BatchTableSpec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Specs/Scene/BatchTableSpec.js b/Specs/Scene/BatchTableSpec.js index e0c050fc8f52..5d049282e280 100644 --- a/Specs/Scene/BatchTableSpec.js +++ b/Specs/Scene/BatchTableSpec.js @@ -208,4 +208,4 @@ defineSuite([ batchTable.destroy(); expect(batchTable.isDestroyed()).toEqual(true); }); -}); \ No newline at end of file +}, 'WebGL'); \ No newline at end of file From 93e6e2f9839fb9fba50d1c0a398b289b9e620cbe Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 20 Sep 2016 14:16:28 -0400 Subject: [PATCH 10/12] Rename get/setEntry to get/setBatchedAttribute. --- Source/Scene/BatchTable.js | 52 +++++++++++++++--------------- Source/Scene/PolylineCollection.js | 6 ++-- Specs/Scene/BatchTableSpec.js | 38 +++++++++++----------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/Source/Scene/BatchTable.js b/Source/Scene/BatchTable.js index a96459a5a4c8..0ee8ac58c74a 100644 --- a/Source/Scene/BatchTable.js +++ b/Source/Scene/BatchTable.js @@ -51,7 +51,7 @@ define([ * @example * // create the batch table * var attributes = [{ - * functionName : 'getShow()', + * functionName : 'getShow', * componentDatatype : ComponentDatatype.UNSIGNED_BYTE, * componentsPerAttribute : 1 * }, { @@ -156,7 +156,7 @@ define([ return foundFloatDatatype ? PixelDatatype.FLOAT : PixelDatatype.UNSIGNED_BYTE; } - function getEntryType(attributes, attributeIndex) { + function getAttributeType(attributes, attributeIndex) { var componentsPerAttribute = attributes[attributeIndex].componentsPerAttribute; if (componentsPerAttribute === 2) { return Cartesian2; @@ -168,10 +168,10 @@ define([ return Number; } - var scratchgetEntryCartesian4 = new Cartesian4(); + var scratchGetAttributeCartesian4 = new Cartesian4(); /** - * Gets the value of an entry in the table. + * Gets the value of an attribute in the table. * * @param {Number} instanceIndex The index of the instance. * @param {Number} attributeIndex The index of the attribute. @@ -181,7 +181,7 @@ define([ * @exception {DeveloperError} instanceIndex is out of range. * @exception {DeveloperError} attributeIndex is out of range. */ - BatchTable.prototype.getEntry = function(instanceIndex, attributeIndex, result) { + BatchTable.prototype.getBatchedAttribute = function(instanceIndex, attributeIndex, result) { //>>includeStart('debug', pragmas.debug); if (instanceIndex < 0 || instanceIndex >= this._numberOfInstances) { throw new DeveloperError('instanceIndex is out of range.'); @@ -193,23 +193,23 @@ define([ var attributes = this._attributes; var index = 4 * attributes.length * instanceIndex + 4 * attributeIndex; - var value = Cartesian4.unpack(this._batchValues, index, scratchgetEntryCartesian4); + var value = Cartesian4.unpack(this._batchValues, index, scratchGetAttributeCartesian4); - var entryType = getEntryType(attributes, attributeIndex); - if (defined(entryType.fromCartesian4)) { - return entryType.fromCartesian4(value, result); - } else if (defined(entryType.clone)) { - return entryType.clone(value, result); + var attributeType = getAttributeType(attributes, attributeIndex); + if (defined(attributeType.fromCartesian4)) { + return attributeType.fromCartesian4(value, result); + } else if (defined(attributeType.clone)) { + return attributeType.clone(value, result); } return value.x; }; - var setEntryScratchValues = [undefined, undefined, new Cartesian2(), new Cartesian3(), new Cartesian4()]; - var setEntryScratchCartesian4 = new Cartesian4(); + var setAttributeScratchValues = [undefined, undefined, new Cartesian2(), new Cartesian3(), new Cartesian4()]; + var setAttributeScratchCartesian4 = new Cartesian4(); /** - * Sets the value of an entry in the table. + * Sets the value of an attribute in the table. * * @param {Number} instanceIndex The index of the instance. * @param {Number} attributeIndex The index of the attribute. @@ -218,7 +218,7 @@ define([ * @exception {DeveloperError} instanceIndex is out of range. * @exception {DeveloperError} attributeIndex is out of range. */ - BatchTable.prototype.setEntry = function(instanceIndex, attributeIndex, value) { + BatchTable.prototype.setBatchedAttribute = function(instanceIndex, attributeIndex, value) { //>>includeStart('debug', pragmas.debug); if (instanceIndex < 0 || instanceIndex >= this._numberOfInstances) { throw new DeveloperError('instanceIndex is out of range.'); @@ -232,22 +232,22 @@ define([ //>>includeEnd('debug'); var attributes = this._attributes; - var result = setEntryScratchValues[attributes[attributeIndex].componentsPerAttribute]; - var currentEntry = this.getEntry(instanceIndex, attributeIndex, result); - var entryType = getEntryType(this._attributes, attributeIndex); - var entriesEqual = defined(entryType.equals) ? entryType.equals(currentEntry, value) : currentEntry === value; + var result = setAttributeScratchValues[attributes[attributeIndex].componentsPerAttribute]; + var currentAttribute = this.getBatchedAttribute(instanceIndex, attributeIndex, result); + var attributeType = getAttributeType(this._attributes, attributeIndex); + var entriesEqual = defined(attributeType.equals) ? attributeType.equals(currentAttribute, value) : currentAttribute === value; if (entriesEqual) { return; } - var entryValue = setEntryScratchCartesian4; - entryValue.x = defined(value.x) ? value.x : value; - entryValue.y = defined(value.y) ? value.y : 0.0; - entryValue.z = defined(value.z) ? value.z : 0.0; - entryValue.w = defined(value.w) ? value.w : 0.0; + var attributeValue = setAttributeScratchCartesian4; + attributeValue.x = defined(value.x) ? value.x : value; + attributeValue.y = defined(value.y) ? value.y : 0.0; + attributeValue.z = defined(value.z) ? value.z : 0.0; + attributeValue.w = defined(value.w) ? value.w : 0.0; var index = 4 * attributes.length * instanceIndex + 4 * attributeIndex; - Cartesian4.pack(entryValue, this._batchValues, index); + Cartesian4.pack(attributeValue, this._batchValues, index); this._batchValuesDirty = true; }; @@ -285,7 +285,7 @@ define([ BatchTable.prototype.update = function(frameState) { var context = frameState.context; if (this._pixelDatatype === PixelDatatype.FLOAT && !context.floatingPointTexture) { - // TODO: We could probably pack the floats to RGBA unsigned bytes but that would add a lot CPU and memory overhead. + // We could probably pack the floats to RGBA unsigned bytes but that would add a lot CPU and memory overhead. throw new RuntimeError('The floating point texture extension is required but not supported.'); } diff --git a/Source/Scene/PolylineCollection.js b/Source/Scene/PolylineCollection.js index cca1e4d26566..a254c9d55847 100644 --- a/Source/Scene/PolylineCollection.js +++ b/Source/Scene/PolylineCollection.js @@ -451,7 +451,7 @@ define([ } if (properties[SHOW_INDEX] || properties[WIDTH_INDEX]) { - this._batchTable.setEntry(polyline._index, 0, new Cartesian2(polyline._width, polyline._show)); + this._batchTable.setBatchedAttribute(polyline._index, 0, new Cartesian2(polyline._width, polyline._show)); } polyline._clean(); @@ -1258,8 +1258,8 @@ define([ widthShowCartesian.x = width; widthShowCartesian.y = show ? 1.0 : 0.0; - batchTable.setEntry(polylineBatchIndex, 0, widthShowCartesian); - batchTable.setEntry(polylineBatchIndex, 1, colorCartesian); + batchTable.setBatchedAttribute(polylineBatchIndex, 0, widthShowCartesian); + batchTable.setBatchedAttribute(polylineBatchIndex, 1, colorCartesian); } }; diff --git a/Specs/Scene/BatchTableSpec.js b/Specs/Scene/BatchTableSpec.js index 5d049282e280..5237321ebd81 100644 --- a/Specs/Scene/BatchTableSpec.js +++ b/Specs/Scene/BatchTableSpec.js @@ -76,29 +76,29 @@ defineSuite([ var color = new Cartesian4(0, 1, 2, 3); for (i = 0; i < batchTable.numberOfInstances; ++i) { - batchTable.setEntry(i, 0, 1); - batchTable.setEntry(i, 1, color); + batchTable.setBatchedAttribute(i, 0, 1); + batchTable.setBatchedAttribute(i, 1, color); } for (i = 0; i < batchTable.numberOfInstances; ++i) { - expect(batchTable.getEntry(3, 0)).toEqual(1); - expect(batchTable.getEntry(3, 1)).toEqual(color); + expect(batchTable.getBatchedAttribute(3, 0)).toEqual(1); + expect(batchTable.getBatchedAttribute(3, 1)).toEqual(color); } color = new Cartesian4(4, 5, 6, 7); - batchTable.setEntry(3, 0, 0); - batchTable.setEntry(3, 1, color); - expect(batchTable.getEntry(3, 0)).toEqual(0); - expect(batchTable.getEntry(3, 1)).toEqual(color); + batchTable.setBatchedAttribute(3, 0, 0); + batchTable.setBatchedAttribute(3, 1, color); + expect(batchTable.getBatchedAttribute(3, 0)).toEqual(0); + expect(batchTable.getBatchedAttribute(3, 1)).toEqual(color); }); it('gets with result parameter', function() { batchTable = new BatchTable(unsignedByteAttributes, 5); var color = new Cartesian4(0, 1, 2, 3); - batchTable.setEntry(0, 1, color); + batchTable.setBatchedAttribute(0, 1, color); var result = new Cartesian4(); - var returndValue = batchTable.getEntry(0, 1, result); + var returndValue = batchTable.getBatchedAttribute(0, 1, result); expect(returndValue).toBe(result); expect(result).toEqual(color); }); @@ -106,47 +106,47 @@ defineSuite([ it('get entry throws when instance index is out of range', function() { batchTable = new BatchTable(unsignedByteAttributes, 5); expect(function() { - batchTable.getEntry(-1, 0); + batchTable.getBatchedAttribute(-1, 0); }).toThrowDeveloperError(); expect(function() { - batchTable.getEntry(100, 0); + batchTable.getBatchedAttribute(100, 0); }).toThrowDeveloperError(); }); it('get entry throws when attribute index is out of range', function() { batchTable = new BatchTable(unsignedByteAttributes, 5); expect(function() { - batchTable.getEntry(0, -1); + batchTable.getBatchedAttribute(0, -1); }).toThrowDeveloperError(); expect(function() { - batchTable.getEntry(0, 100); + batchTable.getBatchedAttribute(0, 100); }).toThrowDeveloperError(); }); it('set entry throws when instance index is out of range', function() { batchTable = new BatchTable(unsignedByteAttributes, 5); expect(function() { - batchTable.setEntry(-1, 0, 0); + batchTable.setBatchedAttribute(-1, 0, 0); }).toThrowDeveloperError(); expect(function() { - batchTable.setEntry(100, 0, 1); + batchTable.setBatchedAttribute(100, 0, 1); }).toThrowDeveloperError(); }); it('set entry throws when attribute index is out of range', function() { batchTable = new BatchTable(unsignedByteAttributes, 5); expect(function() { - batchTable.setEntry(0, -1, 1); + batchTable.setBatchedAttribute(0, -1, 1); }).toThrowDeveloperError(); expect(function() { - batchTable.setEntry(0, 100, 1); + batchTable.setBatchedAttribute(0, 100, 1); }).toThrowDeveloperError(); }); it('set entry throws when value is undefined', function() { batchTable = new BatchTable(unsignedByteAttributes, 5); expect(function() { - batchTable.setEntry(0, 0, undefined); + batchTable.setBatchedAttribute(0, 0, undefined); }).toThrowDeveloperError(); }); From 96ebfabe67766a3a8a612fb4c239a5dc815e2180 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 20 Sep 2016 14:19:33 -0400 Subject: [PATCH 11/12] Remove unneeded TODO comment. --- Source/Scene/PolylineCollection.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/Scene/PolylineCollection.js b/Source/Scene/PolylineCollection.js index a254c9d55847..10869066594e 100644 --- a/Source/Scene/PolylineCollection.js +++ b/Source/Scene/PolylineCollection.js @@ -1247,7 +1247,6 @@ define([ } } - // TODO: add support for color from the batch table? var colorCartesian = scratchPickColorCartesian; colorCartesian.x = Color.floatToByte(pickColor.red); colorCartesian.y = Color.floatToByte(pickColor.green); From 2e0b103c28f1b2ee2defbf7dfa4f15e24538979a Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Wed, 21 Sep 2016 14:18:53 -0400 Subject: [PATCH 12/12] Fix failing polyline test and update CHANGES.md. --- CHANGES.md | 2 ++ Source/Scene/BatchTable.js | 1 + Source/Shaders/PolylineVS.glsl | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 97d99752bf35..e2124ba1d132 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,8 @@ Change Log ### 1.26 - 2016-10-03 +* Breaking changes + * Vertex texture fetch is now required to be supported to render polylines. Maximum vertex texture image units must be greater than zero. * Fixed billboard rotation when sized in meters. [#3979](https://github.com/AnalyticalGraphicsInc/cesium/issues/3979) * Added `DebugCameraPrimitive` to visualize the view frustum of a camera. * Fixed touch events for the timeline [#4305](https://github.com/AnalyticalGraphicsInc/cesium/pull/4305) diff --git a/Source/Scene/BatchTable.js b/Source/Scene/BatchTable.js index 0ee8ac58c74a..01c8b77ecaaa 100644 --- a/Source/Scene/BatchTable.js +++ b/Source/Scene/BatchTable.js @@ -151,6 +151,7 @@ define([ for (var i = 0; i < length; ++i) { if (attributes[i].componentDatatype !== ComponentDatatype.UNSIGNED_BYTE) { foundFloatDatatype = true; + break; } } return foundFloatDatatype ? PixelDatatype.FLOAT : PixelDatatype.UNSIGNED_BYTE; diff --git a/Source/Shaders/PolylineVS.glsl b/Source/Shaders/PolylineVS.glsl index 06eaf8caf73f..7f0664b2c3f8 100644 --- a/Source/Shaders/PolylineVS.glsl +++ b/Source/Shaders/PolylineVS.glsl @@ -27,6 +27,11 @@ void main() float width = widthAndShow.x + 0.5; float show = widthAndShow.y; + if (width < 1.0) + { + show = 0.0; + } + vec4 pickColor = batchTable_getPickColor(batchTableIndex); vec4 p, prev, next;