diff --git a/Apps/Sandcastle/gallery/3D Tiles.html b/Apps/Sandcastle/gallery/3D Tiles.html index f776a342121f..65e88ffbefbe 100644 --- a/Apps/Sandcastle/gallery/3D Tiles.html +++ b/Apps/Sandcastle/gallery/3D Tiles.html @@ -53,7 +53,13 @@ }, { name : 'Composite', url : '../../../Specs/Data/Cesium3DTiles/Composite/Composite/' }, { - name : 'Points', url : '../../../Specs/Data/Cesium3DTiles/Points/PointsRGB/' + name : 'PointCloud', url : '../../../Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGB/' +}, { + name : 'PointCloudConstantColor', url : '../../../Specs/Data/Cesium3DTiles/PointCloud/PointCloudConstantColor/' +}, { + name : 'PointCloudNormals', url : '../../../Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantizedOctEncoded/' +}, { + name : 'PointCloudBatched', url : '../../../Specs/Data/Cesium3DTiles/PointCloud/PointCloudBatched/' }]; var tileset; diff --git a/Source/Core/ComponentDatatype.js b/Source/Core/ComponentDatatype.js index 6b8b484dabde..46130f7569fa 100644 --- a/Source/Core/ComponentDatatype.js +++ b/Source/Core/ComponentDatatype.js @@ -297,5 +297,36 @@ define([ } }; + /** + * Get the ComponentDatatype from its name. + * + * @param {String} name The name of the ComponentDatatype. + * @returns {ComponentDatatype} The ComponentDatatype. + * + * @exception {DeveloperError} name is not a valid value. + */ + ComponentDatatype.fromName = function(name) { + switch (name) { + case 'BYTE': + return ComponentDatatype.BYTE; + case 'UNSIGNED_BYTE': + return ComponentDatatype.UNSIGNED_BYTE; + case 'SHORT': + return ComponentDatatype.SHORT; + case 'UNSIGNED_SHORT': + return ComponentDatatype.UNSIGNED_SHORT; + case 'INT': + return ComponentDatatype.INT; + case 'UNSIGNED_INT': + return ComponentDatatype.UNSIGNED_INT; + case 'FLOAT': + return ComponentDatatype.FLOAT; + case 'DOUBLE': + return ComponentDatatype.DOUBLE; + default: + throw new DeveloperError('name is not a valid value.'); + } + }; + return freezeObject(ComponentDatatype); }); diff --git a/Source/Core/PointGeometry.js b/Source/Core/PointGeometry.js index b7638d0a3fb0..a0336fee833a 100644 --- a/Source/Core/PointGeometry.js +++ b/Source/Core/PointGeometry.js @@ -50,6 +50,9 @@ define([ if (!defined(options.positionsTypedArray)) { throw new DeveloperError('options.positionsTypedArray is required.'); } + if (!defined(options.colorsTypedArray)) { + throw new DeveloperError('options.colorsTypedArray is required'); + } //>>includeEnd('debug'); this._positionsTypedArray = options.positionsTypedArray; @@ -77,18 +80,12 @@ define([ values : positions }); - var colors = pointGeometry._colorsTypedArray; - if (defined(colors)) { - // Check if the colors are provided as rgb or rgba - var colorComponentsPerAttribute = (colors.length === positions.length) ? 3 : 4; - - attributes.color = new GeometryAttribute({ - componentDatatype : ComponentDatatype.UNSIGNED_BYTE, - componentsPerAttribute : colorComponentsPerAttribute, - values : colors, - normalize : true - }); - } + attributes.color = new GeometryAttribute({ + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + componentsPerAttribute : 3, + values : pointGeometry._colorsTypedArray, + normalize : true + }); // User provided bounding sphere to save computation time. var boundingSphere = pointGeometry._boundingSphere; diff --git a/Source/Scene/Batched3DModel3DTileContent.js b/Source/Scene/Batched3DModel3DTileContent.js index 09f4c0de9a5d..881326e54a6c 100644 --- a/Source/Scene/Batched3DModel3DTileContent.js +++ b/Source/Scene/Batched3DModel3DTileContent.js @@ -14,7 +14,7 @@ define([ '../Core/RequestType', '../ThirdParty/when', './Cesium3DTileFeature', - './Cesium3DTileBatchTableResources', + './Cesium3DTileBatchTable', './Cesium3DTileContentState', './Model' ], function( @@ -32,7 +32,7 @@ define([ RequestType, when, Cesium3DTileFeature, - Cesium3DTileBatchTableResources, + Cesium3DTileBatchTable, Cesium3DTileContentState, Model) { 'use strict'; @@ -57,7 +57,7 @@ define([ * The following properties are part of the {@link Cesium3DTileContent} interface. */ this.state = Cesium3DTileContentState.UNLOADED; - this.batchTableResources = undefined; + this.batchTable = undefined; this.featurePropertiesDirty = false; this._contentReadyToProcessPromise = when.defer(); @@ -120,7 +120,7 @@ define([ * Part of the {@link Cesium3DTileContent} interface. */ Batched3DModel3DTileContent.prototype.hasProperty = function(name) { - return this.batchTableResources.hasProperty(name); + return this.batchTable.hasProperty(name); }; /** @@ -199,27 +199,54 @@ define([ var byteLength = view.getUint32(byteOffset, true); byteOffset += sizeOfUint32; - var batchLength = view.getUint32(byteOffset, true); - this._featuresLength = batchLength; + var batchTableJsonByteLength = view.getUint32(byteOffset, true); byteOffset += sizeOfUint32; - var batchTableResources = new Cesium3DTileBatchTableResources(this, batchLength); - this.batchTableResources = batchTableResources; + var batchTableBinaryByteLength = view.getUint32(byteOffset, true); + byteOffset += sizeOfUint32; - var batchTableByteLength = view.getUint32(byteOffset, true); + var batchLength = view.getUint32(byteOffset, true); byteOffset += sizeOfUint32; - if (batchTableByteLength > 0) { - var batchTableString = getStringFromTypedArray(uint8Array, byteOffset, batchTableByteLength); - byteOffset += batchTableByteLength; + // TODO : remove this legacy check before merging into master + // Legacy header: [batchLength] [batchTableByteLength] + // Current header: [batchTableJsonByteLength] [batchTableBinaryByteLength] [batchLength] + // If the header is in the legacy format 'batchLength' will be the start of the JSON string (a quotation mark) or the glTF magic. + // Accordingly the first byte of uint32 will be either 0x22 or 0x67 and so the uint32 will exceed any reasonable 'batchLength'. + if (batchLength > 10000000) { + byteOffset -= sizeOfUint32; + batchLength = batchTableJsonByteLength; + batchTableJsonByteLength = batchTableBinaryByteLength; + batchTableBinaryByteLength = 0; + console.log('Warning: b3dm header is using the legacy format [batchLength] [batchTableByteLength]. The new format is [batchTableJsonByteLength] [batchTableBinaryByteLength] [batchLength] from https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Batched3DModel/README.md.'); + } + + this._featuresLength = batchLength; + + var batchTableJson; + var batchTableBinary; + if (batchTableJsonByteLength > 0) { // PERFORMANCE_IDEA: is it possible to allocate this on-demand? Perhaps keep the // arraybuffer/string compressed in memory and then decompress it when it is first accessed. // // We could also make another request for it, but that would make the property set/get // API async, and would double the number of numbers in some cases. - batchTableResources.batchTable = JSON.parse(batchTableString); + var batchTableString = getStringFromTypedArray(uint8Array, byteOffset, batchTableJsonByteLength); + batchTableJson = JSON.parse(batchTableString); + byteOffset += batchTableJsonByteLength; + + if (batchTableBinaryByteLength > 0) { + // Has a batch table binary + batchTableBinary = new Uint8Array(arrayBuffer, byteOffset, batchTableBinaryByteLength); + // Copy the batchTableBinary section and let the underlying ArrayBuffer be freed + batchTableBinary = new Uint8Array(batchTableBinary); + byteOffset += batchTableBinaryByteLength; + } } + var batchTable = new Cesium3DTileBatchTable(this, batchLength, batchTableJson, batchTableBinary); + this.batchTable = batchTable; + var gltfByteLength = byteStart + byteLength - byteOffset; var gltfView = new Uint8Array(arrayBuffer, byteOffset, gltfByteLength); @@ -229,13 +256,14 @@ define([ gltf : gltfView, cull : false, // The model is already culled by the 3D tiles releaseGltfJson : true, // Models are unique and will not benefit from caching so save memory - vertexShaderLoaded : batchTableResources.getVertexShaderCallback(), - fragmentShaderLoaded : batchTableResources.getFragmentShaderCallback(), - uniformMapLoaded : batchTableResources.getUniformMapCallback(), - pickVertexShaderLoaded : batchTableResources.getPickVertexShaderCallback(), - pickFragmentShaderLoaded : batchTableResources.getPickFragmentShaderCallback(), - pickUniformMapLoaded : batchTableResources.getPickUniformMapCallback(), - basePath : this._url + basePath : this._url, + modelMatrix : this._tile.computedTransform, + vertexShaderLoaded : batchTable.getVertexShaderCallback(), + fragmentShaderLoaded : batchTable.getFragmentShaderCallback(), + uniformMapLoaded : batchTable.getUniformMapCallback(), + pickVertexShaderLoaded : batchTable.getPickVertexShaderCallback(), + pickFragmentShaderLoaded : batchTable.getPickFragmentShaderCallback(), + pickUniformMapLoaded : batchTable.getPickUniformMapCallback() }); this._model = model; @@ -258,7 +286,7 @@ define([ */ Batched3DModel3DTileContent.prototype.applyDebugSettings = function(enabled, color) { color = enabled ? color : Color.WHITE; - this.batchTableResources.setAllColor(color); + this.batchTable.setAllColor(color); }; /** @@ -267,13 +295,14 @@ define([ Batched3DModel3DTileContent.prototype.update = function(tileset, frameState) { var oldAddCommand = frameState.addCommand; if (frameState.passes.render) { - frameState.addCommand = this.batchTableResources.getAddCommand(); + frameState.addCommand = this.batchTable.getAddCommand(); } // In the PROCESSING state we may be calling update() to move forward // the content's resource loading. In the READY state, it will // actually generate commands. - this.batchTableResources.update(tileset, frameState); + this.batchTable.update(tileset, frameState); + this._model.modelMatrix = this._tile.computedTransform; this._model.update(frameState); frameState.addCommand = oldAddCommand; @@ -291,7 +320,7 @@ define([ */ Batched3DModel3DTileContent.prototype.destroy = function() { this._model = this._model && this._model.destroy(); - this.batchTableResources = this.batchTableResources && this.batchTableResources.destroy(); + this.batchTable = this.batchTable && this.batchTable.destroy(); return destroyObject(this); }; diff --git a/Source/Scene/Cesium3DTile.js b/Source/Scene/Cesium3DTile.js index 1e8c748fc095..3bdb3771e680 100644 --- a/Source/Scene/Cesium3DTile.js +++ b/Source/Scene/Cesium3DTile.js @@ -80,7 +80,23 @@ define([ this._header = header; var contentHeader = header.content; - this._boundingVolume = createBoundingVolume(header.boundingVolume); + /** + * The local transform of this tile + * @type {Matrix4} + */ + this.transform = defined(header.transform) ? Matrix4.unpack(header.transform) : Matrix4.clone(Matrix4.IDENTITY); + + /** + * The final computed transform of this tile + * @type {Matrix4} + */ + var parentTransform = defined(parent) ? parent.computedTransform : tileset.modelMatrix; + this.computedTransform = Matrix4.multiply(parentTransform, this.transform, new Matrix4()); + this._computedTransform = Matrix4.clone(this.computedTransform); + + this._transformDirty = true; + + this._boundingVolume = this.createBoundingVolume(header.boundingVolume, this.computedTransform); var contentBoundingVolume; @@ -90,7 +106,7 @@ define([ // but not for culling for traversing the tree since it is not spatial coherence, i.e., // since it only bounds models in the tile, not the entire tile, children may be // outside of this box. - contentBoundingVolume = createBoundingVolume(contentHeader.boundingVolume); + contentBoundingVolume = this.createBoundingVolume(contentHeader.boundingVolume, this.computedTransform); } this._contentBoundingVolume = contentBoundingVolume; @@ -347,6 +363,20 @@ define([ } }, + /** + * Whether the computedTransform has changed this frame. + * + * @memberof Cesium3DTile.prototype + * + * @type {Boolean} + * @readonly + */ + transformDirty : { + get : function() { + return this._transformDirty; + } + }, + /** * @readonly * @private @@ -504,54 +534,78 @@ define([ return this._boundingVolume.distanceToCamera(frameState); }; - function createBoundingVolume(boundingVolumeHeader) { - var volume; - if (boundingVolumeHeader.box) { + var scratchMatrix = new Matrix3(); + var scratchScale = new Cartesian3(); + var scratchHalfAxes = new Matrix3(); + var scratchCenter = new Cartesian3(); + var scratchRectangle = new Rectangle(); + + /** + * Create a bounding volume from the tile's bounding volume header. + * + * @param {Object} boundingVolumeHeader The tile's bounding volume header. + * @param {Matrix4} transform The transform to apply to the bounding volume. + * @param {TileBoundingVolume} [result] The object onto which to store the result. + * + * @returns {TileBoundingVolume} The modified result parameter or a new TileBoundingVolume instance if none was provided. + * + * @private + */ + Cesium3DTile.prototype.createBoundingVolume = function(boundingVolumeHeader, transform, result) { + var center; + if (defined(boundingVolumeHeader.box)) { var box = boundingVolumeHeader.box; - var center = new Cartesian3(box[0], box[1], box[2]); - var halfAxes = Matrix3.fromArray(box, 3); + center = Cartesian3.fromElements(box[0], box[1], box[2], scratchCenter); + var halfAxes = Matrix3.fromArray(box, 3, scratchHalfAxes); - volume = new TileOrientedBoundingBox({ - center: center, - halfAxes: halfAxes - }); - } else if (boundingVolumeHeader.region) { + // Find the transformed center and halfAxes + center = Matrix4.multiplyByPoint(transform, center, center); + var rotationScale = Matrix4.getRotation(transform, scratchMatrix); + halfAxes = Matrix3.multiply(rotationScale, halfAxes, halfAxes); + + if (defined(result)) { + result.update(center, halfAxes); + return result; + } + return new TileOrientedBoundingBox(center, halfAxes); + } else if (defined(boundingVolumeHeader.region)) { var region = boundingVolumeHeader.region; - var rectangleRegion = new Rectangle(region[0], region[1], region[2], region[3]); + var rectangleRegion = Rectangle.unpack(region, 0, scratchRectangle); - volume = new TileBoundingRegion({ + if (defined(result)) { + // Don't update regions when the transform changes + return result; + } + return new TileBoundingRegion({ rectangle : rectangleRegion, minimumHeight : region[4], maximumHeight : region[5] }); - } else if (boundingVolumeHeader.sphere) { + } else if (defined(boundingVolumeHeader.sphere)) { var sphere = boundingVolumeHeader.sphere; - - volume = new TileBoundingSphere( - new Cartesian3(sphere[0], sphere[1], sphere[2]), - sphere[3] - ); - } - - return volume; - } - -// TODO: remove workaround for https://github.com/AnalyticalGraphicsInc/cesium/issues/2657 - function workaround2657(boundingVolume) { - if (defined(boundingVolume.region)) { - var region = boundingVolume.region; - return (region[1] !== region[3]) && (region[0] !== region[2]); - } else { - return true; + center = Cartesian3.fromElements(sphere[0], sphere[1], sphere[2], scratchCenter); + var radius = sphere[3]; + + // Find the transformed center and radius + center = Matrix4.multiplyByPoint(transform, center, center); + var scale = Matrix4.getScale(transform, scratchScale); + var uniformScale = Cartesian3.maximumComponent(scale); + radius *= uniformScale; + + if (defined(result)) { + result.update(center, radius); + return result; + } + return new TileBoundingSphere(center, radius); } - } + }; function applyDebugSettings(tile, tileset, frameState) { - // Tiles do not have a content.box if it is the same as the tile's box. + // Tiles do not have a content.boundingVolume if it is the same as the tile's boundingVolume. var hasContentBoundingVolume = defined(tile._header.content) && defined(tile._header.content.boundingVolume); var showVolume = tileset.debugShowBoundingVolume || (tileset.debugShowContentBoundingVolume && !hasContentBoundingVolume); - if (showVolume && workaround2657(tile._header.boundingVolume)) { + if (showVolume) { if (!defined(tile._debugBoundingVolume)) { tile._debugBoundingVolume = tile._boundingVolume.createDebugVolume(hasContentBoundingVolume ? Color.WHITE : Color.RED); } @@ -560,7 +614,7 @@ define([ tile._debugBoundingVolume = tile._debugBoundingVolume.destroy(); } - if (tileset.debugShowContentBoundingVolume && hasContentBoundingVolume && workaround2657(tile._header.content.boundingVolume)) { + if (tileset.debugShowContentBoundingVolume && hasContentBoundingVolume) { if (!defined(tile._debugContentBoundingVolume)) { tile._debugContentBoundingVolume = tile._contentBoundingVolume.createDebugVolume(Color.BLUE); } @@ -578,12 +632,33 @@ define([ } } + function updateTransform(tile) { + var transformDirty = !Matrix4.equals(tile.computedTransform, tile._computedTransform); + if (transformDirty) { + Matrix4.clone(tile.computedTransform, tile._computedTransform); + + // Update the bounding volumes + var header = tile._header; + var content = tile._header.content; + tile._boundingVolume = tile.createBoundingVolume(header.boundingVolume, tile.computedTransform, tile._boundingVolume); + if (defined(tile._contentBoundingVolume)) { + tile._contentBoundingVolume = tile.createBoundingVolume(content.boundingVolume, tile.computedTransform, tile._contentBoundingVolume); + } + + // Destroy the debug bounding volumes. They will be generated fresh. + tile._debugBoundingVolume = tile._debugBoundingVolume && tile._debugBoundingVolume.destroy(); + tile._debugContentBoundingVolume = tile._debugContentBoundingVolume && tile._debugContentBoundingVolume.destroy(); + } + tile._transformDirty = transformDirty; + } + /** * Get the draw commands needed to render this tile. * * @private */ Cesium3DTile.prototype.update = function(tileset, frameState) { + updateTransform(this); applyDebugSettings(this, tileset, frameState); this._content.update(tileset, frameState); }; diff --git a/Source/Scene/Cesium3DTileBatchTableResources.js b/Source/Scene/Cesium3DTileBatchTable.js similarity index 74% rename from Source/Scene/Cesium3DTileBatchTableResources.js rename to Source/Scene/Cesium3DTileBatchTable.js index 7b9f24c904a5..244d3e8d7a55 100644 --- a/Source/Scene/Cesium3DTileBatchTableResources.js +++ b/Source/Scene/Cesium3DTileBatchTable.js @@ -6,6 +6,7 @@ define([ '../Core/clone', '../Core/Color', '../Core/combine', + '../Core/ComponentDatatype', '../Core/defaultValue', '../Core/defined', '../Core/destroyObject', @@ -22,6 +23,7 @@ define([ '../Renderer/TextureMinificationFilter', './BlendingState', './CullFace', + './getBinaryAccessor', './Pass' ], function( arrayFill, @@ -30,6 +32,7 @@ define([ clone, Color, combine, + ComponentDatatype, defaultValue, defined, destroyObject, @@ -46,13 +49,14 @@ define([ TextureMinificationFilter, BlendingState, CullFace, + getBinaryAccessor, Pass) { 'use strict'; /** * @private */ - function Cesium3DTileBatchTableResources(content, featuresLength) { + function Cesium3DTileBatchTable(content, featuresLength, batchTableJson, batchTableBinary) { featuresLength = defaultValue(featuresLength, 0); /** @@ -65,7 +69,12 @@ define([ /** * @private */ - this.batchTable = undefined; + this.batchTableJson = batchTableJson; + /** + * @private + */ + this.batchTableBinary = batchTableBinary; + this._batchTableBinaryProperties = Cesium3DTileBatchTable.getBinaryProperties(featuresLength, batchTableJson, batchTableBinary); // PERFORMANCE_IDEA: These parallel arrays probably generate cache misses in get/set color/show // and use A LOT of memory. How can we use less memory? @@ -103,35 +112,81 @@ define([ this._textureStep = textureStep; } - function getByteLength(batchTableResources) { - var dimensions = batchTableResources._textureDimensions; + Cesium3DTileBatchTable.getBinaryProperties = function(featuresLength, json, binary) { + var binaryProperties; + if (defined(json)) { + for (var name in json) { + if (json.hasOwnProperty(name)) { + var property = json[name]; + var byteOffset = property.byteOffset; + if (defined(byteOffset)) { + // This is a binary property + var componentType = ComponentDatatype.fromName(property.componentType); + var type = property.type; + //>>includeStart('debug', pragmas.debug); + if (!defined(componentType)) { + throw new DeveloperError('componentType is required.'); + } + if (!defined(type)) { + throw new DeveloperError('type is required.'); + } + if (!defined(binary)) { + throw new DeveloperError('Property ' + name + ' requires a batch table binary.'); + } + //>>includeEnd('debug'); + + var binaryAccessor = getBinaryAccessor(property); + var componentCount = binaryAccessor.componentsPerAttribute; + var classType = binaryAccessor.classType; + var typedArray = binaryAccessor.createArrayBufferView(binary.buffer, binary.byteOffset + byteOffset, featuresLength); + + if (!defined(binaryProperties)) { + binaryProperties = {}; + } + + // Store any information needed to access the binary data, including the typed array, + // componentCount (e.g. a MAT4 would be 16), and the type used to pack and unpack (e.g. Matrix4). + binaryProperties[name] = { + typedArray : typedArray, + componentCount : componentCount, + type : classType + }; + } + } + } + } + return binaryProperties; + }; + + function getByteLength(batchTable) { + var dimensions = batchTable._textureDimensions; return (dimensions.x * dimensions.y) * 4; } - function getBatchValues(batchTableResources) { - if (!defined(batchTableResources._batchValues)) { + function getBatchValues(batchTable) { + if (!defined(batchTable._batchValues)) { // Default batch texture to RGBA = 255: white highlight (RGB) and show/alpha = true/255 (A). - var byteLength = getByteLength(batchTableResources); + var byteLength = getByteLength(batchTable); var bytes = new Uint8Array(byteLength); arrayFill(bytes, 255); - batchTableResources._batchValues = bytes; + batchTable._batchValues = bytes; } - return batchTableResources._batchValues; + return batchTable._batchValues; } - function getShowAlphaProperties(batchTableResources) { - if (!defined(batchTableResources._showAlphaProperties)) { - var byteLength = 2 * batchTableResources.featuresLength; + function getShowAlphaProperties(batchTable) { + if (!defined(batchTable._showAlphaProperties)) { + var byteLength = 2 * batchTable.featuresLength; var bytes = new Uint8Array(byteLength); // [Show = true, Alpha = 255] arrayFill(bytes, 255); - batchTableResources._showAlphaProperties = bytes; + batchTable._showAlphaProperties = bytes; } - return batchTableResources._showAlphaProperties; + return batchTable._showAlphaProperties; } - Cesium3DTileBatchTableResources.prototype.setShow = function(batchId, show) { + Cesium3DTileBatchTable.prototype.setShow = function(batchId, show) { var featuresLength = this.featuresLength; //>>includeStart('debug', pragmas.debug); if (!defined(batchId) || (batchId < 0) || (batchId > featuresLength)) { @@ -165,7 +220,7 @@ define([ } }; - Cesium3DTileBatchTableResources.prototype.getShow = function(batchId) { + Cesium3DTileBatchTable.prototype.getShow = function(batchId) { var featuresLength = this.featuresLength; //>>includeStart('debug', pragmas.debug); if (!defined(batchId) || (batchId < 0) || (batchId > featuresLength)) { @@ -184,7 +239,7 @@ define([ var scratchColor = new Array(4); - Cesium3DTileBatchTableResources.prototype.setColor = function(batchId, color) { + Cesium3DTileBatchTable.prototype.setColor = function(batchId, color) { var featuresLength = this.featuresLength; //>>includeStart('debug', pragmas.debug); if (!defined(batchId) || (batchId < 0) || (batchId > featuresLength)) { @@ -239,7 +294,7 @@ define([ } }; - Cesium3DTileBatchTableResources.prototype.setAllColor = function(color) { + Cesium3DTileBatchTable.prototype.setAllColor = function(color) { //>>includeStart('debug', pragmas.debug); if (!defined(color)) { throw new DeveloperError('color is required.'); @@ -253,7 +308,7 @@ define([ } }; - Cesium3DTileBatchTableResources.prototype.getColor = function(batchId, result) { + Cesium3DTileBatchTable.prototype.getColor = function(batchId, result) { var featuresLength = this.featuresLength; //>>includeStart('debug', pragmas.debug); if (!defined(batchId) || (batchId < 0) || (batchId > featuresLength)) { @@ -282,27 +337,27 @@ define([ result); }; - Cesium3DTileBatchTableResources.prototype.hasProperty = function(name) { + Cesium3DTileBatchTable.prototype.hasProperty = function(name) { //>>includeStart('debug', pragmas.debug); if (!defined(name)) { throw new DeveloperError('name is required.'); } //>>includeEnd('debug'); - var batchTable = this.batchTable; - return defined(batchTable) && defined(batchTable[name]); + var json = this.batchTableJson; + return defined(json) && defined(json[name]); }; - Cesium3DTileBatchTableResources.prototype.getPropertyNames = function() { + Cesium3DTileBatchTable.prototype.getPropertyNames = function() { var names = []; - var batchTable = this.batchTable; + var json = this.batchTableJson; - if (!defined(batchTable)) { + if (!defined(json)) { return names; } - for (var name in batchTable) { - if (batchTable.hasOwnProperty(name)) { + for (var name in json) { + if (json.hasOwnProperty(name)) { names.push(name); } } @@ -310,7 +365,7 @@ define([ return names; }; - Cesium3DTileBatchTableResources.prototype.getProperty = function(batchId, name) { + Cesium3DTileBatchTable.prototype.getProperty = function(batchId, name) { var featuresLength = this.featuresLength; //>>includeStart('debug', pragmas.debug); if (!defined(batchId) || (batchId < 0) || (batchId > featuresLength)) { @@ -322,20 +377,31 @@ define([ } //>>includeEnd('debug'); - if (!defined(this.batchTable)) { + if (!defined(this.batchTableJson)) { return undefined; } - var propertyValues = this.batchTable[name]; + if (defined(this._batchTableBinaryProperties)) { + var binaryProperty = this._batchTableBinaryProperties[name]; + if (defined(binaryProperty)) { + var typedArray = binaryProperty.typedArray; + var componentCount = binaryProperty.componentCount; + if (componentCount === 1) { + return typedArray[batchId]; + } else { + return binaryProperty.type.unpack(typedArray, batchId * componentCount); + } + } + } + var propertyValues = this.batchTableJson[name]; if (!defined(propertyValues)) { return undefined; } - return clone(propertyValues[batchId], true); }; - Cesium3DTileBatchTableResources.prototype.setProperty = function(batchId, name, value) { + Cesium3DTileBatchTable.prototype.setProperty = function(batchId, name, value) { var featuresLength = this.featuresLength; //>>includeStart('debug', pragmas.debug); if (!defined(batchId) || (batchId < 0) || (batchId > featuresLength)) { @@ -347,25 +413,39 @@ define([ } //>>includeEnd('debug'); - if (!defined(this.batchTable)) { - // Tile payload did not have a batch table. Create one for new user-defined properties. - this.batchTable = {}; + if (defined(this._batchTableBinaryProperties)) { + var binaryProperty = this._batchTableBinaryProperties[name]; + if (defined(binaryProperty)) { + var typedArray = binaryProperty.typedArray; + var componentCount = binaryProperty.componentCount; + if (componentCount === 1) { + typedArray[batchId] = value; + } else { + binaryProperty.type.pack(value, typedArray, batchId * componentCount); + } + return; + } } - var propertyValues = this.batchTable[name]; + if (!defined(this.batchTableJson)) { + // Tile payload did not have a batch table. Create one for new user-defined properties. + this.batchTableJson = {}; + } + + var propertyValues = this.batchTableJson[name]; if (!defined(propertyValues)) { - // Property does not exist. Create it. - this.batchTable[name] = new Array(featuresLength); - propertyValues = this.batchTable[name]; + // Property does not exist. Create it. + this.batchTableJson[name] = new Array(featuresLength); + propertyValues = this.batchTableJson[name]; } propertyValues[batchId] = clone(value, true); }; - function getGlslComputeSt(batchTableResources) { + function getGlslComputeSt(batchTable) { // GLSL batchId is zero-based: [0, featuresLength - 1] - if (batchTableResources._textureDimensions.y === 1) { + if (batchTable._textureDimensions.y === 1) { return 'uniform vec4 tile_textureStep; \n' + 'vec2 computeSt(float batchId) \n' + '{ \n' + @@ -392,16 +472,18 @@ define([ /** * @private */ - Cesium3DTileBatchTableResources.prototype.getVertexShaderCallback = function() { + Cesium3DTileBatchTable.prototype.getVertexShaderCallback = function() { if (this.featuresLength === 0) { return; } var that = this; - return function(source) { + return function(source, handleTranslucent) { var renamedSource = ShaderSource.replaceMain(source, 'tile_main'); var newMain; + handleTranslucent = defaultValue(handleTranslucent, true); + if (ContextLimits.maximumVertexTextureImageUnits > 0) { // When VTF is supported, perform per-feature show/hide in the vertex shader newMain = @@ -414,24 +496,28 @@ define([ ' vec2 st = computeSt(a_batchId); \n' + ' vec4 featureProperties = texture2D(tile_batchTexture, st); \n' + ' float show = ceil(featureProperties.a); \n' + // 0 - false, non-zeo - true - ' gl_Position *= show; \n' + // Per-feature show/hide + ' gl_Position *= show; \n'; // Per-feature show/hide // TODO: Translucent should still write depth for picking? For example, we want to grab highlighted building that became translucent // TODO: Same TODOs below in getFragmentShaderCallback - ' bool isStyleTranslucent = (featureProperties.a != 1.0); \n' + - ' if (czm_pass == czm_passTranslucent) \n' + - ' { \n' + - ' if (!isStyleTranslucent && !tile_translucentCommand) \n' + // Do not render opaque features in the translucent pass - ' { \n' + - ' gl_Position *= 0.0; \n' + - ' } \n' + - ' } \n' + - ' else \n' + - ' { \n' + - ' if (isStyleTranslucent) \n' + // Do not render translucent features in the opaque pass - ' { \n' + - ' gl_Position *= 0.0; \n' + - ' } \n' + - ' } \n' + + if (handleTranslucent) { + newMain += + ' bool isStyleTranslucent = (featureProperties.a != 1.0); \n' + + ' if (czm_pass == czm_passTranslucent) \n' + + ' { \n' + + ' if (!isStyleTranslucent && !tile_translucentCommand) \n' + // Do not render opaque features in the translucent pass + ' { \n' + + ' gl_Position *= 0.0; \n' + + ' } \n' + + ' } \n' + + ' else \n' + + ' { \n' + + ' if (isStyleTranslucent) \n' + // Do not render translucent features in the opaque pass + ' { \n' + + ' gl_Position *= 0.0; \n' + + ' } \n' + + ' } \n'; + } + newMain += ' tile_featureColor = featureProperties; \n' + '}'; } else { @@ -448,12 +534,12 @@ define([ }; }; - Cesium3DTileBatchTableResources.prototype.getFragmentShaderCallback = function() { + Cesium3DTileBatchTable.prototype.getFragmentShaderCallback = function() { if (this.featuresLength === 0) { return; } - return function(source) { + return function(source, handleTranslucent) { //TODO: generate entire shader at runtime? //var diffuse = 'diffuse = u_diffuse;'; //var diffuseTexture = 'diffuse = texture2D(u_diffuse, v_texcoord0);'; @@ -483,6 +569,8 @@ define([ var renamedSource = ShaderSource.replaceMain(source, 'tile_main'); var newMain; + handleTranslucent = defaultValue(handleTranslucent, true); + if (ContextLimits.maximumVertexTextureImageUnits > 0) { // When VTF is supported, per-feature show/hide already happened in the fragment shader newMain = @@ -502,22 +590,27 @@ define([ ' vec4 featureProperties = texture2D(tile_batchTexture, tile_featureSt); \n' + ' if (featureProperties.a == 0.0) { \n' + // show: alpha == 0 - false, non-zeo - true ' discard; \n' + - ' } \n' + - ' bool isStyleTranslucent = (featureProperties.a != 1.0); \n' + - ' if (czm_pass == czm_passTranslucent) \n' + - ' { \n' + - ' if (!isStyleTranslucent && !tile_translucentCommand) \n' + // Do not render opaque features in the translucent pass - ' { \n' + - ' discard; \n' + - ' } \n' + - ' } \n' + - ' else \n' + - ' { \n' + - ' if (isStyleTranslucent) \n' + // Do not render translucent features in the opaque pass - ' { \n' + - ' discard; \n' + - ' } \n' + - ' } \n' + + ' } \n'; + + if (handleTranslucent) { + newMain += + ' bool isStyleTranslucent = (featureProperties.a != 1.0); \n' + + ' if (czm_pass == czm_passTranslucent) \n' + + ' { \n' + + ' if (!isStyleTranslucent && !tile_translucentCommand) \n' + // Do not render opaque features in the translucent pass + ' { \n' + + ' discard; \n' + + ' } \n' + + ' } \n' + + ' else \n' + + ' { \n' + + ' if (isStyleTranslucent) \n' + // Do not render translucent features in the opaque pass + ' { \n' + + ' discard; \n' + + ' } \n' + + ' } \n'; + } + newMain += ' tile_main(); \n' + ' gl_FragColor *= featureProperties; \n' + '}'; @@ -527,7 +620,7 @@ define([ }; }; - Cesium3DTileBatchTableResources.prototype.getUniformMapCallback = function() { + Cesium3DTileBatchTable.prototype.getUniformMapCallback = function() { if (this.featuresLength === 0) { return; } @@ -551,7 +644,7 @@ define([ }; }; - Cesium3DTileBatchTableResources.prototype.getPickVertexShaderCallback = function() { + Cesium3DTileBatchTable.prototype.getPickVertexShaderCallback = function() { if (this.featuresLength === 0) { return; } @@ -589,7 +682,7 @@ define([ }; }; - Cesium3DTileBatchTableResources.prototype.getPickFragmentShaderCallback = function() { + Cesium3DTileBatchTable.prototype.getPickFragmentShaderCallback = function() { if (this.featuresLength === 0) { return; } @@ -637,7 +730,7 @@ define([ }; }; - Cesium3DTileBatchTableResources.prototype.getPickUniformMapCallback = function() { + Cesium3DTileBatchTable.prototype.getPickUniformMapCallback = function() { if (this.featuresLength === 0) { return; } @@ -673,7 +766,7 @@ define([ OPAQUE_AND_TRANSLUCENT : 2 }; - Cesium3DTileBatchTableResources.prototype.getAddCommand = function() { + Cesium3DTileBatchTable.prototype.getAddCommand = function() { var styleCommandsNeeded = getStyleCommandsNeeded(this); // TODO: This function most likely will not get optimized. Do something like this later in the render loop. @@ -727,12 +820,12 @@ define([ }; }; - function getStyleCommandsNeeded(batchTableResources) { - var translucentFeaturesLength = batchTableResources._translucentFeaturesLength; + function getStyleCommandsNeeded(batchTable) { + var translucentFeaturesLength = batchTable._translucentFeaturesLength; if (translucentFeaturesLength === 0) { return StyleCommandsNeeded.ALL_OPAQUE; - } else if (translucentFeaturesLength === batchTableResources.featuresLength) { + } else if (translucentFeaturesLength === batchTable.featuresLength) { return StyleCommandsNeeded.ALL_TRANSLUCENT; } @@ -775,8 +868,8 @@ define([ /////////////////////////////////////////////////////////////////////////// - function createTexture(batchTableResources, context, bytes) { - var dimensions = batchTableResources._textureDimensions; + function createTexture(batchTable, context, bytes) { + var dimensions = batchTable._textureDimensions; return new Texture({ context : context, pixelFormat : PixelFormat.RGBA, @@ -793,13 +886,13 @@ define([ }); } - function createPickTexture(batchTableResources, context) { - var featuresLength = batchTableResources.featuresLength; - if (!defined(batchTableResources._pickTexture) && (featuresLength > 0)) { - var pickIds = batchTableResources._pickIds; - var byteLength = getByteLength(batchTableResources); + function createPickTexture(batchTable, context) { + var featuresLength = batchTable.featuresLength; + if (!defined(batchTable._pickTexture) && (featuresLength > 0)) { + var pickIds = batchTable._pickIds; + var byteLength = getByteLength(batchTable); var bytes = new Uint8Array(byteLength); - var content = batchTableResources._content; + var content = batchTable._content; // PERFORMANCE_IDEA: we could skip the pick texture completely by allocating // a continuous range of pickIds and then converting the base pickId + batchId @@ -817,23 +910,23 @@ define([ bytes[offset + 3] = Color.floatToByte(pickColor.alpha); } - batchTableResources._pickTexture = createTexture(batchTableResources, context, bytes); + batchTable._pickTexture = createTexture(batchTable, context, bytes); } } - function updateBatchTexture(batchTableResources) { - var dimensions = batchTableResources._textureDimensions; + function updateBatchTexture(batchTable) { + var dimensions = batchTable._textureDimensions; // PERFORMANCE_IDEA: Instead of rewriting the entire texture, use fine-grained // texture updates when less than, for example, 10%, of the values changed. Or // even just optimize the common case when one feature show/color changed. - batchTableResources._batchTexture.copyFrom({ + batchTable._batchTexture.copyFrom({ width : dimensions.x, height : dimensions.y, - arrayBufferView : batchTableResources._batchValues + arrayBufferView : batchTable._batchValues }); } - Cesium3DTileBatchTableResources.prototype.update = function(tileset, frameState) { + Cesium3DTileBatchTable.prototype.update = function(tileset, frameState) { var context = frameState.context; this._defaultTexture = context.defaultTexture; @@ -854,11 +947,11 @@ define([ } }; - Cesium3DTileBatchTableResources.prototype.isDestroyed = function() { + Cesium3DTileBatchTable.prototype.isDestroyed = function() { return false; }; - Cesium3DTileBatchTableResources.prototype.destroy = function() { + Cesium3DTileBatchTable.prototype.destroy = function() { this._batchTexture = this._batchTexture && this._batchTexture.destroy(); this._pickTexture = this._pickTexture && this._pickTexture.destroy(); @@ -871,5 +964,5 @@ define([ return destroyObject(this); }; - return Cesium3DTileBatchTableResources; + return Cesium3DTileBatchTable; }); diff --git a/Source/Scene/Cesium3DTileContent.js b/Source/Scene/Cesium3DTileContent.js index ab4a7a29e747..2efcd57ccc49 100644 --- a/Source/Scene/Cesium3DTileContent.js +++ b/Source/Scene/Cesium3DTileContent.js @@ -21,7 +21,7 @@ define([ * * @see Batched3DModel3DTileContent * @see Instanced3DModel3DTileContent - * @see Points3DTileContent + * @see PointCloud3DTileContent * @see Composite3DTileContent * @see Tileset3DTileContent * @see Empty3DTileContent @@ -45,12 +45,12 @@ define([ /** * Gets the batch table texture for this tile. * - * @type {Cesium3DTileBatchTableResources} + * @type {Cesium3DTileBatchTable} * @readonly * * @private */ - this.batchTableResources = undefined; + this.batchTable = undefined; /** * Gets or sets if any feature's property changed. Used to diff --git a/Source/Scene/Cesium3DTileContentFactory.js b/Source/Scene/Cesium3DTileContentFactory.js index 4a75007e030c..4a1b14fad74e 100644 --- a/Source/Scene/Cesium3DTileContentFactory.js +++ b/Source/Scene/Cesium3DTileContentFactory.js @@ -3,13 +3,13 @@ define([ './Batched3DModel3DTileContent', './Composite3DTileContent', './Instanced3DModel3DTileContent', - './Points3DTileContent', + './PointCloud3DTileContent', './Tileset3DTileContent' ], function( Batched3DModel3DTileContent, Composite3DTileContent, Instanced3DModel3DTileContent, - Points3DTileContent, + PointCloud3DTileContent, Tileset3DTileContent) { 'use strict'; @@ -24,7 +24,7 @@ define([ return new Batched3DModel3DTileContent(tileset, tile, url); }, pnts : function(tileset, tile, url) { - return new Points3DTileContent(tileset, tile, url); + return new PointCloud3DTileContent(tileset, tile, url); }, i3dm : function(tileset, tile, url) { return new Instanced3DModel3DTileContent(tileset, tile, url); diff --git a/Source/Scene/Cesium3DTileFeature.js b/Source/Scene/Cesium3DTileFeature.js index 923f1c8a15ed..7c9b929521bd 100644 --- a/Source/Scene/Cesium3DTileFeature.js +++ b/Source/Scene/Cesium3DTileFeature.js @@ -43,7 +43,7 @@ define([ */ function Cesium3DTileFeature(tileset, content, batchId) { this._content = content; - this._batchTableResources = content.batchTableResources; + this._batchTable = content.batchTable; this._batchId = batchId; this._color = undefined; // for calling getColor @@ -69,10 +69,10 @@ define([ */ show : { get : function() { - return this._batchTableResources.getShow(this._batchId); + return this._batchTable.getShow(this._batchId); }, set : function(value) { - this._batchTableResources.setShow(this._batchId, value); + this._batchTable.setShow(this._batchId, value); } }, @@ -95,10 +95,10 @@ define([ if (!this._color) { this._color = new Color(); } - return this._batchTableResources.getColor(this._batchId, this._color); + return this._batchTable.getColor(this._batchId, this._color); }, set : function(value) { - this._batchTableResources.setColor(this._batchId, value); + this._batchTable.setColor(this._batchId, value); } } }); @@ -128,7 +128,7 @@ define([ * @see {Cesium3DTileset#properties} */ Cesium3DTileFeature.prototype.getProperty = function(name) { - return this._batchTableResources.getProperty(this._batchId, name); + return this._batchTable.getProperty(this._batchId, name); }; /** @@ -160,7 +160,7 @@ define([ * @see {Cesium3DTileset#properties} */ Cesium3DTileFeature.prototype.setProperty = function(name, value) { - this._batchTableResources.setProperty(this._batchId, name, value); + this._batchTable.setProperty(this._batchId, name, value); // PERFORMANCE_IDEA: Probably overkill, but maybe only mark the tile dirty if the // property is in one of the style's expressions or - if it can be done quickly - diff --git a/Source/Scene/Cesium3DTileFeatureTableResources.js b/Source/Scene/Cesium3DTileFeatureTable.js similarity index 70% rename from Source/Scene/Cesium3DTileFeatureTableResources.js rename to Source/Scene/Cesium3DTileFeatureTable.js index 7334421782f2..22f527661c01 100644 --- a/Source/Scene/Cesium3DTileFeatureTableResources.js +++ b/Source/Scene/Cesium3DTileFeatureTable.js @@ -14,14 +14,14 @@ define([ /** * @private */ - function Cesium3DTileFeatureTableResources(featureTableJSON, featureTableBinary) { - this.json = featureTableJSON; + function Cesium3DTileFeatureTable(featureTableJson, featureTableBinary) { + this.json = featureTableJson; this.buffer = featureTableBinary; this._cachedArrayBufferViews = {}; this.featuresLength = 0; } - Cesium3DTileFeatureTableResources.prototype.getTypedArrayForSemantic = function(semantic, byteOffset, componentType, count, featureSize) { + Cesium3DTileFeatureTable.prototype.getTypedArrayForSemantic = function(semantic, byteOffset, componentType, count, featureSize) { //>>includeStart('debug', pragmas.debug); if (!defined(byteOffset)) { throw new DeveloperError('byteOffset must be defined to read from binary data for semantic: ' + semantic); @@ -42,7 +42,7 @@ define([ return arrayBuffer; }; - Cesium3DTileFeatureTableResources.prototype.getGlobalProperty = function(semantic, componentType, count) { + Cesium3DTileFeatureTable.prototype.getGlobalProperty = function(semantic, componentType, count) { var jsonValue = this.json[semantic]; if (defined(jsonValue)) { var byteOffset = jsonValue.byteOffset; @@ -60,7 +60,22 @@ define([ return jsonValue; }; - Cesium3DTileFeatureTableResources.prototype.getProperty = function(semantic, featureId, componentType, featureSize) { + Cesium3DTileFeatureTable.prototype.getPropertyArray = function(semantic, componentType, featureSize) { + var jsonValue = this.json[semantic]; + if (defined(jsonValue)) { + var byteOffset = jsonValue.byteOffset; + if (defined(byteOffset)) { + // This is a reference to the binary + featureSize = defaultValue(featureSize, 1); + return this.getTypedArrayForSemantic(semantic, byteOffset, componentType, this.featuresLength, featureSize); + } + // If the data is a json array, convert to a typed array + return ComponentDatatype.createTypedArray(componentType, jsonValue); + } + return jsonValue; + }; + + Cesium3DTileFeatureTable.prototype.getProperty = function(semantic, featureId, componentType, featureSize) { var jsonValue = this.json[semantic]; if (defined(jsonValue)) { var byteOffset = jsonValue.byteOffset; @@ -81,5 +96,5 @@ define([ return jsonValue; }; - return Cesium3DTileFeatureTableResources; + return Cesium3DTileFeatureTable; }); \ No newline at end of file diff --git a/Source/Scene/Cesium3DTileStyleEngine.js b/Source/Scene/Cesium3DTileStyleEngine.js index 7d00c0723cf3..ad29ebabd14d 100644 --- a/Source/Scene/Cesium3DTileStyleEngine.js +++ b/Source/Scene/Cesium3DTileStyleEngine.js @@ -110,7 +110,7 @@ define([ } // PERFORMANCE_IDEA: we can create a slightly faster internal interface by directly - // using Cesium3DTileBatchTableResources. We might also be able to use less memory + // using Cesium3DTileBatchTable. We might also be able to use less memory // by using reusing a batchValues array across tiles. for (var i = 0; i < length; ++i) { var feature = content.getFeature(i); diff --git a/Source/Scene/Cesium3DTileset.js b/Source/Scene/Cesium3DTileset.js index 4ca2aab1b039..e39839a175a2 100644 --- a/Source/Scene/Cesium3DTileset.js +++ b/Source/Scene/Cesium3DTileset.js @@ -14,6 +14,7 @@ define([ '../Core/joinUrls', '../Core/loadJson', '../Core/Math', + '../Core/Matrix4', '../Core/Request', '../Core/RequestScheduler', '../Core/RequestType', @@ -39,6 +40,7 @@ define([ joinUrls, loadJson, CesiumMath, + Matrix4, Request, RequestScheduler, RequestType, @@ -61,6 +63,7 @@ define([ * @param {Object} options Object with the following properties: * @param {String} options.url The url to a tileset.json file or to a directory containing a tileset.json file. * @param {Boolean} [options.show=true] Determines if the tileset will be shown. + * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] A 4x4 transformation matrix that transforms the tileset's root tile. * @param {Number} [options.maximumScreenSpaceError=16] The maximum screen-space error used to drive level-of-detail refinement. * @param {Boolean} [options.debugShowStatistics=false] For debugging only. Determines if rendering statistics are output to the console. * @param {Boolean} [options.debugShowPickStatistics=false] For debugging only. Determines if rendering statistics for picking are output to the console. @@ -132,6 +135,14 @@ define([ this._maximumNumberOfLoadedTiles = defaultValue(options.maximumNumberOfLoadedTiles, 256); this._styleEngine = new Cesium3DTileStyleEngine(); + /** + * A 4x4 transformation matrix that transforms the tileset's root tile. + * + * @type {Matrix4} + * @default Matrix4.IDENTITY + */ + this.modelMatrix = defined(options.modelMatrix) ? options.modelMatrix : Matrix4.clone(Matrix4.IDENTITY); + /** * This property is for debugging only; it is not optimized for production use. *
@@ -881,6 +892,9 @@ define([ t.replaced = false; ++stats.visited; + var parentTransform = defined(t.parent) ? t.parent.computedTransform : tileset.modelMatrix; + t.computedTransform = Matrix4.multiply(parentTransform, t.transform, t.computedTransform); + var planeMask = t.visibility(cullingVolume); if (planeMask === CullingVolume.MASK_OUTSIDE) { // Tile is completely outside of the view frustum; therefore diff --git a/Source/Scene/Composite3DTileContent.js b/Source/Scene/Composite3DTileContent.js index 5e7ef0ea0fdc..b0a3c14de0c7 100644 --- a/Source/Scene/Composite3DTileContent.js +++ b/Source/Scene/Composite3DTileContent.js @@ -48,7 +48,7 @@ define([ * The following properties are part of the {@link Cesium3DTileContent} interface. */ this.state = Cesium3DTileContentState.UNLOADED; - this.batchTableResources = undefined; + this.batchTable = undefined; this._contentReadyToProcessPromise = when.defer(); this._readyPromise = when.defer(); diff --git a/Source/Scene/Empty3DTileContent.js b/Source/Scene/Empty3DTileContent.js index bc841c0f7147..29b91f1bc346 100644 --- a/Source/Scene/Empty3DTileContent.js +++ b/Source/Scene/Empty3DTileContent.js @@ -26,7 +26,7 @@ define([ * The following properties are part of the {@link Cesium3DTileContent} interface. */ this.state = undefined; - this.batchTableResources = undefined; + this.batchTable = undefined; this.featurePropertiesDirty = false; this._contentReadyToProcessPromise = when.defer(); diff --git a/Source/Scene/Instanced3DModel3DTileContent.js b/Source/Scene/Instanced3DModel3DTileContent.js index bc3a222c188b..6df988d56792 100644 --- a/Source/Scene/Instanced3DModel3DTileContent.js +++ b/Source/Scene/Instanced3DModel3DTileContent.js @@ -27,9 +27,9 @@ define([ '../ThirdParty/Uri', '../ThirdParty/when', './Cesium3DTileFeature', - './Cesium3DTileBatchTableResources', + './Cesium3DTileBatchTable', './Cesium3DTileContentState', - './Cesium3DTileFeatureTableResources', + './Cesium3DTileFeatureTable', './ModelInstanceCollection' ], function( AttributeCompression, @@ -59,9 +59,9 @@ define([ Uri, when, Cesium3DTileFeature, - Cesium3DTileBatchTableResources, + Cesium3DTileBatchTable, Cesium3DTileContentState, - Cesium3DTileFeatureTableResources, + Cesium3DTileFeatureTable, ModelInstanceCollection) { 'use strict'; @@ -85,7 +85,7 @@ define([ * The following properties are part of the {@link Cesium3DTileContent} interface. */ this.state = Cesium3DTileContentState.UNLOADED; - this.batchTableResources = undefined; + this.batchTable = undefined; this.featurePropertiesDirty = false; this._contentReadyToProcessPromise = when.defer(); @@ -147,14 +147,14 @@ define([ * Part of the {@link Cesium3DTileContent} interface. */ Instanced3DModel3DTileContent.prototype.hasProperty = function(name) { - return this.batchTableResources.hasProperty(name); + return this.batchTable.hasProperty(name); }; /** * Part of the {@link Cesium3DTileContent} interface. */ Instanced3DModel3DTileContent.prototype.getFeature = function(batchId) { - var featuresLength = this._modelInstanceCollection.length; + var featuresLength = this.featuresLength; //>>includeStart('debug', pragmas.debug); if (!defined(batchId) || (batchId < 0) || (batchId >= featuresLength)) { throw new DeveloperError('batchId is required and between zero and featuresLength - 1 (' + (featuresLength - 1) + ').'); @@ -225,10 +225,10 @@ define([ var byteLength = view.getUint32(byteOffset, true); byteOffset += sizeOfUint32; - var featureTableJSONByteLength = view.getUint32(byteOffset, true); + var featureTableJsonByteLength = view.getUint32(byteOffset, true); //>>includeStart('debug', pragmas.debug); - if (featureTableJSONByteLength === 0) { - throw new DeveloperError('featureTableJSONByteLength is zero, the feature table must be defined.'); + if (featureTableJsonByteLength === 0) { + throw new DeveloperError('featureTableJsonByteLength is zero, the feature table must be defined.'); } //>>includeEnd('debug'); byteOffset += sizeOfUint32; @@ -236,7 +236,7 @@ define([ var featureTableBinaryByteLength = view.getUint32(byteOffset, true); byteOffset += sizeOfUint32; - var batchTableJSONByteLength = view.getUint32(byteOffset, true); + var batchTableJsonByteLength = view.getUint32(byteOffset, true); byteOffset += sizeOfUint32; var batchTableBinaryByteLength = view.getUint32(byteOffset, true); @@ -250,19 +250,16 @@ define([ //>>includeEnd('debug'); byteOffset += sizeOfUint32; - var featureTableString = getStringFromTypedArray(uint8Array, byteOffset, featureTableJSONByteLength); - var featureTableJSON = JSON.parse(featureTableString); - byteOffset += featureTableJSONByteLength; + var featureTableString = getStringFromTypedArray(uint8Array, byteOffset, featureTableJsonByteLength); + var featureTableJson = JSON.parse(featureTableString); + byteOffset += featureTableJsonByteLength; var featureTableBinary = new Uint8Array(arrayBuffer, byteOffset, featureTableBinaryByteLength); byteOffset += featureTableBinaryByteLength; - var featureTableResources = new Cesium3DTileFeatureTableResources(featureTableJSON, featureTableBinary); - var instancesLength = featureTableResources.getGlobalProperty('INSTANCES_LENGTH', ComponentDatatype.UNSIGNED_INT); - if (Array.isArray(instancesLength)) { - instancesLength = instancesLength[0]; - } - featureTableResources.featuresLength = instancesLength; + var featureTable = new Cesium3DTileFeatureTable(featureTableJson, featureTableBinary); + var instancesLength = featureTable.getGlobalProperty('INSTANCES_LENGTH', ComponentDatatype.UNSIGNED_INT); + featureTable.featuresLength = instancesLength; //>>includeStart('debug', pragmas.debug); if (!defined(instancesLength)) { @@ -270,16 +267,23 @@ define([ } //>>includeEnd('debug'); - var batchTableResources = new Cesium3DTileBatchTableResources(this, instancesLength); - this.batchTableResources = batchTableResources; - if (batchTableJSONByteLength > 0) { - var batchTableString = getStringFromTypedArray(uint8Array, byteOffset, batchTableJSONByteLength); - batchTableResources.batchTable = JSON.parse(batchTableString); - byteOffset += batchTableJSONByteLength; + var batchTableJson; + var batchTableBinary; + if (batchTableJsonByteLength > 0) { + var batchTableString = getStringFromTypedArray(uint8Array, byteOffset, batchTableJsonByteLength); + batchTableJson = JSON.parse(batchTableString); + byteOffset += batchTableJsonByteLength; + + if (batchTableBinaryByteLength > 0) { + // Has a batch table binary + batchTableBinary = new Uint8Array(arrayBuffer, byteOffset, batchTableBinaryByteLength); + // Copy the batchTableBinary section and let the underlying ArrayBuffer be freed + batchTableBinary = new Uint8Array(batchTableBinary); + byteOffset += batchTableBinaryByteLength; + } } - // TODO: Right now batchTableResources doesn't support binary - byteOffset += batchTableBinaryByteLength; + this.batchTable = new Cesium3DTileBatchTable(this, instancesLength, batchTableJson, batchTableBinary); var gltfByteLength = byteStart + byteLength - byteOffset; //>>includeStart('debug', pragmas.debug); @@ -293,12 +297,13 @@ define([ // Create model instance collection var collectionOptions = { instances : new Array(instancesLength), - batchTableResources : batchTableResources, + batchTable : this.batchTable, boundingVolume : this._tile.contentBoundingVolume.boundingVolume, - cull : false, + center : undefined, + transform : this._tile.computedTransform, + cull : false, // Already culled by 3D Tiles url : undefined, - headers : undefined, - type : RequestType.TILES3D, + requestType : RequestType.TILES3D, gltf : undefined, basePath : undefined }; @@ -312,6 +317,10 @@ define([ collectionOptions.basePath = this._url; } + var eastNorthUp = featureTable.getGlobalProperty('EAST_NORTH_UP'); + + var center = new Cartesian3(); + var instances = collectionOptions.instances; var instancePosition = new Cartesian3(); var instancePositionArray = new Array(3); @@ -325,22 +334,22 @@ define([ var instanceTransform = new Matrix4(); for (var i = 0; i < instancesLength; i++) { // Get the instance position - var position = featureTableResources.getProperty('POSITION', i, ComponentDatatype.FLOAT, 3); + var position = featureTable.getProperty('POSITION', i, ComponentDatatype.FLOAT, 3); if (!defined(position)) { position = instancePositionArray; - var positionQuantized = featureTableResources.getProperty('POSITION_QUANTIZED', i, ComponentDatatype.UNSIGNED_SHORT, 3); + var positionQuantized = featureTable.getProperty('POSITION_QUANTIZED', i, ComponentDatatype.UNSIGNED_SHORT, 3); //>>includeStart('debug', pragmas.debug); if (!defined(positionQuantized)) { throw new DeveloperError('Either POSITION or POSITION_QUANTIZED must be defined for each instance.'); } //>>includeEnd('debug'); - var quantizedVolumeOffset = featureTableResources.getGlobalProperty('QUANTIZED_VOLUME_OFFSET', ComponentDatatype.FLOAT, 3); + var quantizedVolumeOffset = featureTable.getGlobalProperty('QUANTIZED_VOLUME_OFFSET', ComponentDatatype.FLOAT, 3); //>>includeStart('debug', pragmas.debug); if (!defined(quantizedVolumeOffset)) { throw new DeveloperError('Global property: QUANTIZED_VOLUME_OFFSET must be defined for quantized positions.'); } //>>includeEnd('debug'); - var quantizedVolumeScale = featureTableResources.getGlobalProperty('QUANTIZED_VOLUME_SCALE', ComponentDatatype.FLOAT, 3); + var quantizedVolumeScale = featureTable.getGlobalProperty('QUANTIZED_VOLUME_SCALE', ComponentDatatype.FLOAT, 3); //>>includeStart('debug', pragmas.debug); if (!defined(quantizedVolumeScale)) { throw new DeveloperError('Global property: QUANTIZED_VOLUME_SCALE must be defined for quantized positions.'); @@ -352,10 +361,11 @@ define([ } Cartesian3.unpack(position, 0, instancePosition); instanceTranslationRotationScale.translation = instancePosition; + Cartesian3.add(center, instancePosition, center); // Get the instance rotation - var normalUp = featureTableResources.getProperty('NORMAL_UP', i, ComponentDatatype.FLOAT, 3); - var normalRight = featureTableResources.getProperty('NORMAL_RIGHT', i, ComponentDatatype.FLOAT, 3); + var normalUp = featureTable.getProperty('NORMAL_UP', i, ComponentDatatype.FLOAT, 3); + var normalRight = featureTable.getProperty('NORMAL_RIGHT', i, ComponentDatatype.FLOAT, 3); var hasCustomOrientation = false; if (defined(normalUp)) { //>>includeStart('debug', pragmas.debug); @@ -367,8 +377,8 @@ define([ Cartesian3.unpack(normalRight, 0, instanceNormalRight); hasCustomOrientation = true; } else { - var octNormalUp = featureTableResources.getProperty('NORMAL_UP_OCT32P', i, ComponentDatatype.UNSIGNED_SHORT, 2); - var octNormalRight = featureTableResources.getProperty('NORMAL_RIGHT_OCT32P', i, ComponentDatatype.UNSIGNED_SHORT, 2); + var octNormalUp = featureTable.getProperty('NORMAL_UP_OCT32P', i, ComponentDatatype.UNSIGNED_SHORT, 2); + var octNormalRight = featureTable.getProperty('NORMAL_RIGHT_OCT32P', i, ComponentDatatype.UNSIGNED_SHORT, 2); if (defined(octNormalUp)) { //>>includeStart('debug', pragmas.debug); if (!defined(octNormalRight)) { @@ -378,10 +388,11 @@ define([ AttributeCompression.octDecodeInRange(octNormalUp[0], octNormalUp[1], 65535, instanceNormalUp); AttributeCompression.octDecodeInRange(octNormalRight[0], octNormalRight[1], 65535, instanceNormalRight); hasCustomOrientation = true; - } else { - // Custom orientation is not defined, default to WGS84 + } else if (eastNorthUp) { Transforms.eastNorthUpToFixedFrame(instancePosition, Ellipsoid.WGS84, instanceTransform); Matrix4.getRotation(instanceTransform, instanceRotation); + } else { + Matrix3.clone(Matrix3.IDENTITY, instanceRotation); } } if (hasCustomOrientation) { @@ -398,11 +409,11 @@ define([ instanceScale.x = 1.0; instanceScale.y = 1.0; instanceScale.z = 1.0; - var scale = featureTableResources.getProperty('SCALE', i, ComponentDatatype.FLOAT); + var scale = featureTable.getProperty('SCALE', i, ComponentDatatype.FLOAT); if (defined(scale)) { Cartesian3.multiplyByScalar(instanceScale, scale, instanceScale); } - var nonUniformScale = featureTableResources.getProperty('SCALE_NON_UNIFORM', i, ComponentDatatype.FLOAT, 3); + var nonUniformScale = featureTable.getProperty('SCALE_NON_UNIFORM', i, ComponentDatatype.FLOAT, 3); if (defined(nonUniformScale)) { instanceScale.x *= nonUniformScale[0]; instanceScale.y *= nonUniformScale[1]; @@ -411,7 +422,7 @@ define([ instanceTranslationRotationScale.scale = instanceScale; // Get the batchId - var batchId = featureTableResources.getProperty('BATCH_ID', i , ComponentDatatype.UNSIGNED_SHORT); + var batchId = featureTable.getProperty('BATCH_ID', i , ComponentDatatype.UNSIGNED_SHORT); if (!defined(batchId)) { // If BATCH_ID semantic is undefined, batchId is just the instance number batchId = i; @@ -425,6 +436,9 @@ define([ }; } + center = Cartesian3.divideByScalar(center, instancesLength, center); + collectionOptions.center = center; + var modelInstanceCollection = new ModelInstanceCollection(collectionOptions); this._modelInstanceCollection = modelInstanceCollection; this.state = Cesium3DTileContentState.PROCESSING; @@ -446,7 +460,7 @@ define([ */ Instanced3DModel3DTileContent.prototype.applyDebugSettings = function(enabled, color) { color = enabled ? color : Color.WHITE; - this.batchTableResources.setAllColor(color); + this.batchTable.setAllColor(color); }; /** @@ -455,13 +469,14 @@ define([ Instanced3DModel3DTileContent.prototype.update = function(tileset, frameState) { var oldAddCommand = frameState.addCommand; if (frameState.passes.render) { - frameState.addCommand = this.batchTableResources.getAddCommand(); + frameState.addCommand = this.batchTable.getAddCommand(); } // In the PROCESSING state we may be calling update() to move forward // the content's resource loading. In the READY state, it will // actually generate commands. - this.batchTableResources.update(tileset, frameState); + this.batchTable.update(tileset, frameState); + this._modelInstanceCollection.transform = this._tile.computedTransform; this._modelInstanceCollection.update(frameState); frameState.addCommand = oldAddCommand; @@ -479,7 +494,7 @@ define([ */ Instanced3DModel3DTileContent.prototype.destroy = function() { this._modelInstanceCollection = this._modelInstanceCollection && this._modelInstanceCollection.destroy(); - this.batchTableResources = this.batchTableResources && this.batchTableResources.destroy(); + this.batchTable = this.batchTable && this.batchTable.destroy(); return destroyObject(this); }; diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index 4ab67cbc522e..744f179b8f79 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -51,7 +51,7 @@ define([ '../ThirdParty/gltfDefaults', '../ThirdParty/Uri', '../ThirdParty/when', - './getModelAccessor', + './getBinaryAccessor', './HeightReference', './JobType', './ModelAnimationCache', @@ -115,7 +115,7 @@ define([ gltfDefaults, Uri, when, - getModelAccessor, + getBinaryAccessor, HeightReference, JobType, ModelAnimationCache, @@ -2368,7 +2368,7 @@ define([ attributes.push({ index : attributeLocation, vertexBuffer : rendererBuffers[a.bufferView], - componentsPerAttribute : getModelAccessor(a).componentsPerAttribute, + componentsPerAttribute : getBinaryAccessor(a).componentsPerAttribute, componentDatatype : componentType, normalize : false, offsetInBytes : a.byteOffset, @@ -3076,7 +3076,7 @@ define([ else { var positions = accessors[primitive.attributes.POSITION]; count = positions.count; - var accessorInfo = getModelAccessor(positions); + var accessorInfo = getBinaryAccessor(positions); offset = (positions.byteOffset / (accessorInfo.componentsPerAttribute*ComponentDatatype.getSizeInBytes(positions.componentType))); } diff --git a/Source/Scene/ModelAnimationCache.js b/Source/Scene/ModelAnimationCache.js index 9fa635e4c6be..d19ce82e4a52 100644 --- a/Source/Scene/ModelAnimationCache.js +++ b/Source/Scene/ModelAnimationCache.js @@ -8,7 +8,7 @@ define([ '../Core/Quaternion', '../Core/QuaternionSpline', '../Renderer/WebGLConstants', - './getModelAccessor' + './getBinaryAccessor' ], function( Cartesian3, defaultValue, @@ -18,7 +18,7 @@ define([ Quaternion, QuaternionSpline, WebGLConstants, - getModelAccessor) { + getBinaryAccessor) { 'use strict'; /** @@ -36,7 +36,7 @@ define([ var buffer = buffers[bufferView.buffer]; var byteOffset = bufferView.byteOffset + accessor.byteOffset; - var byteLength = accessor.count * getModelAccessor(accessor).componentsPerAttribute; + var byteLength = accessor.count * getBinaryAccessor(accessor).componentsPerAttribute; // buffer.path will be undefined when animations are embedded. return model.cacheKey + '//' + defaultValue(buffer.path, '') + '/' + byteOffset + '/' + byteLength; @@ -67,7 +67,7 @@ define([ // Convert typed array to Cesium types var buffer = loadResources.getBuffer(bufferView); - var typedArray = getModelAccessor(accessor).createArrayBufferView(buffer.buffer, buffer.byteOffset + accessor.byteOffset, count); + var typedArray = getBinaryAccessor(accessor).createArrayBufferView(buffer.buffer, buffer.byteOffset + accessor.byteOffset, count); var i; if ((componentType === WebGLConstants.FLOAT) && (type === 'SCALAR')) { @@ -180,7 +180,7 @@ define([ var type = accessor.type; var count = accessor.count; var buffer = loadResources.getBuffer(bufferView); - var typedArray = getModelAccessor(accessor).createArrayBufferView(buffer.buffer, buffer.byteOffset + accessor.byteOffset, count); + var typedArray = getBinaryAccessor(accessor).createArrayBufferView(buffer.buffer, buffer.byteOffset + accessor.byteOffset, count); matrices = new Array(count); if ((componentType === WebGLConstants.FLOAT) && (type === 'MAT4')) { diff --git a/Source/Scene/ModelInstanceCollection.js b/Source/Scene/ModelInstanceCollection.js index cd618f6f5eb7..4ca06f503797 100644 --- a/Source/Scene/ModelInstanceCollection.js +++ b/Source/Scene/ModelInstanceCollection.js @@ -56,6 +56,11 @@ define([ * @constructor * * @param {Object} options Object with the following properties: + * @param {Object[]} [options.instances] An array of instances, where each instance contains a modelMatrix and optional batchId when options.batchTable is defined. + * @param {Cesium3DTileBatchTable} [options.batchTable] The batch table of the instanced 3D Tile. + * @param {Object} [options.boundingVolume] The bounding volume, typically the bounding volume of the 3D Tile. + * @param {Cartesian3} [options.center] The center point of the instances. + * @param {Matrix4} [options.transform=Matrix4.IDENTITY] An additional transform to apply to all instances, typically the transform of the 3D Tile. * @param {String} [options.url] The url to the .gltf file. * @param {Object} [options.headers] HTTP headers to send with the request. * @param {Object} [options.requestType] The request type, used for budget scheduling in {@link RequestScheduler}. @@ -100,25 +105,24 @@ define([ // When the model instance collection is backed by an instanced 3d-tile, // use its batch table resources to modify the shaders, attributes, and uniform maps. - this._batchTableResources = options.batchTableResources; + this._batchTable = options.batchTable; this._model = undefined; - this._vertexBufferValues = undefined; + this._vertexBufferData = undefined; // Hold onto the vertex buffer data when dynamic is true this._vertexBuffer = undefined; - this._createVertexBuffer = true; - this._vertexBufferDirty = false; + this._batchIdBuffer = undefined; this._instancedUniformsByProgram = undefined; - // Set to true if nodes in the model have off-center transforms. When false, the vertex shader can be optimized. - this._offCenter = undefined; - this._drawCommands = []; this._pickCommands = []; this._modelCommands = undefined; - this._boundingVolume = options.boundingVolume; - this._boundingVolumeModelView = new Matrix4(); - this._boundingVolumeExpand = !defined(options.boundingVolume); + this._boundingVolume = defined(options.boundingVolume) ? options.boundingVolume : createBoundingSphere(this); + this._boundingVolumeExpand = !defined(options.boundingVolume); // Expand the bounding volume by the radius of the loaded model + + this._center = defaultValue(options.center, this._boundingVolume.center); + this.transform = defined(options.transform) ? options.transform : Matrix4.clone(Matrix4.IDENTITY); + this._rtcViewTransform = new Matrix4(); // Holds onto uniform // Passed on to Model this._url = options.url; @@ -163,23 +167,14 @@ define([ } }); - // TODO : maybe this whole step should be a pre-process as part of the 3d tile toolchain - function isOffCenter(collection) { - if (defined(collection._offCenter)) { - return collection._offCenter; + function createBoundingSphere(collection) { + var instancesLength = collection.length; + var points = new Array(instancesLength); + for (var i = 0; i < instancesLength; ++i) { + points[i] = Matrix4.getTranslation(collection._instances[i].modelMatrix, new Cartesian3()); } - var nodes = collection._model._runtime.nodes; - for (var name in nodes) { - if (nodes.hasOwnProperty(name)) { - if(!Matrix4.equalsEpsilon(nodes[name].publicNode._matrix, Matrix4.IDENTITY, CesiumMath.EPSILON2)) { - collection._offCenter = true; - return true; - } - } - } - collection._offCenter = false; - return false; + return BoundingSphere.fromPoints(points); } function getInstancedUniforms(collection, programName) { @@ -188,6 +183,7 @@ define([ } var instancedUniformsByProgram = {}; + collection._instancedUniformsByProgram = instancedUniformsByProgram; var modelSemantics = ['MODEL', 'MODELVIEW', 'MODELVIEWPROJECTION', 'MODELINVERSE', 'MODELVIEWINVERSE', 'MODELVIEWPROJECTIONINVERSE', 'MODELINVERSETRANSPOSE', 'MODELVIEWINVERSETRANSPOSE']; var supportedSemantics = ['MODELVIEW', 'MODELVIEWPROJECTION', 'MODELVIEWINVERSETRANSPOSE']; @@ -229,7 +225,6 @@ define([ } } - collection._instancedUniformsByProgram = instancedUniformsByProgram; return instancedUniformsByProgram[programName]; } @@ -238,9 +233,7 @@ define([ function getVertexShaderCallback(collection) { return function(vs, programName) { var instancedUniforms = getInstancedUniforms(collection, programName); - var dynamic = collection._dynamic; - var offCenter = isOffCenter(collection); - var regex; + var usesBatchTable = defined(collection._batchTable); var renamedSource = ShaderSource.replaceMain(vs, 'czm_old_main'); @@ -263,7 +256,7 @@ define([ } // Remove the uniform declaration - regex = new RegExp('uniform.*' + uniform + '.*'); + var regex = new RegExp('uniform.*' + uniform + '.*'); renamedSource = renamedSource.replace(regex, ''); // Replace all occurrences of the uniform with the global variable @@ -272,29 +265,13 @@ define([ } } - var uniforms = ''; - if (!dynamic) { - uniforms += 'uniform mat4 czm_instanced_collectionModelView;\n'; - } - if (offCenter) { - uniforms += 'uniform mat4 czm_instanced_nodeTransform;\n'; - } - - // When dynamic, czm_instanced_model is the modelView matrix. - // Otherwise, czm_instanced_model is the model's local offset from the bounding volume. + // czm_instanced_model is the model matrix of the instance relative to center + // czm_instanced_modifiedModelView is the transform from the center to view // czm_instanced_nodeTransform is the local offset of the node within the model - var modelView = ''; - if (dynamic && offCenter) { - modelView = 'czm_instanced_modelView = czm_instanced_model * czm_instanced_nodeTransform;\n'; - } else if (dynamic && !offCenter) { - modelView = 'czm_instanced_modelView = czm_instanced_model;\n'; - } else if (!dynamic && offCenter) { - modelView = 'czm_instanced_modelView = czm_instanced_collectionModelView * czm_instanced_model * czm_instanced_nodeTransform;\n'; - } else if (!dynamic && !offCenter) { - modelView = 'czm_instanced_modelView = czm_instanced_collectionModelView * czm_instanced_model;\n'; - } + var uniforms = + 'uniform mat4 czm_instanced_modifiedModelView;\n' + + 'uniform mat4 czm_instanced_nodeTransform;\n'; - var usesBatchTable = defined(collection._batchTableResources); var batchIdAttribute = usesBatchTable ? 'attribute float a_batchId;\n' : ''; var instancedSource = @@ -309,7 +286,7 @@ define([ 'void main()\n' + '{\n' + ' mat4 czm_instanced_model = mat4(czm_modelMatrixRow0.x, czm_modelMatrixRow1.x, czm_modelMatrixRow2.x, 0.0, czm_modelMatrixRow0.y, czm_modelMatrixRow1.y, czm_modelMatrixRow2.y, 0.0, czm_modelMatrixRow0.z, czm_modelMatrixRow1.z, czm_modelMatrixRow2.z, 0.0, czm_modelMatrixRow0.w, czm_modelMatrixRow1.w, czm_modelMatrixRow2.w, 1.0);\n' + - modelView + + ' czm_instanced_modelView = czm_instanced_modifiedModelView * czm_instanced_model * czm_instanced_nodeTransform;\n' + globalVarsMain + ' czm_old_main();\n' + '}'; @@ -317,7 +294,7 @@ define([ vertexShaderCached = instancedSource; if (usesBatchTable) { - instancedSource = collection._batchTableResources.getVertexShaderCallback()(instancedSource); + instancedSource = collection._batchTable.getVertexShaderCallback()(instancedSource); } return instancedSource; @@ -326,8 +303,8 @@ define([ function getFragmentShaderCallback(collection) { return function(fs) { - if (defined(collection._batchTableResources)) { - fs = collection._batchTableResources.getFragmentShaderCallback()(fs); + if (defined(collection._batchTable)) { + fs = collection._batchTable.getFragmentShaderCallback()(fs); } return fs; }; @@ -337,8 +314,8 @@ define([ return function (vs) { // Use the vertex shader that was generated earlier vs = vertexShaderCached; - if (defined(collection._batchTableResources)) { - vs = collection._batchTableResources.getPickVertexShaderCallback()(vs); + if (defined(collection._batchTable)) { + vs = collection._batchTable.getPickVertexShaderCallback()(vs); } return vs; }; @@ -346,16 +323,17 @@ define([ function getPickFragmentShaderCallback(collection) { return function(fs) { - if (defined(collection._batchTableResources)) { - fs = collection._batchTableResources.getPickFragmentShaderCallback()(fs); + if (defined(collection._batchTable)) { + fs = collection._batchTable.getPickFragmentShaderCallback()(fs); } return fs; }; } - function createBoundsModelViewFunction(collection, context) { + function createModifiedModelView(collection, context) { return function() { - return Matrix4.multiplyByTranslation(context.uniformState.view, collection._boundingVolume.center, collection._boundingVolumeModelView); + var rtcTransform = Matrix4.multiplyByTranslation(collection.transform, collection._center, scratchMatrix); + return Matrix4.multiply(context.uniformState.view, rtcTransform, collection._rtcViewTransform); }; } @@ -368,14 +346,8 @@ define([ function getUniformMapCallback(collection, context) { return function(uniformMap, programName, node) { uniformMap = clone(uniformMap); - - if (!collection._dynamic) { - uniformMap.czm_instanced_collectionModelView = createBoundsModelViewFunction(collection, context); - } - - if (isOffCenter(collection)) { - uniformMap.czm_instanced_nodeTransform = createNodeTransformFunction(node); - } + uniformMap.czm_instanced_modifiedModelView = createModifiedModelView(collection, context); + uniformMap.czm_instanced_nodeTransform = createNodeTransformFunction(node); // Remove instanced uniforms from the uniform map var instancedUniforms = getInstancedUniforms(collection, programName); @@ -385,8 +357,8 @@ define([ } } - if (defined(collection._batchTableResources)) { - uniformMap = collection._batchTableResources.getUniformMapCallback()(uniformMap); + if (defined(collection._batchTable)) { + uniformMap = collection._batchTable.getUniformMapCallback()(uniformMap); } return uniformMap; @@ -396,8 +368,8 @@ define([ function getPickUniformMapCallback(collection) { return function(uniformMap) { // Uses the uniform map generated from getUniformMapCallback - if (defined(collection._batchTableResources)) { - uniformMap = collection._batchTableResources.getPickUniformMapCallback()(uniformMap); + if (defined(collection._batchTable)) { + uniformMap = collection._batchTable.getPickUniformMapCallback()(uniformMap); } return uniformMap; }; @@ -405,8 +377,8 @@ define([ function getVertexShaderNonInstancedCallback(collection) { return function(vs) { - if (defined(collection._batchTableResources)) { - vs = collection._batchTableResources.getVertexShaderCallback()(vs); + if (defined(collection._batchTable)) { + vs = collection._batchTable.getVertexShaderCallback()(vs); // Treat a_batchId as a uniform rather than a vertex attribute vs = 'uniform float a_batchId\n;' + vs; } @@ -416,8 +388,8 @@ define([ function getPickVertexShaderNonInstancedCallback(collection) { return function(vs) { - if (defined(collection._batchTableResources)) { - vs = collection._batchTableResources.getPickVertexShaderCallback()(vs); + if (defined(collection._batchTable)) { + vs = collection._batchTable.getPickVertexShaderCallback()(vs); // Treat a_batchId as a uniform rather than a vertex attribute vs = 'uniform float a_batchId\n;' + vs; } @@ -427,95 +399,88 @@ define([ function getUniformMapNonInstancedCallback(collection) { return function(uniformMap) { - if (defined(collection._batchTableResources)) { - uniformMap = collection._batchTableResources.getUniformMapCallback()(uniformMap); + if (defined(collection._batchTable)) { + uniformMap = collection._batchTable.getUniformMapCallback()(uniformMap); } return uniformMap; }; } - var instanceMatrix = new Matrix4(); - - function updateVertexBuffer(collection, context) { - if (!collection._instancingSupported) { - return; - } - - var instanceBufferData = collection._vertexBufferValues; - var vertexBuffer = collection._vertexBuffer; - var createVertexBuffer = collection._createVertexBuffer; + var scratchMatrix = new Matrix4(); + function getVertexBufferData(collection, context, result) { + var instances = collection._instances; var instancesLength = collection.length; - var dynamic = collection._dynamic; - var viewMatrix = context.uniformState.view; - var center = dynamic ? Cartesian3.ZERO : collection._boundingVolume.center; + var collectionCenter = collection._center; + var vertexSizeInFloats = 12; - // When using a batch table, add a batch id attribute to each vertex - var usesBatchTable = defined(collection._batchTableResources); - var vertexSizeInFloats = usesBatchTable ? 13 : 12; - - if (createVertexBuffer) { - instanceBufferData = new Float32Array(instancesLength * vertexSizeInFloats); + if (!defined(result)) { + result = new Float32Array(instancesLength * vertexSizeInFloats); } for (var i = 0; i < instancesLength; ++i) { - var instance = collection._instances[i]; - var modelMatrix = instance.modelMatrix; + var modelMatrix = instances[i].modelMatrix; - if (dynamic) { - Matrix4.multiplyTransformation(viewMatrix, modelMatrix, instanceMatrix); - } else { - instanceMatrix = modelMatrix; - } + // Instance matrix is relative to center + var instanceMatrix = Matrix4.clone(modelMatrix, scratchMatrix); + instanceMatrix[12] -= collectionCenter.x; + instanceMatrix[13] -= collectionCenter.y; + instanceMatrix[14] -= collectionCenter.z; var offset = i * vertexSizeInFloats; // First three rows of the model matrix - instanceBufferData[offset + 0] = instanceMatrix[0]; - instanceBufferData[offset + 1] = instanceMatrix[4]; - instanceBufferData[offset + 2] = instanceMatrix[8]; - instanceBufferData[offset + 3] = instanceMatrix[12] - center.x; - instanceBufferData[offset + 4] = instanceMatrix[1]; - instanceBufferData[offset + 5] = instanceMatrix[5]; - instanceBufferData[offset + 6] = instanceMatrix[9]; - instanceBufferData[offset + 7] = instanceMatrix[13] - center.y; - instanceBufferData[offset + 8] = instanceMatrix[2]; - instanceBufferData[offset + 9] = instanceMatrix[6]; - instanceBufferData[offset + 10] = instanceMatrix[10]; - instanceBufferData[offset + 11] = instanceMatrix[14] - center.z; - - if (usesBatchTable) { - instanceBufferData[offset + 12] = instance.batchId; - } + result[offset + 0] = instanceMatrix[0]; + result[offset + 1] = instanceMatrix[4]; + result[offset + 2] = instanceMatrix[8]; + result[offset + 3] = instanceMatrix[12]; + result[offset + 4] = instanceMatrix[1]; + result[offset + 5] = instanceMatrix[5]; + result[offset + 6] = instanceMatrix[9]; + result[offset + 7] = instanceMatrix[13]; + result[offset + 8] = instanceMatrix[2]; + result[offset + 9] = instanceMatrix[6]; + result[offset + 10] = instanceMatrix[10]; + result[offset + 11] = instanceMatrix[14]; } - if (createVertexBuffer) { - vertexBuffer = Buffer.createVertexBuffer({ - context : context, - typedArray : instanceBufferData, - usage : dynamic ? BufferUsage.STREAM_DRAW : BufferUsage.STATIC_DRAW - }); - collection._vertexBuffer = vertexBuffer; - collection._vertexBufferValues = instanceBufferData; - collection._createVertexBuffer = false; - } else { - vertexBuffer.copyFromArrayView(instanceBufferData); - } + return result; } - function createBoundingVolume(collection) { - if (!defined(collection._boundingVolume)) { - var instancesLength = collection.length; - var points = new Array(instancesLength); + function createVertexBuffer(collection, context) { + var instances = collection._instances; + var instancesLength = collection.length; + var dynamic = collection._dynamic; + var usesBatchTable = defined(collection._batchTable); + + if (usesBatchTable) { + var batchIdBufferData = new Uint16Array(instancesLength); for (var i = 0; i < instancesLength; ++i) { - points[i] = Matrix4.getTranslation(collection._instances[i].modelMatrix, new Cartesian3()); + batchIdBufferData[i] = instances[i].batchId; } + collection._batchIdBuffer = Buffer.createVertexBuffer({ + context : context, + typedArray : batchIdBufferData, + usage : BufferUsage.STATIC_DRAW + }); + } - var boundingSphere = new BoundingSphere(); - BoundingSphere.fromPoints(points, boundingSphere); - collection._boundingVolume = boundingSphere; + var vertexBufferData = getVertexBufferData(collection, context); + if (dynamic) { + // Hold onto the buffer data so we don't have to allocate new memory every frame. + collection._vertexBufferData = vertexBufferData; } + collection._vertexBuffer = Buffer.createVertexBuffer({ + context : context, + typedArray : vertexBufferData, + usage : dynamic ? BufferUsage.STREAM_DRAW : BufferUsage.STATIC_DRAW + }); + } + + function updateVertexBuffer(collection, context) { + var vertexBufferData = getVertexBufferData(collection, context, collection._vertexBufferData); + collection._vertexBuffer.copyFromArrayView(vertexBufferData); } function createModel(collection, context) { @@ -539,13 +504,11 @@ define([ ignoreCommands : true }; - createBoundingVolume(collection); - if (instancingSupported) { - updateVertexBuffer(collection, context); + createVertexBuffer(collection, context); - var usesBatchTable = defined(collection._batchTableResources); - var vertexSizeInFloats = usesBatchTable ? 13 : 12; + var usesBatchTable = defined(collection._batchTable); + var vertexSizeInFloats = 12; var componentSizeInBytes = ComponentDatatype.getSizeInBytes(ComponentDatatype.FLOAT); var instancedAttributes = { @@ -585,12 +548,12 @@ define([ if (usesBatchTable) { instancedAttributes.a_batchId = { index : 0, // updated in Model - vertexBuffer : collection._vertexBuffer, + vertexBuffer : collection._batchIdBuffer, componentsPerAttribute : 1, - componentDatatype : ComponentDatatype.FLOAT, + componentDatatype : ComponentDatatype.UNSIGNED_SHORT, normalize : false, - offsetInBytes : componentSizeInBytes * 12, - strideInBytes : componentSizeInBytes * vertexSizeInFloats, + offsetInBytes : 0, + strideInBytes : 0, instanceDivisor : 1 }; } @@ -622,72 +585,6 @@ define([ } } - function createBatchIdFunction(batchId) { - return function() { - return batchId; - }; - } - - function createCommands(collection, drawCommands, pickCommands) { - collection._modelCommands = drawCommands; - - var i; - var j; - var command; - var commandsLength = drawCommands.length; - var instancesLength = collection.length; - var allowPicking = collection.allowPicking; - var usesBatchTable = defined(collection._batchTableResources); - - var boundingVolume = collection._boundingVolume; - - if (collection._instancingSupported) { - for (i = 0; i < commandsLength; ++i) { - command = clone(drawCommands[i]); - command.instanceCount = instancesLength; - command.boundingVolume = boundingVolume; - command.cull = collection._cull; - collection._drawCommands.push(command); - - if (allowPicking) { - command = clone(pickCommands[i]); - command.instanceCount = instancesLength; - command.boundingVolume = boundingVolume; - command.cull = collection._cull; - collection._pickCommands.push(command); - } - } - } else { - // When instancing is disabled, create commands for every instance. - var instances = collection._instances; - for (i = 0; i < commandsLength; ++i) { - for (j = 0; j < instancesLength; ++j) { - command = clone(drawCommands[i]); - command.modelMatrix = new Matrix4(); - command.boundingVolume = new BoundingSphere(); - command.cull = collection._cull; - command.uniformMap = clone(command.uniformMap); - if (usesBatchTable) { - command.uniformMap.a_batchId = createBatchIdFunction(instances[j].batchId); - } - collection._drawCommands.push(command); - - if (allowPicking) { - command = clone(pickCommands[i]); - command.modelMatrix = new Matrix4(); - command.boundingVolume = new BoundingSphere(); - command.cull = collection._cull; - command.uniformMap = clone(command.uniformMap); - if (usesBatchTable) { - command.uniformMap.a_batchId = createBatchIdFunction(instances[j].batchId); - } - collection._pickCommands.push(command); - } - } - } - } - } - function updateWireframe(collection) { if (collection._debugWireframe !== collection.debugWireframe) { collection._debugWireframe = collection.debugWireframe; @@ -714,12 +611,73 @@ define([ } } - function updateCommands(collection) { - // Only applies when instancing is disabled. The instanced shader handles node transformations. - if (collection._instancingSupported) { - return; + function createCommands(collection, drawCommands, pickCommands) { + var commandsLength = drawCommands.length; + var instancesLength = collection.length; + var allowPicking = collection.allowPicking; + var boundingVolume = collection._boundingVolume; + var cull = collection._cull; + + for (var i = 0; i < commandsLength; ++i) { + var drawCommand = DrawCommand.shallowClone(drawCommands[i]); + drawCommand.instanceCount = instancesLength; + drawCommand.boundingVolume = boundingVolume; + drawCommand.cull = cull; + collection._drawCommands.push(drawCommand); + + if (allowPicking) { + var pickCommand = DrawCommand.shallowClone(pickCommands[i]); + pickCommand.instanceCount = instancesLength; + pickCommand.boundingVolume = boundingVolume; + pickCommand.cull = cull; + collection._pickCommands.push(pickCommand); + } } + } + + function createBatchIdFunction(batchId) { + return function() { + return batchId; + }; + } + + function createCommandsNonInstanced(collection, drawCommands, pickCommands) { + // When instancing is disabled, create commands for every instance. + var instances = collection._instances; + var commandsLength = drawCommands.length; + var instancesLength = collection.length; + var allowPicking = collection.allowPicking; + var usesBatchTable = defined(collection._batchTable); + var cull = collection._cull; + + for (var i = 0; i < commandsLength; ++i) { + for (var j = 0; j < instancesLength; ++j) { + var drawCommand = DrawCommand.shallowClone(drawCommands[i]); + drawCommand.modelMatrix = new Matrix4(); // Updated in updateNonInstancedCommands + drawCommand.boundingVolume = new BoundingSphere(); // Updated in updateNonInstancedCommands + drawCommand.cull = cull; + drawCommand.uniformMap = clone(drawCommand.uniformMap); + if (usesBatchTable) { + drawCommand.uniformMap.a_batchId = createBatchIdFunction(instances[j].batchId); + } + collection._drawCommands.push(drawCommand); + if (allowPicking) { + var pickCommand = DrawCommand.shallowClone(pickCommands[i]); + pickCommand.modelMatrix = new Matrix4(); // Updated in updateNonInstancedCommands + pickCommand.boundingVolume = new BoundingSphere(); // Updated in updateNonInstancedCommands + pickCommand.cull = cull; + pickCommand.uniformMap = clone(pickCommand.uniformMap); + if (usesBatchTable) { + pickCommand.uniformMap.a_batchId = createBatchIdFunction(instances[j].batchId); + } + collection._pickCommands.push(pickCommand); + } + } + } + } + + function updateCommandsNonInstanced(collection) { var modelCommands = collection._modelCommands; var commandsLength = modelCommands.length; var instancesLength = collection.length; @@ -730,10 +688,12 @@ define([ for (var j = 0; j < instancesLength; ++j) { var commandIndex = i * instancesLength + j; var drawCommand = collection._drawCommands[commandIndex]; + var collectionTransform = collection.transform; var instanceMatrix = collection._instances[j].modelMatrix; + instanceMatrix = Matrix4.multiply(collectionTransform, instanceMatrix, scratchMatrix); var nodeMatrix = modelCommand.modelMatrix; var modelMatrix = drawCommand.modelMatrix; - Matrix4.multiplyTransformation(instanceMatrix, nodeMatrix, modelMatrix); + Matrix4.multiply(instanceMatrix, nodeMatrix, modelMatrix); var nodeBoundingSphere = modelCommand.boundingVolume; var boundingSphere = drawCommand.boundingVolume; @@ -783,10 +743,10 @@ define([ } var context = frameState.context; - this._instancingSupported = context.instancedArrays; if (this._state === LoadState.NEEDS_LOAD) { this._state = LoadState.LOADING; + this._instancingSupported = context.instancedArrays; createModel(this, context); var that = this; this._model.readyPromise.otherwise(function(error) { @@ -795,6 +755,7 @@ define([ }); } + var instancingSupported = this._instancingSupported; var model = this._model; model.update(frameState); @@ -808,8 +769,14 @@ define([ } var modelCommands = getModelCommands(model); - createCommands(this, modelCommands.draw, modelCommands.pick); - updateCommands(this); + this._modelCommands = modelCommands.draw; + + if (instancingSupported) { + createCommands(this, modelCommands.draw, modelCommands.pick); + } else { + createCommandsNonInstanced(this, modelCommands.draw, modelCommands.pick); + updateCommandsNonInstanced(this); + } this._readyPromise.resolve(this); return; @@ -821,13 +788,14 @@ define([ // If any node changes due to an animation, update the commands. This could be inefficient if the model is // composed of many nodes and only one changes, however it is probably fine in the general use case. - if (model.dirty) { - updateCommands(this); + // Only applies when instancing is disabled. The instanced shader automatically handles node transformations. + if (!instancingSupported && model.dirty) { + updateCommandsNonInstanced(this); } - if (this._dynamic || this._vertexBufferDirty) { + // Dynamic instances need to update every frame. + if (instancingSupported && this._dynamic) { updateVertexBuffer(this, context); - this._vertexBufferDirty = false; } updateWireframe(this); diff --git a/Source/Scene/PointCloud3DTileContent.js b/Source/Scene/PointCloud3DTileContent.js new file mode 100644 index 000000000000..33f266e52a28 --- /dev/null +++ b/Source/Scene/PointCloud3DTileContent.js @@ -0,0 +1,918 @@ +/*global define*/ +define([ + '../Core/Cartesian3', + '../Core/Color', + '../Core/combine', + '../Core/ComponentDatatype', + '../Core/defaultValue', + '../Core/defined', + '../Core/destroyObject', + '../Core/defineProperties', + '../Core/DeveloperError', + '../Core/getMagic', + '../Core/getStringFromTypedArray', + '../Core/loadArrayBuffer', + '../Core/Matrix3', + '../Core/Matrix4', + '../Core/PrimitiveType', + '../Core/Request', + '../Core/RequestScheduler', + '../Core/RequestType', + '../Renderer/Buffer', + '../Renderer/BufferUsage', + '../Renderer/DrawCommand', + '../Renderer/RenderState', + '../Renderer/ShaderSource', + '../Renderer/ShaderProgram', + '../Renderer/VertexArray', + '../Renderer/WebGLConstants', + '../ThirdParty/when', + './BlendingState', + './Cesium3DTileBatchTable', + './Cesium3DTileContentState', + './Cesium3DTileFeature', + './Cesium3DTileFeatureTable', + './Pass' + ], function( + Cartesian3, + Color, + combine, + ComponentDatatype, + defaultValue, + defined, + destroyObject, + defineProperties, + DeveloperError, + getMagic, + getStringFromTypedArray, + loadArrayBuffer, + Matrix3, + Matrix4, + PrimitiveType, + Request, + RequestScheduler, + RequestType, + Buffer, + BufferUsage, + DrawCommand, + RenderState, + ShaderSource, + ShaderProgram, + VertexArray, + WebGLConstants, + when, + BlendingState, + Cesium3DTileBatchTable, + Cesium3DTileContentState, + Cesium3DTileFeature, + Cesium3DTileFeatureTable, + Pass) { + 'use strict'; + + /** + * Represents the contents of a + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/PointCloud/README.md|Points} + * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles} tileset. + * + * @alias PointCloud3DTileContent + * @constructor + * + * @private + */ + function PointCloud3DTileContent(tileset, tile, url) { + this._url = url; + this._tileset = tileset; + this._tile = tile; + + // Hold onto the payload until the render resources are created + this._parsedContent = undefined; + + this._drawCommand = undefined; + this._pickCommand = undefined; + this._pickId = undefined; // Only defined when batchTable is undefined + this._isTranslucent = false; + this._constantColor = Color.clone(Color.WHITE); + this._rtcCenter = undefined; + + this._opaqueRenderState = undefined; + this._translucentRenderState = undefined; + + this._highlightColor = this._constantColor; + this._pointSize = 2.0; + this._quantizedVolumeScale = undefined; + this._quantizedVolumeOffset = undefined; + + /** + * The following properties are part of the {@link Cesium3DTileContent} interface. + */ + this.state = Cesium3DTileContentState.UNLOADED; + this.batchTable = undefined; + this.featurePropertiesDirty = false; + + this._contentReadyToProcessPromise = when.defer(); + this._readyPromise = when.defer(); + this._features = undefined; + } + + defineProperties(PointCloud3DTileContent.prototype, { + /** + * Part of the {@link Cesium3DTileContent} interface. + */ + featuresLength : { + get : function() { + if (defined(this.batchTable)) { + return this.batchTable.featuresLength; + } + return 0; + } + }, + + /** + * Part of the {@link Cesium3DTileContent} interface. + */ + innerContents : { + get : function() { + return undefined; + } + }, + + /** + * Part of the {@link Cesium3DTileContent} interface. + */ + contentReadyToProcessPromise : { + get : function() { + return this._contentReadyToProcessPromise.promise; + } + }, + + /** + * Part of the {@link Cesium3DTileContent} interface. + */ + readyPromise : { + get : function() { + return this._readyPromise.promise; + } + } + }); + + function createFeatures(content) { + var tileset = content._tileset; + var featuresLength = content.featuresLength; + if (!defined(content._features) && (featuresLength > 0)) { + var features = new Array(featuresLength); + for (var i = 0; i < featuresLength; ++i) { + features[i] = new Cesium3DTileFeature(tileset, content, i); + } + content._features = features; + } + } + + /** + * Part of the {@link Cesium3DTileContent} interface. + */ + PointCloud3DTileContent.prototype.hasProperty = function(name) { + if (defined(this.batchTable)) { + return this.batchTable.hasProperty(name); + } + return false; + }; + + /** + * Part of the {@link Cesium3DTileContent} interface. + * + * In this context a feature refers to a group of points that share the same BATCH_ID. + * For example all the points that represent a door in a house point cloud would be a feature. + * + * Features are backed by a batch table, and can be colored, shown/hidden, picked, etc like features + * in b3dm and i3dm. + * + * When the BATCH_ID semantic is omitted and the point cloud stores per-point properties, they + * are not accessible by getFeature. They are only used for dynamic styling. + */ + PointCloud3DTileContent.prototype.getFeature = function(batchId) { + if (defined(this.batchTable)) { + var featuresLength = this.featuresLength; + //>>includeStart('debug', pragmas.debug); + if (!defined(batchId) || (batchId < 0) || (batchId >= featuresLength)) { + throw new DeveloperError('batchId is required and between zero and featuresLength - 1 (' + (featuresLength - 1) + ').'); + } + //>>includeEnd('debug'); + createFeatures(this); + return this._features[batchId]; + } + return undefined; + }; + + var sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT; + + /** + * Part of the {@link Cesium3DTileContent} interface. + */ + PointCloud3DTileContent.prototype.request = function() { + var that = this; + + var distance = this._tile.distanceToCamera; + var promise = RequestScheduler.schedule(new Request({ + url : this._url, + server : this._tile.requestServer, + requestFunction : loadArrayBuffer, + type : RequestType.TILES3D, + distance : distance + })); + + if (!defined(promise)) { + return false; + } + + this.state = Cesium3DTileContentState.LOADING; + promise.then(function(arrayBuffer) { + if (that.isDestroyed()) { + return when.reject('tileset is destroyed'); + } + that.initialize(arrayBuffer); + }).otherwise(function(error) { + that.state = Cesium3DTileContentState.FAILED; + that._readyPromise.reject(error); + }); + return true; + }; + + /** + * Part of the {@link Cesium3DTileContent} interface. + */ + PointCloud3DTileContent.prototype.initialize = function(arrayBuffer, byteOffset) { + byteOffset = defaultValue(byteOffset, 0); + + var uint8Array = new Uint8Array(arrayBuffer); + var magic = getMagic(uint8Array, byteOffset); + if (magic !== 'pnts') { + throw new DeveloperError('Invalid Points tile. Expected magic=pnts. Read magic=' + magic); + } + + var view = new DataView(arrayBuffer); + byteOffset += sizeOfUint32; // Skip magic number + + //>>includeStart('debug', pragmas.debug); + var version = view.getUint32(byteOffset, true); + if (version !== 1) { + throw new DeveloperError('Only Points tile version 1 is supported. Version ' + version + ' is not.'); + } + //>>includeEnd('debug'); + byteOffset += sizeOfUint32; + + // Skip byteLength + byteOffset += sizeOfUint32; + + var featureTableJsonByteLength = view.getUint32(byteOffset, true); + //>>includeStart('debug', pragmas.debug); + if (featureTableJsonByteLength === 0) { + throw new DeveloperError('Feature table must have a byte length greater than zero'); + } + //>>includeEnd('debug'); + byteOffset += sizeOfUint32; + + var featureTableBinaryByteLength = view.getUint32(byteOffset, true); + byteOffset += sizeOfUint32; + + var batchTableJsonByteLength = view.getUint32(byteOffset, true); + byteOffset += sizeOfUint32; + var batchTableBinaryByteLength = view.getUint32(byteOffset, true); + byteOffset += sizeOfUint32; + + var featureTableString = getStringFromTypedArray(uint8Array, byteOffset, featureTableJsonByteLength); + var featureTableJson = JSON.parse(featureTableString); + byteOffset += featureTableJsonByteLength; + + var featureTableBinary = new Uint8Array(arrayBuffer, byteOffset, featureTableBinaryByteLength); + byteOffset += featureTableBinaryByteLength; + + // Get the batch table JSON and binary + var batchTableJson; + var batchTableBinary; + if (batchTableJsonByteLength > 0) { + // Has a batch table JSON + var batchTableString = getStringFromTypedArray(uint8Array, byteOffset, batchTableJsonByteLength); + batchTableJson = JSON.parse(batchTableString); + byteOffset += batchTableJsonByteLength; + + if (batchTableBinaryByteLength > 0) { + // Has a batch table binary + batchTableBinary = new Uint8Array(arrayBuffer, byteOffset, batchTableBinaryByteLength); + byteOffset += batchTableBinaryByteLength; + } + } + + var featureTable = new Cesium3DTileFeatureTable(featureTableJson, featureTableBinary); + + var pointsLength = featureTable.getGlobalProperty('POINTS_LENGTH'); + featureTable.featuresLength = pointsLength; + + //>>includeStart('debug', pragmas.debug); + if (!defined(pointsLength)) { + throw new DeveloperError('Feature table global property: POINTS_LENGTH must be defined'); + } + //>>includeEnd('debug'); + + // Get the positions + var positions; + var isQuantized = false; + + if (defined(featureTableJson.POSITION)) { + positions = featureTable.getPropertyArray('POSITION', ComponentDatatype.FLOAT, 3); + var rtcCenter = featureTable.getGlobalProperty('RTC_CENTER'); + if (defined(rtcCenter)) { + this._rtcCenter = Cartesian3.unpack(rtcCenter); + } + } else if (defined(featureTableJson.POSITION_QUANTIZED)) { + positions = featureTable.getPropertyArray('POSITION_QUANTIZED', ComponentDatatype.UNSIGNED_SHORT, 3); + isQuantized = true; + + var quantizedVolumeScale = featureTable.getGlobalProperty('QUANTIZED_VOLUME_SCALE'); + //>>includeStart('debug', pragmas.debug); + if (!defined(quantizedVolumeScale)) { + throw new DeveloperError('Global property: QUANTIZED_VOLUME_SCALE must be defined for quantized positions.'); + } + //>>includeEnd('debug'); + this._quantizedVolumeScale = Cartesian3.unpack(quantizedVolumeScale); + + var quantizedVolumeOffset = featureTable.getGlobalProperty('QUANTIZED_VOLUME_OFFSET'); + //>>includeStart('debug', pragmas.debug); + if (!defined(quantizedVolumeOffset)) { + throw new DeveloperError('Global property: QUANTIZED_VOLUME_OFFSET must be defined for quantized positions.'); + } + //>>includeEnd('debug'); + this._quantizedVolumeOffset = Cartesian3.unpack(quantizedVolumeOffset); + } + + //>>includeStart('debug', pragmas.debug); + if (!defined(positions)) { + throw new DeveloperError('Either POSITION or POSITION_QUANTIZED must be defined.'); + } + //>>includeEnd('debug'); + + // Get the colors + var colors; + var isTranslucent = false; + + if (defined(featureTableJson.RGBA)) { + colors = featureTable.getPropertyArray('RGBA', ComponentDatatype.UNSIGNED_BYTE, 4); + isTranslucent = true; + } else if (defined(featureTableJson.RGB)) { + colors = featureTable.getPropertyArray('RGB', ComponentDatatype.UNSIGNED_BYTE, 3); + } else if (defined(featureTableJson.CONSTANT_RGBA)) { + var constantRGBA = featureTable.getGlobalProperty('CONSTANT_RGBA'); + this._constantColor = Color.fromBytes(constantRGBA[0], constantRGBA[1], constantRGBA[2], constantRGBA[3], this._constantColor); + } else { + // Use a default constant color + this._constantColor = Color.clone(Color.DARKGRAY, this._constantColor); + } + + this._isTranslucent = isTranslucent; + + // Get the normals + var normals; + var isOctEncoded16P = false; + + if (defined(featureTableJson.NORMAL)) { + normals = featureTable.getPropertyArray('NORMAL', ComponentDatatype.FLOAT, 3); + } else if (defined(featureTableJson.NORMAL_OCT16P)) { + normals = featureTable.getPropertyArray('NORMAL_OCT16P', ComponentDatatype.UNSIGNED_BYTE, 2); + isOctEncoded16P = true; + } + + // Get the batchIds and batch table + var batchIds; + if (defined(featureTableJson.BATCH_ID)) { + var componentType; + var componentTypeName = featureTableJson.BATCH_ID.componentType; + if (defined(componentTypeName)) { + componentType = ComponentDatatype.fromName(componentTypeName); + } else { + // If the componentType is omitted, default to UNSIGNED_SHORT + componentType = ComponentDatatype.UNSIGNED_SHORT; + } + + batchIds = featureTable.getPropertyArray('BATCH_ID', componentType, 1); + + var batchLength = featureTable.getGlobalProperty('BATCH_LENGTH'); + //>>includeStart('debug', pragmas.debug); + if (!defined(batchLength)) { + throw new DeveloperError('Global property: BATCH_LENGTH must be defined when BATCH_ID is defined.'); + } + //>>includeEnd('debug'); + + if (defined(batchTableBinary)) { + // Copy the batchTableBinary section and let the underlying ArrayBuffer be freed + batchTableBinary = new Uint8Array(batchTableBinary); + } + this.batchTable = new Cesium3DTileBatchTable(this, batchLength, batchTableJson, batchTableBinary); + } + + // If points are not batched and there there are per-point properties, use these properties for styling purposes + var styleableProperties; + if (!defined(batchIds) && defined(batchTableBinary)) { + styleableProperties = Cesium3DTileBatchTable.getBinaryProperties(pointsLength, batchTableJson, batchTableBinary); + } + + this._parsedContent = { + pointsLength : pointsLength, + positions : positions, + colors : colors, + normals : normals, + batchIds : batchIds, + isQuantized : isQuantized, + isOctEncoded16P : isOctEncoded16P, + styleableProperties : styleableProperties + }; + + this.state = Cesium3DTileContentState.PROCESSING; + this._contentReadyToProcessPromise.resolve(this); + }; + + function createResources(content, frameState) { + var context = frameState.context; + var parsedContent = content._parsedContent; + var pointsLength = parsedContent.pointsLength; + var positions = parsedContent.positions; + var colors = parsedContent.colors; + var normals = parsedContent.normals; + var batchIds = parsedContent.batchIds; + var isQuantized = parsedContent.isQuantized; + var isOctEncoded16P = parsedContent.isOctEncoded16P; + var styleableProperties = parsedContent.styleableProperties; + var isTranslucent = content._isTranslucent; + + var hasColors = defined(colors); + var hasNormals = defined(normals); + var hasBatchIds = defined(batchIds); + + var batchTable = content.batchTable; + var hasBatchTable = defined(batchTable); + var hasStyleableProperties = defined(styleableProperties); + + // TODO : How to expose this? Will this be part of the point cloud styling or a property of the tileset? + // Use per-point normals to hide back-facing points. + var backFaceCulling = false; + + var positionAttributeLocation = 0; + var colorAttributeLocation = 1; + var normalAttributeLocation = 2; + var batchIdAttributeLocation = 3; + var numberOfAttributes = 4; + + var styleableShaderAttributes; + var styleableVertexAttributes; + var styleableVertexAttributeLocations; + + if (hasStyleableProperties) { + styleableShaderAttributes = ''; + styleableVertexAttributes = []; + styleableVertexAttributeLocations = {}; + + var attributeLocation = numberOfAttributes; + + for (var name in styleableProperties) { + if (styleableProperties.hasOwnProperty(name)) { + var property = styleableProperties[name]; + // TODO : this will not handle matrix types currently + var componentCount = property.componentCount; + var typedArray = property.typedArray; + var componentDatatype = ComponentDatatype.fromTypedArray(typedArray); + + // Append attributes to shader + var attributeName = 'czm_pnts_' + name; + var attributeType; + if (componentCount === 1) { + attributeType = 'float'; + } else { + attributeType = 'vec' + componentCount; + } + styleableShaderAttributes += 'attribute ' + attributeType + ' ' + attributeName + '; \n'; + + var vertexBuffer = Buffer.createVertexBuffer({ + context : context, + typedArray : property.typedArray, + usage : BufferUsage.STATIC_DRAW + }); + + var vertexAttribute = { + index : attributeLocation, + vertexBuffer : vertexBuffer, + componentsPerAttribute : componentCount, + componentDatatype : componentDatatype, + normalize : false, + offsetInBytes : 0, + strideInBytes : 0 + }; + + styleableVertexAttributes.push(vertexAttribute); + styleableVertexAttributeLocations[attributeName] = attributeLocation; + ++attributeLocation; + } + } + } + + var vs = 'attribute vec3 a_position; \n' + + 'varying vec4 v_color; \n' + + 'uniform float u_pointSize; \n' + + 'uniform vec4 u_highlightColor; \n'; + + if (hasColors) { + if (isTranslucent) { + vs += 'attribute vec4 a_color; \n'; + } else { + vs += 'attribute vec3 a_color; \n'; + } + } + if (hasNormals) { + if (isOctEncoded16P) { + vs += 'attribute vec2 a_normal; \n'; + } else { + vs += 'attribute vec3 a_normal; \n'; + } + } + + if (hasBatchIds) { + vs += 'attribute float a_batchId; \n'; + } + + if (hasStyleableProperties) { + vs += styleableShaderAttributes; + } + + if (isQuantized) { + vs += 'uniform vec3 u_quantizedVolumeScale; \n'; + } + + vs += 'void main() \n' + + '{ \n'; + + if (hasColors) { + if (isTranslucent) { + vs += ' vec4 color = a_color * u_highlightColor; \n'; + } else { + vs += ' vec4 color = vec4(a_color * u_highlightColor.rgb, u_highlightColor.a); \n'; + } + } else { + vs += ' vec4 color = u_highlightColor; \n'; + } + + if (hasNormals) { + if (isOctEncoded16P) { + vs += ' vec3 normal = czm_octDecode(a_normal); \n'; + } else { + vs += ' vec3 normal = a_normal; \n'; + } + + vs += ' normal = czm_normal * normal; \n' + + ' float diffuseStrength = czm_getLambertDiffuse(czm_sunDirectionEC, normal); \n' + + ' diffuseStrength = max(diffuseStrength, 0.4); \n' + // Apply some ambient lighting + ' color *= diffuseStrength; \n'; + } + + if (isQuantized) { + vs += ' vec3 position = a_position * u_quantizedVolumeScale; \n'; + } else { + vs += ' vec3 position = a_position; \n'; + } + + vs += ' v_color = color; \n' + + ' gl_Position = czm_modelViewProjection * vec4(position, 1.0); \n' + + ' gl_PointSize = u_pointSize; \n'; + + if (hasNormals && backFaceCulling) { + vs += ' float visible = step(-normal.z, 0.0); \n' + + ' gl_Position *= visible; \n'; + } + + vs += '} \n'; + + var fs = 'varying vec4 v_color; \n' + + 'void main() \n' + + '{ \n' + + ' gl_FragColor = v_color; \n' + + '} \n'; + + var uniformMap = { + u_pointSize : function() { + return content._pointSize; + }, + u_highlightColor : function() { + return content._highlightColor; + } + }; + + if (isQuantized) { + uniformMap = combine(uniformMap, { + u_quantizedVolumeScale : function() { + return content._quantizedVolumeScale; + } + }); + } + + var positionsVertexBuffer = Buffer.createVertexBuffer({ + context : context, + typedArray : positions, + usage : BufferUsage.STATIC_DRAW + }); + + var colorsVertexBuffer; + if (hasColors) { + colorsVertexBuffer = Buffer.createVertexBuffer({ + context : context, + typedArray : colors, + usage : BufferUsage.STATIC_DRAW + }); + } + + var normalsVertexBuffer; + if (hasNormals) { + normalsVertexBuffer = Buffer.createVertexBuffer({ + context : context, + typedArray : normals, + usage : BufferUsage.STATIC_DRAW + }); + } + + var batchIdsVertexBuffer; + if (hasBatchIds) { + batchIdsVertexBuffer = Buffer.createVertexBuffer({ + context : context, + typedArray : batchIds, + usage : BufferUsage.STATIC_DRAW + }); + } + + var attributes = []; + if (isQuantized) { + attributes.push({ + index : positionAttributeLocation, + vertexBuffer : positionsVertexBuffer, + componentsPerAttribute : 3, + componentDatatype : ComponentDatatype.UNSIGNED_SHORT, + normalize : true, // Convert position to 0 to 1 before entering the shader + offsetInBytes : 0, + strideInBytes : 0 + }); + } else { + attributes.push({ + index : positionAttributeLocation, + vertexBuffer : positionsVertexBuffer, + componentsPerAttribute : 3, + componentDatatype : ComponentDatatype.FLOAT, + normalize : false, + offsetInBytes : 0, + strideInBytes : 0 + }); + } + + if (hasColors) { + var colorComponentsPerAttribute = isTranslucent ? 4 : 3; + attributes.push({ + index : colorAttributeLocation, + vertexBuffer : colorsVertexBuffer, + componentsPerAttribute : colorComponentsPerAttribute, + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + normalize : true, + offsetInBytes : 0, + strideInBytes : 0 + }); + } + + if (hasNormals) { + if (isOctEncoded16P) { + attributes.push({ + index : normalAttributeLocation, + vertexBuffer : normalsVertexBuffer, + componentsPerAttribute : 2, + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + normalize : false, + offsetInBytes : 0, + strideInBytes : 0 + }); + } else { + attributes.push({ + index : normalAttributeLocation, + vertexBuffer : normalsVertexBuffer, + componentsPerAttribute : 3, + componentDatatype : ComponentDatatype.FLOAT, + normalize : false, + offsetInBytes : 0, + strideInBytes : 0 + }); + } + } + + if (hasBatchIds) { + attributes.push({ + index : batchIdAttributeLocation, + vertexBuffer : batchIdsVertexBuffer, + componentsPerAttribute : 1, + componentDatatype : ComponentDatatype.fromTypedArray(batchIds), + normalize : false, + offsetInBytes : 0, + strideInBytes : 0 + }); + } + + if (hasStyleableProperties) { + attributes = attributes.concat(styleableVertexAttributes); + } + + var vertexArray = new VertexArray({ + context : context, + attributes : attributes + }); + + var attributeLocations = { + a_position : positionAttributeLocation + }; + + if (hasColors) { + attributeLocations = combine(attributeLocations, { + a_color : colorAttributeLocation + }); + } + + if (hasNormals) { + attributeLocations = combine(attributeLocations, { + a_normal : normalAttributeLocation + }); + } + + if (hasBatchIds) { + attributeLocations = combine(attributeLocations, { + a_batchId : batchIdAttributeLocation + }); + } + + if (hasStyleableProperties) { + attributeLocations = combine(attributeLocations, styleableVertexAttributeLocations); + } + + var drawVS = vs; + var drawFS = fs; + var drawUniformMap = uniformMap; + + if (hasBatchTable) { + drawVS = batchTable.getVertexShaderCallback()(vs, false); + drawFS = batchTable.getFragmentShaderCallback()(fs, false); + drawUniformMap = batchTable.getUniformMapCallback()(uniformMap); + } + + var shaderProgram = ShaderProgram.fromCache({ + context : context, + vertexShaderSource : drawVS, + fragmentShaderSource : drawFS, + attributeLocations : attributeLocations + }); + + content._opaqueRenderState = RenderState.fromCache({ + depthTest : { + enabled : true + } + }); + + content._translucentRenderState = RenderState.fromCache({ + depthTest : { + enabled : true + }, + depthMask : false, + blending : BlendingState.ALPHA_BLEND + }); + + content._drawCommand = new DrawCommand({ + boundingVolume : content._tile.contentBoundingVolume.boundingSphere, + cull : false, // Already culled by 3D tiles + modelMatrix : new Matrix4(), + primitiveType : PrimitiveType.POINTS, + vertexArray : vertexArray, + count : pointsLength, + shaderProgram : shaderProgram, + uniformMap : drawUniformMap, + renderState : isTranslucent ? content._translucentRenderState : content._opaqueRenderState, + pass : isTranslucent ? Pass.TRANSLUCENT : Pass.OPAQUE, + owner : content + }); + + var pickVS; + var pickFS; + var pickUniformMap; + + if (hasBatchTable) { + pickVS = batchTable.getPickVertexShaderCallback()(vs); + pickFS = batchTable.getPickFragmentShaderCallback()(fs); + pickUniformMap = batchTable.getPickUniformMapCallback()(uniformMap); + } else { + content._pickId = context.createPickId({ + primitive : content + }); + + pickUniformMap = combine(uniformMap, { + czm_pickColor : function() { + return content._pickId.color; + } + }); + + pickVS = vs; + pickFS = ShaderSource.createPickFragmentShaderSource(fs, 'uniform'); + } + + var pickShaderProgram = ShaderProgram.fromCache({ + context : context, + vertexShaderSource : pickVS, + fragmentShaderSource : pickFS, + attributeLocations : attributeLocations + }); + + content._pickCommand = new DrawCommand({ + boundingVolume : content._tile.contentBoundingVolume.boundingSphere, + cull : false, // Already culled by 3D tiles + modelMatrix : new Matrix4(), + primitiveType : PrimitiveType.POINTS, + vertexArray : vertexArray, + count : pointsLength, + shaderProgram : pickShaderProgram, + uniformMap : pickUniformMap, + renderState : isTranslucent ? content._translucentRenderState : content._opaqueRenderState, + pass : isTranslucent ? Pass.TRANSLUCENT : Pass.OPAQUE, + owner : content + }); + } + + /** + * Part of the {@link Cesium3DTileContent} interface. + */ + PointCloud3DTileContent.prototype.applyDebugSettings = function(enabled, color) { + this._highlightColor = enabled ? color : this._constantColor; + }; + + /** + * Part of the {@link Cesium3DTileContent} interface. + */ + PointCloud3DTileContent.prototype.update = function(tileset, frameState) { + var updateModelMatrix = this._tile.transformDirty; + + if (!defined(this._drawCommand)) { + createResources(this, frameState); + updateModelMatrix = true; + + // Set state to ready + this.state = Cesium3DTileContentState.READY; + this._readyPromise.resolve(this); + this._parsedContent = undefined; // Unload + } + + if (updateModelMatrix) { + if (defined(this._rtcCenter)) { + Matrix4.multiplyByTranslation(this._tile.computedTransform, this._rtcCenter, this._drawCommand.modelMatrix); + } else if (defined(this._quantizedVolumeOffset)) { + Matrix4.multiplyByTranslation(this._tile.computedTransform, this._quantizedVolumeOffset, this._drawCommand.modelMatrix); + } else { + Matrix4.clone(this._tile.computedTransform, this._drawCommand.modelMatrix); + } + Matrix4.clone(this._drawCommand.modelMatrix, this._pickCommand.modelMatrix); + } + + // Update the render state + var isTranslucent = (this._highlightColor.alpha < 1.0) || this._isTranslucent; + this._drawCommand.renderState = isTranslucent ? this._translucentRenderState : this._opaqueRenderState; + this._drawCommand.pass = isTranslucent ? Pass.TRANSLUCENT : Pass.OPAQUE; + + if (defined(this.batchTable)) { + this.batchTable.update(tileset, frameState); + } + + var passes = frameState.passes; + if (passes.render) { + frameState.addCommand(this._drawCommand); + } + if (passes.pick) { + frameState.addCommand(this._pickCommand); + } + }; + + /** + * Part of the {@link Cesium3DTileContent} interface. + */ + PointCloud3DTileContent.prototype.isDestroyed = function() { + return false; + }; + + /** + * Part of the {@link Cesium3DTileContent} interface. + */ + PointCloud3DTileContent.prototype.destroy = function() { + var command = this._drawCommand; + var pickCommand = this._pickCommand; + if (defined(command)) { + command.vertexArray = command.vertexArray && command.vertexArray.destroy(); + command.shaderProgram = command.shaderProgram && command.shaderProgram.destroy(); + pickCommand.shaderProgram = pickCommand.shaderProgram && pickCommand.shaderProgram.destroy(); + } + this.batchTable = this.batchTable && this.batchTable.destroy(); + return destroyObject(this); + }; + + return PointCloud3DTileContent; +}); diff --git a/Source/Scene/Points3DTileContent.js b/Source/Scene/Points3DTileContent.js deleted file mode 100644 index b50705dd4dfb..000000000000 --- a/Source/Scene/Points3DTileContent.js +++ /dev/null @@ -1,360 +0,0 @@ -/*global define*/ -define([ - '../Core/BoundingSphere', - '../Core/Cartesian3', - '../Core/Color', - '../Core/defaultValue', - '../Core/defined', - '../Core/destroyObject', - '../Core/defineProperties', - '../Core/DeveloperError', - '../Core/GeometryInstance', - '../Core/getMagic', - '../Core/getStringFromTypedArray', - '../Core/loadArrayBuffer', - '../Core/PointGeometry', - '../Core/Request', - '../Core/RequestScheduler', - '../Core/RequestType', - '../ThirdParty/when', - './Cesium3DTileContentState', - './PointAppearance', - './Primitive' - ], function( - BoundingSphere, - Cartesian3, - Color, - defaultValue, - defined, - destroyObject, - defineProperties, - DeveloperError, - GeometryInstance, - getMagic, - getStringFromTypedArray, - loadArrayBuffer, - PointGeometry, - Request, - RequestScheduler, - RequestType, - when, - Cesium3DTileContentState, - PointAppearance, - Primitive) { - 'use strict'; - - /** - * Represents the contents of a - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Points/README.md|Points} - * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles} tileset. - * - * @alias Points3DTileContent - * @constructor - * - * @private - */ - function Points3DTileContent(tileset, tile, url) { - this._primitive = undefined; - this._url = url; - this._tileset = tileset; - this._tile = tile; - this._constantColor = Color.clone(Color.WHITE); - - /** - * The following properties are part of the {@link Cesium3DTileContent} interface. - */ - this.state = Cesium3DTileContentState.UNLOADED; - this.batchTableResources = undefined; - this.featurePropertiesDirty = false; - this.boundingSphere = tile.contentBoundingVolume.boundingSphere; - - this._contentReadyToProcessPromise = when.defer(); - this._readyPromise = when.defer(); - } - - defineProperties(Points3DTileContent.prototype, { - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - featuresLength : { - get : function() { - // TODO: implement batchTable for pnts tile format - return 0; - } - }, - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - innerContents : { - get : function() { - return undefined; - } - }, - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - contentReadyToProcessPromise : { - get : function() { - return this._contentReadyToProcessPromise.promise; - } - }, - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - readyPromise : { - get : function() { - return this._readyPromise.promise; - } - } - }); - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Points3DTileContent.prototype.hasProperty = function(name) { - // TODO: implement batchTable for pnts tile format - return false; - }; - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Points3DTileContent.prototype.getFeature = function(batchId) { - // TODO: implement batchTable for pnts tile format - return undefined; - }; - - var sizeOfUint32 = Uint32Array.BYTES_PER_ELEMENT; - var sizeOfFloat32 = Float32Array.BYTES_PER_ELEMENT; - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Points3DTileContent.prototype.request = function() { - var that = this; - - var distance = this._tile.distanceToCamera; - var promise = RequestScheduler.schedule(new Request({ - url : this._url, - server : this._tile.requestServer, - requestFunction : loadArrayBuffer, - type : RequestType.TILES3D, - distance : distance - })); - - if (!defined(promise)) { - return false; - } - - this.state = Cesium3DTileContentState.LOADING; - promise.then(function(arrayBuffer) { - if (that.isDestroyed()) { - return when.reject('tileset is destroyed'); - } - that.initialize(arrayBuffer); - }).otherwise(function(error) { - that.state = Cesium3DTileContentState.FAILED; - that._readyPromise.reject(error); - }); - return true; - }; - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Points3DTileContent.prototype.initialize = function(arrayBuffer, byteOffset) { - byteOffset = defaultValue(byteOffset, 0); - - var uint8Array = new Uint8Array(arrayBuffer); - var magic = getMagic(uint8Array, byteOffset); - if (magic !== 'pnts') { - throw new DeveloperError('Invalid Points tile. Expected magic=pnts. Read magic=' + magic); - } - - var view = new DataView(arrayBuffer); - byteOffset += sizeOfUint32; // Skip magic number - - //>>includeStart('debug', pragmas.debug); - var version = view.getUint32(byteOffset, true); - if (version !== 1) { - throw new DeveloperError('Only Points tile version 1 is supported. Version ' + version + ' is not.'); - } - //>>includeEnd('debug'); - byteOffset += sizeOfUint32; - - // Skip byteLength - byteOffset += sizeOfUint32; - - var pointsLength = view.getUint32(byteOffset, true); - byteOffset += sizeOfUint32; - - var batchTableJSONByteLength = view.getUint32(byteOffset, true); - byteOffset += sizeOfUint32; - - var batchTableBinaryByteLength = view.getUint32(byteOffset, true); - byteOffset += sizeOfUint32; - - var positions = new Float32Array(arrayBuffer, byteOffset, pointsLength * 3); - byteOffset += pointsLength * 3 * sizeOfFloat32; - - var colors; - var translucent = false; - var hasConstantColor = false; - - if (batchTableJSONByteLength > 0) { - // Get the batch table JSON - var batchTableString = getStringFromTypedArray(uint8Array, byteOffset, batchTableJSONByteLength); - var batchTableJSON = JSON.parse(batchTableString); - byteOffset += batchTableJSONByteLength; - - // Get the batch table binary - var batchTableBinary; - if (batchTableBinaryByteLength > 0) { - batchTableBinary = new Uint8Array(arrayBuffer, byteOffset, batchTableBinaryByteLength); - } - byteOffset += batchTableBinaryByteLength; - - // Get the point colors - var tiles3DRGB = batchTableJSON.TILES3D_RGB; - var tiles3DRGBA = batchTableJSON.TILES3D_RGBA; - var tiles3DColor = batchTableJSON.TILES3D_COLOR; - - if (defined(tiles3DRGBA)) { - colors = new Uint8Array(batchTableBinary, tiles3DRGBA.byteOffset, pointsLength * 4); - translucent = true; - } else if (defined(tiles3DRGB)) { - colors = new Uint8Array(batchTableBinary, tiles3DRGB.byteOffset, pointsLength * 3); - } else if (defined(tiles3DColor)) { - this._constantColor = Color.fromBytes(tiles3DColor[0], tiles3DColor[1], tiles3DColor[2], tiles3DColor[3], this._constantColor); - hasConstantColor = true; - } - } - - var hasColors = defined(colors); - - if (!hasColors && !hasConstantColor) { - this._constantColor = Color.DARKGRAY; - } - - var vs = 'attribute vec3 position3DHigh; \n' + - 'attribute vec3 position3DLow; \n' + - 'uniform float pointSize; \n'; - if (hasColors) { - if (translucent) { - vs += 'attribute vec4 color; \n' + - 'varying vec4 v_color; \n'; - } else { - vs += 'attribute vec3 color; \n' + - 'varying vec3 v_color; \n'; - } - } - vs += 'void main() \n' + - '{ \n' + - ' gl_Position = czm_modelViewProjectionRelativeToEye * czm_computePosition(); \n' + - ' gl_PointSize = pointSize; \n'; - if (hasColors) { - vs += ' v_color = color; \n'; - } - vs += '}'; - - var fs = 'uniform vec4 highlightColor; \n'; - if (hasColors) { - if (translucent) { - fs += 'varying vec4 v_color; \n'; - } else { - fs += 'varying vec3 v_color; \n'; - } - } - fs += 'void main() \n' + - '{ \n'; - - if (hasColors) { - if (translucent) { - fs += ' gl_FragColor = v_color * highlightColor; \n'; - } else { - fs += ' gl_FragColor = vec4(v_color * highlightColor.rgb, highlightColor.a); \n'; - } - } else { - fs += ' gl_FragColor = highlightColor; \n'; - } - - fs += '} \n'; - - // TODO: performance test with 'interleave : true' - var instance = new GeometryInstance({ - geometry : new PointGeometry({ - positionsTypedArray : positions, - colorsTypedArray : colors, - boundingSphere : this.boundingSphere - }) - }); - - var appearance = new PointAppearance({ - highlightColor : this._constantColor, - translucent : translucent, - vertexShaderSource : vs, - fragmentShaderSource : fs - }); - - var primitive = new Primitive({ - geometryInstances : instance, - appearance : appearance, - asynchronous : false, - allowPicking : false, - cull : false, - rtcCenter : this.boundingSphere.center - }); - - this._primitive = primitive; - this.state = Cesium3DTileContentState.PROCESSING; - this._contentReadyToProcessPromise.resolve(this); - - var that = this; - - primitive.readyPromise.then(function(primitive) { - that.state = Cesium3DTileContentState.READY; - that._readyPromise.resolve(that); - }).otherwise(function(error) { - that.state = Cesium3DTileContentState.FAILED; - that._readyPromise.reject(error); - }); - }; - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Points3DTileContent.prototype.applyDebugSettings = function(enabled, color) { - color = enabled ? color : this._constantColor; - this._primitive.appearance.uniforms.highlightColor = color; - }; - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Points3DTileContent.prototype.update = function(tileset, frameState) { - // In the PROCESSING state we may be calling update() to move forward - // the content's resource loading. In the READY state, it will - // actually generate commands. - this._primitive.update(frameState); - }; - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Points3DTileContent.prototype.isDestroyed = function() { - return false; - }; - - /** - * Part of the {@link Cesium3DTileContent} interface. - */ - Points3DTileContent.prototype.destroy = function() { - this._primitive = this._primitive && this._primitive.destroy(); - return destroyObject(this); - }; - - return Points3DTileContent; -}); diff --git a/Source/Scene/TileBoundingRegion.js b/Source/Scene/TileBoundingRegion.js index 490d8d438e0c..27ae6143a157 100644 --- a/Source/Scene/TileBoundingRegion.js +++ b/Source/Scene/TileBoundingRegion.js @@ -292,6 +292,12 @@ define([ return this._orientedBoundingBox.intersectPlane(plane); }; + /** + * Creates a debug primitive that shows the outline of the tile bounding region. + * + * @param {Color} color The desired color of the primitive's mesh + * @return {Primitive} + */ TileBoundingRegion.prototype.createDebugVolume = function(color) { //>>includeStart('debug', pragmas.debug); if (!defined(color)) { diff --git a/Source/Scene/TileBoundingSphere.js b/Source/Scene/TileBoundingSphere.js index 2063a23083fe..480cb5ddf1b5 100644 --- a/Source/Scene/TileBoundingSphere.js +++ b/Source/Scene/TileBoundingSphere.js @@ -121,6 +121,20 @@ define([ return BoundingSphere.intersectPlane(this._boundingSphere, plane); }; + /** + * Update the bounding sphere after the tile is transformed. + */ + TileBoundingSphere.prototype.update = function(center, radius) { + Cartesian3.clone(center, this._boundingSphere.center); + this._boundingSphere.radius = radius; + }; + + /** + * Creates a debug primitive that shows the outline of the sphere. + * + * @param {Color} color The desired color of the primitive's mesh + * @return {Primitive} + */ TileBoundingSphere.prototype.createDebugVolume = function(color) { //>>includeStart('debug', pragmas.debug); if (!defined(color)) { diff --git a/Source/Scene/TileOrientedBoundingBox.js b/Source/Scene/TileOrientedBoundingBox.js index 332df381b4b9..1f5db032b50a 100644 --- a/Source/Scene/TileOrientedBoundingBox.js +++ b/Source/Scene/TileOrientedBoundingBox.js @@ -9,6 +9,7 @@ define([ '../Core/defineProperties', '../Core/DeveloperError', '../Core/GeometryInstance', + '../Core/Matrix3', '../Core/Matrix4', '../Core/OrientedBoundingBox', './PerInstanceColorAppearance', @@ -23,16 +24,15 @@ define([ defineProperties, DeveloperError, GeometryInstance, + Matrix3, Matrix4, OrientedBoundingBox, PerInstanceColorAppearance, Primitive) { 'use strict'; - function TileOrientedBoundingBox(options) { - options = defaultValue(options, defaultValue.EMPTY_OBJECT); - this._orientedBoundingBox = new OrientedBoundingBox(options.center, options.halfAxes); - + function TileOrientedBoundingBox(center, halfAxes) { + this._orientedBoundingBox = new OrientedBoundingBox(center, halfAxes); this._boundingSphere = BoundingSphere.fromOrientedBoundingBox(this._orientedBoundingBox); } @@ -98,6 +98,21 @@ define([ return this._orientedBoundingBox.intersectPlane(plane); }; + /** + * Update the bounding box after the tile is transformed. + */ + TileOrientedBoundingBox.prototype.update = function(center, halfAxes) { + Cartesian3.clone(center, this._orientedBoundingBox.center); + Matrix3.clone(halfAxes, this._orientedBoundingBox.halfAxes); + BoundingSphere.fromOrientedBoundingBox(this._orientedBoundingBox, this._boundingSphere); + }; + + /** + * Creates a debug primitive that shows the outline of the box. + * + * @param {Color} color The desired color of the primitive's mesh + * @return {Primitive} + */ TileOrientedBoundingBox.prototype.createDebugVolume = function(color) { //>>includeStart('debug', pragmas.debug); if (!defined(color)) { diff --git a/Source/Scene/Tileset3DTileContent.js b/Source/Scene/Tileset3DTileContent.js index 21cb73ad056a..b303b8134ba7 100644 --- a/Source/Scene/Tileset3DTileContent.js +++ b/Source/Scene/Tileset3DTileContent.js @@ -32,7 +32,7 @@ define([ * The following properties are part of the {@link Cesium3DTileContent} interface. */ this.state = Cesium3DTileContentState.UNLOADED; - this.batchTableResources = undefined; + this.batchTable = undefined; this.featurePropertiesDirty = false; this._contentReadyToProcessPromise = when.defer(); diff --git a/Source/Scene/getBinaryAccessor.js b/Source/Scene/getBinaryAccessor.js new file mode 100644 index 000000000000..e4aa0036f26a --- /dev/null +++ b/Source/Scene/getBinaryAccessor.js @@ -0,0 +1,64 @@ +/*global define*/ +define([ + '../Core/Cartesian2', + '../Core/Cartesian3', + '../Core/Cartesian4', + '../Core/ComponentDatatype', + '../Core/Matrix2', + '../Core/Matrix3', + '../Core/Matrix4' + ], function( + Cartesian2, + Cartesian3, + Cartesian4, + ComponentDatatype, + Matrix2, + Matrix3, + Matrix4) { + 'use strict'; + + var ComponentsPerAttribute = { + SCALAR : 1, + VEC2 : 2, + VEC3 : 3, + VEC4 : 4, + MAT2 : 4, + MAT3 : 9, + MAT4 : 16 + }; + + var ClassPerType = { + SCALAR : undefined, + VEC2 : Cartesian2, + VEC3 : Cartesian3, + VEC4 : Cartesian4, + MAT2 : Matrix2, + MAT3 : Matrix3, + MAT4 : Matrix4 + }; + + /** + * @private + */ + function getBinaryAccessor(accessor) { + var componentType = accessor.componentType; + var componentDatatype; + if (typeof componentType === 'string') { + componentDatatype = ComponentDatatype.fromName(componentType); + } else { + componentDatatype = componentType; + } + + var componentsPerAttribute = ComponentsPerAttribute[accessor.type]; + var classType = ClassPerType[accessor.type]; + return { + componentsPerAttribute : componentsPerAttribute, + classType : classType, + createArrayBufferView : function(buffer, byteOffset, length) { + return ComponentDatatype.createArrayBufferView(componentDatatype, buffer, byteOffset, componentsPerAttribute * length); + } + }; + } + + return getBinaryAccessor; +}); diff --git a/Source/Scene/getModelAccessor.js b/Source/Scene/getModelAccessor.js deleted file mode 100644 index 59ba2d6c2472..000000000000 --- a/Source/Scene/getModelAccessor.js +++ /dev/null @@ -1,34 +0,0 @@ -/*global define*/ -define([ - '../Core/ComponentDatatype' - ], function( - ComponentDatatype) { - 'use strict'; - - var ComponentsPerAttribute = { - SCALAR : 1, - VEC2 : 2, - VEC3 : 3, - VEC4 : 4, - MAT2 : 4, - MAT3 : 9, - MAT4 : 16 - }; - - /** - * @private - */ - function getModelAccessor(accessor) { - var componentDatatype = accessor.componentType; - var componentsPerAttribute = ComponentsPerAttribute[accessor.type]; - - return { - componentsPerAttribute : componentsPerAttribute, - createArrayBufferView : function(buffer, byteOffset, length) { - return ComponentDatatype.createArrayBufferView(componentDatatype, buffer, byteOffset, componentsPerAttribute * length); - } - }; - } - - return getModelAccessor; -}); diff --git a/Specs/Cesium3DTilesTester.js b/Specs/Cesium3DTilesTester.js index f1aad250f284..dd0701710532 100644 --- a/Specs/Cesium3DTilesTester.js +++ b/Specs/Cesium3DTilesTester.js @@ -2,6 +2,7 @@ define([ 'Core/Color', 'Core/defaultValue', + 'Core/defined', 'Scene/Cesium3DTileContentFactory', 'Scene/Cesium3DTileContentState', 'Scene/Cesium3DTileset', @@ -10,6 +11,7 @@ define([ ], function( Color, defaultValue, + defined, Cesium3DTileContentFactory, Cesium3DTileContentState, Cesium3DTileset, @@ -17,9 +19,31 @@ define([ pollToPromise) { 'use strict'; + var mockTile = { + contentBoundingVolume : new TileBoundingSphere(), + _header : { + content : { + boundingVolume : { + sphere : [0.0, 0.0, 0.0, 1.0] + } + } + } + }; + function Cesium3DTilesTester() { } + function padStringToByteAlignment(string, byteAlignment) { + var length = string.length; + var paddedLength = Math.ceil(length / byteAlignment) * byteAlignment; // Round up to the required alignment + var padding = paddedLength - length; + var whitespace = ''; + for (var i = 0; i < padding; ++i) { + whitespace += ' '; + } + return string + whitespace; + } + function expectRender(scene, tileset) { tileset.show = false; expect(scene.renderForSpecs()).toEqual([0, 0, 0, 255]); @@ -40,7 +64,7 @@ define([ // Verify render before being picked expectRender(scene, tileset); - // Change the color of the picked instance to yellow + // Change the color of the picked feature to yellow var picked = scene.pickForSpecs(); expect(picked).toBeDefined(); picked.color = Color.clone(Color.YELLOW, picked.color); @@ -82,15 +106,22 @@ define([ Cesium3DTilesTester.loadTileExpectError = function(scene, arrayBuffer, type) { var tileset = {}; - var tile = { - contentBoundingVolume : new TileBoundingSphere() - }; var url = ''; - var content = Cesium3DTileContentFactory[type](tileset, tile, url); + var content = Cesium3DTileContentFactory[type](tileset, mockTile, url); expect(function() { content.initialize(arrayBuffer); content.update(tileset, scene.frameState); }).toThrowDeveloperError(); + return content; + }; + + Cesium3DTilesTester.loadTile = function(scene, arrayBuffer, type) { + var tileset = {}; + var url = ''; + var content = Cesium3DTileContentFactory[type](tileset, mockTile, url); + content.initialize(arrayBuffer); + content.update(tileset, scene.frameState); + return content; }; // Use counter to prevent models from sharing the same cache key, @@ -100,11 +131,8 @@ define([ var tileset = { baseUrl : counter++ }; - var tile = { - contentBoundingVolume : new TileBoundingSphere() - }; var url = ''; - var content = Cesium3DTileContentFactory[type](tileset, tile, url); + var content = Cesium3DTileContentFactory[type](tileset, mockTile, url); content.initialize(arrayBuffer); content.update(tileset, scene.frameState); @@ -119,11 +147,8 @@ define([ var tileset = { loadTileset : Cesium3DTileset.prototype.loadTileset }; - var tile = { - contentBoundingVolume : new TileBoundingSphere() - }; var url = 'invalid'; - var content = Cesium3DTileContentFactory[type](tileset, tile, url); + var content = Cesium3DTileContentFactory[type](tileset, mockTile, url); content.request(); return content.readyPromise.then(function(content) { @@ -178,7 +203,7 @@ define([ var version = defaultValue(options.version, 1); var featuresLength = defaultValue(options.featuresLength, 1); - var headerByteLength = 20; + var headerByteLength = 24; var byteLength = headerByteLength; var buffer = new ArrayBuffer(byteLength); var view = new DataView(buffer); @@ -188,8 +213,9 @@ define([ view.setUint8(3, magic[3]); view.setUint32(4, version, true); // version view.setUint32(8, byteLength, true); // byteLength - view.setUint32(12, featuresLength, true); // featuresLength - view.setUint32(16, 0, true); // batchTableByteLength + view.setUint32(12, 0, true); // batchTableJsonByteLength + view.setUint32(16, 0, true); // batchTableBinaryByteLength + view.setUint32(20, featuresLength, true); // batchLength return buffer; }; @@ -205,16 +231,16 @@ define([ var gltfUriByteLength = gltfUri.length; var featuresLength = defaultValue(options.featuresLength, 1); - var featureTableJSON = { + var featureTableJson = { INSTANCES_LENGTH : featuresLength, POSITION : new Array(featuresLength * 3).fill(0) }; - var featureTableJSONString = JSON.stringify(featureTableJSON); - var featureTableJSONByteLength = featureTableJSONString.length; + var featureTableJsonString = JSON.stringify(featureTableJson); + var featureTableJsonByteLength = featureTableJsonString.length; var headerByteLength = 32; var uriByteLength = gltfUri.length; - var byteLength = headerByteLength + featureTableJSONByteLength + uriByteLength; + var byteLength = headerByteLength + featureTableJsonByteLength + uriByteLength; var buffer = new ArrayBuffer(byteLength); var view = new DataView(buffer); view.setUint8(0, magic[0]); @@ -223,16 +249,16 @@ define([ view.setUint8(3, magic[3]); view.setUint32(4, version, true); // version view.setUint32(8, byteLength, true); // byteLength - view.setUint32(12, featureTableJSONByteLength, true); // featureTableJSONByteLength + view.setUint32(12, featureTableJsonByteLength, true); // featureTableJsonByteLength view.setUint32(16, 0, true); // featureTableBinaryByteLength - view.setUint32(20, 0, true); // batchTableJSONByteLength + view.setUint32(20, 0, true); // batchTableJsonByteLength view.setUint32(24, 0, true); // batchTableBinaryByteLength - view.setUint32(38, gltfFormat, true); // gltfFormat + view.setUint32(28, gltfFormat, true); // gltfFormat var i; var byteOffset = headerByteLength; - for (i = 0; i < featureTableJSONByteLength; i++) { - view.setUint8(byteOffset, featureTableJSONString.charCodeAt(i)); + for (i = 0; i < featureTableJsonByteLength; i++) { + view.setUint8(byteOffset, featureTableJsonString.charCodeAt(i)); byteOffset++; } for (i = 0; i < gltfUriByteLength; i++) { @@ -242,26 +268,53 @@ define([ return buffer; }; - Cesium3DTilesTester.generatePointsTileBuffer = function(options) { + Cesium3DTilesTester.generatePointCloudTileBuffer = function(options) { // Procedurally generate the tile array buffer for testing purposes options = defaultValue(options, defaultValue.EMPTY_OBJECT); var magic = defaultValue(options.magic, [112, 110, 116, 115]); var version = defaultValue(options.version, 1); + var featureTableJson = options.featureTableJson; + if (!defined(featureTableJson)) { + featureTableJson = { + POINTS_LENGTH : 1, + POSITIONS : { + byteOffset : 0 + } + }; + } - var headerByteLength = 24; - var byteLength = headerByteLength; + var featureTableJsonString = JSON.stringify(featureTableJson); + featureTableJsonString = padStringToByteAlignment(featureTableJsonString, 4); + var featureTableJsonByteLength = defaultValue(options.featureTableJsonByteLength, featureTableJsonString.length); + + var featureTableBinary = new ArrayBuffer(12); // Enough space to hold 3 floats + var featureTableBinaryByteLength = featureTableBinary.byteLength; + + var headerByteLength = 28; + var byteLength = headerByteLength + featureTableJsonByteLength + featureTableBinaryByteLength; var buffer = new ArrayBuffer(byteLength); var view = new DataView(buffer); view.setUint8(0, magic[0]); view.setUint8(1, magic[1]); view.setUint8(2, magic[2]); view.setUint8(3, magic[3]); - view.setUint32(4, version, true); // version - view.setUint32(8, byteLength, true); // byteLength - view.setUint32(12, 0, true); // pointsLength - view.setUint32(16, 0, true); // batchTableJSONByteLength - view.setUint32(20, 0, true); // batchTableBinaryByteLength + view.setUint32(4, version, true); // version + view.setUint32(8, byteLength, true); // byteLength + view.setUint32(12, featureTableJsonByteLength, true); // featureTableJsonByteLength + view.setUint32(16, featureTableBinaryByteLength, true); // featureTableBinaryByteLength + view.setUint32(20, 0, true); // batchTableJsonByteLength + view.setUint32(24, 0, true); // batchTableBinaryByteLength + var i; + var byteOffset = headerByteLength; + for (i = 0; i < featureTableJsonByteLength; i++) { + view.setUint8(byteOffset, featureTableJsonString.charCodeAt(i)); + byteOffset++; + } + for (i = 0; i < featureTableBinaryByteLength; i++) { + view.setUint8(byteOffset, featureTableBinary[i]); + byteOffset++; + } return buffer; }; diff --git a/Specs/Core/ComponentDatatypeSpec.js b/Specs/Core/ComponentDatatypeSpec.js index d646cc26bbc6..5d65b5e19e61 100644 --- a/Specs/Core/ComponentDatatypeSpec.js +++ b/Specs/Core/ComponentDatatypeSpec.js @@ -149,4 +149,21 @@ defineSuite([ ComponentDatatype.createTypedArray(ComponentDatatype.BYTE, undefined, 0, 1); }).toThrowDeveloperError(); }); + + it('fromName works', function() { + expect(ComponentDatatype.fromName('BYTE')).toEqual(ComponentDatatype.BYTE); + expect(ComponentDatatype.fromName('UNSIGNED_BYTE')).toEqual(ComponentDatatype.UNSIGNED_BYTE); + expect(ComponentDatatype.fromName('SHORT')).toEqual(ComponentDatatype.SHORT); + expect(ComponentDatatype.fromName('UNSIGNED_SHORT')).toEqual(ComponentDatatype.UNSIGNED_SHORT); + expect(ComponentDatatype.fromName('INT')).toEqual(ComponentDatatype.INT); + expect(ComponentDatatype.fromName('UNSIGNED_INT')).toEqual(ComponentDatatype.UNSIGNED_INT); + expect(ComponentDatatype.fromName('FLOAT')).toEqual(ComponentDatatype.FLOAT); + expect(ComponentDatatype.fromName('DOUBLE')).toEqual(ComponentDatatype.DOUBLE); + }); + + it('fromName throws without name', function() { + expect(function() { + ComponentDatatype.fromName(); + }).toThrowDeveloperError(); + }); }); diff --git a/Specs/Core/PointGeometrySpec.js b/Specs/Core/PointGeometrySpec.js index cf3f25605f38..079f6db8d640 100644 --- a/Specs/Core/PointGeometrySpec.js +++ b/Specs/Core/PointGeometrySpec.js @@ -23,6 +23,14 @@ defineSuite([ }).toThrowDeveloperError(); }); + it('throws without colorsTypedArray', function() { + expect(function() { + return new PointGeometry({ + positionsTypedArray : positionsTypedArray + }); + }).toThrowDeveloperError(); + }); + it('creates with boundingSphere', function() { var points = new PointGeometry({ positionsTypedArray : positionsTypedArray, diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedNoBuildings/batchedNoBuildings.b3dm b/Specs/Data/Cesium3DTiles/Batched/BatchedNoBuildings/batchedNoBuildings.b3dm index 8ea73b2de8fc..04d731aed164 100644 Binary files a/Specs/Data/Cesium3DTiles/Batched/BatchedNoBuildings/batchedNoBuildings.b3dm and b/Specs/Data/Cesium3DTiles/Batched/BatchedNoBuildings/batchedNoBuildings.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedNoBuildings/tileset.json b/Specs/Data/Cesium3DTiles/Batched/BatchedNoBuildings/tileset.json index 9417edc3ea97..c1840f87350c 100644 --- a/Specs/Data/Cesium3DTiles/Batched/BatchedNoBuildings/tileset.json +++ b/Specs/Data/Cesium3DTiles/Batched/BatchedNoBuildings/tileset.json @@ -5,19 +5,27 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 }, "Longitude": { - "minimum": -1.319700073733107, - "maximum": -1.3196596973299783 + "minimum": -1.3196930452470341, + "maximum": -1.3196617964314208 }, "Latitude": { - "minimum": 0.6988583918578102, - "maximum": 0.6988896067140962 + "minimum": 0.6988594477444204, + "maximum": 0.698883763781271 }, "Height": { "minimum": 6, "maximum": 14 + }, + "info": { + "minimum": null, + "maximum": null + }, + "rooms": { + "minimum": null, + "maximum": null } }, "geometricError": 70, diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucent/batchedTranslucent.b3dm b/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucent/batchedTranslucent.b3dm index 3f734b65801c..5498baa16a75 100644 Binary files a/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucent/batchedTranslucent.b3dm and b/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucent/batchedTranslucent.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucent/tileset.json b/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucent/tileset.json index 2ac943018abb..aa7867c1faed 100644 --- a/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucent/tileset.json +++ b/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucent/tileset.json @@ -5,15 +5,15 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 }, "Longitude": { - "minimum": -1.3196994451761477, - "maximum": -1.3196602320106057 + "minimum": -1.3196812329810825, + "maximum": -1.3196599624193912 }, "Latitude": { - "minimum": 0.69885861761053, - "maximum": 0.698889386494805 + "minimum": 0.6988634273243843, + "maximum": 0.6988863863403311 }, "Height": { "minimum": 6, diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucentOpaqueMix/batchedTranslucentOpaqueMix.b3dm b/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucentOpaqueMix/batchedTranslucentOpaqueMix.b3dm index fa97766ee302..550e53970f87 100644 Binary files a/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucentOpaqueMix/batchedTranslucentOpaqueMix.b3dm and b/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucentOpaqueMix/batchedTranslucentOpaqueMix.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucentOpaqueMix/tileset.json b/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucentOpaqueMix/tileset.json index 06bcd5223646..a578526a9949 100644 --- a/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucentOpaqueMix/tileset.json +++ b/Specs/Data/Cesium3DTiles/Batched/BatchedTranslucentOpaqueMix/tileset.json @@ -5,15 +5,15 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 }, "Longitude": { - "minimum": -1.319699786622918, - "maximum": -1.3196599027619818 + "minimum": -1.3197000541327293, + "maximum": -1.3196647916486712 }, "Latitude": { - "minimum": 0.6988587817979215, - "maximum": 0.6988896073997394 + "minimum": 0.6988632475321589, + "maximum": 0.6988890296629459 }, "Height": { "minimum": 6, diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTable/batchedWithBatchTable.b3dm b/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTable/batchedWithBatchTable.b3dm index 9c2a6c679d05..84f203c2d047 100644 Binary files a/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTable/batchedWithBatchTable.b3dm and b/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTable/batchedWithBatchTable.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTable/tileset.json b/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTable/tileset.json index 4f5ed1645570..b006dcfbf10d 100644 --- a/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTable/tileset.json +++ b/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTable/tileset.json @@ -5,15 +5,15 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 }, "Longitude": { - "minimum": -1.319700073733107, - "maximum": -1.3196596973299783 + "minimum": -1.3196930452470341, + "maximum": -1.3196617964314208 }, "Latitude": { - "minimum": 0.6988583918578102, - "maximum": 0.6988896067140962 + "minimum": 0.6988594477444204, + "maximum": 0.698883763781271 }, "Height": { "minimum": 6, diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTableBinary/batchedWithBatchTableBinary.b3dm b/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTableBinary/batchedWithBatchTableBinary.b3dm new file mode 100644 index 000000000000..287c0d0c9024 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTableBinary/batchedWithBatchTableBinary.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTableBinary/tileset.json b/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTableBinary/tileset.json new file mode 100644 index 000000000000..95f7ec998e1a --- /dev/null +++ b/Specs/Data/Cesium3DTiles/Batched/BatchedWithBatchTableBinary/tileset.json @@ -0,0 +1,49 @@ +{ + "asset": { + "version": "0.0" + }, + "properties": { + "id": { + "minimum": 0, + "maximum": 9 + }, + "Longitude": { + "minimum": -1.3196930452470341, + "maximum": -1.3196617964314208 + }, + "Latitude": { + "minimum": 0.6988594477444204, + "maximum": 0.698883763781271 + }, + "Height": { + "minimum": 6, + "maximum": 14 + }, + "code": { + "minimum": 0, + "maximum": 9 + }, + "cartographic": { + "minimum": null, + "maximum": null + } + }, + "geometricError": 70, + "root": { + "refine": "add", + "boundingVolume": { + "region": [ + -1.3197004795898053, + 0.6988582109, + -1.3196595204101946, + 0.6988897891, + 0, + 20 + ] + }, + "geometricError": 0, + "content": { + "url": "batchedWithBatchTableBinary.b3dm" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformBox/batchedWithTransformBox.b3dm b/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformBox/batchedWithTransformBox.b3dm new file mode 100644 index 000000000000..7cff23140303 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformBox/batchedWithTransformBox.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformBox/tileset.json b/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformBox/tileset.json new file mode 100644 index 000000000000..3932b4d5260a --- /dev/null +++ b/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformBox/tileset.json @@ -0,0 +1,65 @@ +{ + "asset": { + "version": "0.0" + }, + "properties": { + "id": { + "minimum": 0, + "maximum": 9 + }, + "Longitude": { + "minimum": -1.319698184523387, + "maximum": -1.3196644681653795 + }, + "Latitude": { + "minimum": 0.6988679665373897, + "maximum": 0.698889770493337 + }, + "Height": { + "minimum": 6, + "maximum": 12 + } + }, + "geometricError": 70, + "root": { + "transform": [ + 0.9686356343768792, + 0.24848542777253735, + 0, + 0, + -0.15986460744966327, + 0.623177611820219, + 0.765567091384559, + 0, + 0.19023226619126932, + -0.7415555652213445, + 0.6433560667227647, + 0, + 1215011.9317263428, + -4736309.3434217675, + 4081602.0044800863, + 1 + ], + "refine": "add", + "boundingVolume": { + "box": [ + 0, + 10, + 0, + 200, + 0, + 0, + 0, + 200, + 0, + 0, + 0, + 20 + ] + }, + "geometricError": 0, + "content": { + "url": "batchedWithTransformBox.b3dm" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformRegion/batchedWithTransformRegion.b3dm b/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformRegion/batchedWithTransformRegion.b3dm new file mode 100644 index 000000000000..7cff23140303 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformRegion/batchedWithTransformRegion.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformRegion/tileset.json b/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformRegion/tileset.json new file mode 100644 index 000000000000..e7fa5064d32b --- /dev/null +++ b/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformRegion/tileset.json @@ -0,0 +1,59 @@ +{ + "asset": { + "version": "0.0" + }, + "properties": { + "id": { + "minimum": 0, + "maximum": 9 + }, + "Longitude": { + "minimum": -1.319698184523387, + "maximum": -1.3196644681653795 + }, + "Latitude": { + "minimum": 0.6988679665373897, + "maximum": 0.698889770493337 + }, + "Height": { + "minimum": 6, + "maximum": 12 + } + }, + "geometricError": 70, + "root": { + "transform": [ + 0.9686356343768792, + 0.24848542777253735, + 0, + 0, + -0.15986460744966327, + 0.623177611820219, + 0.765567091384559, + 0, + 0.19023226619126932, + -0.7415555652213445, + 0.6433560667227647, + 0, + 1215011.9317263428, + -4736309.3434217675, + 4081602.0044800863, + 1 + ], + "refine": "add", + "boundingVolume": { + "region": [ + -1.3197004795898053, + 0.6988582109, + -1.3196595204101946, + 0.6988897891, + 0, + 20 + ] + }, + "geometricError": 0, + "content": { + "url": "batchedWithTransformRegion.b3dm" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformSphere/batchedWithTransformSphere.b3dm b/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformSphere/batchedWithTransformSphere.b3dm new file mode 100644 index 000000000000..7cff23140303 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformSphere/batchedWithTransformSphere.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformSphere/tileset.json b/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformSphere/tileset.json new file mode 100644 index 000000000000..4478c14c6fe9 --- /dev/null +++ b/Specs/Data/Cesium3DTiles/Batched/BatchedWithTransformSphere/tileset.json @@ -0,0 +1,57 @@ +{ + "asset": { + "version": "0.0" + }, + "properties": { + "id": { + "minimum": 0, + "maximum": 9 + }, + "Longitude": { + "minimum": -1.319698184523387, + "maximum": -1.3196644681653795 + }, + "Latitude": { + "minimum": 0.6988679665373897, + "maximum": 0.698889770493337 + }, + "Height": { + "minimum": 6, + "maximum": 12 + } + }, + "geometricError": 70, + "root": { + "transform": [ + 0.9686356343768792, + 0.24848542777253735, + 0, + 0, + -0.15986460744966327, + 0.623177611820219, + 0.765567091384559, + 0, + 0.19023226619126932, + -0.7415555652213445, + 0.6433560667227647, + 0, + 1215011.9317263428, + -4736309.3434217675, + 4081602.0044800863, + 1 + ], + "refine": "add", + "boundingVolume": { + "sphere": [ + 0, + 0, + 0, + 141.42 + ] + }, + "geometricError": 0, + "content": { + "url": "batchedWithTransformSphere.b3dm" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/batchedWithoutBatchTable.b3dm b/Specs/Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/batchedWithoutBatchTable.b3dm index e7f2e4519f19..98835e4fb11b 100644 Binary files a/Specs/Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/batchedWithoutBatchTable.b3dm and b/Specs/Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/batchedWithoutBatchTable.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/tileset.json b/Specs/Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/tileset.json index 79be35ef5f63..d4b36aef0675 100644 --- a/Specs/Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/tileset.json +++ b/Specs/Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/tileset.json @@ -5,19 +5,27 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 }, "Longitude": { - "minimum": -1.319700073733107, - "maximum": -1.3196596973299783 + "minimum": -1.3196930452470341, + "maximum": -1.3196617964314208 }, "Latitude": { - "minimum": 0.6988583918578102, - "maximum": 0.6988896067140962 + "minimum": 0.6988594477444204, + "maximum": 0.698883763781271 }, "Height": { "minimum": 6, "maximum": 14 + }, + "info": { + "minimum": null, + "maximum": null + }, + "rooms": { + "minimum": null, + "maximum": null } }, "geometricError": 70, diff --git a/Specs/Data/Cesium3DTiles/Composite/Composite/composite.cmpt b/Specs/Data/Cesium3DTiles/Composite/Composite/composite.cmpt index 7db1c20ba734..ef0305af8892 100644 Binary files a/Specs/Data/Cesium3DTiles/Composite/Composite/composite.cmpt and b/Specs/Data/Cesium3DTiles/Composite/Composite/composite.cmpt differ diff --git a/Specs/Data/Cesium3DTiles/Composite/CompositeOfComposite/compositeOfComposite.cmpt b/Specs/Data/Cesium3DTiles/Composite/CompositeOfComposite/compositeOfComposite.cmpt index aa82753bc620..9d5c3c9fec4c 100644 Binary files a/Specs/Data/Cesium3DTiles/Composite/CompositeOfComposite/compositeOfComposite.cmpt and b/Specs/Data/Cesium3DTiles/Composite/CompositeOfComposite/compositeOfComposite.cmpt differ diff --git a/Specs/Data/Cesium3DTiles/Instanced/InstancedGltfExternal/instancedGltfExternal.i3dm b/Specs/Data/Cesium3DTiles/Instanced/InstancedGltfExternal/instancedGltfExternal.i3dm index b2d487f7cf81..7e4672cef841 100644 Binary files a/Specs/Data/Cesium3DTiles/Instanced/InstancedGltfExternal/instancedGltfExternal.i3dm and b/Specs/Data/Cesium3DTiles/Instanced/InstancedGltfExternal/instancedGltfExternal.i3dm differ diff --git a/Specs/Data/Cesium3DTiles/Instanced/InstancedQuantizedWithBatchTable/instancedQuantizedWithBatchTable.i3dm b/Specs/Data/Cesium3DTiles/Instanced/InstancedQuantizedWithBatchTable/instancedQuantizedWithBatchTable.i3dm index 6cda4a9b52ed..a7eae5ab1037 100644 Binary files a/Specs/Data/Cesium3DTiles/Instanced/InstancedQuantizedWithBatchTable/instancedQuantizedWithBatchTable.i3dm and b/Specs/Data/Cesium3DTiles/Instanced/InstancedQuantizedWithBatchTable/instancedQuantizedWithBatchTable.i3dm differ diff --git a/Specs/Data/Cesium3DTiles/Instanced/InstancedScaleNonUniformWithBatchTable/instancedScaleNonUniformWithBatchTable.i3dm b/Specs/Data/Cesium3DTiles/Instanced/InstancedScaleNonUniformWithBatchTable/instancedScaleNonUniformWithBatchTable.i3dm index 86272889b782..6f3d4009c5d8 100644 Binary files a/Specs/Data/Cesium3DTiles/Instanced/InstancedScaleNonUniformWithBatchTable/instancedScaleNonUniformWithBatchTable.i3dm and b/Specs/Data/Cesium3DTiles/Instanced/InstancedScaleNonUniformWithBatchTable/instancedScaleNonUniformWithBatchTable.i3dm differ diff --git a/Specs/Data/Cesium3DTiles/Instanced/InstancedScaleWithBatchTable/instancedScaleWithBatchTable.i3dm b/Specs/Data/Cesium3DTiles/Instanced/InstancedScaleWithBatchTable/instancedScaleWithBatchTable.i3dm index 3e554332295a..e1ce39530968 100644 Binary files a/Specs/Data/Cesium3DTiles/Instanced/InstancedScaleWithBatchTable/instancedScaleWithBatchTable.i3dm and b/Specs/Data/Cesium3DTiles/Instanced/InstancedScaleWithBatchTable/instancedScaleWithBatchTable.i3dm differ diff --git a/Specs/Data/Cesium3DTiles/Instanced/InstancedWithBatchTable/instancedWithBatchTable.i3dm b/Specs/Data/Cesium3DTiles/Instanced/InstancedWithBatchTable/instancedWithBatchTable.i3dm index 9f11383aa8c2..0f005a0312fb 100644 Binary files a/Specs/Data/Cesium3DTiles/Instanced/InstancedWithBatchTable/instancedWithBatchTable.i3dm and b/Specs/Data/Cesium3DTiles/Instanced/InstancedWithBatchTable/instancedWithBatchTable.i3dm differ diff --git a/Specs/Data/Cesium3DTiles/Instanced/InstancedWithBatchTableBinary/instancedWithBatchTableBinary.i3dm b/Specs/Data/Cesium3DTiles/Instanced/InstancedWithBatchTableBinary/instancedWithBatchTableBinary.i3dm new file mode 100644 index 000000000000..b8340e87ba25 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Instanced/InstancedWithBatchTableBinary/instancedWithBatchTableBinary.i3dm differ diff --git a/Specs/Data/Cesium3DTiles/Instanced/InstancedWithBatchTableBinary/tileset.json b/Specs/Data/Cesium3DTiles/Instanced/InstancedWithBatchTableBinary/tileset.json new file mode 100644 index 000000000000..06554edcce9c --- /dev/null +++ b/Specs/Data/Cesium3DTiles/Instanced/InstancedWithBatchTableBinary/tileset.json @@ -0,0 +1,41 @@ +{ + "asset": { + "version": "0.0" + }, + "properties": { + "id": { + "minimum": 0, + "maximum": 99 + }, + "Longitude": { + "minimum": -1.3197004048940548, + "maximum": -1.3196602716044172 + }, + "Latitude": { + "minimum": 0.6988585409308616, + "maximum": 0.6988894207110236 + }, + "Height": { + "minimum": 0, + "maximum": 80 + } + }, + "geometricError": 40, + "root": { + "refine": "add", + "boundingVolume": { + "region": [ + -1.3197004795898053, + 0.6988582109, + -1.3196595204101946, + 0.6988897891, + 0, + 80 + ] + }, + "geometricError": 0, + "content": { + "url": "instancedWithBatchTableBinary.i3dm" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/Instanced/InstancedWithTransform/instancedWithTransform.i3dm b/Specs/Data/Cesium3DTiles/Instanced/InstancedWithTransform/instancedWithTransform.i3dm new file mode 100644 index 000000000000..938f85a0d930 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Instanced/InstancedWithTransform/instancedWithTransform.i3dm differ diff --git a/Specs/Data/Cesium3DTiles/Instanced/InstancedWithTransform/tileset.json b/Specs/Data/Cesium3DTiles/Instanced/InstancedWithTransform/tileset.json new file mode 100644 index 000000000000..83966ae726e0 --- /dev/null +++ b/Specs/Data/Cesium3DTiles/Instanced/InstancedWithTransform/tileset.json @@ -0,0 +1,47 @@ +{ + "asset": { + "version": "0.0" + }, + "geometricError": 40, + "root": { + "transform": [ + 0.968635634376879, + 0.24848542777253738, + 0, + 0, + -0.15986460789456303, + 0.6231776135545087, + 0.76556708987993, + 0, + 0.190232265817391, + -0.7415555637639074, + 0.6433560685132107, + 0, + 1215012.7877715407, + -4736312.680421811, + 4081604.8995823865, + 1 + ], + "refine": "add", + "boundingVolume": { + "box": [ + 0, + 0, + 0, + 215, + 0, + 0, + 0, + 215, + 0, + 0, + 0, + 30 + ] + }, + "geometricError": 0, + "content": { + "url": "instancedWithTransform.i3dm" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/Instanced/InstancedWithoutBatchTable/instancedWithoutBatchTable.i3dm b/Specs/Data/Cesium3DTiles/Instanced/InstancedWithoutBatchTable/instancedWithoutBatchTable.i3dm index e61b1ba3e1b1..9d9442d63ec4 100644 Binary files a/Specs/Data/Cesium3DTiles/Instanced/InstancedWithoutBatchTable/instancedWithoutBatchTable.i3dm and b/Specs/Data/Cesium3DTiles/Instanced/InstancedWithoutBatchTable/instancedWithoutBatchTable.i3dm differ diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudBatched/pointCloudBatched.pnts b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudBatched/pointCloudBatched.pnts new file mode 100644 index 000000000000..3a2da42171ce Binary files /dev/null and b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudBatched/pointCloudBatched.pnts differ diff --git a/Specs/Data/Cesium3DTiles/Points/PointsNoColor/tileset.json b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudBatched/tileset.json similarity index 53% rename from Specs/Data/Cesium3DTiles/Points/PointsNoColor/tileset.json rename to Specs/Data/Cesium3DTiles/PointCloud/PointCloudBatched/tileset.json index 3ef73ca11f9b..7da76d80e07d 100644 --- a/Specs/Data/Cesium3DTiles/Points/PointsNoColor/tileset.json +++ b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudBatched/tileset.json @@ -2,20 +2,20 @@ "asset": { "version": "0.0" }, - "geometricError": 346.4, + "geometricError": 17.32, "root": { "refine": "add", "boundingVolume": { "sphere": [ - 1215011.9317263428, - -4736309.3434217675, - 4081602.0044800863, - 100 + 1215012.8828876738, + -4736313.051199594, + 4081605.22126042, + 5 ] }, "geometricError": 0, "content": { - "url": "pointsNoColor.pnts" + "url": "pointCloudBatched.pnts" } } } diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudConstantColor/pointCloudConstantColor.pnts b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudConstantColor/pointCloudConstantColor.pnts new file mode 100644 index 000000000000..6b9884d3644f Binary files /dev/null and b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudConstantColor/pointCloudConstantColor.pnts differ diff --git a/Specs/Data/Cesium3DTiles/Points/PointsConstantColor/tileset.json b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudConstantColor/tileset.json similarity index 53% rename from Specs/Data/Cesium3DTiles/Points/PointsConstantColor/tileset.json rename to Specs/Data/Cesium3DTiles/PointCloud/PointCloudConstantColor/tileset.json index 892badc10bb3..86f287b67821 100644 --- a/Specs/Data/Cesium3DTiles/Points/PointsConstantColor/tileset.json +++ b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudConstantColor/tileset.json @@ -2,20 +2,20 @@ "asset": { "version": "0.0" }, - "geometricError": 346.4, + "geometricError": 17.32, "root": { "refine": "add", "boundingVolume": { "sphere": [ - 1215011.9317263428, - -4736309.3434217675, - 4081602.0044800863, - 100 + 1215012.8828876738, + -4736313.051199594, + 4081605.22126042, + 5 ] }, "geometricError": 0, "content": { - "url": "pointsConstantColor.pnts" + "url": "pointCloudConstantColor.pnts" } } } diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNoColor/pointCloudNoColor.pnts b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNoColor/pointCloudNoColor.pnts new file mode 100644 index 000000000000..0bb9d9781179 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNoColor/pointCloudNoColor.pnts differ diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNoColor/tileset.json b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNoColor/tileset.json new file mode 100644 index 000000000000..1ba137876a77 --- /dev/null +++ b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNoColor/tileset.json @@ -0,0 +1,21 @@ +{ + "asset": { + "version": "0.0" + }, + "geometricError": 17.32, + "root": { + "refine": "add", + "boundingVolume": { + "sphere": [ + 1215012.8828876738, + -4736313.051199594, + 4081605.22126042, + 5 + ] + }, + "geometricError": 0, + "content": { + "url": "pointCloudNoColor.pnts" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNormals/pointCloudNormals.pnts b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNormals/pointCloudNormals.pnts new file mode 100644 index 000000000000..288ad797ba15 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNormals/pointCloudNormals.pnts differ diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNormals/tileset.json b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNormals/tileset.json new file mode 100644 index 000000000000..cbd112148fe4 --- /dev/null +++ b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNormals/tileset.json @@ -0,0 +1,21 @@ +{ + "asset": { + "version": "0.0" + }, + "geometricError": 17.32, + "root": { + "refine": "add", + "boundingVolume": { + "sphere": [ + 1215012.8828876738, + -4736313.051199594, + 4081605.22126042, + 5 + ] + }, + "geometricError": 0, + "content": { + "url": "pointCloudNormals.pnts" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNormalsOctEncoded/pointCloudNormalsOctEncoded.pnts b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNormalsOctEncoded/pointCloudNormalsOctEncoded.pnts new file mode 100644 index 000000000000..11da150ab15e Binary files /dev/null and b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNormalsOctEncoded/pointCloudNormalsOctEncoded.pnts differ diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNormalsOctEncoded/tileset.json b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNormalsOctEncoded/tileset.json new file mode 100644 index 000000000000..dda4b23c12b1 --- /dev/null +++ b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudNormalsOctEncoded/tileset.json @@ -0,0 +1,21 @@ +{ + "asset": { + "version": "0.0" + }, + "geometricError": 17.32, + "root": { + "refine": "add", + "boundingVolume": { + "sphere": [ + 1215012.8828876738, + -4736313.051199594, + 4081605.22126042, + 5 + ] + }, + "geometricError": 0, + "content": { + "url": "pointCloudNormalsOctEncoded.pnts" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantized/pointCloudQuantized.pnts b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantized/pointCloudQuantized.pnts new file mode 100644 index 000000000000..5e5c39d5491b Binary files /dev/null and b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantized/pointCloudQuantized.pnts differ diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantized/tileset.json b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantized/tileset.json new file mode 100644 index 000000000000..fd46571f8aec --- /dev/null +++ b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantized/tileset.json @@ -0,0 +1,21 @@ +{ + "asset": { + "version": "0.0" + }, + "geometricError": 17.32, + "root": { + "refine": "add", + "boundingVolume": { + "sphere": [ + 1215012.8828876738, + -4736313.051199594, + 4081605.22126042, + 5 + ] + }, + "geometricError": 0, + "content": { + "url": "pointCloudQuantized.pnts" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantizedOctEncoded/pointCloudQuantizedOctEncoded.pnts b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantizedOctEncoded/pointCloudQuantizedOctEncoded.pnts new file mode 100644 index 000000000000..09cf69134c32 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantizedOctEncoded/pointCloudQuantizedOctEncoded.pnts differ diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantizedOctEncoded/tileset.json b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantizedOctEncoded/tileset.json new file mode 100644 index 000000000000..21a1a017e1ed --- /dev/null +++ b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudQuantizedOctEncoded/tileset.json @@ -0,0 +1,21 @@ +{ + "asset": { + "version": "0.0" + }, + "geometricError": 17.32, + "root": { + "refine": "add", + "boundingVolume": { + "sphere": [ + 1215012.8828876738, + -4736313.051199594, + 4081605.22126042, + 5 + ] + }, + "geometricError": 0, + "content": { + "url": "pointCloudQuantizedOctEncoded.pnts" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGB/pointCloudRGB.pnts b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGB/pointCloudRGB.pnts new file mode 100644 index 000000000000..d5acddd8ec4a Binary files /dev/null and b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGB/pointCloudRGB.pnts differ diff --git a/Specs/Data/Cesium3DTiles/Points/PointsRGB/tileset.json b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGB/tileset.json similarity index 54% rename from Specs/Data/Cesium3DTiles/Points/PointsRGB/tileset.json rename to Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGB/tileset.json index b8db256b795c..166b270b98be 100644 --- a/Specs/Data/Cesium3DTiles/Points/PointsRGB/tileset.json +++ b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGB/tileset.json @@ -2,20 +2,20 @@ "asset": { "version": "0.0" }, - "geometricError": 346.4, + "geometricError": 17.32, "root": { "refine": "add", "boundingVolume": { "sphere": [ - 1215011.9317263428, - -4736309.3434217675, - 4081602.0044800863, - 100 + 1215012.8828876738, + -4736313.051199594, + 4081605.22126042, + 5 ] }, "geometricError": 0, "content": { - "url": "pointsRGB.pnts" + "url": "pointCloudRGB.pnts" } } } diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGBA/pointCloudRGBA.pnts b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGBA/pointCloudRGBA.pnts new file mode 100644 index 000000000000..5ac869b31de9 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGBA/pointCloudRGBA.pnts differ diff --git a/Specs/Data/Cesium3DTiles/Points/PointsRGBA/tileset.json b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGBA/tileset.json similarity index 54% rename from Specs/Data/Cesium3DTiles/Points/PointsRGBA/tileset.json rename to Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGBA/tileset.json index 4aa6a48bfa08..8aca46b846aa 100644 --- a/Specs/Data/Cesium3DTiles/Points/PointsRGBA/tileset.json +++ b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudRGBA/tileset.json @@ -2,20 +2,20 @@ "asset": { "version": "0.0" }, - "geometricError": 346.4, + "geometricError": 17.32, "root": { "refine": "add", "boundingVolume": { "sphere": [ - 1215011.9317263428, - -4736309.3434217675, - 4081602.0044800863, - 100 + 1215012.8828876738, + -4736313.051199594, + 4081605.22126042, + 5 ] }, "geometricError": 0, "content": { - "url": "pointsRGBA.pnts" + "url": "pointCloudRGBA.pnts" } } } diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWGS84/pointCloudWGS84.pnts b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWGS84/pointCloudWGS84.pnts new file mode 100644 index 000000000000..481f0ad8a017 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWGS84/pointCloudWGS84.pnts differ diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWGS84/tileset.json b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWGS84/tileset.json new file mode 100644 index 000000000000..e07802ddb35c --- /dev/null +++ b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWGS84/tileset.json @@ -0,0 +1,21 @@ +{ + "asset": { + "version": "0.0" + }, + "geometricError": 17.32, + "root": { + "refine": "add", + "boundingVolume": { + "sphere": [ + 1215012.8828876738, + -4736313.051199594, + 4081605.22126042, + 5 + ] + }, + "geometricError": 0, + "content": { + "url": "pointCloudWGS84.pnts" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithPerPointProperties/pointCloudWithPerPointProperties.pnts b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithPerPointProperties/pointCloudWithPerPointProperties.pnts new file mode 100644 index 000000000000..39d2bb713587 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithPerPointProperties/pointCloudWithPerPointProperties.pnts differ diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithPerPointProperties/tileset.json b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithPerPointProperties/tileset.json new file mode 100644 index 000000000000..16e5859f6652 --- /dev/null +++ b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithPerPointProperties/tileset.json @@ -0,0 +1,21 @@ +{ + "asset": { + "version": "0.0" + }, + "geometricError": 17.32, + "root": { + "refine": "add", + "boundingVolume": { + "sphere": [ + 1215012.8828876738, + -4736313.051199594, + 4081605.22126042, + 5 + ] + }, + "geometricError": 0, + "content": { + "url": "pointCloudWithPerPointProperties.pnts" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithTransform/pointCloudWithTransform.pnts b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithTransform/pointCloudWithTransform.pnts new file mode 100644 index 000000000000..04ee7ed436f6 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithTransform/pointCloudWithTransform.pnts differ diff --git a/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithTransform/tileset.json b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithTransform/tileset.json new file mode 100644 index 000000000000..16d86434b967 --- /dev/null +++ b/Specs/Data/Cesium3DTiles/PointCloud/PointCloudWithTransform/tileset.json @@ -0,0 +1,39 @@ +{ + "asset": { + "version": "0.0" + }, + "geometricError": 17.32, + "root": { + "transform": [ + 0.968635634376879, + 0.24848542777253735, + 0, + 0, + -0.15986460794399626, + 0.6231776137472074, + 0.7655670897127491, + 0, + 0.190232265775849, + -0.7415555636019701, + 0.6433560687121489, + 0, + 1215012.8828876738, + -4736313.051199594, + 4081605.22126042, + 1 + ], + "refine": "add", + "boundingVolume": { + "sphere": [ + 0, + 0, + 0, + 5 + ] + }, + "geometricError": 0, + "content": { + "url": "pointCloudWithTransform.pnts" + } + } +} diff --git a/Specs/Data/Cesium3DTiles/Points/PointsConstantColor/pointsConstantColor.pnts b/Specs/Data/Cesium3DTiles/Points/PointsConstantColor/pointsConstantColor.pnts deleted file mode 100644 index 1e774521372b..000000000000 Binary files a/Specs/Data/Cesium3DTiles/Points/PointsConstantColor/pointsConstantColor.pnts and /dev/null differ diff --git a/Specs/Data/Cesium3DTiles/Points/PointsNoColor/pointsNoColor.pnts b/Specs/Data/Cesium3DTiles/Points/PointsNoColor/pointsNoColor.pnts deleted file mode 100644 index 39ea10577711..000000000000 Binary files a/Specs/Data/Cesium3DTiles/Points/PointsNoColor/pointsNoColor.pnts and /dev/null differ diff --git a/Specs/Data/Cesium3DTiles/Points/PointsRGB/pointsRGB.pnts b/Specs/Data/Cesium3DTiles/Points/PointsRGB/pointsRGB.pnts deleted file mode 100644 index c6f314c74cc6..000000000000 Binary files a/Specs/Data/Cesium3DTiles/Points/PointsRGB/pointsRGB.pnts and /dev/null differ diff --git a/Specs/Data/Cesium3DTiles/Points/PointsRGBA/pointsRGBA.pnts b/Specs/Data/Cesium3DTiles/Points/PointsRGBA/pointsRGBA.pnts deleted file mode 100644 index 50197734882d..000000000000 Binary files a/Specs/Data/Cesium3DTiles/Points/PointsRGBA/pointsRGBA.pnts and /dev/null differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ll.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ll.b3dm index da5d6d610eb7..6e5e1599da0f 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ll.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ll.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/lr.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/lr.b3dm index aeaacde4977e..c6c194e74e94 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/lr.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/lr.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/parent.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/parent.b3dm index fb219365156e..e5721889b1ca 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/parent.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/parent.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/tileset.json b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/tileset.json index d5e57251d371..42e39360bce1 100644 --- a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/tileset.json +++ b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/tileset.json @@ -6,15 +6,15 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 }, "Longitude": { - "minimum": -1.3197209267166137, - "maximum": -1.319639102447024 + "minimum": -1.3197190069941716, + "maximum": -1.3196399825465384 }, "Latitude": { - "minimum": 0.6988426520676222, - "maximum": 0.6989055039320631 + "minimum": 0.6988468038519597, + "maximum": 0.6989046685398855 }, "Height": { "minimum": 6, diff --git a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ul.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ul.b3dm index 8a01b920e620..4fd75a2453b6 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ul.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ul.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ur.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ur.b3dm index 296f6e76f37b..bd80912f82b7 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ur.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ur.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/ll.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/ll.b3dm index da5d6d610eb7..6e5e1599da0f 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/ll.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/ll.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/lr.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/lr.b3dm index aeaacde4977e..c6c194e74e94 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/lr.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/lr.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/parent.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/parent.b3dm index fb219365156e..e5721889b1ca 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/parent.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/parent.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/tileset.json b/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/tileset.json index 034e7e1bdc58..88fe55cc95b9 100644 --- a/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/tileset.json +++ b/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/tileset.json @@ -5,7 +5,7 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 } }, "geometricError": 70, diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/ul.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/ul.b3dm index 8a01b920e620..4fd75a2453b6 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/ul.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/ul.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/ur.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/ur.b3dm index 296f6e76f37b..bd80912f82b7 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/ur.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetEmptyRoot/ur.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/ll.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/ll.b3dm deleted file mode 100644 index da5d6d610eb7..000000000000 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/ll.b3dm and /dev/null differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/lr.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/lr.b3dm index aeaacde4977e..c6c194e74e94 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/lr.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/lr.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/parent.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/parent.b3dm deleted file mode 100644 index fb219365156e..000000000000 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/parent.b3dm and /dev/null differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/tileset.json b/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/tileset.json index 585c782161d1..efb501751d52 100644 --- a/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/tileset.json +++ b/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/tileset.json @@ -5,7 +5,7 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 } }, "geometricError": 70, diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/ul.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/ul.b3dm index 8a01b920e620..4fd75a2453b6 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/ul.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/ul.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/ur.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/ur.b3dm index 296f6e76f37b..bd80912f82b7 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/ur.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetInvalid/ur.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/lr.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/lr.b3dm index aeaacde4977e..c6c194e74e94 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/lr.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/lr.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/parent.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/parent.b3dm index fb219365156e..e5721889b1ca 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/parent.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/parent.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset.json b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset.json index 311c926966b9..8d31883fad28 100644 --- a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset.json +++ b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset.json @@ -5,7 +5,7 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 } }, "geometricError": 240, diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset3/ll.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset3/ll.b3dm index da5d6d610eb7..6e5e1599da0f 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset3/ll.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset3/ll.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/ul.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/ul.b3dm index 8a01b920e620..4fd75a2453b6 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/ul.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/ul.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/ur.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/ur.b3dm index 296f6e76f37b..bd80912f82b7 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/ur.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/ur.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/ll.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/ll.b3dm index da5d6d610eb7..6e5e1599da0f 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/ll.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/ll.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/lr.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/lr.b3dm index aeaacde4977e..c6c194e74e94 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/lr.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/lr.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/parent.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/parent.b3dm index fb219365156e..e5721889b1ca 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/parent.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/parent.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/tileset.json b/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/tileset.json index 47b0ce90823b..1f9374cf5388 100644 --- a/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/tileset.json +++ b/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/tileset.json @@ -5,7 +5,7 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 } }, "geometricError": 240, diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/ul.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/ul.b3dm index 8a01b920e620..4fd75a2453b6 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/ul.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/ul.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/ur.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/ur.b3dm index 296f6e76f37b..bd80912f82b7 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/ur.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetRefinementMix/ur.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/ll.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/ll.b3dm index da5d6d610eb7..6e5e1599da0f 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/ll.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/ll.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/lr.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/lr.b3dm index aeaacde4977e..c6c194e74e94 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/lr.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/lr.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/parent.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/parent.b3dm index fb219365156e..e5721889b1ca 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/parent.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/parent.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/tileset.json b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/tileset.json index 8e4a1093b03b..757798d0cc9b 100644 --- a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/tileset.json +++ b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/tileset.json @@ -5,7 +5,7 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 } }, "geometricError": 240, diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/ul.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/ul.b3dm index 8a01b920e620..4fd75a2453b6 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/ul.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/ul.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/ur.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/ur.b3dm index 296f6e76f37b..bd80912f82b7 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/ur.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement1/ur.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/ll.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/ll.b3dm index da5d6d610eb7..6e5e1599da0f 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/ll.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/ll.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/lr.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/lr.b3dm index aeaacde4977e..c6c194e74e94 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/lr.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/lr.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/parent.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/parent.b3dm index fb219365156e..e5721889b1ca 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/parent.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/parent.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/tileset.json b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/tileset.json index f7d011d72ebd..3ad7d67ae54b 100644 --- a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/tileset.json +++ b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/tileset.json @@ -5,7 +5,7 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 } }, "geometricError": 240, diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/ul.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/ul.b3dm index 8a01b920e620..4fd75a2453b6 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/ul.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/ul.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/ur.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/ur.b3dm index 296f6e76f37b..bd80912f82b7 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/ur.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement2/ur.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/ll.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/ll.b3dm index da5d6d610eb7..6e5e1599da0f 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/ll.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/ll.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/lr.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/lr.b3dm index aeaacde4977e..c6c194e74e94 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/lr.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/lr.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/parent.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/parent.b3dm index fb219365156e..e5721889b1ca 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/parent.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/parent.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/tileset.json b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/tileset.json index f4c0efe3c0c7..5c1b9cc3d90b 100644 --- a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/tileset.json +++ b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/tileset.json @@ -5,7 +5,7 @@ "properties": { "id": { "minimum": 0, - "maximum": 99 + "maximum": 9 } }, "geometricError": 240, diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/ul.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/ul.b3dm index 8a01b920e620..4fd75a2453b6 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/ul.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/ul.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/ur.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/ur.b3dm index 296f6e76f37b..bd80912f82b7 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/ur.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetReplacement3/ur.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithTransforms/buildings.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithTransforms/buildings.b3dm new file mode 100644 index 000000000000..7cff23140303 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithTransforms/buildings.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithTransforms/instances.i3dm b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithTransforms/instances.i3dm new file mode 100644 index 000000000000..ca9546623627 Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithTransforms/instances.i3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithTransforms/tileset.json b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithTransforms/tileset.json new file mode 100644 index 000000000000..485065689787 --- /dev/null +++ b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithTransforms/tileset.json @@ -0,0 +1,89 @@ +{ + "asset": { + "version": "0.0" + }, + "geometricError": 70, + "root": { + "boundingVolume": { + "box": [ + 0, + 10, + 0, + 200, + 0, + 0, + 0, + 200, + 0, + 0, + 0, + 20 + ] + }, + "transform": [ + 0.9686356343768792, + 0.24848542777253735, + 0, + 0, + -0.15986460744966327, + 0.623177611820219, + 0.765567091384559, + 0, + 0.19023226619126932, + -0.7415555652213445, + 0.6433560667227647, + 0, + 1215011.9317263428, + -4736309.3434217675, + 4081602.0044800863, + 1 + ], + "geometricError": 40, + "refine": "add", + "content": { + "url": "buildings.b3dm" + }, + "children": [ + { + "boundingVolume": { + "box": [ + 0, + 0, + 0, + 215, + 0, + 0, + 0, + 215, + 0, + 0, + 0, + 30 + ] + }, + "transform": [ + 0.35355339059327373, + 0.3535533905932738, + 0, + 0, + -0.3535533905932738, + 0.35355339059327373, + 0, + 0, + 0, + 0, + 0.5, + 0, + 0, + 0, + 5, + 1 + ], + "geometricError": 0, + "content": { + "url": "instances.i3dm" + } + } + ] + } +} diff --git a/Specs/Scene/Batched3DModel3DTileContentSpec.js b/Specs/Scene/Batched3DModel3DTileContentSpec.js index 0207446fc48f..ff34b4915793 100644 --- a/Specs/Scene/Batched3DModel3DTileContentSpec.js +++ b/Specs/Scene/Batched3DModel3DTileContentSpec.js @@ -3,12 +3,14 @@ defineSuite([ 'Scene/Batched3DModel3DTileContent', 'Core/Cartesian3', 'Core/HeadingPitchRange', + 'Core/Transforms', 'Specs/Cesium3DTilesTester', 'Specs/createScene' ], function( Batched3DModel3DTileContent, Cartesian3, HeadingPitchRange, + Transforms, Cesium3DTilesTester, createScene) { 'use strict'; @@ -18,22 +20,32 @@ defineSuite([ var centerLatitude = 0.698874; var withBatchTableUrl = './Data/Cesium3DTiles/Batched/BatchedWithBatchTable/'; + var withBatchTableBinaryUrl = './Data/Cesium3DTiles/Batched/BatchedWithBatchTableBinary/'; var withoutBatchTableUrl = './Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/'; var translucentUrl = './Data/Cesium3DTiles/Batched/BatchedTranslucent/'; var translucentOpaqueMixUrl = './Data/Cesium3DTiles/Batched/BatchedTranslucentOpaqueMix/'; + var withTransformBoxUrl = './Data/Cesium3DTiles/Batched/BatchedWithTransformBox/'; + var withTransformSphereUrl = './Data/Cesium3DTiles/Batched/BatchedWithTransformSphere/'; + var withTransformRegionUrl = './Data/Cesium3DTiles/Batched/BatchedWithTransformRegion/'; + + function setCamera(longitude, latitude) { + // One instance is located at the center, point the camera there + var center = Cartesian3.fromRadians(longitude, latitude); + scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 15.0)); + } beforeAll(function() { scene = createScene(); - - // One building in each data set is always located in the center, so point the camera there - var center = Cartesian3.fromRadians(centerLongitude, centerLatitude); - scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 15.0)); }); afterAll(function() { scene.destroyForSpecs(); }); + beforeEach(function() { + setCamera(centerLongitude, centerLatitude); + }); + afterEach(function() { scene.primitives.removeAll(); }); @@ -52,6 +64,41 @@ defineSuite([ return Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'b3dm'); }); + it('recognizes the legacy b3dm format', function() { + var headerByteLength = 20; + var batchTableJson = {name:['test']}; + var batchTableString = JSON.stringify(batchTableJson); + var batchTableByteLength = batchTableString.length; + var byteLength = headerByteLength + batchTableByteLength; + var buffer = new ArrayBuffer(byteLength); + var view = new DataView(buffer); + var magic = [98, 51, 100, 109]; + var version = 1; + var batchLength = 1; + + view.setUint8(0, magic[0]); + view.setUint8(1, magic[1]); + view.setUint8(2, magic[2]); + view.setUint8(3, magic[3]); + view.setUint32(4, version, true); + view.setUint32(8, byteLength, true); + view.setUint32(12, batchLength, true); + view.setUint32(16, batchTableByteLength, true); + + var i; + var byteOffset = headerByteLength; + for (i = 0; i < batchTableByteLength; i++) { + view.setUint8(byteOffset, batchTableString.charCodeAt(i)); + byteOffset++; + } + + // Expect to throw DeveloperError in Model due to invalid gltf magic + var tile = Cesium3DTilesTester.loadTileExpectError(scene, buffer, 'b3dm'); + expect(tile.batchTable.batchTableJson).toEqual(batchTableJson); + expect(tile.batchTable.batchTableBinary).toBeUndefined(); + expect(tile.batchTable.featuresLength).toEqual(1); + }); + it('throws with empty gltf', function() { // Expect to throw DeveloperError in Model due to invalid gltf magic var arrayBuffer = Cesium3DTilesTester.generateBatchedTileBuffer(); @@ -72,6 +119,12 @@ defineSuite([ }); }); + it('renders with batch table binary', function() { + return Cesium3DTilesTester.loadTileset(scene, withBatchTableBinaryUrl).then(function(tileset) { + Cesium3DTilesTester.expectRenderTileset(scene, tileset); + }); + }); + it('renders without batch table', function() { return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { Cesium3DTilesTester.expectRenderTileset(scene, tileset); @@ -90,6 +143,49 @@ defineSuite([ }); }); + function expectRenderWithTransform(url) { + return Cesium3DTilesTester.loadTileset(scene, url).then(function(tileset) { + Cesium3DTilesTester.expectRenderTileset(scene, tileset); + + var newLongitude = -1.31962; + var newLatitude = 0.698874; + var newCenter = Cartesian3.fromRadians(newLongitude, newLatitude, 0.0); + var newTransform = Transforms.headingPitchRollToFixedFrame(newCenter, 0.0, 0.0, 0.0); + + // Update tile transform + tileset._root.transform = newTransform; + scene.renderForSpecs(); + + // Move the camera to the new location + setCamera(newLongitude, newLatitude); + Cesium3DTilesTester.expectRenderTileset(scene, tileset); + }); + } + + it('renders with a tile transform and box bounding volume', function() { + return expectRenderWithTransform(withTransformBoxUrl); + }); + + it('renders with a tile transform and sphere bounding volume', function() { + return expectRenderWithTransform(withTransformSphereUrl); + }); + + it('renders with a tile transform and region bounding volume', function() { + return Cesium3DTilesTester.loadTileset(scene, withTransformRegionUrl).then(function(tileset) { + Cesium3DTilesTester.expectRenderTileset(scene, tileset); + }); + }); + + it('can get features and properties', function() { + return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { + var content = tileset._root.content; + expect(content.featuresLength).toBe(10); + expect(content.innerContents).toBeUndefined(); + expect(content.hasProperty('id')).toBe(true); + expect(content.getFeature(0)).toBeDefined(); + }); + }); + it('throws when calling getFeature with invalid index', function() { return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { var content = tileset._root.content; diff --git a/Specs/Scene/Cesium3DTileBatchTableResourcesSpec.js b/Specs/Scene/Cesium3DTileBatchTableResourcesSpec.js deleted file mode 100644 index c5cf033bca9f..000000000000 --- a/Specs/Scene/Cesium3DTileBatchTableResourcesSpec.js +++ /dev/null @@ -1,490 +0,0 @@ -/*global defineSuite*/ -defineSuite([ - 'Scene/Cesium3DTileBatchTableResources', - 'Core/Cartesian3', - 'Core/Color', - 'Core/HeadingPitchRange', - 'Renderer/ContextLimits', - 'Specs/Cesium3DTilesTester', - 'Specs/createScene' - ], function( - Cesium3DTileBatchTableResources, - Cartesian3, - Color, - HeadingPitchRange, - ContextLimits, - Cesium3DTilesTester, - createScene) { - 'use strict'; - - var scene; - var centerLongitude = -1.31968; - var centerLatitude = 0.698874; - - var withBatchTableUrl = './Data/Cesium3DTiles/Batched/BatchedWithBatchTable/'; - var withoutBatchTableUrl = './Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/'; - var batchLengthZeroUrl = './Data/Cesium3DTiles/Batched/BatchedNoBuildings/'; - - var result = new Color(); - - var mockContent = { - getFeature : function(batchId) { - return {}; - } - }; - - beforeAll(function() { - scene = createScene(); - - // One building in each data set is always located in the center, so point the camera there - var center = Cartesian3.fromRadians(centerLongitude, centerLatitude, 5.0); - scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 10.0)); - }); - - afterAll(function() { - scene.destroyForSpecs(); - }); - - afterEach(function() { - scene.primitives.removeAll(); - }); - - function expectRender(tileset) { - tileset.show = false; - expect(scene.renderForSpecs()).toEqual([0, 0, 0, 255]); - tileset.show = true; - var pixelColor = scene.renderForSpecs(); - expect(pixelColor).not.toEqual([0, 0, 0, 255]); - return pixelColor; - } - - it('setShow throws with invalid batchId', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.setShow(); - }).toThrowDeveloperError(); - expect(function() { - resources.setShow(-1); - }).toThrowDeveloperError(); - expect(function() { - resources.setShow(2); - }).toThrowDeveloperError(); - }); - - it('setShow throws with undefined value', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.setShow(0); - }).toThrowDeveloperError(); - }); - - it('setShow', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - - // Batch resources are undefined by default - expect(resources._batchValues).toBeUndefined(); - expect(resources._batchTexture).toBeUndefined(); - - // Check that batch resources are still undefined because value is true by default - resources.setShow(0, true); - resources.update(mockContent, scene.frameState); - expect(resources._batchValues).toBeUndefined(); - expect(resources._batchTexture).toBeUndefined(); - expect(resources.getShow(0)).toEqual(true); - - // Check that batch values are dirty and resources are created when value changes - resources.setShow(0, false); - expect(resources._batchValuesDirty).toEqual(true); - resources.update(mockContent, scene.frameState); - expect(resources._batchValues).toBeDefined(); - expect(resources._batchTexture).toBeDefined(); - expect(resources._batchValuesDirty).toEqual(false); - expect(resources.getShow(0)).toEqual(false); - - // Check that dirty stays false when value is the same - resources.setShow(0, false); - expect(resources._batchValuesDirty).toEqual(false); - expect(resources.getShow(0)).toEqual(false); - }); - - it('getShow throws with invalid batchId', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.getShow(); - }).toThrowDeveloperError(); - expect(function() { - resources.getShow(-1); - }).toThrowDeveloperError(); - expect(function() { - resources.getShow(2); - }).toThrowDeveloperError(); - }); - - it('getShow', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - // Show is true by default - expect(resources.getShow(0)).toEqual(true); - resources.setShow(0, false); - expect(resources.getShow(0)).toEqual(false); - }); - - it('setColor throws with invalid batchId', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.setColor(); - }).toThrowDeveloperError(); - expect(function() { - resources.setColor(-1); - }).toThrowDeveloperError(); - expect(function() { - resources.setColor(2); - }).toThrowDeveloperError(); - }); - - it('setColor throws with undefined value', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.setColor(0); - }).toThrowDeveloperError(); - }); - - it('setColor', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - - // Batch resources are undefined by default - expect(resources._batchValues).toBeUndefined(); - expect(resources._batchTexture).toBeUndefined(); - - // Check that batch resources are still undefined because value is true by default - resources.setColor(0, Color.WHITE); - resources.update(mockContent, scene.frameState); - expect(resources._batchValues).toBeUndefined(); - expect(resources._batchTexture).toBeUndefined(); - expect(resources.getColor(0, result)).toEqual(Color.WHITE); - - // Check that batch values are dirty and resources are created when value changes - resources.setColor(0, Color.YELLOW); - expect(resources._batchValuesDirty).toEqual(true); - resources.update(mockContent, scene.frameState); - expect(resources._batchValues).toBeDefined(); - expect(resources._batchTexture).toBeDefined(); - expect(resources._batchValuesDirty).toEqual(false); - expect(resources.getColor(0, result)).toEqual(Color.YELLOW); - - // Check that dirty stays false when value is the same - resources.setColor(0, Color.YELLOW); - expect(resources._batchValuesDirty).toEqual(false); - expect(resources.getColor(0, result)).toEqual(Color.YELLOW); - }); - - it('setAllColor throws with undefined value', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.setAllColor(); - }).toThrowDeveloperError(); - }); - - it('setAllColor', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 2); - resources.setAllColor(Color.YELLOW); - expect(resources.getColor(0, result)).toEqual(Color.YELLOW); - expect(resources.getColor(1, result)).toEqual(Color.YELLOW); - }); - - it('getColor throws with invalid batchId', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.getColor(); - }).toThrowDeveloperError(); - expect(function() { - resources.getColor(-1); - }).toThrowDeveloperError(); - expect(function() { - resources.getColor(2); - }).toThrowDeveloperError(); - }); - - it('getColor throws with undefined result', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.getColor(0); - }).toThrowDeveloperError(); - }); - - it('getColor', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - // Color is true by default - expect(resources.getColor(0, result)).toEqual(Color.WHITE); - resources.setColor(0, Color.YELLOW); - expect(resources.getColor(0, result)).toEqual(Color.YELLOW); - }); - - it('hasProperty throws with undefined name', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.hasProperty(); - }).toThrowDeveloperError(); - }); - - it('hasProperty', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(resources.hasProperty('height')).toEqual(false); - resources.batchTable = { - height: [0.0] - }; - expect(resources.hasProperty('height')).toEqual(true); - expect(resources.hasProperty('id')).toEqual(false); - }); - - it('getPropertyNames', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(resources.getPropertyNames()).toEqual([]); - resources.batchTable = { - height: [0.0], - id : [0] - }; - expect(resources.getPropertyNames()).toEqual(['height', 'id']); - }); - - it('getProperty throws with invalid batchId', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.getProperty(); - }).toThrowDeveloperError(); - expect(function() { - resources.getProperty(-1); - }).toThrowDeveloperError(); - expect(function() { - resources.getProperty(2); - }).toThrowDeveloperError(); - }); - - it('getProperty throws with undefined name', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.getProperty(0); - }).toThrowDeveloperError(); - }); - - it('getProperty', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(resources.getProperty(0, 'height')).toBeUndefined(); - resources.batchTable = { - height: [1.0] - }; - expect(resources.getProperty(0, 'height')).toEqual(1.0); - expect(resources.getProperty(0, 'id')).toBeUndefined(); - }); - - it('setProperty throws with invalid batchId', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.setProperty(); - }).toThrowDeveloperError(); - expect(function() { - resources.setProperty(-1); - }).toThrowDeveloperError(); - expect(function() { - resources.setProperty(2); - }).toThrowDeveloperError(); - }); - - it('setProperty throws with undefined name', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 1); - expect(function() { - resources.setProperty(0); - }).toThrowDeveloperError(); - }); - - it('setProperty without existing batch table', function() { - // Check that a batch table is created with a height of 1.0 for the first resource and undefined for the others - var resources = new Cesium3DTileBatchTableResources(mockContent, 3); - resources.setProperty(0, 'height', 1.0); - - expect(resources.batchTable.height.length).toEqual(3); - expect(resources.getProperty(0, 'height')).toEqual(1.0); - expect(resources.getProperty(1, 'height')).toBeUndefined(); - expect(resources.getProperty(2, 'height')).toBeUndefined(); - }); - - it('setProperty with existing batch table', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 2); - resources.batchTable = { - height : [1.0, 2.0] - }; - resources.setProperty(0, 'height', 3.0); - - expect(resources.getProperty(0, 'height')).toEqual(3.0); - expect(resources.getProperty(1, 'height')).toEqual(2.0); - }); - - it('setProperty with object value', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 2); - resources.batchTable = { - info : [{name : 'building0', year : 2000}, {name : 'building1', year : 2001}] - }; - resources.setProperty(0, 'info', {name : 'building0_new', year : 2002}); - - expect(resources.getProperty(0, 'info')).toEqual({name : 'building0_new', year : 2002}); - expect(resources.getProperty(1, 'info')).toEqual({name : 'building1', year : 2001}); - }); - - it('setProperty with array value', function() { - var resources = new Cesium3DTileBatchTableResources(mockContent, 2); - resources.batchTable = { - rooms : [['room1', 'room2'], ['room3', 'room4']] - }; - resources.setProperty(0, 'rooms', ['room1_new', 'room2']); - - expect(resources.getProperty(0, 'rooms')).toEqual(['room1_new', 'room2']); - expect(resources.getProperty(1, 'rooms')).toEqual(['room3', 'room4']); - }); - - it('renders tileset with batch table', function() { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; - - // Each feature in the b3dm file has an id property from 0 to 99, - // check that the 2nd resource has an id of 2 - expect(content.getFeature(2).getProperty('id')).toEqual(2); - - // Check that a property can be an array - expect(content.getFeature(2).getProperty('rooms')).toEqual(['room2_a', 'room2_b', 'room2_c']); - - // Check that a property can be an object - expect(content.getFeature(2).getProperty('info')).toEqual({name : 'building2', year : 2}); - - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - }); - }); - - it('renders tileset without batch table', function() { - return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; - - expect(content.getFeature(2).getProperty('id')).toBeUndefined(); - - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - }); - }); - - it('renders when vertex texture fetch is not supported', function() { - // Disable VTF - var maximumVertexTextureImageUnits = ContextLimits.maximumVertexTextureImageUnits; - ContextLimits._maximumVertexTextureImageUnits = 0; - - return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - - // Re-enable VTF - ContextLimits._maximumVertexTextureImageUnits = maximumVertexTextureImageUnits; - }); - }); - - it('renders with featuresLength greater than maximumTextureSize', function() { - // Set maximum texture size to 64 temporarily. Batch length of b3dm file is 100. - var maximumTextureSize = ContextLimits.maximumTextureSize; - ContextLimits._maximumTextureSize = 64; - - return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; - expect(content.featuresLength).toBeGreaterThan(ContextLimits._maximumTextureSize); - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - - // Reset maximum texture size - ContextLimits._maximumVertexTextureImageUnits = maximumTextureSize; - }); - }); - - it('renders with featuresLength of zero', function() { - return Cesium3DTilesTester.loadTileset(scene, batchLengthZeroUrl).then(function(tileset) { - expectRender(tileset); - - // Expect the picked primitive to be the entire model rather than a single building - var picked = scene.pickForSpecs().primitive; - expect(picked).toBe(tileset._root.content._model); - }); - }); - - it('renders with debug color', function() { - return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - var color = expectRender(tileset); - tileset.debugColorizeTiles = true; - var debugColor = expectRender(tileset); - expect(debugColor).not.toEqual(color); - tileset.debugColorizeTiles = false; - debugColor = expectRender(tileset); - expect(debugColor).toEqual(color); - }); - }); - - it('renders translucent style', function() { - return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - var resources = tileset._root.content.batchTableResources; - - var opaqueColor = expectRender(tileset); - - // Render transparent - resources.setAllColor(new Color(1.0, 1.0, 1.0, 0.5)); - var translucentColor = expectRender(tileset); - expect(translucentColor).not.toEqual(opaqueColor); - - // Render restored to opaque - resources.setAllColor(Color.WHITE); - var restoredOpaque = expectRender(tileset); - expect(restoredOpaque).toEqual(opaqueColor); - - // Generate both translucent and opaque commands - resources.setColor(0, new Color(1.0, 1.0, 1.0, 0.5)); - expectRender(tileset); - - // Fully transparent - resources.setAllColor(new Color(1.0, 1.0, 1.0, 0.0)); - expect(scene.renderForSpecs()).toEqual([0, 0, 0, 255]); - }); - }); - - it('renders translucent style when vertex texture fetch is not supported', function() { - // Disable VTF - var maximumVertexTextureImageUnits = ContextLimits.maximumVertexTextureImageUnits; - ContextLimits._maximumVertexTextureImageUnits = 0; - - return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - var resources = tileset._root.content.batchTableResources; - - var opaqueColor = expectRender(tileset); - - // Render transparent - resources.setAllColor(new Color(1.0, 1.0, 1.0, 0.5)); - var translucentColor = expectRender(tileset); - expect(translucentColor).not.toEqual(opaqueColor); - - // Render restored to opaque - resources.setAllColor(Color.WHITE); - var restoredOpaque = expectRender(tileset); - expect(restoredOpaque).toEqual(opaqueColor); - - // Generate both translucent and opaque commands - resources.setColor(0, new Color(1.0, 1.0, 1.0, 0.5)); - expectRender(tileset); - - // Fully transparent - resources.setAllColor(new Color(1.0, 1.0, 1.0, 0.0)); - expect(scene.renderForSpecs()).toEqual([0, 0, 0, 255]); - - // Re-enable VTF - ContextLimits._maximumVertexTextureImageUnits = maximumVertexTextureImageUnits; - }); - }); - - it('destroys', function() { - return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; - var resources = content.batchTableResources; - expect(resources.isDestroyed()).toEqual(false); - scene.primitives.remove(tileset); - expect(resources.isDestroyed()).toEqual(true); - }); - }); - -}, 'WebGL'); diff --git a/Specs/Scene/Cesium3DTileBatchTableSpec.js b/Specs/Scene/Cesium3DTileBatchTableSpec.js new file mode 100644 index 000000000000..f717358910cd --- /dev/null +++ b/Specs/Scene/Cesium3DTileBatchTableSpec.js @@ -0,0 +1,639 @@ +/*global defineSuite*/ +defineSuite([ + 'Scene/Cesium3DTileBatchTable', + 'Core/Cartesian2', + 'Core/Cartesian3', + 'Core/Cartesian4', + 'Core/Color', + 'Core/HeadingPitchRange', + 'Core/Matrix2', + 'Core/Matrix3', + 'Core/Matrix4', + 'Renderer/ContextLimits', + 'Specs/Cesium3DTilesTester', + 'Specs/createScene' + ], function( + Cesium3DTileBatchTable, + Cartesian2, + Cartesian3, + Cartesian4, + Color, + HeadingPitchRange, + Matrix2, + Matrix3, + Matrix4, + ContextLimits, + Cesium3DTilesTester, + createScene) { + 'use strict'; + + var scene; + var centerLongitude = -1.31968; + var centerLatitude = 0.698874; + + var withBatchTableUrl = './Data/Cesium3DTiles/Batched/BatchedWithBatchTable/'; + var withoutBatchTableUrl = './Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/'; + var batchLengthZeroUrl = './Data/Cesium3DTiles/Batched/BatchedNoBuildings/'; + + var result = new Color(); + + var mockContent = { + getFeature : function(batchId) { + return {}; + } + }; + + beforeAll(function() { + scene = createScene(); + + // One building in each data set is always located in the center, so point the camera there + var center = Cartesian3.fromRadians(centerLongitude, centerLatitude, 5.0); + scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 10.0)); + }); + + afterAll(function() { + scene.destroyForSpecs(); + }); + + afterEach(function() { + scene.primitives.removeAll(); + }); + + function expectRender(tileset) { + tileset.show = false; + expect(scene.renderForSpecs()).toEqual([0, 0, 0, 255]); + tileset.show = true; + var pixelColor = scene.renderForSpecs(); + expect(pixelColor).not.toEqual([0, 0, 0, 255]); + return pixelColor; + } + + it('setShow throws with invalid batchId', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.setShow(); + }).toThrowDeveloperError(); + expect(function() { + batchTable.setShow(-1); + }).toThrowDeveloperError(); + expect(function() { + batchTable.setShow(2); + }).toThrowDeveloperError(); + }); + + it('setShow throws with undefined value', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.setShow(0); + }).toThrowDeveloperError(); + }); + + it('setShow', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + + // Batch table resources are undefined by default + expect(batchTable._batchValues).toBeUndefined(); + expect(batchTable._batchTexture).toBeUndefined(); + + // Check that batch table resources are still undefined because value is true by default + batchTable.setShow(0, true); + batchTable.update(mockContent, scene.frameState); + expect(batchTable._batchValues).toBeUndefined(); + expect(batchTable._batchTexture).toBeUndefined(); + expect(batchTable.getShow(0)).toEqual(true); + + // Check that batch values are dirty and resources are created when value changes + batchTable.setShow(0, false); + expect(batchTable._batchValuesDirty).toEqual(true); + batchTable.update(mockContent, scene.frameState); + expect(batchTable._batchValues).toBeDefined(); + expect(batchTable._batchTexture).toBeDefined(); + expect(batchTable._batchValuesDirty).toEqual(false); + expect(batchTable.getShow(0)).toEqual(false); + + // Check that dirty stays false when value is the same + batchTable.setShow(0, false); + expect(batchTable._batchValuesDirty).toEqual(false); + expect(batchTable.getShow(0)).toEqual(false); + }); + + it('getShow throws with invalid batchId', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.getShow(); + }).toThrowDeveloperError(); + expect(function() { + batchTable.getShow(-1); + }).toThrowDeveloperError(); + expect(function() { + batchTable.getShow(2); + }).toThrowDeveloperError(); + }); + + it('getShow', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + // Show is true by default + expect(batchTable.getShow(0)).toEqual(true); + batchTable.setShow(0, false); + expect(batchTable.getShow(0)).toEqual(false); + }); + + it('setColor throws with invalid batchId', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.setColor(); + }).toThrowDeveloperError(); + expect(function() { + batchTable.setColor(-1); + }).toThrowDeveloperError(); + expect(function() { + batchTable.setColor(2); + }).toThrowDeveloperError(); + }); + + it('setColor throws with undefined value', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.setColor(0); + }).toThrowDeveloperError(); + }); + + it('setColor', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + + // Batch table resources are undefined by default + expect(batchTable._batchValues).toBeUndefined(); + expect(batchTable._batchTexture).toBeUndefined(); + + // Check that batch table resources are still undefined because value is true by default + batchTable.setColor(0, Color.WHITE); + batchTable.update(mockContent, scene.frameState); + expect(batchTable._batchValues).toBeUndefined(); + expect(batchTable._batchTexture).toBeUndefined(); + expect(batchTable.getColor(0, result)).toEqual(Color.WHITE); + + // Check that batch values are dirty and resources are created when value changes + batchTable.setColor(0, Color.YELLOW); + expect(batchTable._batchValuesDirty).toEqual(true); + batchTable.update(mockContent, scene.frameState); + expect(batchTable._batchValues).toBeDefined(); + expect(batchTable._batchTexture).toBeDefined(); + expect(batchTable._batchValuesDirty).toEqual(false); + expect(batchTable.getColor(0, result)).toEqual(Color.YELLOW); + + // Check that dirty stays false when value is the same + batchTable.setColor(0, Color.YELLOW); + expect(batchTable._batchValuesDirty).toEqual(false); + expect(batchTable.getColor(0, result)).toEqual(Color.YELLOW); + }); + + it('setAllColor throws with undefined value', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.setAllColor(); + }).toThrowDeveloperError(); + }); + + it('setAllColor', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 2); + batchTable.setAllColor(Color.YELLOW); + expect(batchTable.getColor(0, result)).toEqual(Color.YELLOW); + expect(batchTable.getColor(1, result)).toEqual(Color.YELLOW); + }); + + it('getColor throws with invalid batchId', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.getColor(); + }).toThrowDeveloperError(); + expect(function() { + batchTable.getColor(-1); + }).toThrowDeveloperError(); + expect(function() { + batchTable.getColor(2); + }).toThrowDeveloperError(); + }); + + it('getColor throws with undefined result', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.getColor(0); + }).toThrowDeveloperError(); + }); + + it('getColor', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + // Color is true by default + expect(batchTable.getColor(0, result)).toEqual(Color.WHITE); + batchTable.setColor(0, Color.YELLOW); + expect(batchTable.getColor(0, result)).toEqual(Color.YELLOW); + }); + + it('hasProperty throws with undefined name', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.hasProperty(); + }).toThrowDeveloperError(); + }); + + it('hasProperty', function() { + var batchTableJson = { + height: [0.0] + }; + var batchTable = new Cesium3DTileBatchTable(mockContent, 1, batchTableJson); + expect(batchTable.hasProperty('height')).toEqual(true); + expect(batchTable.hasProperty('id')).toEqual(false); + }); + + it('getPropertyNames', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(batchTable.getPropertyNames()).toEqual([]); + + var batchTableJson = { + height: [0.0], + id : [0] + }; + batchTable = new Cesium3DTileBatchTable(mockContent, 1, batchTableJson); + expect(batchTable.getPropertyNames()).toEqual(['height', 'id']); + }); + + it('getProperty throws with invalid batchId', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.getProperty(); + }).toThrowDeveloperError(); + expect(function() { + batchTable.getProperty(-1); + }).toThrowDeveloperError(); + expect(function() { + batchTable.getProperty(2); + }).toThrowDeveloperError(); + }); + + it('getProperty throws with undefined name', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.getProperty(0); + }).toThrowDeveloperError(); + }); + + it('getProperty', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(batchTable.getProperty(0, 'height')).toBeUndefined(); + + var batchTableJson = { + height: [1.0] + }; + batchTable = new Cesium3DTileBatchTable(mockContent, 1, batchTableJson); + expect(batchTable.getProperty(0, 'height')).toEqual(1.0); + expect(batchTable.getProperty(0, 'id')).toBeUndefined(); + }); + + it('setProperty throws with invalid batchId', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.setProperty(); + }).toThrowDeveloperError(); + expect(function() { + batchTable.setProperty(-1); + }).toThrowDeveloperError(); + expect(function() { + batchTable.setProperty(2); + }).toThrowDeveloperError(); + }); + + it('setProperty throws with undefined name', function() { + var batchTable = new Cesium3DTileBatchTable(mockContent, 1); + expect(function() { + batchTable.setProperty(0); + }).toThrowDeveloperError(); + }); + + it('setProperty without existing batch table', function() { + // Check that a batch table is created with a height of 1.0 for the first resource and undefined for the others + var batchTable = new Cesium3DTileBatchTable(mockContent, 3); + batchTable.setProperty(0, 'height', 1.0); + + expect(batchTable.batchTableJson.height.length).toEqual(3); + expect(batchTable.getProperty(0, 'height')).toEqual(1.0); + expect(batchTable.getProperty(1, 'height')).toBeUndefined(); + expect(batchTable.getProperty(2, 'height')).toBeUndefined(); + }); + + it('setProperty with existing batch table', function() { + var batchTableJson = { + height : [1.0, 2.0] + }; + var batchTable = new Cesium3DTileBatchTable(mockContent, 2, batchTableJson); + batchTable.setProperty(0, 'height', 3.0); + + expect(batchTable.getProperty(0, 'height')).toEqual(3.0); + expect(batchTable.getProperty(1, 'height')).toEqual(2.0); + }); + + it('setProperty with object value', function() { + var batchTableJson = { + info : [{name : 'building0', year : 2000}, {name : 'building1', year : 2001}] + }; + var batchTable = new Cesium3DTileBatchTable(mockContent, 2, batchTableJson); + batchTable.setProperty(0, 'info', {name : 'building0_new', year : 2002}); + + expect(batchTable.getProperty(0, 'info')).toEqual({name : 'building0_new', year : 2002}); + expect(batchTable.getProperty(1, 'info')).toEqual({name : 'building1', year : 2001}); + }); + + it('setProperty with array value', function() { + var batchTableJson = { + rooms : [['room1', 'room2'], ['room3', 'room4']] + }; + var batchTable = new Cesium3DTileBatchTable(mockContent, 2, batchTableJson); + batchTable.setProperty(0, 'rooms', ['room1_new', 'room2']); + + expect(batchTable.getProperty(0, 'rooms')).toEqual(['room1_new', 'room2']); + expect(batchTable.getProperty(1, 'rooms')).toEqual(['room3', 'room4']); + }); + + it('throws if the binary property does not specify a componentType', function() { + var batchTableJson = { + propertyScalar : { + byteOffset : 0, + type : 'SCALAR' + } + }; + var batchTableBinary = new Float64Array([0, 1]); + expect(function() { + return new Cesium3DTileBatchTable(mockContent, 2, batchTableJson, batchTableBinary); + }).toThrowDeveloperError(); + }); + + it('throws if the binary property does not specify a type', function() { + var batchTableJson = { + propertyScalar : { + byteOffset : 0, + componentType : 'DOUBLE' + } + }; + var batchTableBinary = new Float64Array([0, 1]); + expect(function() { + return new Cesium3DTileBatchTable(mockContent, 2, batchTableJson, batchTableBinary); + }).toThrowDeveloperError(); + }); + + it('throws if a binary property exists but there is no batchTableBinary', function() { + var batchTableJson = { + propertyScalar : { + byteOffset : 0, + componentType : 'DOUBLE', + type : 'SCALAR' + } + }; + expect(function() { + return new Cesium3DTileBatchTable(mockContent, 2, batchTableJson); + }).toThrowDeveloperError(); + }); + + function concatTypedArrays(arrays) { + var i; + var length = arrays.length; + + var byteLength = 0; + for (i = 0; i < length; ++i) { + byteLength += arrays[i].byteLength; + } + var buffer = new Uint8Array(byteLength); + + var byteOffset = 0; + for (i = 0; i < length; ++i) { + var data = new Uint8Array(arrays[i].buffer); + byteLength = data.length; + for (var j = 0; j < byteLength; ++j) { + buffer[byteOffset++] = data[j]; + } + } + return buffer; + } + + it('getProperty and setProperty work for binary properties', function() { + var propertyScalarBinary = new Float64Array([0, 1]); + var propertyVec2Binary = new Float32Array([2, 3, 4, 5]); + var propertyVec3Binary = new Int32Array([6, 7, 8, 9, 10, 11]); + var propertyVec4Binary = new Uint32Array([12, 13, 14, 15, 16, 17, 18, 19]); + var propertyMat2Binary = new Int16Array([20, 21, 22, 23, 24, 25, 26, 27]); + var propertyMat3Binary = new Uint16Array([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45]); + var propertyMat4Binary = new Uint8Array([46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77]); + + var buffers = [propertyScalarBinary, propertyVec2Binary, propertyVec3Binary, propertyVec4Binary, propertyMat2Binary, propertyMat3Binary, propertyMat4Binary]; + var batchTableBinary = concatTypedArrays(buffers); + var batchTableJson = { + propertyScalar : { + byteOffset : 0, + componentType : 'DOUBLE', + type : 'SCALAR' + }, + propertyVec2 : { + byteOffset : 16, + componentType : 'FLOAT', + type : 'VEC2' + }, + propertyVec3 : { + byteOffset : 32, + componentType : 'INT', + type : 'VEC3' + }, + propertyVec4 : { + byteOffset : 56, + componentType : 'UNSIGNED_INT', + type : 'VEC4' + }, + propertyMat2 : { + byteOffset : 88, + componentType : 'SHORT', + type : 'MAT2' + }, + propertyMat3 : { + byteOffset : 104, + componentType : 'UNSIGNED_SHORT', + type : 'MAT3' + }, + propertyMat4 : { + byteOffset : 140, + componentType : 'UNSIGNED_BYTE', + type : 'MAT4' + } + }; + + var batchTable = new Cesium3DTileBatchTable(mockContent, 2, batchTableJson, batchTableBinary); + + expect(batchTable.getProperty(1, 'propertyScalar')).toEqual(1); + expect(batchTable.getProperty(1, 'propertyVec2')).toEqual(new Cartesian2(4, 5)); + expect(batchTable.getProperty(1, 'propertyVec3')).toEqual(new Cartesian3(9, 10, 11)); + expect(batchTable.getProperty(1, 'propertyVec4')).toEqual(new Cartesian4(16, 17, 18, 19)); + expect(batchTable.getProperty(1, 'propertyMat2')).toEqual(new Matrix2(24, 26, 25, 27)); // Constructor is row-major, data is column major + expect(batchTable.getProperty(1, 'propertyMat3')).toEqual(new Matrix3(37, 40, 43, 38, 41, 44, 39, 42, 45)); // Constructor is row-major, data is column major + expect(batchTable.getProperty(1, 'propertyMat4')).toEqual(new Matrix4(62, 66, 70, 74, 63, 67, 71, 75, 64, 68, 72, 76, 65, 69, 73, 77)); // Constructor is row-major, data is column major + + batchTable.setProperty(1, 'propertyScalar', 2); + batchTable.setProperty(1, 'propertyVec2', new Cartesian2(5, 6)); + batchTable.setProperty(1, 'propertyVec3', new Cartesian3(10, 11, 12)); + batchTable.setProperty(1, 'propertyVec4', new Cartesian4(17, 18, 19, 20)); + batchTable.setProperty(1, 'propertyMat2', new Matrix2(25, 27, 26, 28)); + batchTable.setProperty(1, 'propertyMat3', new Matrix3(38, 41, 44, 39, 42, 45, 40, 43, 46)); + batchTable.setProperty(1, 'propertyMat4', new Matrix4(63, 67, 71, 75, 64, 68, 72, 76, 65, 69, 73, 77, 66, 70, 74, 78)); + + expect(batchTable.getProperty(1, 'propertyScalar')).toEqual(2); + expect(batchTable.getProperty(1, 'propertyVec2')).toEqual(new Cartesian2(5, 6)); + expect(batchTable.getProperty(1, 'propertyVec3')).toEqual(new Cartesian3(10, 11, 12)); + expect(batchTable.getProperty(1, 'propertyVec4')).toEqual(new Cartesian4(17, 18, 19, 20)); + expect(batchTable.getProperty(1, 'propertyMat2')).toEqual(new Matrix2(25, 27, 26, 28)); + expect(batchTable.getProperty(1, 'propertyMat3')).toEqual(new Matrix3(38, 41, 44, 39, 42, 45, 40, 43, 46)); + expect(batchTable.getProperty(1, 'propertyMat4')).toEqual(new Matrix4(63, 67, 71, 75, 64, 68, 72, 76, 65, 69, 73, 77, 66, 70, 74, 78)); + }); + + it('renders tileset with batch table', function() { + return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { + var content = tileset._root.content; + + // Each feature in the b3dm file has an id property from 0 to 9, + // check that the 2nd resource has an id of 2 + expect(content.getFeature(2).getProperty('id')).toEqual(2); + + // Check that a property can be an array + expect(content.getFeature(2).getProperty('rooms')).toEqual(['room2_a', 'room2_b', 'room2_c']); + + // Check that a property can be an object + expect(content.getFeature(2).getProperty('info')).toEqual({name : 'building2', year : 2}); + + Cesium3DTilesTester.expectRenderTileset(scene, tileset); + }); + }); + + it('renders tileset without batch table', function() { + return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { + var content = tileset._root.content; + + expect(content.getFeature(2).getProperty('id')).toBeUndefined(); + + Cesium3DTilesTester.expectRenderTileset(scene, tileset); + }); + }); + + it('renders when vertex texture fetch is not supported', function() { + // Disable VTF + var maximumVertexTextureImageUnits = ContextLimits.maximumVertexTextureImageUnits; + ContextLimits._maximumVertexTextureImageUnits = 0; + + return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { + Cesium3DTilesTester.expectRenderTileset(scene, tileset); + + // Re-enable VTF + ContextLimits._maximumVertexTextureImageUnits = maximumVertexTextureImageUnits; + }); + }); + + it('renders with featuresLength greater than maximumTextureSize', function() { + // Set maximum texture size to 4 temporarily. Batch length of b3dm file is 10. + var maximumTextureSize = ContextLimits.maximumTextureSize; + ContextLimits._maximumTextureSize = 4; + + return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { + var content = tileset._root.content; + expect(content.featuresLength).toBeGreaterThan(ContextLimits._maximumTextureSize); + Cesium3DTilesTester.expectRenderTileset(scene, tileset); + + // Reset maximum texture size + ContextLimits._maximumVertexTextureImageUnits = maximumTextureSize; + }); + }); + + it('renders with featuresLength of zero', function() { + return Cesium3DTilesTester.loadTileset(scene, batchLengthZeroUrl).then(function(tileset) { + expectRender(tileset); + + // Expect the picked primitive to be the entire model rather than a single building + var picked = scene.pickForSpecs().primitive; + expect(picked).toBe(tileset._root.content._model); + }); + }); + + it('renders with debug color', function() { + return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { + var color = expectRender(tileset); + tileset.debugColorizeTiles = true; + var debugColor = expectRender(tileset); + expect(debugColor).not.toEqual(color); + tileset.debugColorizeTiles = false; + debugColor = expectRender(tileset); + expect(debugColor).toEqual(color); + }); + }); + + it('renders translucent style', function() { + return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { + var batchTable = tileset._root.content.batchTable; + + var opaqueColor = expectRender(tileset); + + // Render transparent + batchTable.setAllColor(new Color(1.0, 1.0, 1.0, 0.5)); + var translucentColor = expectRender(tileset); + expect(translucentColor).not.toEqual(opaqueColor); + + // Render restored to opaque + batchTable.setAllColor(Color.WHITE); + var restoredOpaque = expectRender(tileset); + expect(restoredOpaque).toEqual(opaqueColor); + + // Generate both translucent and opaque commands + batchTable.setColor(0, new Color(1.0, 1.0, 1.0, 0.5)); + expectRender(tileset); + + // Fully transparent + batchTable.setAllColor(new Color(1.0, 1.0, 1.0, 0.0)); + expect(scene.renderForSpecs()).toEqual([0, 0, 0, 255]); + }); + }); + + it('renders translucent style when vertex texture fetch is not supported', function() { + // Disable VTF + var maximumVertexTextureImageUnits = ContextLimits.maximumVertexTextureImageUnits; + ContextLimits._maximumVertexTextureImageUnits = 0; + + return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { + var batchTable = tileset._root.content.batchTable; + + var opaqueColor = expectRender(tileset); + + // Render transparent + batchTable.setAllColor(new Color(1.0, 1.0, 1.0, 0.5)); + var translucentColor = expectRender(tileset); + expect(translucentColor).not.toEqual(opaqueColor); + + // Render restored to opaque + batchTable.setAllColor(Color.WHITE); + var restoredOpaque = expectRender(tileset); + expect(restoredOpaque).toEqual(opaqueColor); + + // Generate both translucent and opaque commands + batchTable.setColor(0, new Color(1.0, 1.0, 1.0, 0.5)); + expectRender(tileset); + + // Fully transparent + batchTable.setAllColor(new Color(1.0, 1.0, 1.0, 0.0)); + expect(scene.renderForSpecs()).toEqual([0, 0, 0, 255]); + + // Re-enable VTF + ContextLimits._maximumVertexTextureImageUnits = maximumVertexTextureImageUnits; + }); + }); + + it('destroys', function() { + return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { + var content = tileset._root.content; + var batchTable = content.batchTable; + expect(batchTable.isDestroyed()).toEqual(false); + scene.primitives.remove(tileset); + expect(batchTable.isDestroyed()).toEqual(true); + }); + }); + +}, 'WebGL'); diff --git a/Specs/Scene/Cesium3DTileFeatureTableResourcesSpec.js b/Specs/Scene/Cesium3DTileFeatureTableSpec.js similarity index 62% rename from Specs/Scene/Cesium3DTileFeatureTableResourcesSpec.js rename to Specs/Scene/Cesium3DTileFeatureTableSpec.js index 135dfa1a21be..08cc3d7d3525 100644 --- a/Specs/Scene/Cesium3DTileFeatureTableResourcesSpec.js +++ b/Specs/Scene/Cesium3DTileFeatureTableSpec.js @@ -1,65 +1,74 @@ /*global defineSuite*/ defineSuite([ - 'Core/ComponentDatatype', - 'Scene/Cesium3DTileFeatureTableResources' + 'Scene/Cesium3DTileFeatureTable', + 'Core/ComponentDatatype' ], function( - ComponentDatatype, - Cesium3DTileFeatureTableResources) { + Cesium3DTileFeatureTable, + ComponentDatatype) { 'use strict'; it('getTypedArrayForSemantic throws exception if byteOffset is not defined', function() { - var featureTable = new Cesium3DTileFeatureTableResources(); + var featureTable = new Cesium3DTileFeatureTable(); expect(function() { featureTable.getTypedArrayForSemantic('TEST', undefined, ComponentDatatype.UNSIGNED_INT, 5, 1); }).toThrowDeveloperError(); }); it('getTypedArrayForSemantic throws exception if componentType is not defined', function() { - var featureTable = new Cesium3DTileFeatureTableResources(); + var featureTable = new Cesium3DTileFeatureTable(); expect(function() { featureTable.getTypedArrayForSemantic('TEST', 0, undefined, 5, 1); }).toThrowDeveloperError(); }); it('getTypedArrayForSemantic throws exception if count is not defined', function() { - var featureTable = new Cesium3DTileFeatureTableResources(); + var featureTable = new Cesium3DTileFeatureTable(); expect(function() { featureTable.getTypedArrayForSemantic('TEST', 0, ComponentDatatype.UNSIGNED_INT, undefined, 1); }).toThrowDeveloperError(); }); it('loads from JSON', function() { - var featureTable = new Cesium3DTileFeatureTableResources({ + var featureTable = new Cesium3DTileFeatureTable({ TEST : [0, 1, 2, 3, 4, 5] }); + featureTable.featuresLength = 3; var all = featureTable.getGlobalProperty('TEST', ComponentDatatype.UNSIGNED_BYTE); expect(all).toEqual([0, 1, 2, 3, 4, 5]); var feature = featureTable.getProperty('TEST', 1, ComponentDatatype.UNSIGNED_BYTE, 2); expect(feature).toEqual([2, 3]); + var properties = featureTable.getPropertyArray('TEST', ComponentDatatype.UNSIGNED_BYTE, 2); + expect(properties).toEqual([0, 1, 2, 3, 4, 5]); }); it('loads from cached array buffer views', function() { - var featureTable = new Cesium3DTileFeatureTableResources({ + var featureTable = new Cesium3DTileFeatureTable({ TEST : { byteOffset : Number.POSITIVE_INFINITY } }); + featureTable.featuresLength = 3; featureTable._cachedArrayBufferViews.TEST = new Uint8Array([0, 1, 2, 3, 4, 5]); - var all = featureTable.getGlobalProperty('TEST', ComponentDatatype.UNSIGNED_BYTE, 5); - expect(all).toEqual([0, 1, 2, 3, 4]); + var all = featureTable.getGlobalProperty('TEST', ComponentDatatype.UNSIGNED_BYTE, 6); + expect(all).toEqual([0, 1, 2, 3, 4, 5]); var feature = featureTable.getProperty('TEST', 1, ComponentDatatype.UNSIGNED_BYTE, 2); expect(feature).toEqual([2, 3]); + var properties = featureTable.getPropertyArray('TEST', ComponentDatatype.UNSIGNED_BYTE, 2); + expect(properties).toEqual([0, 1, 2, 3, 4, 5]); }); it('loads from JSON byteOffset', function() { - var featureTable = new Cesium3DTileFeatureTableResources({ + var featureTable = new Cesium3DTileFeatureTable({ TEST : { byteOffset : 4 } }, new Uint8Array([0, 0, 0, 0, 0, 1, 2, 3, 4, 5])); - var all = featureTable.getGlobalProperty('TEST', ComponentDatatype.UNSIGNED_BYTE, 5); - expect(all).toEqual([0, 1, 2, 3, 4]); + featureTable.featuresLength = 3; + var all = featureTable.getGlobalProperty('TEST', ComponentDatatype.UNSIGNED_BYTE, 6); + expect(all).toEqual([0, 1, 2, 3, 4, 5]); var feature = featureTable.getProperty('TEST', 1, ComponentDatatype.UNSIGNED_BYTE, 2); expect(feature).toEqual([2, 3]); + var properties = featureTable.getPropertyArray('TEST', ComponentDatatype.UNSIGNED_BYTE, 2); + expect(properties).toEqual([0, 1, 2, 3, 4, 5]); }); }); \ No newline at end of file diff --git a/Specs/Scene/Cesium3DTileSpec.js b/Specs/Scene/Cesium3DTileSpec.js index 2051d8bcdbe9..59131e0d0bfd 100644 --- a/Specs/Scene/Cesium3DTileSpec.js +++ b/Specs/Scene/Cesium3DTileSpec.js @@ -4,20 +4,28 @@ defineSuite([ 'Scene/TileBoundingRegion', 'Scene/TileOrientedBoundingBox', 'Core/Cartesian3', + 'Core/clone', 'Core/defined', + 'Core/Math', 'Core/Matrix3', + 'Core/Matrix4', 'Core/Rectangle', 'Core/SphereOutlineGeometry', + 'Core/Transforms', 'Specs/createScene' ], function( Cesium3DTile, TileBoundingRegion, TileOrientedBoundingBox, Cartesian3, + clone, defined, + CesiumMath, Matrix3, + Matrix4, Rectangle, SphereOutlineGeometry, + Transforms, createScene) { 'use strict'; @@ -36,12 +44,12 @@ defineSuite([ content : { url : '0/0.b3dm', boundingVolume : { - sphere: [0.0, 0.0, 0.0, 5.0] + sphere: [0.0, 0.0, 1.0, 5.0] } }, - children : [], - boundingVolume : { - sphere: [0.0, 0.0, 0.0, 5.0] + children : [], + boundingVolume : { + sphere: [0.0, 0.0, 1.0, 5.0] } }; @@ -85,11 +93,11 @@ defineSuite([ content : { url : '0/0.b3dm', boundingVolume : { - box : [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0] + box : [0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 2.0] } }, boundingVolume: { - box : [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0] + box : [0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 2.0] } }; @@ -105,14 +113,28 @@ defineSuite([ } }; + var mockTileset = { + debugShowBoundingVolume : true, + modelMatrix : Matrix4.IDENTITY + }; + + var centerLongitude = -1.31968; + var centerLatitude = 0.698874; + + function getTileTransform(longitude, latitude) { + var transformCenter = Cartesian3.fromRadians(longitude, latitude, 0.0); + var transformMatrix = Transforms.headingPitchRollToFixedFrame(transformCenter, 0.0, 0.0, 0.0); + return Matrix4.pack(transformMatrix, new Array(16)); + } + it('throws if content has an unsupported extension', function() { expect(function() { - return new Cesium3DTile(undefined, '/some_url', tileWithInvalidExtension, undefined); + return new Cesium3DTile(mockTileset, '/some_url', tileWithInvalidExtension, undefined); }).toThrowDeveloperError(); }); it('destroys', function() { - var tile = new Cesium3DTile(undefined, '/some_url', tileWithBoundingSphere, undefined); + var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined); expect(tile.isDestroyed()).toEqual(false); tile.destroy(); expect(tile.isDestroyed()).toEqual(true); @@ -120,7 +142,7 @@ defineSuite([ describe('bounding volumes', function() { it('can have a bounding sphere', function() { - var tile = new Cesium3DTile(undefined, '/some_url', tileWithBoundingSphere, undefined); + var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined); var radius = tileWithBoundingSphere.boundingVolume.sphere[3]; expect(tile.contentBoundingVolume).toBeDefined(); expect(tile.contentBoundingVolume.boundingVolume.radius).toEqual(radius); @@ -128,11 +150,11 @@ defineSuite([ }); it('can have a content bounding sphere', function() { - var tile = new Cesium3DTile(undefined, '/some_url', tileWithContentBoundingSphere, undefined); + var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithContentBoundingSphere, undefined); var radius = tileWithContentBoundingSphere.content.boundingVolume.sphere[3]; expect(tile.contentBoundingVolume).toBeDefined(); expect(tile.contentBoundingVolume.boundingVolume.radius).toEqual(radius); - expect(tile.contentBoundingVolume.boundingVolume.center).toEqual(Cartesian3.ZERO); + expect(tile.contentBoundingVolume.boundingVolume.center).toEqual(new Cartesian3(0.0, 0.0, 1.0)); }); it('can have a bounding region', function() { @@ -140,7 +162,7 @@ defineSuite([ var rectangle = new Rectangle(box[0], box[1], box[2], box[3]); var minimumHeight = tileWithBoundingRegion.boundingVolume.region[4]; var maximumHeight = tileWithBoundingRegion.boundingVolume.region[5]; - var tile = new Cesium3DTile(undefined, '/some_url', tileWithBoundingRegion, undefined); + var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingRegion, undefined); var tbr = new TileBoundingRegion({rectangle: rectangle, minimumHeight: minimumHeight, maximumHeight: maximumHeight}); expect(tile.contentBoundingVolume).toBeDefined(); expect(tile.contentBoundingVolume).toEqual(tbr); @@ -148,7 +170,7 @@ defineSuite([ it('can have a content bounding region', function() { var region = tileWithContentBoundingRegion.content.boundingVolume.region; - var tile = new Cesium3DTile(undefined, '/some_url', tileWithContentBoundingRegion, undefined); + var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithContentBoundingRegion, undefined); expect(tile._contentBoundingVolume).toBeDefined(); var tbb = new TileBoundingRegion({ rectangle: new Rectangle(region[0], region[1], region[2], region[3]), @@ -160,37 +182,92 @@ defineSuite([ it('can have an oriented bounding box', function() { var box = tileWithBoundingBox.boundingVolume.box; - var tile = new Cesium3DTile(undefined, '/some_url', tileWithBoundingBox, undefined); + var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingBox, undefined); expect(tile.contentBoundingVolume).toBeDefined(); var center = new Cartesian3(box[0], box[1], box[2]); var halfAxes = Matrix3.fromArray(box, 3); - var obb = new TileOrientedBoundingBox({ - center: center, - halfAxes: halfAxes - }); + var obb = new TileOrientedBoundingBox(center, halfAxes); expect(tile.contentBoundingVolume).toEqual(obb); }); it('can have a content oriented bounding box', function() { var box = tileWithContentBoundingBox.boundingVolume.box; - var tile = new Cesium3DTile(undefined, '/some_url', tileWithContentBoundingBox, undefined); + var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithContentBoundingBox, undefined); expect(tile.contentBoundingVolume).toBeDefined(); var center = new Cartesian3(box[0], box[1], box[2]); var halfAxes = Matrix3.fromArray(box, 3); - var obb = new TileOrientedBoundingBox({ - center: center, - halfAxes: halfAxes - }); + var obb = new TileOrientedBoundingBox(center, halfAxes); expect(tile.contentBoundingVolume).toEqual(obb); }); + + it('tile transform affects bounding sphere', function() { + var header = clone(tileWithContentBoundingSphere, true); + header.transform = getTileTransform(centerLongitude, centerLatitude); + var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined); + var boundingSphere = tile._boundingVolume.boundingVolume; + var contentBoundingSphere = tile._contentBoundingVolume.boundingVolume; + + var boundingVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude, 1.0); + expect(boundingSphere.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON4); + expect(boundingSphere.radius).toEqual(5.0); // No change + + expect(contentBoundingSphere.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON4); + expect(contentBoundingSphere.radius).toEqual(5.0); // No change + }); + + it('tile transform affects oriented bounding box', function() { + var header = clone(tileWithContentBoundingBox, true); + header.transform = getTileTransform(centerLongitude, centerLatitude); + var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined); + var boundingBox = tile._boundingVolume.boundingVolume; + var contentBoundingBox = tile._contentBoundingVolume.boundingVolume; + + var boundingVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude, 1.0); + expect(boundingBox.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON7); + expect(contentBoundingBox.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON7); + }); + + it('tile transform does not affect bounding region', function() { + var header = clone(tileWithContentBoundingRegion, true); + header.transform = getTileTransform(centerLongitude, centerLatitude); + var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined); + var boundingRegion = tile._boundingVolume; + var contentBoundingRegion = tile._contentBoundingVolume; + + var region = header.boundingVolume.region; + var rectangle = Rectangle.unpack(region); + expect(boundingRegion.rectangle).toEqual(rectangle); + expect(contentBoundingRegion.rectangle).toEqual(rectangle); + }); + + it('tile transform changes', function() { + var mockTileset = { + modelMatrix : Matrix4.IDENTITY + }; + var header = clone(tileWithBoundingSphere, true); + header.transform = getTileTransform(centerLongitude, centerLatitude); + var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined); + var boundingSphere = tile._boundingVolume.boundingVolume; + + // Check the original transform + var boundingVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude); + expect(boundingSphere.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON7); + + // Change the transform + var newLongitude = -1.012; + var newLatitude = 0.698874; + tile.computedTransform = getTileTransform(newLongitude, newLatitude); + tile.update(mockTileset); + + // Check the new transform + var newCenter = Cartesian3.fromRadians(newLongitude, newLatitude); + expect(boundingSphere.center).toEqualEpsilon(newCenter, CesiumMath.EPSILON7); + }); }); describe('debug bounding volumes', function() { it('can be a bounding region', function() { var scene = createScene(); - var mockTileset = { - debugShowBoundingVolume: true - }; var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingRegion, undefined); tile.update(mockTileset, scene.frameState); expect(tile._debugBoundingVolume).toBeDefined(); @@ -198,9 +275,6 @@ defineSuite([ it('can be an oriented bounding box', function() { var scene = createScene(); - var mockTileset = { - debugShowBoundingVolume: true - }; var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingBox, undefined); tile.update(mockTileset, scene.frameState); expect(tile._debugBoundingVolume).toBeDefined(); @@ -208,9 +282,6 @@ defineSuite([ it('can be a bounding sphere', function() { var scene = createScene(); - var mockTileset = { - debugShowBoundingVolume: true - }; var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined); tile.update(mockTileset, scene.frameState); expect(tile._debugBoundingVolume).toBeDefined(); diff --git a/Specs/Scene/Cesium3DTilesetSpec.js b/Specs/Scene/Cesium3DTilesetSpec.js index cb596d74aa49..e40c2a78167a 100644 --- a/Specs/Scene/Cesium3DTilesetSpec.js +++ b/Specs/Scene/Cesium3DTilesetSpec.js @@ -6,6 +6,7 @@ defineSuite([ 'Core/defined', 'Core/HeadingPitchRange', 'Core/loadWithXhr', + 'Core/Matrix4', 'Core/RequestScheduler', 'Scene/Cesium3DTile', 'Scene/Cesium3DTileContentState', @@ -23,6 +24,7 @@ defineSuite([ defined, HeadingPitchRange, loadWithXhr, + Matrix4, RequestScheduler, Cesium3DTile, Cesium3DTileContentState, @@ -71,6 +73,9 @@ defineSuite([ // 1 tile with opaque and translucent features var translucentOpaqueMixUrl = './Data/Cesium3DTiles/Batched/BatchedTranslucentOpaqueMix/'; + // Root tile is transformed from local space to wgs84, child tile is rotated, scales, and translated locally + var tilesetWithTransformsUrl = './Data/Cesium3DTiles/Tilesets/TilesetWithTransforms'; + var styleUrl = './Data/Cesium3DTiles/Style/style.json'; var originalMaximumRequests; @@ -211,7 +216,7 @@ defineSuite([ expect(properties).toBeDefined(); expect(properties.id).toBeDefined(); expect(properties.id.minimum).toEqual(0); - expect(properties.id.maximum).toEqual(99); + expect(properties.id.maximum).toEqual(9); expect(tileset._geometricError).toEqual(240.0); expect(tileset._root).toBeDefined(); @@ -727,7 +732,7 @@ defineSuite([ }); it('debugColorizeTiles', function() { - // More precise test is in Cesium3DTileBatchTableResourcesSpec + // More precise test is in Cesium3DTileBatchTableSpec return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) { viewRootOnly(); tileset.debugColorizeTiles = true; @@ -942,12 +947,12 @@ defineSuite([ return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { var showColor = scene.renderForSpecs(); - // Each feature in the b3dm file has an id property from 0 to 99 - // ${id} >= 100 will always evaluate to false + // Each feature in the b3dm file has an id property from 0 to 9 + // ${id} >= 10 will always evaluate to false tileset.style = new Cesium3DTileStyle({show : '${id} >= 50 * 2'}); expect(scene.renderForSpecs()).toEqual([0, 0, 0, 255]); - // ${id} < 100 will always evaluate to true + // ${id} < 10 will always evaluate to true tileset.style = new Cesium3DTileStyle({show : '${id} < 200 / 2'}); expect(scene.renderForSpecs()).toEqual(showColor); }); @@ -1040,8 +1045,8 @@ defineSuite([ return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { var showColor = scene.renderForSpecs(); - // Initially, all feature ids are less than 100 - tileset.style = new Cesium3DTileStyle({show : '${id} < 100'}); + // Initially, all feature ids are less than 10 + tileset.style = new Cesium3DTileStyle({show : '${id} < 10'}); expect(scene.renderForSpecs()).toEqual(showColor); // Change feature ids so the show expression will evaluate to false @@ -1051,14 +1056,14 @@ defineSuite([ var feature; for (i = 0; i < length; ++i) { feature = content.getFeature(i); - feature.setProperty('id', feature.getProperty('id') + 100); + feature.setProperty('id', feature.getProperty('id') + 10); } expect(scene.renderForSpecs()).toEqual([0, 0, 0, 255]); // Change ids back for (i = 0; i < length; ++i) { feature = content.getFeature(i); - feature.setProperty('id', feature.getProperty('id') - 100); + feature.setProperty('id', feature.getProperty('id') - 10); } expect(scene.renderForSpecs()).toEqual(showColor); }); @@ -1066,8 +1071,8 @@ defineSuite([ it('applies style with complex color expression to a tileset', function() { return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - // Each feature in the b3dm file has an id property from 0 to 99 - // ${id} >= 100 will always evaluate to false + // Each feature in the b3dm file has an id property from 0 to 9 + // ${id} >= 10 will always evaluate to false tileset.style = new Cesium3DTileStyle({color : '(${id} >= 50 * 2) ? color("red") : color("blue")'}); var color = scene.renderForSpecs(); expect(color[0]).toEqual(0); @@ -1075,7 +1080,7 @@ defineSuite([ expect(color[2]).toBeGreaterThan(0); expect(color[3]).toEqual(255); - // ${id} < 100 will always evaluate to true + // ${id} < 10 will always evaluate to true tileset.style = new Cesium3DTileStyle({color : '(${id} < 50 * 2) ? color("red") : color("blue")'}); color = scene.renderForSpecs(); expect(color[0]).toBeGreaterThan(0); @@ -1087,11 +1092,11 @@ defineSuite([ it('applies conditional color style to a tileset', function() { return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - // ${id} < 100 will always evaluate to true + // ${id} < 10 will always evaluate to true tileset.style = new Cesium3DTileStyle({ color : { conditions : { - '${id} < 100' : 'color("red")', + '${id} < 10' : 'color("red")', 'true' : 'color("blue")' } } @@ -1102,11 +1107,11 @@ defineSuite([ expect(color[2]).toEqual(0); expect(color[3]).toEqual(255); - // ${id}>= 100 will always evaluate to false + // ${id}>= 10 will always evaluate to false tileset.style = new Cesium3DTileStyle({ color : { conditions : { - '${id} >= 100' : 'color("red")', + '${id} >= 10' : 'color("red")', 'true' : 'color("blue")' } } @@ -1121,7 +1126,7 @@ defineSuite([ it('loads style from uri', function() { return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - // ${id} < 100 will always evaluate to true + // ${id} < 10 will always evaluate to true tileset.style = new Cesium3DTileStyle(styleUrl); return tileset.style.readyPromise.then(function(style) { var color = scene.renderForSpecs(); @@ -1431,4 +1436,27 @@ defineSuite([ }).toThrowDeveloperError(); }); + it('propagates tile transform down the tree', function() { + return Cesium3DTilesTester.loadTileset(scene, tilesetWithTransformsUrl).then(function(tileset) { + scene.renderForSpecs(); + var root = tileset._root; + var rootTransform = Matrix4.unpack(root._header.transform); + + var child = root.children[0]; + var childTransform = Matrix4.unpack(child._header.transform); + var computedTransform = Matrix4.multiply(rootTransform, childTransform, new Matrix4()); + + expect(tileset._selectedTiles.length).toBe(2); + expect(root.computedTransform).toEqual(rootTransform); + expect(child.computedTransform).toEqual(computedTransform); + + // Set the tileset's modelMatrix + var tilesetTransform = Matrix4.fromTranslation(new Cartesian3(0.0, 1.0, 0.0)); + tileset.modelMatrix = tilesetTransform; + computedTransform = Matrix4.multiply(tilesetTransform, computedTransform, computedTransform); + scene.renderForSpecs(); + expect(child.computedTransform).toEqual(computedTransform); + }); + }); + }, 'WebGL'); diff --git a/Specs/Scene/Instanced3DModel3DTileContentSpec.js b/Specs/Scene/Instanced3DModel3DTileContentSpec.js index 99d9d9e9827c..d6326f5be6d6 100644 --- a/Specs/Scene/Instanced3DModel3DTileContentSpec.js +++ b/Specs/Scene/Instanced3DModel3DTileContentSpec.js @@ -3,6 +3,7 @@ defineSuite([ 'Scene/Instanced3DModel3DTileContent', 'Core/Cartesian3', 'Core/HeadingPitchRange', + 'Core/Transforms', 'Scene/Cesium3DTileContentState', 'Scene/TileBoundingSphere', 'Specs/Cesium3DTilesTester', @@ -11,6 +12,7 @@ defineSuite([ Instanced3DModel3DTileContent, Cartesian3, HeadingPitchRange, + Transforms, Cesium3DTileContentState, TileBoundingSphere, Cesium3DTilesTester, @@ -18,11 +20,12 @@ defineSuite([ 'use strict'; var scene; - var originLongitude = -1.3197004048940548; - var originLatitude = 0.6988585409308616; + var centerLongitude = -1.31968; + var centerLatitude = 0.698874; var gltfExternalUrl = './Data/Cesium3DTiles/Instanced/InstancedGltfExternal/'; var withBatchTableUrl = './Data/Cesium3DTiles/Instanced/InstancedWithBatchTable/'; + var withBatchTableBinaryUrl = './Data/Cesium3DTiles/Instanced/InstancedWithBatchTableBinary/'; var withoutBatchTableUrl = './Data/Cesium3DTiles/Instanced/InstancedWithoutBatchTable/'; var orientationUrl = './Data/Cesium3DTiles/Instanced/InstancedOrientationWithBatchTable/'; var oct16POrientationUrl = './Data/Cesium3DTiles/Instanced/InstancedOct32POrientationWithBatchTable/'; @@ -30,12 +33,20 @@ defineSuite([ var scaleNonUniformUrl = './Data/Cesium3DTiles/Instanced/InstancedScaleNonUniformWithBatchTable/'; var quantizedUrl = './Data/Cesium3DTiles/Instanced/InstancedQuantizedWithBatchTable/'; var quantizedOct32POrientationUrl = './Data/Cesium3DTiles/Instanced/InstancedQuantizedOct32POrientationWithBatchTable/'; + var withTransformUrl = './Data/Cesium3DTiles/Instanced/InstancedWithTransform/'; + + function setCamera(longitude, latitude) { + // One instance is located at the center, point the camera there + var center = Cartesian3.fromRadians(longitude, latitude); + scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 36.0)); + } beforeAll(function() { scene = createScene(); - // One instance is located on the bottom corner, point the camera there - var bottomCorner = Cartesian3.fromRadians(originLongitude, originLatitude, 5.0); - scene.camera.lookAt(bottomCorner, new HeadingPitchRange(0.0, -1.57, 50.0)); + }); + + beforeEach(function() { + setCamera(centerLongitude, centerLatitude); }); afterAll(function() { @@ -92,6 +103,17 @@ defineSuite([ return Cesium3DTilesTester.rejectsReadyPromiseOnFailedRequest('i3dm'); }); + var mockTile = { + contentBoundingVolume : new TileBoundingSphere(), + _header : { + content : { + boundingVolume : { + sphere : [0.0, 0.0, 0.0, 1.0] + } + } + } + }; + it('loads with no instances, but does not become ready', function() { var arrayBuffer = Cesium3DTilesTester.generateInstancedTileBuffer({ featuresLength : 0, @@ -99,11 +121,8 @@ defineSuite([ }); var tileset = {}; - var tile = { - contentBoundingVolume : new TileBoundingSphere() - }; var url = ''; - var instancedTile = new Instanced3DModel3DTileContent(tileset, tile, url); + var instancedTile = new Instanced3DModel3DTileContent(tileset, mockTile, url); instancedTile.initialize(arrayBuffer); // Expect the tile to never reach the ready state due to returning early in ModelInstanceCollection for (var i = 0; i < 10; ++i) { @@ -124,6 +143,12 @@ defineSuite([ }); }); + it('renders with batch table binary', function() { + return Cesium3DTilesTester.loadTileset(scene, withBatchTableBinaryUrl).then(function(tileset) { + Cesium3DTilesTester.expectRenderTileset(scene, tileset); + }); + }); + it('renders without batch table', function() { return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { Cesium3DTilesTester.expectRenderTileset(scene, tileset); @@ -166,6 +191,25 @@ defineSuite([ }); }); + it('renders with tile transform', function() { + return Cesium3DTilesTester.loadTileset(scene, withTransformUrl).then(function(tileset) { + Cesium3DTilesTester.expectRenderTileset(scene, tileset); + + var newLongitude = -1.31962; + var newLatitude = 0.698874; + var newCenter = Cartesian3.fromRadians(newLongitude, newLatitude, 15.0); + var newTransform = Transforms.headingPitchRollToFixedFrame(newCenter, 0.0, 0.0, 0.0); + + // Update tile transform + tileset._root.transform = newTransform; + scene.renderForSpecs(); + + // Move the camera to the new location + setCamera(newLongitude, newLatitude); + Cesium3DTilesTester.expectRenderTileset(scene, tileset); + }); + }); + it('renders when instancing is disabled', function() { // Disable extension var instancedArrays = scene.context._instancedArrays; diff --git a/Specs/Scene/PointCloud3DTileContentSpec.js b/Specs/Scene/PointCloud3DTileContentSpec.js new file mode 100644 index 000000000000..aa3362a4e294 --- /dev/null +++ b/Specs/Scene/PointCloud3DTileContentSpec.js @@ -0,0 +1,338 @@ +/*global defineSuite*/ +defineSuite([ + 'Scene/PointCloud3DTileContent', + 'Core/Cartesian3', + 'Core/Color', + 'Core/ComponentDatatype', + 'Core/HeadingPitchRange', + 'Core/Transforms', + 'Specs/Cesium3DTilesTester', + 'Specs/createScene' + ], function( + PointCloud3DTileContent, + Cartesian3, + Color, + ComponentDatatype, + HeadingPitchRange, + Transforms, + Cesium3DTilesTester, + createScene) { + 'use strict'; + + var scene; + var centerLongitude = -1.31968; + var centerLatitude = 0.698874; + + var pointCloudRGBUrl = './Data/Cesium3DTiles/PointCloud/PointCloudRGB'; + var pointCloudRGBAUrl = './Data/Cesium3DTiles/PointCloud/PointCloudRGBA'; + var pointCloudNoColorUrl = './Data/Cesium3DTiles/PointCloud/PointCloudNoColor'; + var pointCloudConstantColorUrl = './Data/Cesium3DTiles/PointCloud/PointCloudConstantColor'; + var pointCloudNormalsUrl = './Data/Cesium3DTiles/PointCloud/PointCloudNormals'; + var pointCloudNormalsOctEncodedUrl = './Data/Cesium3DTiles/PointCloud/PointCloudNormalsOctEncoded'; + var pointCloudQuantizedUrl = './Data/Cesium3DTiles/PointCloud/PointCloudQuantized'; + var pointCloudQuantizedOctEncodedUrl = './Data/Cesium3DTiles/PointCloud/PointCloudQuantizedOctEncoded'; + var pointCloudWGS84Url = './Data/Cesium3DTiles/PointCloud/PointCloudWGS84'; + var pointCloudBatchedUrl = './Data/Cesium3DTiles/PointCloud/PointCloudBatched'; + var pointCloudWithPerPointPropertiesUrl = './Data/Cesium3DTiles/PointCloud/PointCloudWithPerPointProperties'; + var pointCloudWithTransformUrl = './Data/Cesium3DTiles/PointCloud/PointCloudWithTransform'; + + function setCamera(longitude, latitude) { + // Point the camera to the center of the tile + var center = Cartesian3.fromRadians(longitude, latitude, 5.0); + scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 5.0)); + } + + beforeAll(function() { + // Point tiles use RTC, which for now requires scene3DOnly to be true + scene = createScene({ + scene3DOnly : true + }); + + scene.frameState.passes.render = true; + }); + + afterAll(function() { + scene.destroyForSpecs(); + }); + + beforeEach(function() { + setCamera(centerLongitude, centerLatitude); + }); + + afterEach(function() { + scene.primitives.removeAll(); + }); + + function expectRenderPointCloud(tileset) { + tileset.show = false; + expect(scene.renderForSpecs()).toEqual([0, 0, 0, 255]); + tileset.show = true; + var pixelColor = scene.renderForSpecs(); + expect(pixelColor).not.toEqual([0, 0, 0, 255]); + return pixelColor; + } + + it('throws with invalid magic', function() { + var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ + magic : [120, 120, 120, 120] + }); + return Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts'); + }); + + it('throws with invalid version', function() { + var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ + version: 2 + }); + return Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts'); + }); + + it('throws if featureTableJsonByteLength is 0', function() { + var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ + featureTableJsonByteLength : 0 + }); + return Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts'); + }); + + it('throws if the feature table does not contain POINTS_LENGTH', function() { + var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ + featureTableJson : { + POSITION : { + byteOffset : 0 + } + } + }); + return Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts'); + }); + + it('throws if the feature table does not contain POSITION or POSITION_QUANTIZED', function() { + var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ + featureTableJson : { + POINTS_LENGTH : 1 + } + }); + return Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts'); + }); + + it('throws if the positions are quantized and the feature table does not contain QUANTIZED_VOLUME_SCALE', function() { + var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ + featureTableJson : { + POINTS_LENGTH : 1, + POSITION_QUANTIZED : { + byteOffset : 0 + }, + QUANTIZED_VOLUME_OFFSET : [0.0, 0.0, 0.0] + } + }); + return Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts'); + }); + + it('throws if the positions are quantized and the feature table does not contain QUANTIZED_VOLUME_OFFSET', function() { + var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ + featureTableJson : { + POINTS_LENGTH : 1, + POSITION_QUANTIZED : { + byteOffset : 0 + }, + QUANTIZED_VOLUME_SCALE : [1.0, 1.0, 1.0] + } + }); + return Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts'); + }); + + it('throws if the BATCH_ID semantic is defined but BATCHES_LENGTH is not', function() { + var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ + featureTableJson : { + POINTS_LENGTH : 2, + POSITION : [0.0, 0.0, 0.0, 1.0, 1.0, 1.0], + BATCH_ID : [0, 1] + } + }); + return Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts'); + }); + + it('BATCH_ID semantic uses componentType of UNSIGNED_SHORT by default', function() { + var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ + featureTableJson : { + POINTS_LENGTH : 2, + POSITION : [0.0, 0.0, 0.0, 1.0, 1.0, 1.0], + BATCH_ID : [0, 1], + BATCH_LENGTH : 2 + } + }); + var content = Cesium3DTilesTester.loadTile(scene, arrayBuffer, 'pnts'); + expect(content._drawCommand._vertexArray._attributes[1].componentDatatype).toEqual(ComponentDatatype.UNSIGNED_SHORT); + }); + + it('resolves readyPromise', function() { + return Cesium3DTilesTester.resolvesReadyPromise(scene, pointCloudRGBUrl); + }); + + it('rejects readyPromise on failed request', function() { + return Cesium3DTilesTester.rejectsReadyPromiseOnFailedRequest('pnts'); + }); + + it('renders point cloud with rgb colors', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(expectRenderPointCloud); + }); + + it('renders point cloud with rgba colors', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBAUrl).then(expectRenderPointCloud); + }); + + it('renders point cloud with no colors', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudNoColorUrl).then(expectRenderPointCloud); + }); + + it('renders point cloud with constant colors', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudConstantColorUrl).then(expectRenderPointCloud); + }); + + it('renders point cloud with normals', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudNormalsUrl).then(expectRenderPointCloud); + }); + + it('renders point cloud with oct encoded normals', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudNormalsOctEncodedUrl).then(expectRenderPointCloud); + }); + + it('renders point cloud with quantized positions', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudQuantizedUrl).then(expectRenderPointCloud); + }); + + it('renders point cloud with quantized positions and oct-encoded normals', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudQuantizedOctEncodedUrl).then(expectRenderPointCloud); + }); + + it('renders point cloud that are not defined relative to center', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudWGS84Url).then(expectRenderPointCloud); + }); + + it('renders point cloud with batch table', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(expectRenderPointCloud); + }); + + it('renders point cloud with per-point properties', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudWithPerPointPropertiesUrl).then(expectRenderPointCloud); + }); + + it('renders point cloud with tile transform', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudWithTransformUrl).then(function(tileset) { + expectRenderPointCloud(tileset); + + var newLongitude = -1.31962; + var newLatitude = 0.698874; + var newCenter = Cartesian3.fromRadians(newLongitude, newLatitude, 5.0); + var newTransform = Transforms.headingPitchRollToFixedFrame(newCenter, 0.0, 0.0, 0.0); + + // Update tile transform + tileset._root.transform = newTransform; + scene.renderForSpecs(); + + // Move the camera to the new location + setCamera(newLongitude, newLatitude); + expectRenderPointCloud(tileset); + }); + }); + + it('renders with debug color', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) { + var color = expectRenderPointCloud(tileset); + tileset.debugColorizeTiles = true; + var debugColor = expectRenderPointCloud(tileset); + expect(debugColor).not.toEqual(color); + tileset.debugColorizeTiles = false; + debugColor = expectRenderPointCloud(tileset); + expect(debugColor).toEqual(color); + }); + }); + + it('picks', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) { + var content = tileset._root.content; + tileset.show = false; + var picked = scene.pickForSpecs(); + expect(picked).toBeUndefined(); + tileset.show = true; + picked = scene.pickForSpecs(); + expect(picked).toBeDefined(); + expect(picked.primitive).toBe(content); + }); + }); + + it('picks based on batchId', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) { + var pixelColor = scene.renderForSpecs(); + + // Change the color of the picked feature to yellow + var picked = scene.pickForSpecs(); + expect(picked).toBeDefined(); + picked.color = Color.clone(Color.YELLOW, picked.color); + + // Expect the pixel color to be some shade of yellow + var newPixelColor = scene.renderForSpecs(); + expect(newPixelColor).not.toEqual(pixelColor); + + // Turn show off. Expect a different feature to get picked. + picked.show = false; + var newPicked = scene.pickForSpecs(); + expect(newPicked).not.toBe(picked); + }); + }); + + it('point cloud without batch table works', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) { + var content = tileset._root.content; + expect(content.featuresLength).toBe(0); + expect(content.innerContents).toBeUndefined(); + expect(content.hasProperty('name')).toBe(false); + expect(content.getFeature(0)).toBeUndefined(); + }); + }); + + it('batched point cloud works', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) { + var content = tileset._root.content; + expect(content.featuresLength).toBe(8); + expect(content.innerContents).toBeUndefined(); + expect(content.hasProperty('name')).toBe(true); + expect(content.getFeature(0)).toBeDefined(); + }); + }); + + it('point cloud with per-point properties work', function() { + // When the batch table contains per-point properties, aka no batching, then a Cesium3DTileBatchTable is not + // created. There is no per-point show/color/pickId because the overhead is too high. Instead points are styled + // based on their properties, and these are not accessible from the API. + return Cesium3DTilesTester.loadTileset(scene, pointCloudWithPerPointPropertiesUrl).then(function(tileset) { + var content = tileset._root.content; + expect(content.featuresLength).toBe(0); + expect(content.innerContents).toBeUndefined(); + expect(content.hasProperty('name')).toBe(false); + expect(content.getFeature(0)).toBeUndefined(); + }); + }); + + it('throws when calling getFeature with invalid index', function() { + return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) { + var content = tileset._root.content; + expect(function(){ + content.getFeature(-1); + }).toThrowDeveloperError(); + expect(function(){ + content.getFeature(1000); + }).toThrowDeveloperError(); + expect(function(){ + content.getFeature(); + }).toThrowDeveloperError(); + }); + }); + + it('destroys', function() { + return Cesium3DTilesTester.tileDestroys(scene, pointCloudRGBUrl); + }); + + it('destroys before loading finishes', function() { + return Cesium3DTilesTester.tileDestroysBeforeLoad(scene, pointCloudRGBUrl); + }); + +}, 'WebGL'); diff --git a/Specs/Scene/Points3DTileContentSpec.js b/Specs/Scene/Points3DTileContentSpec.js deleted file mode 100644 index c70e863fc396..000000000000 --- a/Specs/Scene/Points3DTileContentSpec.js +++ /dev/null @@ -1,119 +0,0 @@ -/*global defineSuite*/ -defineSuite([ - 'Scene/Points3DTileContent', - 'Core/Cartesian3', - 'Core/HeadingPitchRange', - 'Specs/Cesium3DTilesTester', - 'Specs/createScene' - ], function( - Points3DTileContent, - Cartesian3, - HeadingPitchRange, - Cesium3DTilesTester, - createScene) { - 'use strict'; - - var scene; - var centerLongitude = -1.31968; - var centerLatitude = 0.698874; - - var pointsRGBUrl = './Data/Cesium3DTiles/Points/PointsRGB'; - var pointsRGBAUrl = './Data/Cesium3DTiles/Points/PointsRGBA'; - var pointsNoColorUrl = './Data/Cesium3DTiles/Points/PointsNoColor'; - var pointsConstantColorUrl = './Data/Cesium3DTiles/Points/PointsConstantColor'; - - beforeAll(function() { - // Point tiles use RTC, which for now requires scene3DOnly to be true - scene = createScene({ - scene3DOnly : true - }); - - scene.frameState.passes.render = true; - - // Point the camera to the center of the tile - var center = Cartesian3.fromRadians(centerLongitude, centerLatitude, 5.0); - scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 10.0)); - }); - - afterAll(function() { - scene.destroyForSpecs(); - }); - - afterEach(function() { - scene.primitives.removeAll(); - }); - - function expectRenderPoints(tileset) { - tileset.show = false; - expect(scene.renderForSpecs()).toEqual([0, 0, 0, 255]); - tileset.show = true; - var pixelColor = scene.renderForSpecs(); - expect(pixelColor).not.toEqual([0, 0, 0, 255]); - return pixelColor; - } - - it('throws with invalid magic', function() { - var arrayBuffer = Cesium3DTilesTester.generatePointsTileBuffer({ - magic : [120, 120, 120, 120] - }); - return Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts'); - }); - - it('throws with invalid version', function() { - var arrayBuffer = Cesium3DTilesTester.generatePointsTileBuffer({ - version: 2 - }); - return Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts'); - }); - - it('throws with no points', function() { - // Throws in Buffer due to vertex buffer size of zero - var arrayBuffer = Cesium3DTilesTester.generatePointsTileBuffer(); - return Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts'); - }); - - it('resolves readyPromise', function() { - return Cesium3DTilesTester.resolvesReadyPromise(scene, pointsRGBUrl); - }); - - it('rejects readyPromise on failed request', function() { - return Cesium3DTilesTester.rejectsReadyPromiseOnFailedRequest('pnts'); - }); - - it('renders points with rgb colors', function() { - return Cesium3DTilesTester.loadTileset(scene, pointsRGBUrl).then(expectRenderPoints); - }); - - it('renders points with rgba colors', function() { - return Cesium3DTilesTester.loadTileset(scene, pointsRGBAUrl).then(expectRenderPoints); - }); - - it('renders points with no colors', function() { - return Cesium3DTilesTester.loadTileset(scene, pointsNoColorUrl).then(expectRenderPoints); - }); - - it('renders points with constant colors', function() { - return Cesium3DTilesTester.loadTileset(scene, pointsConstantColorUrl).then(expectRenderPoints); - }); - - it('renders with debug color', function() { - return Cesium3DTilesTester.loadTileset(scene, pointsRGBUrl).then(function(tileset) { - var color = expectRenderPoints(tileset); - tileset.debugColorizeTiles = true; - var debugColor = expectRenderPoints(tileset); - expect(debugColor).not.toEqual(color); - tileset.debugColorizeTiles = false; - debugColor = expectRenderPoints(tileset); - expect(debugColor).toEqual(color); - }); - }); - - it('destroys', function() { - return Cesium3DTilesTester.tileDestroys(scene, pointsRGBUrl); - }); - - it('destroys before loading finishes', function() { - return Cesium3DTilesTester.tileDestroysBeforeLoad(scene, pointsRGBUrl); - }); - -}, 'WebGL'); diff --git a/Specs/Scene/TileOrientedBoundingBoxSpec.js b/Specs/Scene/TileOrientedBoundingBoxSpec.js index 4b7c1ed8a73b..79d3248b6648 100644 --- a/Specs/Scene/TileOrientedBoundingBoxSpec.js +++ b/Specs/Scene/TileOrientedBoundingBoxSpec.js @@ -21,7 +21,7 @@ defineSuite([ var center = new Cartesian3(0.0, 0.0, 0.0); var halfAxes = Matrix3.fromScale(new Cartesian3(0.5, 0.5, 0.5), new Matrix3()); - var tileBoundingVolume = new TileOrientedBoundingBox({center: center, halfAxes: halfAxes}); + var tileBoundingVolume = new TileOrientedBoundingBox(center, halfAxes); var frameState = createFrameState();