diff --git a/Source/Scene/Batched3DModel3DTileContent.js b/Source/Scene/Batched3DModel3DTileContent.js deleted file mode 100644 index 7b56649add47..000000000000 --- a/Source/Scene/Batched3DModel3DTileContent.js +++ /dev/null @@ -1,489 +0,0 @@ -import Cartesian3 from "../Core/Cartesian3.js"; -import Color from "../Core/Color.js"; -import ComponentDatatype from "../Core/ComponentDatatype.js"; -import defined from "../Core/defined.js"; -import deprecationWarning from "../Core/deprecationWarning.js"; -import destroyObject from "../Core/destroyObject.js"; -import DeveloperError from "../Core/DeveloperError.js"; -import Matrix4 from "../Core/Matrix4.js"; -import RequestType from "../Core/RequestType.js"; -import Pass from "../Renderer/Pass.js"; -import B3dmParser from "./B3dmParser.js"; -import Cesium3DTileBatchTable from "./Cesium3DTileBatchTable.js"; -import Cesium3DTileFeature from "./Cesium3DTileFeature.js"; -import Cesium3DTileFeatureTable from "./Cesium3DTileFeatureTable.js"; -import ClassificationModel from "./ClassificationModel.js"; -import Model from "./Model.js"; -import ModelAnimationLoop from "./ModelAnimationLoop.js"; -import ModelUtility from "./ModelUtility.js"; - -/** - * Represents the contents of a - * {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification/TileFormats/Batched3DModel|Batched 3D Model} - * tile in a {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification|3D Tiles} tileset. - *

- * Implements the {@link Cesium3DTileContent} interface. - *

- * - * @alias Batched3DModel3DTileContent - * @constructor - * - * @private - */ -function Batched3DModel3DTileContent( - tileset, - tile, - resource, - arrayBuffer, - byteOffset -) { - this._tileset = tileset; - this._tile = tile; - this._resource = resource; - this._model = undefined; - this._batchTable = undefined; - this._features = undefined; - - this._classificationType = tileset.vectorClassificationOnly - ? undefined - : tileset.classificationType; - - this._metadata = undefined; - - // Populate from gltf when available - this._batchIdAttributeName = undefined; - this._diffuseAttributeOrUniformName = {}; - - this._rtcCenterTransform = undefined; - this._contentModelMatrix = undefined; - - this.featurePropertiesDirty = false; - this._group = undefined; - - initialize(this, arrayBuffer, byteOffset); -} - -// This can be overridden for testing purposes -Batched3DModel3DTileContent._deprecationWarning = deprecationWarning; - -Object.defineProperties(Batched3DModel3DTileContent.prototype, { - featuresLength: { - get: function () { - return this.batchTable.featuresLength; - }, - }, - - pointsLength: { - get: function () { - return this._model.pointsLength; - }, - }, - - trianglesLength: { - get: function () { - return this._model.trianglesLength; - }, - }, - - geometryByteLength: { - get: function () { - return this._model.geometryByteLength; - }, - }, - - texturesByteLength: { - get: function () { - return this._model.texturesByteLength; - }, - }, - - batchTableByteLength: { - get: function () { - return this.batchTable.batchTableByteLength; - }, - }, - - innerContents: { - get: function () { - return undefined; - }, - }, - - readyPromise: { - get: function () { - return this._model.readyPromise; - }, - }, - - tileset: { - get: function () { - return this._tileset; - }, - }, - - tile: { - get: function () { - return this._tile; - }, - }, - - url: { - get: function () { - return this._resource.getUrlComponent(true); - }, - }, - - metadata: { - get: function () { - return this._metadata; - }, - set: function (value) { - this._metadata = value; - }, - }, - - batchTable: { - get: function () { - return this._batchTable; - }, - }, - - group: { - get: function () { - return this._group; - }, - set: function (value) { - this._group = value; - }, - }, -}); - -function getBatchIdAttributeName(gltf) { - let batchIdAttributeName = ModelUtility.getAttributeOrUniformBySemantic( - gltf, - "_BATCHID" - ); - if (!defined(batchIdAttributeName)) { - batchIdAttributeName = ModelUtility.getAttributeOrUniformBySemantic( - gltf, - "BATCHID" - ); - if (defined(batchIdAttributeName)) { - Batched3DModel3DTileContent._deprecationWarning( - "b3dm-legacy-batchid", - "The glTF in this b3dm uses the semantic `BATCHID`. Application-specific semantics should be prefixed with an underscore: `_BATCHID`." - ); - } - } - return batchIdAttributeName; -} - -function getVertexShaderCallback(content) { - return function (vs, programId) { - const batchTable = content._batchTable; - const handleTranslucent = !defined(content._classificationType); - - const gltf = content._model.gltfInternal; - if (defined(gltf)) { - content._batchIdAttributeName = getBatchIdAttributeName(gltf); - content._diffuseAttributeOrUniformName[ - programId - ] = ModelUtility.getDiffuseAttributeOrUniform(gltf, programId); - } - - const callback = batchTable.getVertexShaderCallback( - handleTranslucent, - content._batchIdAttributeName, - content._diffuseAttributeOrUniformName[programId] - ); - return defined(callback) ? callback(vs) : vs; - }; -} - -function getFragmentShaderCallback(content) { - return function (fs, programId) { - const batchTable = content._batchTable; - const handleTranslucent = !defined(content._classificationType); - - const gltf = content._model.gltfInternal; - if (defined(gltf)) { - content._diffuseAttributeOrUniformName[ - programId - ] = ModelUtility.getDiffuseAttributeOrUniform(gltf, programId); - } - const callback = batchTable.getFragmentShaderCallback( - handleTranslucent, - content._diffuseAttributeOrUniformName[programId], - false - ); - return defined(callback) ? callback(fs) : fs; - }; -} - -function getPickIdCallback(content) { - return function () { - return content._batchTable.getPickId(); - }; -} - -function getClassificationFragmentShaderCallback(content) { - return function (fs) { - const batchTable = content._batchTable; - const callback = batchTable.getClassificationFragmentShaderCallback(); - return defined(callback) ? callback(fs) : fs; - }; -} - -function createColorChangedCallback(content) { - return function (batchId, color) { - content._model.updateCommands(batchId, color); - }; -} - -function initialize(content, arrayBuffer, byteOffset) { - const tileset = content._tileset; - const tile = content._tile; - const resource = content._resource; - - const b3dm = B3dmParser.parse(arrayBuffer, byteOffset); - - let batchLength = b3dm.batchLength; - - const featureTableJson = b3dm.featureTableJson; - const featureTableBinary = b3dm.featureTableBinary; - const featureTable = new Cesium3DTileFeatureTable( - featureTableJson, - featureTableBinary - ); - - batchLength = featureTable.getGlobalProperty("BATCH_LENGTH"); - featureTable.featuresLength = batchLength; - - const batchTableJson = b3dm.batchTableJson; - const batchTableBinary = b3dm.batchTableBinary; - - let colorChangedCallback; - if (defined(content._classificationType)) { - colorChangedCallback = createColorChangedCallback(content); - } - - const batchTable = new Cesium3DTileBatchTable( - content, - batchLength, - batchTableJson, - batchTableBinary, - colorChangedCallback - ); - content._batchTable = batchTable; - - const gltfView = b3dm.gltf; - - const pickObject = { - content: content, - primitive: tileset, - }; - - content._rtcCenterTransform = Matrix4.IDENTITY; - const rtcCenter = featureTable.getGlobalProperty( - "RTC_CENTER", - ComponentDatatype.FLOAT, - 3 - ); - if (defined(rtcCenter)) { - content._rtcCenterTransform = Matrix4.fromTranslation( - Cartesian3.fromArray(rtcCenter) - ); - } - - content._contentModelMatrix = Matrix4.multiply( - tile.computedTransform, - content._rtcCenterTransform, - new Matrix4() - ); - - if (!defined(content._classificationType)) { - // PERFORMANCE_IDEA: patch the shader on demand, e.g., the first time show/color changes. - // The pick shader still needs to be patched. - content._model = new Model({ - gltf: gltfView, - cull: false, // The model is already culled by 3D Tiles - releaseGltfJson: true, // Models are unique and will not benefit from caching so save memory - opaquePass: Pass.CESIUM_3D_TILE, // Draw opaque portions of the model during the 3D Tiles pass - basePath: resource, - requestType: RequestType.TILES3D, - modelMatrix: content._contentModelMatrix, - upAxis: tileset._modelUpAxis, - forwardAxis: tileset._modelForwardAxis, - shadows: tileset.shadows, - debugWireframe: tileset.debugWireframe, - incrementallyLoadTextures: false, - vertexShaderLoaded: getVertexShaderCallback(content), - fragmentShaderLoaded: getFragmentShaderCallback(content), - uniformMapLoaded: batchTable.getUniformMapCallback(), - pickIdLoaded: getPickIdCallback(content), - addBatchIdToGeneratedShaders: batchLength > 0, // If the batch table has values in it, generated shaders will need a batchId attribute - pickObject: pickObject, - lightColor: tileset.lightColor, - imageBasedLighting: tileset.imageBasedLighting, - backFaceCulling: tileset.backFaceCulling, - showOutline: tileset.showOutline, - showCreditsOnScreen: tileset.showCreditsOnScreen, - }); - content._model.readyPromise.then(function (model) { - model.activeAnimations.addAll({ - loop: ModelAnimationLoop.REPEAT, - }); - }); - } else { - // This transcodes glTF to an internal representation for geometry so we can take advantage of the re-batching of vector data. - // For a list of limitations on the input glTF, see the documentation for classificationType of Cesium3DTileset. - content._model = new ClassificationModel({ - gltf: gltfView, - cull: false, // The model is already culled by 3D Tiles - basePath: resource, - requestType: RequestType.TILES3D, - modelMatrix: content._contentModelMatrix, - upAxis: tileset._modelUpAxis, - forwardAxis: tileset._modelForwardAxis, - debugWireframe: tileset.debugWireframe, - vertexShaderLoaded: getVertexShaderCallback(content), - classificationShaderLoaded: getClassificationFragmentShaderCallback( - content - ), - uniformMapLoaded: batchTable.getUniformMapCallback(), - pickIdLoaded: getPickIdCallback(content), - classificationType: content._classificationType, - batchTable: batchTable, - }); - } -} - -function createFeatures(content) { - const featuresLength = content.featuresLength; - if (!defined(content._features) && featuresLength > 0) { - const features = new Array(featuresLength); - for (let i = 0; i < featuresLength; ++i) { - features[i] = new Cesium3DTileFeature(content, i); - } - content._features = features; - } -} - -Batched3DModel3DTileContent.prototype.hasProperty = function (batchId, name) { - return this._batchTable.hasProperty(batchId, name); -}; - -Batched3DModel3DTileContent.prototype.getFeature = function (batchId) { - //>>includeStart('debug', pragmas.debug); - const featuresLength = this.featuresLength; - 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]; -}; - -Batched3DModel3DTileContent.prototype.applyDebugSettings = function ( - enabled, - color -) { - color = enabled ? color : Color.WHITE; - if (this.featuresLength === 0) { - this._model.color = color; - } else { - this._batchTable.setAllColor(color); - } -}; - -Batched3DModel3DTileContent.prototype.applyStyle = function (style) { - if (this.featuresLength === 0) { - const hasColorStyle = defined(style) && defined(style.color); - const hasShowStyle = defined(style) && defined(style.show); - this._model.color = hasColorStyle - ? style.color.evaluateColor(undefined, this._model.color) - : Color.clone(Color.WHITE, this._model.color); - this._model.show = hasShowStyle ? style.show.evaluate(undefined) : true; - } else { - this._batchTable.applyStyle(style); - } -}; - -Batched3DModel3DTileContent.prototype.update = function (tileset, frameState) { - const commandStart = frameState.commandList.length; - - const model = this._model; - const tile = this._tile; - const batchTable = this._batchTable; - - // 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. - batchTable.update(tileset, frameState); - - this._contentModelMatrix = Matrix4.multiply( - tile.computedTransform, - this._rtcCenterTransform, - this._contentModelMatrix - ); - model.modelMatrix = this._contentModelMatrix; - - model.shadows = tileset.shadows; - model.lightColor = tileset.lightColor; - model.imageBasedLighting = tileset.imageBasedLighting; - model.backFaceCulling = tileset.backFaceCulling; - model.debugWireframe = tileset.debugWireframe; - model.showCreditsOnScreen = tileset.showCreditsOnScreen; - model.splitDirection = tileset.splitDirection; - - // Update clipping planes - const tilesetClippingPlanes = tileset.clippingPlanes; - model.referenceMatrix = tileset.clippingPlanesOriginMatrix; - if (defined(tilesetClippingPlanes) && tile.clippingPlanesDirty) { - // Dereference the clipping planes from the model if they are irrelevant. - // Link/Dereference directly to avoid ownership checks. - // This will also trigger synchronous shader regeneration to remove or add the clipping plane and color blending code. - model._clippingPlanes = - tilesetClippingPlanes.enabled && tile._isClipped - ? tilesetClippingPlanes - : undefined; - } - - // If the model references a different ClippingPlaneCollection due to the tileset's collection being replaced with a - // ClippingPlaneCollection that gives this tile the same clipping status, update the model to use the new ClippingPlaneCollection. - if ( - defined(tilesetClippingPlanes) && - defined(model._clippingPlanes) && - model._clippingPlanes !== tilesetClippingPlanes - ) { - model._clippingPlanes = tilesetClippingPlanes; - } - - model.update(frameState); - - // If any commands were pushed, add derived commands - const commandEnd = frameState.commandList.length; - if ( - commandStart < commandEnd && - (frameState.passes.render || frameState.passes.pick) && - !defined(this._classificationType) - ) { - batchTable.addDerivedCommands(frameState, commandStart); - } -}; - -Batched3DModel3DTileContent.prototype.isDestroyed = function () { - return false; -}; - -Batched3DModel3DTileContent.prototype.destroy = function () { - this._model = this._model && this._model.destroy(); - this._batchTable = this._batchTable && this._batchTable.destroy(); - return destroyObject(this); -}; -export default Batched3DModel3DTileContent; diff --git a/Source/Scene/Cesium3DTileContentFactory.js b/Source/Scene/Cesium3DTileContentFactory.js index 66381eea0126..6da667bca14e 100644 --- a/Source/Scene/Cesium3DTileContentFactory.js +++ b/Source/Scene/Cesium3DTileContentFactory.js @@ -1,10 +1,7 @@ -import Batched3DModel3DTileContent from "./Batched3DModel3DTileContent.js"; import Composite3DTileContent from "./Composite3DTileContent.js"; import Geometry3DTileContent from "./Geometry3DTileContent.js"; import Implicit3DTileContent from "./Implicit3DTileContent.js"; -import Instanced3DModel3DTileContent from "./Instanced3DModel3DTileContent.js"; import Model3DTileContent from "./ModelExperimental/Model3DTileContent.js"; -import PointCloud3DTileContent from "./PointCloud3DTileContent.js"; import Tileset3DTileContent from "./Tileset3DTileContent.js"; import Vector3DTileContent from "./Vector3DTileContent.js"; import RuntimeError from "../Core/RuntimeError.js"; @@ -16,16 +13,7 @@ import RuntimeError from "../Core/RuntimeError.js"; */ const Cesium3DTileContentFactory = { b3dm: function (tileset, tile, resource, arrayBuffer, byteOffset) { - if (tileset.enableModelExperimental) { - return Model3DTileContent.fromB3dm( - tileset, - tile, - resource, - arrayBuffer, - byteOffset - ); - } - return new Batched3DModel3DTileContent( + return Model3DTileContent.fromB3dm( tileset, tile, resource, @@ -34,16 +22,7 @@ const Cesium3DTileContentFactory = { ); }, pnts: function (tileset, tile, resource, arrayBuffer, byteOffset) { - if (tileset.enableModelExperimental) { - return Model3DTileContent.fromPnts( - tileset, - tile, - resource, - arrayBuffer, - byteOffset - ); - } - return new PointCloud3DTileContent( + return Model3DTileContent.fromPnts( tileset, tile, resource, @@ -52,16 +31,7 @@ const Cesium3DTileContentFactory = { ); }, i3dm: function (tileset, tile, resource, arrayBuffer, byteOffset) { - if (tileset.enableModelExperimental) { - return Model3DTileContent.fromI3dm( - tileset, - tile, - resource, - arrayBuffer, - byteOffset - ); - } - return new Instanced3DModel3DTileContent( + return Model3DTileContent.fromI3dm( tileset, tile, resource, diff --git a/Source/Scene/Instanced3DModel3DTileContent.js b/Source/Scene/Instanced3DModel3DTileContent.js deleted file mode 100644 index 59048adef504..000000000000 --- a/Source/Scene/Instanced3DModel3DTileContent.js +++ /dev/null @@ -1,597 +0,0 @@ -import AttributeCompression from "../Core/AttributeCompression.js"; -import Cartesian3 from "../Core/Cartesian3.js"; -import Color from "../Core/Color.js"; -import ComponentDatatype from "../Core/ComponentDatatype.js"; -import defined from "../Core/defined.js"; -import deprecationWarning from "../Core/deprecationWarning.js"; -import destroyObject from "../Core/destroyObject.js"; -import DeveloperError from "../Core/DeveloperError.js"; -import Ellipsoid from "../Core/Ellipsoid.js"; -import getStringFromTypedArray from "../Core/getStringFromTypedArray.js"; -import Matrix3 from "../Core/Matrix3.js"; -import Matrix4 from "../Core/Matrix4.js"; -import Quaternion from "../Core/Quaternion.js"; -import RequestType from "../Core/RequestType.js"; -import RuntimeError from "../Core/RuntimeError.js"; -import Transforms from "../Core/Transforms.js"; -import TranslationRotationScale from "../Core/TranslationRotationScale.js"; -import Pass from "../Renderer/Pass.js"; -import Cesium3DTileBatchTable from "./Cesium3DTileBatchTable.js"; -import Cesium3DTileFeature from "./Cesium3DTileFeature.js"; -import Cesium3DTileFeatureTable from "./Cesium3DTileFeatureTable.js"; -import I3dmParser from "./I3dmParser.js"; -import ModelInstanceCollection from "./ModelInstanceCollection.js"; -import ModelAnimationLoop from "./ModelAnimationLoop.js"; - -/** - * Represents the contents of a - * {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification/TileFormats/Instanced3DModel|Instanced 3D Model} - * tile in a {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification|3D Tiles} tileset. - *

- * Implements the {@link Cesium3DTileContent} interface. - *

- * - * @alias Instanced3DModel3DTileContent - * @constructor - * - * @private - */ -function Instanced3DModel3DTileContent( - tileset, - tile, - resource, - arrayBuffer, - byteOffset -) { - this._tileset = tileset; - this._tile = tile; - this._resource = resource; - this._modelInstanceCollection = undefined; - - this._metadata = undefined; - - this._batchTable = undefined; - this._features = undefined; - - this.featurePropertiesDirty = false; - this._group = undefined; - - initialize(this, arrayBuffer, byteOffset); -} - -// This can be overridden for testing purposes -Instanced3DModel3DTileContent._deprecationWarning = deprecationWarning; - -Object.defineProperties(Instanced3DModel3DTileContent.prototype, { - featuresLength: { - get: function () { - return this._batchTable.featuresLength; - }, - }, - - pointsLength: { - get: function () { - return 0; - }, - }, - - trianglesLength: { - get: function () { - const model = this._modelInstanceCollection._model; - if (defined(model)) { - return model.trianglesLength; - } - return 0; - }, - }, - - geometryByteLength: { - get: function () { - const model = this._modelInstanceCollection._model; - if (defined(model)) { - return model.geometryByteLength; - } - return 0; - }, - }, - - texturesByteLength: { - get: function () { - const model = this._modelInstanceCollection._model; - if (defined(model)) { - return model.texturesByteLength; - } - return 0; - }, - }, - - batchTableByteLength: { - get: function () { - return this._batchTable.batchTableByteLength; - }, - }, - - innerContents: { - get: function () { - return undefined; - }, - }, - - readyPromise: { - get: function () { - return this._modelInstanceCollection.readyPromise; - }, - }, - - tileset: { - get: function () { - return this._tileset; - }, - }, - - tile: { - get: function () { - return this._tile; - }, - }, - - url: { - get: function () { - return this._resource.getUrlComponent(true); - }, - }, - - metadata: { - get: function () { - return this._metadata; - }, - set: function (value) { - this._metadata = value; - }, - }, - - batchTable: { - get: function () { - return this._batchTable; - }, - }, - - group: { - get: function () { - return this._group; - }, - set: function (value) { - this._group = value; - }, - }, -}); - -function getPickIdCallback(content) { - return function () { - return content._batchTable.getPickId(); - }; -} - -const propertyScratch1 = new Array(4); -const propertyScratch2 = new Array(4); - -function initialize(content, arrayBuffer, byteOffset) { - const i3dm = I3dmParser.parse(arrayBuffer, byteOffset); - - const gltfFormat = i3dm.gltfFormat; - const gltfView = i3dm.gltf; - const featureTableJson = i3dm.featureTableJson; - const featureTableBinary = i3dm.featureTableBinary; - const batchTableJson = i3dm.batchTableJson; - const batchTableBinary = i3dm.batchTableBinary; - - const featureTable = new Cesium3DTileFeatureTable( - featureTableJson, - featureTableBinary - ); - const instancesLength = featureTable.getGlobalProperty("INSTANCES_LENGTH"); - featureTable.featuresLength = instancesLength; - - if (!defined(instancesLength)) { - throw new RuntimeError( - "Feature table global property: INSTANCES_LENGTH must be defined" - ); - } - - content._batchTable = new Cesium3DTileBatchTable( - content, - instancesLength, - batchTableJson, - batchTableBinary - ); - - const tileset = content._tileset; - - // Create model instance collection - const collectionOptions = { - instances: new Array(instancesLength), - batchTable: content._batchTable, - cull: false, // Already culled by 3D Tiles - url: undefined, - requestType: RequestType.TILES3D, - gltf: undefined, - basePath: undefined, - incrementallyLoadTextures: false, - upAxis: tileset._modelUpAxis, - forwardAxis: tileset._modelForwardAxis, - opaquePass: Pass.CESIUM_3D_TILE, // Draw opaque portions during the 3D Tiles pass - pickIdLoaded: getPickIdCallback(content), - imageBasedLighting: tileset.imageBasedLighting, - backFaceCulling: tileset.backFaceCulling, - showOutline: tileset.showOutline, - showCreditsOnScreen: tileset.showCreditsOnScreen, - }; - - if (gltfFormat === 0) { - let gltfUrl = getStringFromTypedArray(gltfView); - - // We need to remove padding from the end of the model URL in case this tile was part of a composite tile. - // This removes all white space and null characters from the end of the string. - gltfUrl = gltfUrl.replace(/[\s\0]+$/, ""); - collectionOptions.url = content._resource.getDerivedResource({ - url: gltfUrl, - }); - } else { - collectionOptions.gltf = gltfView; - collectionOptions.basePath = content._resource.clone(); - } - - const eastNorthUp = featureTable.getGlobalProperty("EAST_NORTH_UP"); - - let rtcCenter; - const rtcCenterArray = featureTable.getGlobalProperty( - "RTC_CENTER", - ComponentDatatype.FLOAT, - 3 - ); - if (defined(rtcCenterArray)) { - rtcCenter = Cartesian3.unpack(rtcCenterArray); - } - - const instances = collectionOptions.instances; - const instancePosition = new Cartesian3(); - const instancePositionArray = new Array(3); - const instanceNormalRight = new Cartesian3(); - const instanceNormalUp = new Cartesian3(); - const instanceNormalForward = new Cartesian3(); - const instanceRotation = new Matrix3(); - const instanceQuaternion = new Quaternion(); - let instanceScale = new Cartesian3(); - const instanceTranslationRotationScale = new TranslationRotationScale(); - const instanceTransform = new Matrix4(); - for (let i = 0; i < instancesLength; i++) { - // Get the instance position - let position = featureTable.getProperty( - "POSITION", - ComponentDatatype.FLOAT, - 3, - i, - propertyScratch1 - ); - if (!defined(position)) { - position = instancePositionArray; - const positionQuantized = featureTable.getProperty( - "POSITION_QUANTIZED", - ComponentDatatype.UNSIGNED_SHORT, - 3, - i, - propertyScratch1 - ); - if (!defined(positionQuantized)) { - throw new RuntimeError( - "Either POSITION or POSITION_QUANTIZED must be defined for each instance." - ); - } - const quantizedVolumeOffset = featureTable.getGlobalProperty( - "QUANTIZED_VOLUME_OFFSET", - ComponentDatatype.FLOAT, - 3 - ); - if (!defined(quantizedVolumeOffset)) { - throw new RuntimeError( - "Global property: QUANTIZED_VOLUME_OFFSET must be defined for quantized positions." - ); - } - const quantizedVolumeScale = featureTable.getGlobalProperty( - "QUANTIZED_VOLUME_SCALE", - ComponentDatatype.FLOAT, - 3 - ); - if (!defined(quantizedVolumeScale)) { - throw new RuntimeError( - "Global property: QUANTIZED_VOLUME_SCALE must be defined for quantized positions." - ); - } - for (let j = 0; j < 3; j++) { - position[j] = - (positionQuantized[j] / 65535.0) * quantizedVolumeScale[j] + - quantizedVolumeOffset[j]; - } - } - Cartesian3.unpack(position, 0, instancePosition); - if (defined(rtcCenter)) { - Cartesian3.add(instancePosition, rtcCenter, instancePosition); - } - instanceTranslationRotationScale.translation = instancePosition; - - // Get the instance rotation - const normalUp = featureTable.getProperty( - "NORMAL_UP", - ComponentDatatype.FLOAT, - 3, - i, - propertyScratch1 - ); - const normalRight = featureTable.getProperty( - "NORMAL_RIGHT", - ComponentDatatype.FLOAT, - 3, - i, - propertyScratch2 - ); - let hasCustomOrientation = false; - if (defined(normalUp)) { - if (!defined(normalRight)) { - throw new RuntimeError( - "To define a custom orientation, both NORMAL_UP and NORMAL_RIGHT must be defined." - ); - } - Cartesian3.unpack(normalUp, 0, instanceNormalUp); - Cartesian3.unpack(normalRight, 0, instanceNormalRight); - hasCustomOrientation = true; - } else { - const octNormalUp = featureTable.getProperty( - "NORMAL_UP_OCT32P", - ComponentDatatype.UNSIGNED_SHORT, - 2, - i, - propertyScratch1 - ); - const octNormalRight = featureTable.getProperty( - "NORMAL_RIGHT_OCT32P", - ComponentDatatype.UNSIGNED_SHORT, - 2, - i, - propertyScratch2 - ); - if (defined(octNormalUp)) { - if (!defined(octNormalRight)) { - throw new RuntimeError( - "To define a custom orientation with oct-encoded vectors, both NORMAL_UP_OCT32P and NORMAL_RIGHT_OCT32P must be defined." - ); - } - AttributeCompression.octDecodeInRange( - octNormalUp[0], - octNormalUp[1], - 65535, - instanceNormalUp - ); - AttributeCompression.octDecodeInRange( - octNormalRight[0], - octNormalRight[1], - 65535, - instanceNormalRight - ); - hasCustomOrientation = true; - } else if (eastNorthUp) { - Transforms.eastNorthUpToFixedFrame( - instancePosition, - Ellipsoid.WGS84, - instanceTransform - ); - Matrix4.getMatrix3(instanceTransform, instanceRotation); - } else { - Matrix3.clone(Matrix3.IDENTITY, instanceRotation); - } - } - if (hasCustomOrientation) { - Cartesian3.cross( - instanceNormalRight, - instanceNormalUp, - instanceNormalForward - ); - Cartesian3.normalize(instanceNormalForward, instanceNormalForward); - Matrix3.setColumn( - instanceRotation, - 0, - instanceNormalRight, - instanceRotation - ); - Matrix3.setColumn( - instanceRotation, - 1, - instanceNormalUp, - instanceRotation - ); - Matrix3.setColumn( - instanceRotation, - 2, - instanceNormalForward, - instanceRotation - ); - } - Quaternion.fromRotationMatrix(instanceRotation, instanceQuaternion); - instanceTranslationRotationScale.rotation = instanceQuaternion; - - // Get the instance scale - instanceScale = Cartesian3.fromElements(1.0, 1.0, 1.0, instanceScale); - const scale = featureTable.getProperty( - "SCALE", - ComponentDatatype.FLOAT, - 1, - i - ); - if (defined(scale)) { - Cartesian3.multiplyByScalar(instanceScale, scale, instanceScale); - } - const nonUniformScale = featureTable.getProperty( - "SCALE_NON_UNIFORM", - ComponentDatatype.FLOAT, - 3, - i, - propertyScratch1 - ); - if (defined(nonUniformScale)) { - instanceScale.x *= nonUniformScale[0]; - instanceScale.y *= nonUniformScale[1]; - instanceScale.z *= nonUniformScale[2]; - } - instanceTranslationRotationScale.scale = instanceScale; - - // Get the batchId - let batchId = featureTable.getProperty( - "BATCH_ID", - ComponentDatatype.UNSIGNED_SHORT, - 1, - i - ); - if (!defined(batchId)) { - // If BATCH_ID semantic is undefined, batchId is just the instance number - batchId = i; - } - - // Create the model matrix and the instance - Matrix4.fromTranslationRotationScale( - instanceTranslationRotationScale, - instanceTransform - ); - const modelMatrix = instanceTransform.clone(); - instances[i] = { - modelMatrix: modelMatrix, - batchId: batchId, - }; - } - - content._modelInstanceCollection = new ModelInstanceCollection( - collectionOptions - ); - content._modelInstanceCollection.readyPromise - .catch(function () { - // Any readyPromise failure is handled in modelInstanceCollection - }) - .then(function (collection) { - if (content._modelInstanceCollection.ready) { - collection.activeAnimations.addAll({ - loop: ModelAnimationLoop.REPEAT, - }); - } - }); -} - -function createFeatures(content) { - const featuresLength = content.featuresLength; - if (!defined(content._features) && featuresLength > 0) { - const features = new Array(featuresLength); - for (let i = 0; i < featuresLength; ++i) { - features[i] = new Cesium3DTileFeature(content, i); - } - content._features = features; - } -} - -Instanced3DModel3DTileContent.prototype.hasProperty = function (batchId, name) { - return this._batchTable.hasProperty(batchId, name); -}; - -Instanced3DModel3DTileContent.prototype.getFeature = function (batchId) { - const 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]; -}; - -Instanced3DModel3DTileContent.prototype.applyDebugSettings = function ( - enabled, - color -) { - color = enabled ? color : Color.WHITE; - this._batchTable.setAllColor(color); -}; - -Instanced3DModel3DTileContent.prototype.applyStyle = function (style) { - this._batchTable.applyStyle(style); -}; - -Instanced3DModel3DTileContent.prototype.update = function ( - tileset, - frameState -) { - const commandStart = frameState.commandList.length; - - // 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._batchTable.update(tileset, frameState); - this._modelInstanceCollection.modelMatrix = this._tile.computedTransform; - this._modelInstanceCollection.shadows = this._tileset.shadows; - this._modelInstanceCollection.lightColor = this._tileset.lightColor; - this._modelInstanceCollection.imageBasedLighting = this._tileset.imageBasedLighting; - this._modelInstanceCollection.backFaceCulling = this._tileset.backFaceCulling; - this._modelInstanceCollection.debugWireframe = this._tileset.debugWireframe; - this._modelInstanceCollection.showCreditsOnScreen = this._tileset.showCreditsOnScreen; - this._modelInstanceCollection.splitDirection = this._tileset.splitDirection; - - const model = this._modelInstanceCollection._model; - - if (defined(model)) { - // Update for clipping planes - const tilesetClippingPlanes = this._tileset.clippingPlanes; - model.referenceMatrix = this._tileset.clippingPlanesOriginMatrix; - if (defined(tilesetClippingPlanes) && this._tile.clippingPlanesDirty) { - // Dereference the clipping planes from the model if they are irrelevant - saves on shading - // Link/Dereference directly to avoid ownership checks. - model._clippingPlanes = - tilesetClippingPlanes.enabled && this._tile._isClipped - ? tilesetClippingPlanes - : undefined; - } - - // If the model references a different ClippingPlaneCollection due to the tileset's collection being replaced with a - // ClippingPlaneCollection that gives this tile the same clipping status, update the model to use the new ClippingPlaneCollection. - if ( - defined(tilesetClippingPlanes) && - defined(model._clippingPlanes) && - model._clippingPlanes !== tilesetClippingPlanes - ) { - model._clippingPlanes = tilesetClippingPlanes; - } - } - - this._modelInstanceCollection.update(frameState); - - // If any commands were pushed, add derived commands - const commandEnd = frameState.commandList.length; - if ( - commandStart < commandEnd && - (frameState.passes.render || frameState.passes.pick) - ) { - this._batchTable.addDerivedCommands(frameState, commandStart, false); - } -}; - -Instanced3DModel3DTileContent.prototype.isDestroyed = function () { - return false; -}; - -Instanced3DModel3DTileContent.prototype.destroy = function () { - this._modelInstanceCollection = - this._modelInstanceCollection && this._modelInstanceCollection.destroy(); - this._batchTable = this._batchTable && this._batchTable.destroy(); - - return destroyObject(this); -}; -export default Instanced3DModel3DTileContent; diff --git a/Source/Scene/ModelExperimental/Model3DTileContent.js b/Source/Scene/ModelExperimental/Model3DTileContent.js index db2f7cc66ce6..83d6050d240f 100644 --- a/Source/Scene/ModelExperimental/Model3DTileContent.js +++ b/Source/Scene/ModelExperimental/Model3DTileContent.js @@ -24,6 +24,7 @@ export default function Model3DTileContent(tileset, tile, resource) { this._resource = resource; this._model = undefined; + this._readyPromise = undefined; this._metadata = undefined; this._group = undefined; } @@ -84,7 +85,7 @@ Object.defineProperties(Model3DTileContent.prototype, { readyPromise: { get: function () { - return this._model.readyPromise; + return this._readyPromise; }, }, @@ -269,12 +270,14 @@ Model3DTileContent.fromGltf = function (tileset, tile, resource, gltf) { ); const model = ModelExperimental.fromGltf(modelOptions); - model.readyPromise.then(function (model) { + content._model = model; + // Include the animation setup in the ready promise to avoid an uncaught exception + content._readyPromise = model.readyPromise.then(function (model) { model.activeAnimations.addAll({ loop: ModelAnimationLoop.REPEAT, }); + return model; }); - content._model = model; return content; }; @@ -302,12 +305,14 @@ Model3DTileContent.fromB3dm = function ( ); const model = ModelExperimental.fromB3dm(modelOptions); - model.readyPromise.then(function (model) { + content._model = model; + // Include the animation setup in the ready promise to avoid an uncaught exception + content._readyPromise = model.readyPromise.then(function (model) { model.activeAnimations.addAll({ loop: ModelAnimationLoop.REPEAT, }); + return model; }); - content._model = model; return content; }; @@ -335,12 +340,14 @@ Model3DTileContent.fromI3dm = function ( ); const model = ModelExperimental.fromI3dm(modelOptions); - model.readyPromise.then(function (model) { + content._model = model; + // Include the animation setup in the ready promise to avoid an uncaught exception + content._readyPromise = model.readyPromise.then(function (model) { model.activeAnimations.addAll({ loop: ModelAnimationLoop.REPEAT, }); + return model; }); - content._model = model; return content; }; @@ -366,7 +373,10 @@ Model3DTileContent.fromPnts = function ( content, additionalOptions ); - content._model = ModelExperimental.fromPnts(modelOptions); + const model = ModelExperimental.fromPnts(modelOptions); + content._model = model; + content._readyPromise = model.readyPromise; + return content; }; @@ -384,7 +394,10 @@ Model3DTileContent.fromGeoJson = function (tileset, tile, resource, geoJson) { content, additionalOptions ); - content._model = ModelExperimental.fromGeoJson(modelOptions); + const model = ModelExperimental.fromGeoJson(modelOptions); + content._model = model; + content._readyPromise = model.readyPromise; + return content; }; diff --git a/Source/Scene/PointCloud3DTileContent.js b/Source/Scene/PointCloud3DTileContent.js deleted file mode 100644 index 05d7b8d8fa34..000000000000 --- a/Source/Scene/PointCloud3DTileContent.js +++ /dev/null @@ -1,383 +0,0 @@ -import Color from "../Core/Color.js"; -import combine from "../Core/combine.js"; -import defaultValue from "../Core/defaultValue.js"; -import defined from "../Core/defined.js"; -import destroyObject from "../Core/destroyObject.js"; -import DeveloperError from "../Core/DeveloperError.js"; -import CesiumMath from "../Core/Math.js"; -import Pass from "../Renderer/Pass.js"; -import Cesium3DTileBatchTable from "./Cesium3DTileBatchTable.js"; -import Cesium3DTileFeature from "./Cesium3DTileFeature.js"; -import Cesium3DTileRefine from "./Cesium3DTileRefine.js"; -import PointCloud from "./PointCloud.js"; -import PointCloudShading from "./PointCloudShading.js"; -import SceneMode from "./SceneMode.js"; - -/** - * Represents the contents of a - * {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification/TileFormats/PointCloud|Point Cloud} - * tile in a {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification|3D Tiles} tileset. - *

- * Implements the {@link Cesium3DTileContent} interface. - *

- * - * @alias PointCloud3DTileContent - * @constructor - * - * @private - */ -function PointCloud3DTileContent( - tileset, - tile, - resource, - arrayBuffer, - byteOffset -) { - this._tileset = tileset; - this._tile = tile; - this._resource = resource; - - this._metadata = undefined; - - this._pickId = undefined; // Only defined when batchTable is undefined - this._batchTable = undefined; // Used when feature table contains BATCH_ID semantic - this._styleDirty = false; - this._features = undefined; - this.featurePropertiesDirty = false; - this._group = undefined; - - this._pointCloud = new PointCloud({ - arrayBuffer: arrayBuffer, - byteOffset: byteOffset, - cull: false, - opaquePass: Pass.CESIUM_3D_TILE, - vertexShaderLoaded: getVertexShaderLoaded(this), - fragmentShaderLoaded: getFragmentShaderLoaded(this), - uniformMapLoaded: getUniformMapLoaded(this), - batchTableLoaded: getBatchTableLoaded(this), - pickIdLoaded: getPickIdLoaded(this), - }); -} - -Object.defineProperties(PointCloud3DTileContent.prototype, { - featuresLength: { - get: function () { - if (defined(this._batchTable)) { - return this._batchTable.featuresLength; - } - return 0; - }, - }, - - pointsLength: { - get: function () { - return this._pointCloud.pointsLength; - }, - }, - - trianglesLength: { - get: function () { - return 0; - }, - }, - - geometryByteLength: { - get: function () { - return this._pointCloud.geometryByteLength; - }, - }, - - texturesByteLength: { - get: function () { - return 0; - }, - }, - - batchTableByteLength: { - get: function () { - if (defined(this._batchTable)) { - return this._batchTable.batchTableByteLength; - } - return 0; - }, - }, - - innerContents: { - get: function () { - return undefined; - }, - }, - - readyPromise: { - get: function () { - return this._pointCloud.readyPromise; - }, - }, - - tileset: { - get: function () { - return this._tileset; - }, - }, - - tile: { - get: function () { - return this._tile; - }, - }, - - url: { - get: function () { - return this._resource.getUrlComponent(true); - }, - }, - - metadata: { - get: function () { - return this._metadata; - }, - set: function (value) { - this._metadata = value; - }, - }, - - batchTable: { - get: function () { - return this._batchTable; - }, - }, - - group: { - get: function () { - return this._group; - }, - set: function (value) { - this._group = value; - }, - }, -}); - -function getVertexShaderLoaded(content) { - return function (vs) { - if (defined(content._batchTable)) { - return content._batchTable.getVertexShaderCallback( - false, - "a_batchId", - undefined - )(vs); - } - return vs; - }; -} - -function getFragmentShaderLoaded(content) { - return function (fs) { - if (defined(content._batchTable)) { - return content._batchTable.getFragmentShaderCallback( - false, - undefined, - false - )(fs); - } - return `uniform vec4 czm_pickColor;\n${fs}`; - }; -} - -function getUniformMapLoaded(content) { - return function (uniformMap) { - if (defined(content._batchTable)) { - return content._batchTable.getUniformMapCallback()(uniformMap); - } - return combine(uniformMap, { - czm_pickColor: function () { - return content._pickId.color; - }, - }); - }; -} - -function getBatchTableLoaded(content) { - return function (batchLength, batchTableJson, batchTableBinary) { - content._batchTable = new Cesium3DTileBatchTable( - content, - batchLength, - batchTableJson, - batchTableBinary - ); - }; -} - -function getPickIdLoaded(content) { - return function () { - return defined(content._batchTable) - ? content._batchTable.getPickId() - : "czm_pickColor"; - }; -} - -function getGeometricError(content) { - const pointCloudShading = content._tileset.pointCloudShading; - const sphereVolume = content._tile.contentBoundingVolume.boundingSphere.volume(); - const baseResolutionApproximation = CesiumMath.cbrt( - sphereVolume / content.pointsLength - ); - - let geometricError = content._tile.geometricError; - if (geometricError === 0) { - if ( - defined(pointCloudShading) && - defined(pointCloudShading.baseResolution) - ) { - geometricError = pointCloudShading.baseResolution; - } else { - geometricError = baseResolutionApproximation; - } - } - return geometricError; -} - -function createFeatures(content) { - const featuresLength = content.featuresLength; - if (!defined(content._features) && featuresLength > 0) { - const features = new Array(featuresLength); - for (let i = 0; i < featuresLength; ++i) { - features[i] = new Cesium3DTileFeature(content, i); - } - content._features = features; - } -} - -PointCloud3DTileContent.prototype.hasProperty = function (batchId, name) { - if (defined(this._batchTable)) { - return this._batchTable.hasProperty(batchId, 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)) { - return undefined; - } - const 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]; -}; - -PointCloud3DTileContent.prototype.applyDebugSettings = function ( - enabled, - color -) { - this._pointCloud.color = enabled ? color : Color.WHITE; -}; - -PointCloud3DTileContent.prototype.applyStyle = function (style) { - if (defined(this._batchTable)) { - this._batchTable.applyStyle(style); - } else { - this._styleDirty = true; - } -}; - -const defaultShading = new PointCloudShading(); - -PointCloud3DTileContent.prototype.update = function (tileset, frameState) { - const pointCloud = this._pointCloud; - const pointCloudShading = defaultValue( - tileset.pointCloudShading, - defaultShading - ); - const tile = this._tile; - const batchTable = this._batchTable; - const mode = frameState.mode; - const clippingPlanes = tileset.clippingPlanes; - - if (!defined(this._pickId) && !defined(batchTable)) { - this._pickId = frameState.context.createPickId({ - primitive: tileset, - content: this, - }); - } - - if (defined(batchTable)) { - batchTable.update(tileset, frameState); - } - - let boundingSphere; - if (defined(tile._contentBoundingVolume)) { - boundingSphere = - mode === SceneMode.SCENE3D - ? tile._contentBoundingVolume.boundingSphere - : tile._contentBoundingVolume2D.boundingSphere; - } else { - boundingSphere = - mode === SceneMode.SCENE3D - ? tile._boundingVolume.boundingSphere - : tile._boundingVolume2D.boundingSphere; - } - - const styleDirty = this._styleDirty; - this._styleDirty = false; - - pointCloud.clippingPlanesOriginMatrix = tileset.clippingPlanesOriginMatrix; - pointCloud.style = defined(batchTable) ? undefined : tileset.style; - pointCloud.styleDirty = styleDirty; - pointCloud.modelMatrix = tile.computedTransform; - pointCloud.time = tileset.timeSinceLoad; - pointCloud.shadows = tileset.shadows; - pointCloud.boundingSphere = boundingSphere; - pointCloud.clippingPlanes = clippingPlanes; - pointCloud.isClipped = - defined(clippingPlanes) && clippingPlanes.enabled && tile._isClipped; - pointCloud.clippingPlanesDirty = tile.clippingPlanesDirty; - pointCloud.attenuation = pointCloudShading.attenuation; - pointCloud.backFaceCulling = pointCloudShading.backFaceCulling; - pointCloud.normalShading = pointCloudShading.normalShading; - pointCloud.geometricError = getGeometricError(this); - pointCloud.geometricErrorScale = pointCloudShading.geometricErrorScale; - pointCloud.splitDirection = tileset.splitDirection; - if ( - defined(pointCloudShading) && - defined(pointCloudShading.maximumAttenuation) - ) { - pointCloud.maximumAttenuation = pointCloudShading.maximumAttenuation; - } else if (tile.refine === Cesium3DTileRefine.ADD) { - pointCloud.maximumAttenuation = 5.0; - } else { - pointCloud.maximumAttenuation = tileset.maximumScreenSpaceError; - } - - pointCloud.update(frameState); -}; - -PointCloud3DTileContent.prototype.isDestroyed = function () { - return false; -}; - -PointCloud3DTileContent.prototype.destroy = function () { - this._pickId = this._pickId && this._pickId.destroy(); - this._pointCloud = this._pointCloud && this._pointCloud.destroy(); - this._batchTable = this._batchTable && this._batchTable.destroy(); - return destroyObject(this); -}; -export default PointCloud3DTileContent; diff --git a/Specs/Cesium3DTilesTester.js b/Specs/Cesium3DTilesTester.js index eeab03585900..d0bdecd3321d 100644 --- a/Specs/Cesium3DTilesTester.js +++ b/Specs/Cesium3DTilesTester.js @@ -8,6 +8,7 @@ import { Resource, Cesium3DTileContentFactory, Cesium3DTileset, + PointCloudShading, TileBoundingSphere, RuntimeError, } from "../../Source/Cesium.js"; @@ -177,6 +178,9 @@ Cesium3DTilesTester.rejectsReadyPromiseOnError = function ( imageBasedLighting: new ImageBasedLighting({ imageBasedLighting: new Cartesian2(1, 1), }), + pointCloudShading: new PointCloudShading(), + featureIdLabel: "featureId_0", + instanceFeatureIdLabel: "instanceFeatureId_0", }; const url = Resource.createIfNeeded(""); const content = Cesium3DTileContentFactory[type]( diff --git a/Specs/Scene/Batched3DModel3DTileContentClassificationSpec.js b/Specs/Scene/Batched3DModel3DTileContentClassificationSpec.js deleted file mode 100644 index f59bc554c257..000000000000 --- a/Specs/Scene/Batched3DModel3DTileContentClassificationSpec.js +++ /dev/null @@ -1,233 +0,0 @@ -import { - Cartesian3, - Cartographic, - Color, - ColorGeometryInstanceAttribute, - destroyObject, - Ellipsoid, - GeometryInstance, - HeadingPitchRange, - Math as CesiumMath, - Matrix4, - Rectangle, - RectangleGeometry, - Pass, - RenderState, - ClassificationType, - PerInstanceColorAppearance, - Primitive, - StencilConstants, -} from "../../Source/Cesium.js"; -import Cesium3DTilesTester from "../Cesium3DTilesTester.js"; -import createScene from "../createScene.js"; - -describe( - "Scene/Batched3DModel3DTileContentClassification", - function () { - let scene; - let modelMatrix; - const centerLongitude = -1.31968; - const centerLatitude = 0.698874; - - const withBatchTableUrl = - "./Data/Cesium3DTiles/Batched/BatchedWithBatchTable/tileset.json"; - const withBatchTableBinaryUrl = - "./Data/Cesium3DTiles/Batched/BatchedWithBatchTableBinary/tileset.json"; - - let globePrimitive; - let tilesetPrimitive; - let reusableGlobePrimitive; - let reusableTilesetPrimitive; - - function setCamera(longitude, latitude) { - // One feature is located at the center, point the camera there - const center = Cartesian3.fromRadians(longitude, latitude); - scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 15.0)); - } - - function createPrimitive(rectangle, pass) { - let renderState; - if (pass === Pass.CESIUM_3D_TILE) { - renderState = RenderState.fromCache({ - stencilTest: StencilConstants.setCesium3DTileBit(), - stencilMask: StencilConstants.CESIUM_3D_TILE_MASK, - depthTest: { - enabled: true, - }, - }); - } - const depthColorAttribute = ColorGeometryInstanceAttribute.fromColor( - new Color(0.0, 0.0, 0.0, 1.0) - ); - return new Primitive({ - geometryInstances: new GeometryInstance({ - geometry: new RectangleGeometry({ - ellipsoid: Ellipsoid.WGS84, - rectangle: rectangle, - }), - id: "depth rectangle", - attributes: { - color: depthColorAttribute, - }, - }), - appearance: new PerInstanceColorAppearance({ - translucent: false, - flat: true, - renderState: renderState, - }), - asynchronous: false, - }); - } - - function MockPrimitive(primitive, pass) { - this._primitive = primitive; - this._pass = pass; - this.show = true; - } - - MockPrimitive.prototype.update = function (frameState) { - if (!this.show) { - return; - } - - const commandList = frameState.commandList; - const startLength = commandList.length; - this._primitive.update(frameState); - - for (let i = startLength; i < commandList.length; ++i) { - const command = commandList[i]; - command.pass = this._pass; - } - }; - - MockPrimitive.prototype.isDestroyed = function () { - return false; - }; - - MockPrimitive.prototype.destroy = function () { - return destroyObject(this); - }; - - beforeAll(function () { - scene = createScene(); - - const translation = Ellipsoid.WGS84.geodeticSurfaceNormalCartographic( - new Cartographic(centerLongitude, centerLatitude) - ); - Cartesian3.multiplyByScalar(translation, -5.0, translation); - modelMatrix = Matrix4.fromTranslation(translation); - - const offset = CesiumMath.toRadians(0.01); - const rectangle = new Rectangle( - centerLongitude - offset, - centerLatitude - offset, - centerLongitude + offset, - centerLatitude + offset - ); - reusableGlobePrimitive = createPrimitive(rectangle, Pass.GLOBE); - reusableTilesetPrimitive = createPrimitive( - rectangle, - Pass.CESIUM_3D_TILE - ); - }); - - afterAll(function () { - reusableGlobePrimitive.destroy(); - reusableTilesetPrimitive.destroy(); - scene.destroyForSpecs(); - }); - - beforeEach(function () { - setCamera(centerLongitude, centerLatitude); - - // wrap rectangle primitive so it gets executed during the globe pass and 3D Tiles pass to lay down depth - globePrimitive = new MockPrimitive(reusableGlobePrimitive, Pass.GLOBE); - tilesetPrimitive = new MockPrimitive( - reusableTilesetPrimitive, - Pass.CESIUM_3D_TILE - ); - - scene.primitives.add(globePrimitive); - scene.primitives.add(tilesetPrimitive); - }); - - afterEach(function () { - scene.primitives.removeAll(); - globePrimitive = - globePrimitive && - !globePrimitive.isDestroyed() && - globePrimitive.destroy(); - tilesetPrimitive = - tilesetPrimitive && - !tilesetPrimitive.isDestroyed() && - tilesetPrimitive.destroy(); - }); - - it("classifies 3D Tiles", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl, { - classificationType: ClassificationType.CESIUM_3D_TILE, - modelMatrix: modelMatrix, - }).then(function (tileset) { - globePrimitive.show = false; - tilesetPrimitive.show = true; - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - globePrimitive.show = true; - tilesetPrimitive.show = false; - Cesium3DTilesTester.expectRenderBlank(scene, tileset); - globePrimitive.show = true; - tilesetPrimitive.show = true; - }); - }); - - it("classifies globe", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl, { - classificationType: ClassificationType.TERRAIN, - modelMatrix: modelMatrix, - }).then(function (tileset) { - globePrimitive.show = false; - tilesetPrimitive.show = true; - Cesium3DTilesTester.expectRenderBlank(scene, tileset); - globePrimitive.show = true; - tilesetPrimitive.show = false; - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - globePrimitive.show = true; - tilesetPrimitive.show = true; - }); - }); - - it("classifies both 3D Tiles and globe", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl, { - classificationType: ClassificationType.BOTH, - modelMatrix: modelMatrix, - }).then(function (tileset) { - globePrimitive.show = false; - tilesetPrimitive.show = true; - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - globePrimitive.show = true; - tilesetPrimitive.show = false; - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - globePrimitive.show = true; - tilesetPrimitive.show = true; - }); - }); - - it("renders with batch table", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl, { - classificationType: ClassificationType.BOTH, - modelMatrix: modelMatrix, - }).then(function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - }); - }); - - it("renders with binary batch table", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableBinaryUrl, { - classificationType: ClassificationType.BOTH, - modelMatrix: modelMatrix, - }).then(function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - }); - }); - }, - "WebGL" -); diff --git a/Specs/Scene/Batched3DModel3DTileContentSpec.js b/Specs/Scene/Batched3DModel3DTileContentSpec.js deleted file mode 100644 index 2529a447c5b6..000000000000 --- a/Specs/Scene/Batched3DModel3DTileContentSpec.js +++ /dev/null @@ -1,549 +0,0 @@ -import { - B3dmParser, - Cartesian3, - Cesium3DContentGroup, - ContentMetadata, - Color, - HeadingPitchRange, - HeadingPitchRoll, - Matrix4, - Transforms, - Cesium3DTilePass, - ClippingPlane, - ClippingPlaneCollection, - MetadataClass, - GroupMetadata, - Model, -} from "../../Source/Cesium.js"; -import Cesium3DTilesTester from "../Cesium3DTilesTester.js"; -import createScene from "../createScene.js"; - -describe( - "Scene/Batched3DModel3DTileContent", - function () { - let scene; - const centerLongitude = -1.31968; - const centerLatitude = 0.698874; - - const withBatchTableUrl = - "./Data/Cesium3DTiles/Batched/BatchedWithBatchTable/tileset.json"; - const withBatchTableBinaryUrl = - "./Data/Cesium3DTiles/Batched/BatchedWithBatchTableBinary/tileset.json"; - const withoutBatchTableUrl = - "./Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/tileset.json"; - const translucentUrl = - "./Data/Cesium3DTiles/Batched/BatchedTranslucent/tileset.json"; - const translucentOpaqueMixUrl = - "./Data/Cesium3DTiles/Batched/BatchedTranslucentOpaqueMix/tileset.json"; - const withTransformBoxUrl = - "./Data/Cesium3DTiles/Batched/BatchedWithTransformBox/tileset.json"; - const withTransformSphereUrl = - "./Data/Cesium3DTiles/Batched/BatchedWithTransformSphere/tileset.json"; - const withTransformRegionUrl = - "./Data/Cesium3DTiles/Batched/BatchedWithTransformRegion/tileset.json"; - const texturedUrl = - "./Data/Cesium3DTiles/Batched/BatchedTextured/tileset.json"; - const withRtcCenterUrl = - "./Data/Cesium3DTiles/Batched/BatchedWithRtcCenter/tileset.json"; - const withCopyrightUrl = - "./Data/Cesium3DTiles/Batched/BatchedWithCopyright/tileset.json"; - - function setCamera(longitude, latitude) { - // One feature is located at the center, point the camera there - const center = Cartesian3.fromRadians(longitude, latitude); - scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 15.0)); - } - - beforeAll(function () { - scene = createScene(); - - // Keep the error from logging to the console when running tests - spyOn(B3dmParser, "_deprecationWarning"); - }); - - afterAll(function () { - scene.destroyForSpecs(); - }); - - beforeEach(function () { - setCamera(centerLongitude, centerLatitude); - }); - - afterEach(function () { - scene.primitives.removeAll(); - }); - - it("resolves readyPromise", function () { - return Cesium3DTilesTester.resolvesReadyPromise( - scene, - withoutBatchTableUrl - ); - }); - - it("renders with batch table", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - 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); - } - ); - }); - - it("renders with all features translucent", function () { - return Cesium3DTilesTester.loadTileset(scene, translucentUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - it("renders with a mix of opaque and translucent features", function () { - return Cesium3DTilesTester.loadTileset( - scene, - translucentOpaqueMixUrl - ).then(function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - }); - }); - - it("renders with textures", function () { - return Cesium3DTilesTester.loadTileset(scene, texturedUrl).then(function ( - tileset - ) { - Cesium3DTilesTester.expectRender(scene, tileset); - }); - }); - - function expectRenderWithTransform(url) { - return Cesium3DTilesTester.loadTileset(scene, url).then(function ( - tileset - ) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - - const newLongitude = -1.31962; - const newLatitude = 0.698874; - const newCenter = Cartesian3.fromRadians( - newLongitude, - newLatitude, - 0.0 - ); - const newHPR = new HeadingPitchRoll(); - const newTransform = Transforms.headingPitchRollToFixedFrame( - newCenter, - newHPR - ); - - // 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 expectRenderWithTransform(withTransformRegionUrl); - }); - - it("picks with batch table", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then( - function (tileset) { - const content = tileset.root.content; - tileset.show = false; - expect(scene).toPickPrimitive(undefined); - tileset.show = true; - expect(scene).toPickAndCall(function (result) { - expect(result).toBeDefined(); - expect(result.primitive).toBe(tileset); - expect(result.content).toBe(content); - }); - } - ); - }); - - it("picks without batch table", function () { - return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then( - function (tileset) { - const content = tileset.root.content; - tileset.show = false; - expect(scene).toPickPrimitive(undefined); - tileset.show = true; - expect(scene).toPickAndCall(function (result) { - expect(result).toBeDefined(); - expect(result.primitive).toBe(tileset); - expect(result.content).toBe(content); - }); - } - ); - }); - - it("can get features and properties", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then( - function (tileset) { - const content = tileset.root.content; - expect(content.featuresLength).toBe(10); - expect(content.innerContents).toBeUndefined(); - expect(content.hasProperty(0, "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) { - const content = tileset.root.content; - expect(function () { - content.getFeature(-1); - }).toThrowDeveloperError(); - expect(function () { - content.getFeature(1000); - }).toThrowDeveloperError(); - expect(function () { - content.getFeature(); - }).toThrowDeveloperError(); - } - ); - }); - - it("gets memory usage", function () { - return Cesium3DTilesTester.loadTileset(scene, texturedUrl).then(function ( - tileset - ) { - const content = tileset.root.content; - - // 10 buildings, 36 ushort indices and 24 vertices per building, 8 float components (position, normal, uv) and 1 uint component (batchId) per vertex. - // 10 * ((24 * (8 * 4 + 1 * 4)) + (36 * 2)) = 9360 - const geometryByteLength = 9360; - - // Texture is 128x128 RGBA bytes, not mipmapped - const texturesByteLength = 65536; - - // One RGBA byte pixel per feature - const batchTexturesByteLength = content.featuresLength * 4; - const pickTexturesByteLength = content.featuresLength * 4; - - // Features have not been picked or colored yet, so the batch table contribution is 0. - expect(content.geometryByteLength).toEqual(geometryByteLength); - expect(content.texturesByteLength).toEqual(texturesByteLength); - expect(content.batchTableByteLength).toEqual(0); - - // Color a feature and expect the texture memory to increase - content.getFeature(0).color = Color.RED; - scene.renderForSpecs(); - expect(content.geometryByteLength).toEqual(geometryByteLength); - expect(content.texturesByteLength).toEqual(texturesByteLength); - expect(content.batchTableByteLength).toEqual(batchTexturesByteLength); - - // Pick the tile and expect the texture memory to increase - scene.pickForSpecs(); - expect(content.geometryByteLength).toEqual(geometryByteLength); - expect(content.texturesByteLength).toEqual(texturesByteLength); - expect(content.batchTableByteLength).toEqual( - batchTexturesByteLength + pickTexturesByteLength - ); - }); - }); - - it("Links model to tileset clipping planes based on bounding volume clipping", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then( - function (tileset) { - const tile = tileset.root; - const content = tile.content; - const model = content._model; - const passOptions = Cesium3DTilePass.getPassOptions( - Cesium3DTilePass.RENDER - ); - - expect(model.clippingPlanes).toBeUndefined(); - - const clippingPlaneCollection = new ClippingPlaneCollection({ - planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], - }); - tileset.clippingPlanes = clippingPlaneCollection; - clippingPlaneCollection.update(scene.frameState); - tile.update(tileset, scene.frameState, passOptions); - - expect(model.clippingPlanes).toBeDefined(); - expect(model.clippingPlanes).toBe(tileset.clippingPlanes); - - tile._isClipped = false; - tile.update(tileset, scene.frameState, passOptions); - - expect(model.clippingPlanes).toBeUndefined(); - } - ); - }); - - it("Links model to tileset clipping planes if tileset clipping planes are reassigned", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then( - function (tileset) { - const tile = tileset.root; - const model = tile.content._model; - const passOptions = Cesium3DTilePass.getPassOptions( - Cesium3DTilePass.RENDER - ); - - expect(model.clippingPlanes).toBeUndefined(); - - const clippingPlaneCollection = new ClippingPlaneCollection({ - planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], - }); - tileset.clippingPlanes = clippingPlaneCollection; - clippingPlaneCollection.update(scene.frameState); - tile.update(tileset, scene.frameState, passOptions); - - expect(model.clippingPlanes).toBeDefined(); - expect(model.clippingPlanes).toBe(tileset.clippingPlanes); - - const newClippingPlaneCollection = new ClippingPlaneCollection({ - planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], - }); - tileset.clippingPlanes = newClippingPlaneCollection; - newClippingPlaneCollection.update(scene.frameState); - expect(model.clippingPlanes).not.toBe(tileset.clippingPlanes); - - tile.update(tileset, scene.frameState, passOptions); - expect(model.clippingPlanes).toBe(tileset.clippingPlanes); - } - ); - }); - - it("rebuilds Model shaders when clipping planes change", function () { - spyOn(Model, "_getClippingFunction").and.callThrough(); - - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then( - function (tileset) { - const tile = tileset.root; - const passOptions = Cesium3DTilePass.getPassOptions( - Cesium3DTilePass.RENDER - ); - - const clippingPlaneCollection = new ClippingPlaneCollection({ - planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], - }); - tileset.clippingPlanes = clippingPlaneCollection; - clippingPlaneCollection.update(scene.frameState); - tile.update(tileset, scene.frameState, passOptions); - - expect(Model._getClippingFunction.calls.count()).toEqual(1); - } - ); - }); - - it("transforms model positions by RTC_CENTER property in the features table", function () { - return Cesium3DTilesTester.loadTileset(scene, withRtcCenterUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - - const rtcTransform = tileset.root.content._rtcCenterTransform; - expect(rtcTransform).toEqual( - Matrix4.fromTranslation(new Cartesian3(0.1, 0.2, 0.3)) - ); - - let expectedModelTransform = Matrix4.multiply( - tileset.root.transform, - rtcTransform, - new Matrix4() - ); - expect(tileset.root.content._contentModelMatrix).toEqual( - expectedModelTransform - ); - expect(tileset.root.content._model._modelMatrix).toEqual( - expectedModelTransform - ); - - // Update tile transform - const newLongitude = -1.31962; - const newLatitude = 0.698874; - const newCenter = Cartesian3.fromRadians( - newLongitude, - newLatitude, - 0.0 - ); - const newHPR = new HeadingPitchRoll(); - const newTransform = Transforms.headingPitchRollToFixedFrame( - newCenter, - newHPR - ); - tileset.root.transform = newTransform; - scene.camera.lookAt(newCenter, new HeadingPitchRange(0.0, 0.0, 15.0)); - scene.renderForSpecs(); - - expectedModelTransform = Matrix4.multiply( - tileset.root.computedTransform, - rtcTransform, - expectedModelTransform - ); - expect(tileset.root.content._model._modelMatrix).toEqual( - expectedModelTransform - ); - } - ); - }); - - it("gets copyright from glTF", function () { - return Cesium3DTilesTester.loadTileset(scene, withCopyrightUrl).then( - function (tileset) { - const creditDisplay = scene.frameState.creditDisplay; - const credits = - creditDisplay._currentFrameCredits.lightboxCredits.values; - expect(credits.length).toEqual(1); - expect(credits[0].credit.html).toEqual("Sample Copyright"); - } - ); - }); - - it("shows copyright from glTF on screen", function () { - return Cesium3DTilesTester.loadTileset(scene, withCopyrightUrl, { - showCreditsOnScreen: true, - }).then(function (tileset) { - const creditDisplay = scene.frameState.creditDisplay; - const credits = creditDisplay._currentFrameCredits.screenCredits.values; - expect(credits.length).toEqual(1); - expect(credits[0].credit.html).toEqual("Sample Copyright"); - }); - }); - - it("toggles showing copyright from glTF on screen", function () { - return Cesium3DTilesTester.loadTileset(scene, withCopyrightUrl, { - showCreditsOnScreen: false, - }).then(function (tileset) { - const creditDisplay = scene.frameState.creditDisplay; - const lightboxCredits = - creditDisplay._currentFrameCredits.lightboxCredits.values; - const screenCredits = - creditDisplay._currentFrameCredits.screenCredits.values; - - expect(lightboxCredits.length).toEqual(1); - expect(lightboxCredits[0].credit.html).toEqual("Sample Copyright"); - expect(screenCredits.length).toEqual(0); - - tileset.showCreditsOnScreen = true; - scene.renderForSpecs(); - expect(screenCredits.length).toEqual(1); - expect(screenCredits[0].credit.html).toEqual("Sample Copyright"); - expect(lightboxCredits.length).toEqual(0); - - tileset.showCreditsOnScreen = false; - scene.renderForSpecs(); - expect(lightboxCredits.length).toEqual(1); - expect(lightboxCredits[0].credit.html).toEqual("Sample Copyright"); - expect(screenCredits.length).toEqual(0); - }); - }); - - it("destroys", function () { - return Cesium3DTilesTester.tileDestroys(scene, withoutBatchTableUrl); - }); - - describe("metadata", function () { - let metadataClass; - let groupMetadata; - let contentMetadataClass; - let contentMetadata; - - beforeAll(function () { - metadataClass = new MetadataClass({ - id: "test", - class: { - properties: { - name: { - type: "STRING", - }, - height: { - type: "SCALAR", - componentType: "FLOAT32", - }, - }, - }, - }); - - groupMetadata = new GroupMetadata({ - id: "testGroup", - group: { - properties: { - name: "Test Group", - height: 35.6, - }, - }, - class: metadataClass, - }); - - contentMetadataClass = new MetadataClass({ - id: "contentTest", - class: { - properties: { - author: { - type: "STRING", - }, - color: { - type: "VEC3", - componentType: "UINT8", - }, - }, - }, - }); - - contentMetadata = new ContentMetadata({ - content: { - properties: { - author: "Test Author", - color: [255, 0, 0], - }, - }, - class: contentMetadataClass, - }); - }); - - it("assigns groupMetadata", function () { - return Cesium3DTilesTester.loadTileset( - scene, - withoutBatchTableUrl - ).then(function (tileset) { - const content = tileset.root.content; - content.group = new Cesium3DContentGroup({ metadata: groupMetadata }); - expect(content.group.metadata).toBe(groupMetadata); - }); - }); - - it("assigns metadata", function () { - return Cesium3DTilesTester.loadTileset( - scene, - withoutBatchTableUrl - ).then(function (tileset) { - const content = tileset.root.content; - content.metadata = contentMetadata; - expect(content.metadata).toBe(contentMetadata); - }); - }); - }); - }, - "WebGL" -); diff --git a/Specs/Scene/Cesium3DTileBatchTableSpec.js b/Specs/Scene/Cesium3DTileBatchTableSpec.js index eaa621990836..0cbd9aa6a8a0 100644 --- a/Specs/Scene/Cesium3DTileBatchTableSpec.js +++ b/Specs/Scene/Cesium3DTileBatchTableSpec.js @@ -17,7 +17,9 @@ import Cesium3DTilesTester from "../Cesium3DTilesTester.js"; import createScene from "../createScene.js"; import concatTypedArrays from "../concatTypedArrays.js"; -describe( +// Since b3dm tilesets now use ModelFeatureTable, disabling these tests until Cesium3DTileBatchTable and +// ModelFeatureTable can be consolidated +xdescribe( "Scene/Cesium3DTileBatchTable", function () { let scene; diff --git a/Specs/Scene/Cesium3DTilesetSpec.js b/Specs/Scene/Cesium3DTilesetSpec.js index 63048b9eab3f..fa325d564bcd 100644 --- a/Specs/Scene/Cesium3DTilesetSpec.js +++ b/Specs/Scene/Cesium3DTilesetSpec.js @@ -1118,14 +1118,9 @@ describe( b3dmGeometryMemory * 2 + i3dmGeometryMemory * 3; const expectedTextureMemory = texturesByteLength * 5; - // This test was revised for ModelExperimental, which tracks shared memory - // differently from Model. return Cesium3DTilesTester.loadTileset( scene, - tilesetWithExternalResourcesUrl, - { - enableModelExperimental: true, - } + tilesetWithExternalResourcesUrl ).then(function (tileset) { // Contents are not aware of whether their resources are shared by // other contents, so check ResourceCache. @@ -3888,7 +3883,7 @@ describe( }); }); - it("creates duplicate backface commands", function () { + xit("creates duplicate backface commands", function () { return Cesium3DTilesTester.loadTileset( scene, tilesetReplacement3Url, diff --git a/Specs/Scene/Composite3DTileContentSpec.js b/Specs/Scene/Composite3DTileContentSpec.js index 2622baa91d63..ff3b49996be0 100644 --- a/Specs/Scene/Composite3DTileContentSpec.js +++ b/Specs/Scene/Composite3DTileContentSpec.js @@ -108,8 +108,7 @@ describe( it("rejects readyPromise on error", function () { // Try loading a composite tile with an instanced tile that has an invalid url. - // Expect promise to be rejected in Model, ModelInstanceCollection, - // Instanced3DModel3DTileContent, and Composite3DTileContent. + // Expect promise to be rejected in ModelExperimental, Model3DTileContent and Composite3DTileContent. const arrayBuffer = Cesium3DTilesTester.generateCompositeTileBuffer({ tiles: [ Cesium3DTilesTester.generateInstancedTileBuffer({ diff --git a/Specs/Scene/Implicit3DTileContentSpec.js b/Specs/Scene/Implicit3DTileContentSpec.js index a81d9836ffaf..8eb8b7292219 100644 --- a/Specs/Scene/Implicit3DTileContentSpec.js +++ b/Specs/Scene/Implicit3DTileContentSpec.js @@ -1,5 +1,4 @@ import { - Batched3DModel3DTileContent, Cartesian3, Cesium3DContentGroup, Cesium3DTile, @@ -17,6 +16,7 @@ import { Matrix3, Matrix4, MetadataClass, + Model3DTileContent, Multiple3DTileContent, Resource, TileBoundingSphere, @@ -949,9 +949,7 @@ describe( // The root tile of this tileset only has one available content const transcodedRoot = tileset.root.children[0]; const transcodedRootHeader = transcodedRoot._header; - expect(transcodedRoot.content).toBeInstanceOf( - Batched3DModel3DTileContent - ); + expect(transcodedRoot.content).toBeInstanceOf(Model3DTileContent); expect(transcodedRootHeader.contents[0]).toEqual({ uri: "ground/0/0/0.b3dm", }); @@ -993,9 +991,7 @@ describe( // The root tile of this tileset only has one available content const transcodedRoot = tileset.root.children[0]; const transcodedRootHeader = transcodedRoot._header; - expect(transcodedRoot.content).toBeInstanceOf( - Batched3DModel3DTileContent - ); + expect(transcodedRoot.content).toBeInstanceOf(Model3DTileContent); expect(transcodedRootHeader.contents[0]).toEqual({ uri: "ground/0/0/0.b3dm", }); @@ -1011,9 +1007,7 @@ describe( // The root tile of this tileset only has one available content const transcodedRoot = tileset.root.children[0]; const transcodedRootHeader = transcodedRoot._header; - expect(transcodedRoot.content).toBeInstanceOf( - Batched3DModel3DTileContent - ); + expect(transcodedRoot.content).toBeInstanceOf(Model3DTileContent); expect(transcodedRootHeader.contents[0]).toEqual({ uri: "ground/0/0/0.b3dm", }); diff --git a/Specs/Scene/Instanced3DModel3DTileContentSpec.js b/Specs/Scene/Instanced3DModel3DTileContentSpec.js deleted file mode 100644 index 4d76b59e986b..000000000000 --- a/Specs/Scene/Instanced3DModel3DTileContentSpec.js +++ /dev/null @@ -1,585 +0,0 @@ -import { - Cartesian3, - Cesium3DContentGroup, - Color, - ContentMetadata, - HeadingPitchRange, - HeadingPitchRoll, - Transforms, - Cesium3DTilePass, - ClippingPlane, - ClippingPlaneCollection, - MetadataClass, - GroupMetadata, - Model, -} from "../../Source/Cesium.js"; -import Cesium3DTilesTester from "../Cesium3DTilesTester.js"; -import createScene from "../createScene.js"; - -describe( - "Scene/Instanced3DModel3DTileContent", - function () { - let scene; - const centerLongitude = -1.31968; - const centerLatitude = 0.698874; - - const gltfExternalUrl = - "./Data/Cesium3DTiles/Instanced/InstancedGltfExternal/tileset.json"; - const withBatchTableUrl = - "./Data/Cesium3DTiles/Instanced/InstancedWithBatchTable/tileset.json"; - const withBatchTableBinaryUrl = - "./Data/Cesium3DTiles/Instanced/InstancedWithBatchTableBinary/tileset.json"; - const withoutBatchTableUrl = - "./Data/Cesium3DTiles/Instanced/InstancedWithoutBatchTable/tileset.json"; - const orientationUrl = - "./Data/Cesium3DTiles/Instanced/InstancedOrientation/tileset.json"; - const oct16POrientationUrl = - "./Data/Cesium3DTiles/Instanced/InstancedOct32POrientation/tileset.json"; - const scaleUrl = - "./Data/Cesium3DTiles/Instanced/InstancedScale/tileset.json"; - const scaleNonUniformUrl = - "./Data/Cesium3DTiles/Instanced/InstancedScaleNonUniform/tileset.json"; - const rtcUrl = "./Data/Cesium3DTiles/Instanced/InstancedRTC/tileset.json"; - const quantizedUrl = - "./Data/Cesium3DTiles/Instanced/InstancedQuantized/tileset.json"; - const quantizedOct32POrientationUrl = - "./Data/Cesium3DTiles/Instanced/InstancedQuantizedOct32POrientation/tileset.json"; - const withTransformUrl = - "./Data/Cesium3DTiles/Instanced/InstancedWithTransform/tileset.json"; - const withBatchIdsUrl = - "./Data/Cesium3DTiles/Instanced/InstancedWithBatchIds/tileset.json"; - const texturedUrl = - "./Data/Cesium3DTiles/Instanced/InstancedTextured/tileset.json"; - const withCopyrightUrl = - "./Data/Cesium3DTiles/Instanced/InstancedWithCopyright/tileset.json"; - - function setCamera(longitude, latitude) { - // One instance is located at the center, point the camera there - const center = Cartesian3.fromRadians(longitude, latitude); - scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 27.0)); - } - - beforeAll(function () { - scene = createScene(); - }); - - beforeEach(function () { - scene.morphTo3D(0.0); - setCamera(centerLongitude, centerLatitude); - }); - - afterAll(function () { - scene.destroyForSpecs(); - }); - - afterEach(function () { - scene.primitives.removeAll(); - }); - - it("throws with invalid format", function () { - const arrayBuffer = Cesium3DTilesTester.generateInstancedTileBuffer({ - gltfFormat: 2, - }); - Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, "i3dm"); - }); - - it("throws with invalid version", function () { - const arrayBuffer = Cesium3DTilesTester.generateInstancedTileBuffer({ - version: 2, - }); - Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, "i3dm"); - }); - - it("resolves readyPromise", function () { - return Cesium3DTilesTester.resolvesReadyPromise( - scene, - withoutBatchTableUrl - ); - }); - - it("rejects readyPromise on error", function () { - // Try loading a tile with an invalid url. - // Expect promise to be rejected in Model, then in ModelInstanceCollection, and - // finally in Instanced3DModel3DTileContent. - const arrayBuffer = Cesium3DTilesTester.generateInstancedTileBuffer({ - gltfFormat: 0, - gltfUri: "not-a-real-path", - }); - return Cesium3DTilesTester.rejectsReadyPromiseOnError( - scene, - arrayBuffer, - "i3dm" - ); - }); - - it("renders with external gltf", function () { - return Cesium3DTilesTester.loadTileset(scene, gltfExternalUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - it("renders with batch table", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - 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); - } - ); - }); - - it("renders with feature defined orientation", function () { - return Cesium3DTilesTester.loadTileset(scene, orientationUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - it("renders with feature defined Oct32P encoded orientation", function () { - return Cesium3DTilesTester.loadTileset(scene, oct16POrientationUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - it("renders with feature defined scale", function () { - return Cesium3DTilesTester.loadTileset(scene, scaleUrl).then(function ( - tileset - ) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - }); - }); - - it("renders with feature defined non-uniform scale", function () { - return Cesium3DTilesTester.loadTileset(scene, scaleNonUniformUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - it("renders with RTC_CENTER semantic", function () { - return Cesium3DTilesTester.loadTileset(scene, rtcUrl).then(function ( - tileset - ) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - }); - }); - - it("renders with feature defined quantized position", function () { - return Cesium3DTilesTester.loadTileset(scene, quantizedUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - it("renders with feature defined quantized position and Oct32P encoded orientation", function () { - return Cesium3DTilesTester.loadTileset( - scene, - quantizedOct32POrientationUrl - ).then(function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - }); - }); - - it("renders with batch ids", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchIdsUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - it("renders with tile transform", function () { - return Cesium3DTilesTester.loadTileset(scene, withTransformUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - - const newLongitude = -1.31962; - const newLatitude = 0.698874; - const newCenter = Cartesian3.fromRadians( - newLongitude, - newLatitude, - 10.0 - ); - const newTransform = Transforms.headingPitchRollToFixedFrame( - newCenter, - new HeadingPitchRoll() - ); - - // Update tile transform - tileset.root.transform = newTransform; - - // Move the camera to the new location - setCamera(newLongitude, newLatitude); - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - it("renders with textures", function () { - return Cesium3DTilesTester.loadTileset(scene, texturedUrl).then(function ( - tileset - ) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - }); - }); - - it("renders in 2D", function () { - return Cesium3DTilesTester.loadTileset(scene, gltfExternalUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - tileset.maximumScreenSpaceError = 2.0; - scene.morphTo2D(0.0); - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - it("renders in 2D with tile transform", function () { - return Cesium3DTilesTester.loadTileset(scene, withTransformUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - tileset.maximumScreenSpaceError = 2.0; - scene.morphTo2D(0.0); - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - it("renders in CV", function () { - return Cesium3DTilesTester.loadTileset(scene, gltfExternalUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - scene.morphToColumbusView(0.0); - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - it("renders in CV with tile transform", function () { - return Cesium3DTilesTester.loadTileset(scene, withTransformUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - scene.morphToColumbusView(0.0); - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - } - ); - }); - - it("renders when instancing is disabled", function () { - // Disable extension - const instancedArrays = scene.context._instancedArrays; - scene.context._instancedArrays = undefined; - - return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRenderTileset(scene, tileset); - // Re-enable extension - scene.context._instancedArrays = instancedArrays; - } - ); - }); - - it("throws when calling getFeature with invalid index", function () { - return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then( - function (tileset) { - const content = tileset.root.content; - expect(function () { - content.getFeature(-1); - }).toThrowDeveloperError(); - expect(function () { - content.getFeature(10000); - }).toThrowDeveloperError(); - expect(function () { - content.getFeature(); - }).toThrowDeveloperError(); - } - ); - }); - - it("gets memory usage", function () { - return Cesium3DTilesTester.loadTileset(scene, texturedUrl).then(function ( - tileset - ) { - const content = tileset.root.content; - - // Box model - 36 ushort indices and 24 vertices per building, 8 float components (position, normal, uv) per vertex. - // (24 * 8 * 4) + (36 * 2) = 840 - const geometryByteLength = 840; - - // Texture is 128x128 RGBA bytes, not mipmapped - const texturesByteLength = 65536; - - // One RGBA byte pixel per feature - const batchTexturesByteLength = content.featuresLength * 4; - const pickTexturesByteLength = content.featuresLength * 4; - - // Features have not been picked or colored yet, so the batch table contribution is 0. - expect(content.geometryByteLength).toEqual(geometryByteLength); - expect(content.texturesByteLength).toEqual(texturesByteLength); - expect(content.batchTableByteLength).toEqual(0); - - // Color a feature and expect the texture memory to increase - content.getFeature(0).color = Color.RED; - scene.renderForSpecs(); - expect(content.geometryByteLength).toEqual(geometryByteLength); - expect(content.texturesByteLength).toEqual(texturesByteLength); - expect(content.batchTableByteLength).toEqual(batchTexturesByteLength); - - // Pick the tile and expect the texture memory to increase - scene.pickForSpecs(); - expect(content.geometryByteLength).toEqual(geometryByteLength); - expect(content.texturesByteLength).toEqual(texturesByteLength); - expect(content.batchTableByteLength).toEqual( - batchTexturesByteLength + pickTexturesByteLength - ); - }); - }); - - it("Links model to tileset clipping planes based on bounding volume clipping", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then( - function (tileset) { - const tile = tileset.root; - const content = tile.content; - const model = content._modelInstanceCollection._model; - const passOptions = Cesium3DTilePass.getPassOptions( - Cesium3DTilePass.RENDER - ); - - expect(model.clippingPlanes).toBeUndefined(); - - const clippingPlaneCollection = new ClippingPlaneCollection({ - planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], - }); - tileset.clippingPlanes = clippingPlaneCollection; - clippingPlaneCollection.update(scene.frameState); - tile.update(tileset, scene.frameState, passOptions); - - expect(model.clippingPlanes).toBeDefined(); - expect(model.clippingPlanes).toBe(tileset.clippingPlanes); - - tile._isClipped = false; - tile.update(tileset, scene.frameState, passOptions); - - expect(model.clippingPlanes).toBeUndefined(); - } - ); - }); - - it("Links model to tileset clipping planes if tileset clipping planes are reassigned", function () { - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then( - function (tileset) { - const tile = tileset.root; - const model = tile.content._modelInstanceCollection._model; - const passOptions = Cesium3DTilePass.getPassOptions( - Cesium3DTilePass.RENDER - ); - - expect(model.clippingPlanes).toBeUndefined(); - - const clippingPlaneCollection = new ClippingPlaneCollection({ - planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], - }); - tileset.clippingPlanes = clippingPlaneCollection; - clippingPlaneCollection.update(scene.frameState); - tile.update(tileset, scene.frameState, passOptions); - - expect(model.clippingPlanes).toBeDefined(); - expect(model.clippingPlanes).toBe(tileset.clippingPlanes); - - const newClippingPlaneCollection = new ClippingPlaneCollection({ - planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], - }); - tileset.clippingPlanes = newClippingPlaneCollection; - newClippingPlaneCollection.update(scene.frameState); - expect(model.clippingPlanes).not.toBe(tileset.clippingPlanes); - - tile.update(tileset, scene.frameState, passOptions); - expect(model.clippingPlanes).toBe(tileset.clippingPlanes); - } - ); - }); - - it("rebuilds Model shaders when clipping planes change", function () { - spyOn(Model, "_getClippingFunction").and.callThrough(); - - return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then( - function (tileset) { - const tile = tileset.root; - const content = tile.content; - const clippingPlaneCollection = new ClippingPlaneCollection({ - planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], - }); - const passOptions = Cesium3DTilePass.getPassOptions( - Cesium3DTilePass.RENDER - ); - tileset.clippingPlanes = clippingPlaneCollection; - clippingPlaneCollection.update(scene.frameState); - content.clippingPlanesDirty = true; - tile.update(tileset, scene.frameState, passOptions); - - expect(Model._getClippingFunction.calls.count()).toEqual(1); - } - ); - }); - - it("gets copyright from glTF", function () { - return Cesium3DTilesTester.loadTileset(scene, withCopyrightUrl).then( - function (tileset) { - const creditDisplay = scene.frameState.creditDisplay; - const credits = - creditDisplay._currentFrameCredits.lightboxCredits.values; - expect(credits.length).toEqual(1); - expect(credits[0].credit.html).toEqual("Sample Copyright"); - } - ); - }); - - it("shows copyright from glTF on screen", function () { - return Cesium3DTilesTester.loadTileset(scene, withCopyrightUrl, { - showCreditsOnScreen: true, - }).then(function (tileset) { - const creditDisplay = scene.frameState.creditDisplay; - const credits = creditDisplay._currentFrameCredits.screenCredits.values; - expect(credits.length).toEqual(1); - expect(credits[0].credit.html).toEqual("Sample Copyright"); - }); - }); - - it("toggles showing copyright from glTF on screen", function () { - return Cesium3DTilesTester.loadTileset(scene, withCopyrightUrl, { - showCreditsOnScreen: false, - }).then(function (tileset) { - const creditDisplay = scene.frameState.creditDisplay; - const lightboxCredits = - creditDisplay._currentFrameCredits.lightboxCredits.values; - const screenCredits = - creditDisplay._currentFrameCredits.screenCredits.values; - - expect(lightboxCredits.length).toEqual(1); - expect(lightboxCredits[0].credit.html).toEqual("Sample Copyright"); - expect(screenCredits.length).toEqual(0); - - tileset.showCreditsOnScreen = true; - scene.renderForSpecs(); - expect(screenCredits.length).toEqual(1); - expect(screenCredits[0].credit.html).toEqual("Sample Copyright"); - expect(lightboxCredits.length).toEqual(0); - - tileset.showCreditsOnScreen = false; - scene.renderForSpecs(); - expect(lightboxCredits.length).toEqual(1); - expect(lightboxCredits[0].credit.html).toEqual("Sample Copyright"); - expect(screenCredits.length).toEqual(0); - }); - }); - - it("destroys", function () { - return Cesium3DTilesTester.tileDestroys(scene, withoutBatchTableUrl); - }); - - describe("metadata", function () { - let metadataClass; - let groupMetadata; - let contentMetadataClass; - let contentMetadata; - - beforeAll(function () { - metadataClass = new MetadataClass({ - id: "test", - class: { - properties: { - name: { - type: "STRING", - }, - height: { - type: "SCALAR", - componentType: "FLOAT32", - }, - }, - }, - }); - - groupMetadata = new GroupMetadata({ - id: "testGroup", - group: { - properties: { - name: "Test Group", - height: 35.6, - }, - }, - class: metadataClass, - }); - - contentMetadataClass = new MetadataClass({ - id: "contentTest", - class: { - properties: { - author: { - type: "STRING", - }, - color: { - type: "VEC3", - componentType: "UINT8", - }, - }, - }, - }); - - contentMetadata = new ContentMetadata({ - content: { - properties: { - author: "Test Author", - color: [255, 0, 0], - }, - }, - class: contentMetadataClass, - }); - }); - - it("assigns group metadata", function () { - return Cesium3DTilesTester.loadTileset( - scene, - withoutBatchTableUrl - ).then(function (tileset) { - const content = tileset.root.content; - content.group = new Cesium3DContentGroup({ metadata: groupMetadata }); - expect(content.group.metadata).toBe(groupMetadata); - }); - }); - - it("assigns metadata", function () { - return Cesium3DTilesTester.loadTileset( - scene, - withoutBatchTableUrl - ).then(function (tileset) { - const content = tileset.root.content; - content.metadata = contentMetadata; - expect(content.metadata).toBe(contentMetadata); - }); - }); - }); - }, - "WebGL" -); diff --git a/Specs/Scene/PointCloud3DTileContentSpec.js b/Specs/Scene/PointCloud3DTileContentSpec.js deleted file mode 100644 index ab8a738d8ade..000000000000 --- a/Specs/Scene/PointCloud3DTileContentSpec.js +++ /dev/null @@ -1,1294 +0,0 @@ -import { - Cartesian3, - Cesium3DContentGroup, - Cesium3DTilePass, - Cesium3DTileRefine, - Cesium3DTileStyle, - ClippingPlane, - ClippingPlaneCollection, - Color, - ComponentDatatype, - ContentMetadata, - defined, - DracoLoader, - Expression, - HeadingPitchRange, - HeadingPitchRoll, - Math as CesiumMath, - MetadataClass, - GroupMetadata, - Pass, - PerspectiveFrustum, - RuntimeError, - Transforms, -} from "../../Source/Cesium.js"; -import Cesium3DTilesTester from "../Cesium3DTilesTester.js"; -import createCanvas from "../createCanvas.js"; -import createScene from "../createScene.js"; -import pollToPromise from "../pollToPromise.js"; - -describe( - "Scene/PointCloud3DTileContent", - function () { - let scene; - const centerLongitude = -1.31968; - const centerLatitude = 0.698874; - - const pointCloudRGBUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudRGB/tileset.json"; - const pointCloudRGBAUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudRGBA/tileset.json"; - const pointCloudRGB565Url = - "./Data/Cesium3DTiles/PointCloud/PointCloudRGB565/tileset.json"; - const pointCloudNoColorUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudNoColor/tileset.json"; - const pointCloudConstantColorUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudConstantColor/tileset.json"; - const pointCloudNormalsUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudNormals/tileset.json"; - const pointCloudNormalsOctEncodedUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudNormalsOctEncoded/tileset.json"; - const pointCloudQuantizedUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudQuantized/tileset.json"; - const pointCloudQuantizedOctEncodedUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudQuantizedOctEncoded/tileset.json"; - const pointCloudDracoUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudDraco/tileset.json"; - const pointCloudDracoPartialUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudDracoPartial/tileset.json"; - const pointCloudDracoBatchedUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudDracoBatched/tileset.json"; - const pointCloudWGS84Url = - "./Data/Cesium3DTiles/PointCloud/PointCloudWGS84/tileset.json"; - const pointCloudBatchedUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudBatched/tileset.json"; - const pointCloudWithPerPointPropertiesUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudWithPerPointProperties/tileset.json"; - const pointCloudWithUnicodePropertyIdsUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudWithUnicodePropertyIds/tileset.json"; - const pointCloudWithTransformUrl = - "./Data/Cesium3DTiles/PointCloud/PointCloudWithTransform/tileset.json"; - const pointCloudTilesetUrl = - "./Data/Cesium3DTiles/Tilesets/TilesetPoints/tileset.json"; - - function setCamera(longitude, latitude) { - // Point the camera to the center of the tile - const center = Cartesian3.fromRadians(longitude, latitude, 5.0); - scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 5.0)); - } - - beforeAll(function () { - scene = createScene(); - scene.frameState.passes.render = true; - }); - - afterAll(function () { - scene.destroyForSpecs(); - }); - - beforeEach(function () { - scene.morphTo3D(0.0); - - const camera = scene.camera; - camera.frustum = new PerspectiveFrustum(); - camera.frustum.aspectRatio = - scene.drawingBufferWidth / scene.drawingBufferHeight; - camera.frustum.fov = CesiumMath.toRadians(60.0); - - setCamera(centerLongitude, centerLatitude); - }); - - afterEach(function () { - scene.primitives.removeAll(); - }); - - it("throws with invalid version", function () { - const arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ - version: 2, - }); - Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, "pnts"); - }); - - it("throws if featureTableJsonByteLength is 0", function () { - const arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ - featureTableJsonByteLength: 0, - }); - Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, "pnts"); - }); - - it("throws if the feature table does not contain POINTS_LENGTH", function () { - const arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ - featureTableJson: { - POSITION: { - byteOffset: 0, - }, - }, - }); - Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, "pnts"); - }); - - it("throws if the feature table does not contain POSITION or POSITION_QUANTIZED", function () { - const arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ - featureTableJson: { - POINTS_LENGTH: 1, - }, - }); - Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, "pnts"); - }); - - it("throws if the positions are quantized and the feature table does not contain QUANTIZED_VOLUME_SCALE", function () { - const arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ - featureTableJson: { - POINTS_LENGTH: 1, - POSITION_QUANTIZED: { - byteOffset: 0, - }, - QUANTIZED_VOLUME_OFFSET: [0.0, 0.0, 0.0], - }, - }); - Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, "pnts"); - }); - - it("throws if the positions are quantized and the feature table does not contain QUANTIZED_VOLUME_OFFSET", function () { - const arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ - featureTableJson: { - POINTS_LENGTH: 1, - POSITION_QUANTIZED: { - byteOffset: 0, - }, - QUANTIZED_VOLUME_SCALE: [1.0, 1.0, 1.0], - }, - }); - Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, "pnts"); - }); - - it("throws if the BATCH_ID semantic is defined but BATCH_LENGTH is not", function () { - const arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({ - featureTableJson: { - POINTS_LENGTH: 2, - POSITION: [0.0, 0.0, 0.0, 1.0, 1.0, 1.0], - BATCH_ID: [0, 1], - }, - }); - Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, "pnts"); - }); - - it("BATCH_ID semantic uses componentType of UNSIGNED_SHORT by default", function () { - const 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, - }, - }); - const content = Cesium3DTilesTester.loadTile(scene, arrayBuffer, "pnts"); - expect( - content._pointCloud._drawCommand._vertexArray._attributes[1] - .componentDatatype - ).toEqual(ComponentDatatype.UNSIGNED_SHORT); - }); - - it("gets tileset properties", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - const root = tileset.root; - const content = root.content; - expect(content.tileset).toBe(tileset); - expect(content.tile).toBe(root); - expect(content.url.indexOf(root._header.content.uri) > -1).toBe(true); - } - ); - }); - - it("resolves readyPromise", function () { - return Cesium3DTilesTester.resolvesReadyPromise(scene, pointCloudRGBUrl); - }); - - it("renders point cloud with rgb colors", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - } - ); - }); - - it("renders point cloud with rgba colors", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBAUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - } - ); - }); - - it("renders point cloud with rgb565 colors", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGB565Url).then( - function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - } - ); - }); - - it("renders point cloud with no colors", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudNoColorUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - } - ); - }); - - it("renders point cloud with constant colors", function () { - return Cesium3DTilesTester.loadTileset( - scene, - pointCloudConstantColorUrl - ).then(function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - }); - }); - - it("renders point cloud with normals", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudNormalsUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - } - ); - }); - - it("renders point cloud with oct encoded normals", function () { - return Cesium3DTilesTester.loadTileset( - scene, - pointCloudNormalsOctEncodedUrl - ).then(function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - }); - }); - - it("renders point cloud with quantized positions", function () { - return Cesium3DTilesTester.loadTileset( - scene, - pointCloudQuantizedUrl - ).then(function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - }); - }); - - it("renders point cloud with quantized positions and oct-encoded normals", function () { - return Cesium3DTilesTester.loadTileset( - scene, - pointCloudQuantizedOctEncodedUrl - ).then(function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - }); - }); - - it("renders point cloud with draco encoded positions, normals, colors, and batch table properties", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudDracoUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - // Test that Draco-encoded batch table properties are functioning correctly - tileset.style = new Cesium3DTileStyle({ - color: "vec4(Number(${secondaryColor}[0] < 1.0), 0.0, 0.0, 1.0)", - }); - - expect(scene).toRenderAndCall(function (rgba) { - // Produces a red color - expect(rgba[0]).toBeGreaterThan(rgba[1]); - expect(rgba[0]).toBeGreaterThan(rgba[2]); - }); - } - ); - }); - - it("renders point cloud with draco encoded positions and uncompressed normals and colors", function () { - return Cesium3DTilesTester.loadTileset( - scene, - pointCloudDracoPartialUrl - ).then(function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - }); - }); - - it("renders point cloud with draco encoded positions, colors, and batch ids", function () { - return Cesium3DTilesTester.loadTileset( - scene, - pointCloudDracoBatchedUrl - ).then(function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - }); - }); - - it("error decoding a draco point cloud causes loading to fail", function () { - const readyPromise = pollToPromise(function () { - return DracoLoader._taskProcessorReady; - }); - DracoLoader._getDecoderTaskProcessor(); - return readyPromise - .then(function () { - const decoder = DracoLoader._getDecoderTaskProcessor(); - spyOn(decoder, "scheduleTask").and.callFake(function () { - return Promise.reject({ message: "my error" }); - }); - return Cesium3DTilesTester.loadTileset(scene, pointCloudDracoUrl); - }) - .then(function (tileset) { - const root = tileset.root; - return root.contentReadyPromise; - }) - .then(function () { - fail("should not resolve"); - }) - .catch(function (error) { - expect(error.message).toBe("my error"); - }); - }); - - it("renders point cloud that are not defined relative to center", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudWGS84Url).then( - function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - } - ); - }); - - it("renders point cloud with batch table", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then( - function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - } - ); - }); - - it("renders point cloud with per-point properties", function () { - return Cesium3DTilesTester.loadTileset( - scene, - pointCloudWithPerPointPropertiesUrl - ).then(function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - }); - }); - - it("renders point cloud with tile transform", function () { - return Cesium3DTilesTester.loadTileset( - scene, - pointCloudWithTransformUrl - ).then(function (tileset) { - Cesium3DTilesTester.expectRender(scene, tileset); - - const newLongitude = -1.31962; - const newLatitude = 0.698874; - const newCenter = Cartesian3.fromRadians( - newLongitude, - newLatitude, - 5.0 - ); - const newHPR = new HeadingPitchRoll(); - const newTransform = Transforms.headingPitchRollToFixedFrame( - newCenter, - newHPR - ); - - // Update tile transform - tileset.root.transform = newTransform; - - // Move the camera to the new location - setCamera(newLongitude, newLatitude); - Cesium3DTilesTester.expectRender(scene, tileset); - }); - }); - - it("renders with debug color", function () { - CesiumMath.setRandomNumberSeed(0); - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - let color; - expect(scene).toRenderAndCall(function (rgba) { - color = rgba; - }); - tileset.debugColorizeTiles = true; - expect(scene).notToRender(color); - tileset.debugColorizeTiles = false; - expect(scene).toRender(color); - } - ); - }); - - it("renders in CV", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - scene.morphToColumbusView(0.0); - setCamera(centerLongitude, centerLatitude); - Cesium3DTilesTester.expectRender(scene, tileset); - } - ); - }); - - it("renders in 2D", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - scene.morphTo2D(0.0); - setCamera(centerLongitude, centerLatitude); - tileset.maximumScreenSpaceError = 3; - Cesium3DTilesTester.expectRender(scene, tileset); - } - ); - }); - - it("picks", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - const content = tileset.root.content; - tileset.show = false; - expect(scene).toPickPrimitive(undefined); - tileset.show = true; - expect(scene).toPickAndCall(function (result) { - expect(result).toBeDefined(); - expect(result.primitive).toBe(tileset); - expect(result.content).toBe(content); - }); - } - ); - }); - - it("picks based on batchId", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then( - function (tileset) { - // Get the original color - let color; - expect(scene).toRenderAndCall(function (rgba) { - color = rgba; - }); - - // Change the color of the picked feature to yellow - expect(scene).toPickAndCall(function (first) { - expect(first).toBeDefined(); - - first.color = Color.clone(Color.YELLOW, first.color); - - // Expect the pixel color to be some shade of yellow - expect(scene).notToRender(color); - - // Turn show off. Expect a different feature to get picked. - first.show = false; - expect(scene).toPickAndCall(function (second) { - expect(second).toBeDefined(); - expect(second).not.toBe(first); - }); - }); - } - ); - }); - - it("point cloud without batch table works", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - const content = tileset.root.content; - expect(content.featuresLength).toBe(0); - expect(content.innerContents).toBeUndefined(); - expect(content.hasProperty(0, "name")).toBe(false); - expect(content.getFeature(0)).toBeUndefined(); - } - ); - }); - - it("batched point cloud works", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then( - function (tileset) { - const content = tileset.root.content; - expect(content.featuresLength).toBe(8); - expect(content.innerContents).toBeUndefined(); - expect(content.hasProperty(0, "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) { - const content = tileset.root.content; - expect(content.featuresLength).toBe(0); - expect(content.innerContents).toBeUndefined(); - expect(content.hasProperty(0, "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) { - const content = tileset.root.content; - expect(function () { - content.getFeature(-1); - }).toThrowDeveloperError(); - expect(function () { - content.getFeature(1000); - }).toThrowDeveloperError(); - expect(function () { - content.getFeature(); - }).toThrowDeveloperError(); - } - ); - }); - - it("Supports back face culling when there are per-point normals", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then( - function (tileset) { - const content = tileset.root.content; - - // Get the number of picked sections with back face culling on - let pickedCountCulling = 0; - let pickedCount = 0; - let picked; - - expect(scene).toPickAndCall(function (result) { - // Set culling to true - tileset.pointCloudShading.backFaceCulling = true; - - expect(scene).toPickAndCall(function (result) { - picked = result; - }); - - /* jshint loopfunc: true */ - while (defined(picked)) { - picked.show = false; - //eslint-disable-next-line no-loop-func - expect(scene).toPickAndCall(function (result) { - picked = result; - }); - ++pickedCountCulling; - } - - // Set the shows back to true - const length = content.featuresLength; - for (let i = 0; i < length; ++i) { - const feature = content.getFeature(i); - feature.show = true; - } - - // Set culling to false - tileset.pointCloudShading.backFaceCulling = false; - - expect(scene).toPickAndCall(function (result) { - picked = result; - }); - - /* jshint loopfunc: true */ - while (defined(picked)) { - picked.show = false; - //eslint-disable-next-line no-loop-func - expect(scene).toPickAndCall(function (result) { - picked = result; - }); - ++pickedCount; - } - - expect(pickedCount).toBeGreaterThan(pickedCountCulling); - }); - } - ); - }); - - let noAttenuationPixelCount; - function attenuationTest(postLoadCallback) { - const scene = createScene({ - canvas: createCanvas(10, 10), - }); - noAttenuationPixelCount = scene.logarithmicDepthBuffer ? 20 : 16; - const center = new Cartesian3.fromRadians( - centerLongitude, - centerLatitude, - 5.0 - ); - scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 5.0)); - scene.postProcessStages.fxaa.enabled = false; - scene.camera.zoomIn(6); - - return Cesium3DTilesTester.loadTileset(scene, pointCloudNoColorUrl).then( - function (tileset) { - tileset.pointCloudShading.eyeDomeLighting = false; - tileset.root.refine = Cesium3DTileRefine.REPLACE; - postLoadCallback(scene, tileset); - scene.destroyForSpecs(); - } - ); - } - - it("attenuates points based on geometric error", function () { - return attenuationTest(function (scene, tileset) { - tileset.pointCloudShading.attenuation = true; - tileset.pointCloudShading.geometricErrorScale = 1.0; - tileset.pointCloudShading.maximumAttenuation = undefined; - tileset.pointCloudShading.baseResolution = undefined; - tileset.maximumScreenSpaceError = 16; - expect(scene).toRenderPixelCountAndCall(function (pixelCount) { - expect(pixelCount).toBeGreaterThan(noAttenuationPixelCount); - }); - }); - }); - - it("modulates attenuation using the tileset screen space error", function () { - return attenuationTest(function (scene, tileset) { - tileset.pointCloudShading.attenuation = true; - tileset.pointCloudShading.geometricErrorScale = 1.0; - tileset.pointCloudShading.maximumAttenuation = undefined; - tileset.pointCloudShading.baseResolution = undefined; - tileset.maximumScreenSpaceError = 1; - expect(scene).toRenderPixelCountAndCall(function (pixelCount) { - expect(pixelCount).toEqual(noAttenuationPixelCount); - }); - }); - }); - - it("modulates attenuation using the maximumAttenuation parameter", function () { - return attenuationTest(function (scene, tileset) { - tileset.pointCloudShading.attenuation = true; - tileset.pointCloudShading.geometricErrorScale = 1.0; - tileset.pointCloudShading.maximumAttenuation = 1; - tileset.pointCloudShading.baseResolution = undefined; - tileset.maximumScreenSpaceError = 16; - expect(scene).toRenderPixelCountAndCall(function (pixelCount) { - expect(pixelCount).toEqual(noAttenuationPixelCount); - }); - }); - }); - - it("modulates attenuation using the baseResolution parameter", function () { - return attenuationTest(function (scene, tileset) { - // pointCloudNoColorUrl is a single tile with GeometricError = 0, - // which results in default baseResolution being computed - tileset.pointCloudShading.attenuation = true; - tileset.pointCloudShading.geometricErrorScale = 1.0; - tileset.pointCloudShading.maximumAttenuation = undefined; - tileset.pointCloudShading.baseResolution = 0.2; - tileset.maximumScreenSpaceError = 16; - expect(scene).toRenderPixelCountAndCall(function (pixelCount) { - expect(pixelCount).toEqual(noAttenuationPixelCount); - }); - }); - }); - - it("modulates attenuation using the geometricErrorScale parameter", function () { - return attenuationTest(function (scene, tileset) { - tileset.pointCloudShading.attenuation = true; - tileset.pointCloudShading.geometricErrorScale = 0.2; - tileset.pointCloudShading.maximumAttenuation = undefined; - tileset.pointCloudShading.baseResolution = 1.0; - tileset.maximumScreenSpaceError = 1; - expect(scene).toRenderPixelCountAndCall(function (pixelCount) { - expect(pixelCount).toEqual(noAttenuationPixelCount); - }); - }); - }); - - it("attenuates points based on geometric error in 2D", function () { - return attenuationTest(function (scene, tileset) { - scene.morphTo2D(0); - tileset.pointCloudShading.attenuation = true; - tileset.pointCloudShading.geometricErrorScale = 1.0; - tileset.pointCloudShading.maximumAttenuation = undefined; - tileset.pointCloudShading.baseResolution = undefined; - tileset.maximumScreenSpaceError = 16; - expect(scene).toRenderPixelCountAndCall(function (pixelCount) { - expect(pixelCount).toBeGreaterThan(noAttenuationPixelCount); - }); - }); - }); - - it("applies shader style", function () { - let tileset, content; - return Cesium3DTilesTester.loadTileset( - scene, - pointCloudWithPerPointPropertiesUrl - ).then(function (t) { - tileset = t; - content = tileset.root.content; - - // Solid red color - tileset.style = new Cesium3DTileStyle({ - color: 'color("red")', - }); - - expect(scene).toRender([255, 0, 0, 255]); - expect(content._pointCloud._styleTranslucent).toBe(false); - - // Applies translucency - tileset.style = new Cesium3DTileStyle({ - color: "rgba(255, 0, 0, 0.005)", - }); - - expect(scene).toRenderAndCall(function (rgba) { - // Pixel is a darker red - expect(rgba[0]).toBeLessThan(255); - expect(rgba[1]).toBe(0); - expect(rgba[2]).toBe(0); - expect(rgba[3]).toBe(255); - expect(content._pointCloud._styleTranslucent).toBe(true); - }); - - // Style with property - tileset.style = new Cesium3DTileStyle({ - color: "color() * ${temperature}", - }); - - expect(scene).toRenderAndCall(function (rgba) { - // Pixel color is some shade of gray - expect(rgba[0]).toBe(rgba[1]); - expect(rgba[0]).toBe(rgba[2]); - expect(rgba[0]).toBeGreaterThan(0); - expect(rgba[0]).toBeLessThan(255); - }); - - // When no conditions are met the default color is white - tileset.style = new Cesium3DTileStyle({ - color: { - conditions: [ - ["${secondaryColor}[0] > 1.0", 'color("red")'], // This condition will not be met - ], - }, - }); - - expect(scene).toRender([255, 255, 255, 255]); - - // Apply style with conditions - tileset.style = new Cesium3DTileStyle({ - color: { - conditions: [ - ["${temperature} < 0.1", 'color("#000099")'], - ["${temperature} < 0.2", 'color("#00cc99", 1.0)'], - ["${temperature} < 0.3", 'color("#66ff33", 0.5)'], - ["${temperature} < 0.4", "rgba(255, 255, 0, 0.1)"], - ["${temperature} < 0.5", "rgb(255, 128, 0)"], - ["${temperature} < 0.6", 'color("red")'], - ["${temperature} < 0.7", 'color("rgb(255, 102, 102)")'], - ["${temperature} < 0.8", "hsl(0.875, 1.0, 0.6)"], - ["${temperature} < 0.9", "hsla(0.83, 1.0, 0.5, 0.1)"], - ["true", 'color("#FFFFFF", 1.0)'], - ], - }, - }); - - expect(scene).notToRender([0, 0, 0, 255]); - - // Apply show style - tileset.style = new Cesium3DTileStyle({ - show: true, - }); - - expect(scene).notToRender([0, 0, 0, 255]); - - // Apply show style that hides all points - tileset.style = new Cesium3DTileStyle({ - show: false, - }); - - expect(scene).toRender([0, 0, 0, 255]); - - // Apply show style with property - tileset.style = new Cesium3DTileStyle({ - show: "${temperature} > 0.1", - }); - - expect(scene).notToRender([0, 0, 0, 255]); - tileset.style = new Cesium3DTileStyle({ - show: "${temperature} > 1.0", - }); - - expect(scene).toRender([0, 0, 0, 255]); - - // Apply style with point cloud semantics - tileset.style = new Cesium3DTileStyle({ - color: "${COLOR} / 2.0", - show: "${POSITION}[0] > 0.5", - }); - - expect(scene).notToRender([0, 0, 0, 255]); - - // Apply pointSize style - tileset.style = new Cesium3DTileStyle({ - pointSize: 5.0, - }); - - expect(scene).notToRender([0, 0, 0, 255]); - }); - }); - - it("applies shader style with unicode property IDs", function () { - return Cesium3DTilesTester.loadTileset( - scene, - pointCloudWithUnicodePropertyIdsUrl - ).then(function (tileset) { - tileset.style = new Cesium3DTileStyle({ - color: "color() * ${feature['temperature ℃']}", - }); - - expect(scene).toRenderAndCall(function (rgba) { - // Pixel color is some shade of gray - expect(rgba[0]).toBe(rgba[1]); - expect(rgba[0]).toBe(rgba[2]); - expect(rgba[0]).toBeGreaterThan(0); - expect(rgba[0]).toBeLessThan(255); - }); - }); - }); - - it("rebuilds shader style when expression changes", function () { - let tileset; - return Cesium3DTilesTester.loadTileset(scene, pointCloudTilesetUrl).then( - function (t) { - tileset = t; - // Solid red color - tileset.style = new Cesium3DTileStyle({ - color: 'color("red")', - }); - - expect(scene).toRender([255, 0, 0, 255]); - - tileset.style.color = new Expression('color("lime")'); - tileset.makeStyleDirty(); - expect(scene).toRender([0, 255, 0, 255]); - - tileset.style.color = new Expression('color("blue", 0.5)'); - tileset.makeStyleDirty(); - expect(scene).toRenderAndCall(function (rgba) { - expect(rgba).toEqualEpsilon([0, 0, 255, 255], 5); - }); - - let i; - let commands = scene.frameState.commandList; - let commandsLength = commands.length; - expect(commandsLength).toBeGreaterThan(1); // Just check that at least some children are rendered - for (i = 0; i < commandsLength; ++i) { - expect(commands[i].pass).toBe(Pass.TRANSLUCENT); - } - - tileset.style.color = new Expression('color("yellow")'); - tileset.makeStyleDirty(); - expect(scene).toRender([255, 255, 0, 255]); - - commands = scene.frameState.commandList; - commandsLength = commands.length; - for (i = 0; i < commandsLength; ++i) { - expect(commands[i].pass).not.toBe(Pass.TRANSLUCENT); - } - } - ); - }); - - it("applies shader style to point cloud with normals", function () { - return Cesium3DTilesTester.loadTileset( - scene, - pointCloudQuantizedOctEncodedUrl - ).then(function (tileset) { - tileset.style = new Cesium3DTileStyle({ - color: 'color("red")', - }); - - expect(scene).toRenderAndCall(function (rgba) { - expect(rgba[0]).toBeGreaterThan(0); - expect(rgba[0]).toBeLessThan(255); - }); - }); - }); - - it("applies shader style to point cloud with normals", function () { - return Cesium3DTilesTester.loadTileset( - scene, - pointCloudQuantizedOctEncodedUrl - ).then(function (tileset) { - tileset.style = new Cesium3DTileStyle({ - color: 'color("red")', - }); - - expect(scene).toRenderAndCall(function (rgba) { - expect(rgba[0]).toBeGreaterThan(0); - }); - }); - }); - - it("applies shader style to point cloud without colors", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudNoColorUrl).then( - function (tileset) { - tileset.style = new Cesium3DTileStyle({ - color: 'color("red")', - }); - - expect(scene).toRender([255, 0, 0, 255]); - } - ); - }); - - it("throws if style references the NORMAL semantic but the point cloud does not have per-point normals", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - tileset.style = new Cesium3DTileStyle({ - color: "${NORMAL}[0] > 0.5", - }); - - expect(function () { - scene.renderForSpecs(); - }).toThrowError(RuntimeError); - } - ); - }); - - it("does not apply shader style if the point cloud has a batch table", function () { - let content, shaderProgram; - return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then( - function (tileset) { - content = tileset.root.content; - shaderProgram = content._pointCloud._drawCommand.shaderProgram; - tileset.style = new Cesium3DTileStyle({ - color: 'color("red")', - }); - - scene.renderForSpecs(); - expect(content._pointCloud._drawCommand.shaderProgram).toBe( - shaderProgram - ); - - // Point cloud is styled through the batch table - expect(scene).notToRender([0, 0, 0, 255]); - } - ); - }); - - it("throws when shader style is invalid", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - tileset.style = new Cesium3DTileStyle({ - show: '1 < "2"', - }); - - expect(function () { - scene.renderForSpecs(); - }).toThrowError(RuntimeError); - } - ); - }); - - it("gets memory usage", function () { - const promises = [ - Cesium3DTilesTester.loadTileset(scene, pointCloudNoColorUrl), - Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl), - Cesium3DTilesTester.loadTileset(scene, pointCloudNormalsUrl), - Cesium3DTilesTester.loadTileset( - scene, - pointCloudQuantizedOctEncodedUrl - ), - ]; - - // 1000 points - const expectedGeometryMemory = [ - 1000 * 12, // 3 floats (xyz) - 1000 * 15, // 3 floats (xyz), 3 bytes (rgb) - 1000 * 27, // 3 floats (xyz), 3 bytes (rgb), 3 floats (normal) - 1000 * 11, // 3 shorts (quantized xyz), 3 bytes (rgb), 2 bytes (oct-encoded normal) - ]; - - return Promise.all(promises).then(function (tilesets) { - const length = tilesets.length; - for (let i = 0; i < length; ++i) { - const content = tilesets[i].root.content; - expect(content.geometryByteLength).toEqual(expectedGeometryMemory[i]); - expect(content.texturesByteLength).toEqual(0); - } - }); - }); - - it("gets memory usage for batch point cloud", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then( - function (tileset) { - const content = tileset.root.content; - - // Point cloud consists of positions, colors, normals, and batchIds - // 3 floats (xyz), 3 floats (normal), 1 byte (batchId) - const pointCloudGeometryMemory = 1000 * 25; - - // 2 properties each with 8 features each - // dimensions: VEC3 of FLOAT - // id: UNSIGNED_INT - const binaryPropertyMemory = 8 * (12 + 4); - - // One RGBA byte pixel per feature - const batchTexturesByteLength = content.featuresLength * 4; - const pickTexturesByteLength = content.featuresLength * 4; - - // Features have not been picked or colored yet, so the batch table contribution is 0. - expect(content.geometryByteLength).toEqual(pointCloudGeometryMemory); - expect(content.texturesByteLength).toEqual(0); - expect(content.batchTableByteLength).toEqual(binaryPropertyMemory); - - // Color a feature and expect the texture memory to increase - content.getFeature(0).color = Color.RED; - scene.renderForSpecs(); - expect(content.geometryByteLength).toEqual(pointCloudGeometryMemory); - expect(content.texturesByteLength).toEqual(0); - expect(content.batchTableByteLength).toEqual( - binaryPropertyMemory + batchTexturesByteLength - ); - - // Pick the tile and expect the texture memory to increase - scene.pickForSpecs(); - expect(content.geometryByteLength).toEqual(pointCloudGeometryMemory); - expect(content.texturesByteLength).toEqual(0); - expect(content.batchTableByteLength).toEqual( - binaryPropertyMemory + - batchTexturesByteLength + - pickTexturesByteLength - ); - } - ); - }); - - it("rebuilds shaders when clipping planes are enabled, change between union and intersection, or change count", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - const tile = tileset.root; - tile._isClipped = true; - const content = tile.content; - const passOptions = Cesium3DTilePass.getPassOptions( - Cesium3DTilePass.RENDER - ); - - const noClipFS = - content._pointCloud._drawCommand.shaderProgram._fragmentShaderText; - expect(noClipFS.indexOf("clip") !== -1).toBe(false); - - const clippingPlanes = new ClippingPlaneCollection({ - planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], - unionClippingRegions: false, - }); - tileset.clippingPlanes = clippingPlanes; - - clippingPlanes.update(scene.frameState); - tile.update(tileset, scene.frameState, passOptions); - const clipOneIntersectFS = - content._pointCloud._drawCommand.shaderProgram._fragmentShaderText; - expect(clipOneIntersectFS.indexOf("= clip(") !== -1).toBe(true); - expect(clipOneIntersectFS.indexOf("float clip") !== -1).toBe(true); - - clippingPlanes.unionClippingRegions = true; - - clippingPlanes.update(scene.frameState); - tile.update(tileset, scene.frameState, passOptions); - const clipOneUnionFS = - content._pointCloud._drawCommand.shaderProgram._fragmentShaderText; - expect(clipOneUnionFS.indexOf("= clip(") !== -1).toBe(true); - expect(clipOneUnionFS.indexOf("float clip") !== -1).toBe(true); - expect(clipOneUnionFS).not.toEqual(clipOneIntersectFS); - - clippingPlanes.add(new ClippingPlane(Cartesian3.UNIT_Y, 1.0)); - - clippingPlanes.update(scene.frameState); - tile.update(tileset, scene.frameState, passOptions); - const clipTwoUnionFS = - content._pointCloud._drawCommand.shaderProgram._fragmentShaderText; - expect(clipTwoUnionFS.indexOf("= clip(") !== -1).toBe(true); - expect(clipTwoUnionFS.indexOf("float clip") !== -1).toBe(true); - expect(clipTwoUnionFS).not.toEqual(clipOneIntersectFS); - expect(clipTwoUnionFS).not.toEqual(clipOneUnionFS); - } - ); - }); - - it("clipping planes selectively disable rendering", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - let color; - expect(scene).toRenderAndCall(function (rgba) { - color = rgba; - }); - - const clipPlane = new ClippingPlane(Cartesian3.UNIT_Z, -10.0); - tileset.clippingPlanes = new ClippingPlaneCollection({ - planes: [clipPlane], - }); - - expect(scene).notToRender(color); - - clipPlane.distance = 0.0; - - expect(scene).toRender(color); - } - ); - }); - - it("clipping planes apply edge styling", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - let color; - expect(scene).toRenderAndCall(function (rgba) { - color = rgba; - }); - - const clipPlane = new ClippingPlane(Cartesian3.UNIT_Z, -10.0); - tileset.clippingPlanes = new ClippingPlaneCollection({ - planes: [clipPlane], - modelMatrix: Transforms.eastNorthUpToFixedFrame( - tileset.boundingSphere.center - ), - edgeWidth: 20.0, - edgeColor: Color.RED, - }); - - expect(scene).notToRender(color); - } - ); - }); - - it("clipping planes union regions (Uint8)", function () { - // Force uint8 mode - there's a slight rendering difference between - // float and packed uint8 clipping planes for this test due to the small context - spyOn(ClippingPlaneCollection, "useFloatTexture").and.returnValue(false); - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - let color; - expect(scene).toRenderAndCall(function (rgba) { - color = rgba; - }); - - tileset.clippingPlanes = new ClippingPlaneCollection({ - planes: [ - new ClippingPlane(Cartesian3.UNIT_Z, 0.0), - new ClippingPlane(Cartesian3.UNIT_X, 0.0), - ], - modelMatrix: Transforms.eastNorthUpToFixedFrame( - tileset.boundingSphere.center - ), - unionClippingRegions: true, - }); - - expect(scene).notToRender(color); - - tileset.clippingPlanes.unionClippingRegions = false; - - expect(scene).toRender(color); - } - ); - }); - - it("clipping planes union regions (Float)", function () { - if (!ClippingPlaneCollection.useFloatTexture(scene.context)) { - // This configuration for the test fails in uint8 mode due to the small context - return; - } - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - let color; - expect(scene).toRenderAndCall(function (rgba) { - color = rgba; - }); - - tileset.clippingPlanes = new ClippingPlaneCollection({ - planes: [ - new ClippingPlane(Cartesian3.UNIT_Z, -10.0), - new ClippingPlane(Cartesian3.UNIT_X, 1.0), - ], - modelMatrix: Transforms.eastNorthUpToFixedFrame( - tileset.boundingSphere.center - ), - unionClippingRegions: true, - }); - - expect(scene).notToRender(color); - - tileset.clippingPlanes.unionClippingRegions = false; - - expect(scene).toRender(color); - } - ); - }); - - it("destroys", function () { - return Cesium3DTilesTester.tileDestroys(scene, pointCloudRGBUrl); - }); - - describe("metadata", function () { - let metadataClass; - let groupMetadata; - let contentMetadataClass; - let contentMetadata; - - beforeAll(function () { - metadataClass = new MetadataClass({ - id: "test", - class: { - properties: { - name: { - type: "STRING", - }, - height: { - type: "SCALAR", - componentType: "FLOAT32", - }, - }, - }, - }); - - groupMetadata = new GroupMetadata({ - id: "testGroup", - group: { - properties: { - name: "Test Group", - height: 35.6, - }, - }, - class: metadataClass, - }); - - contentMetadataClass = new MetadataClass({ - id: "contentTest", - class: { - properties: { - author: { - type: "STRING", - }, - color: { - type: "VEC3", - componentType: "UINT8", - }, - }, - }, - }); - - contentMetadata = new ContentMetadata({ - content: { - properties: { - author: "Test Author", - color: [255, 0, 0], - }, - }, - class: contentMetadataClass, - }); - }); - - it("assigns groupMetadata", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - const content = tileset.root.content; - content.group = new Cesium3DContentGroup({ - metadata: groupMetadata, - }); - expect(content.group.metadata).toBe(groupMetadata); - } - ); - }); - - it("assigns metadata", function () { - return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then( - function (tileset) { - const content = tileset.root.content; - content.metadata = contentMetadata; - expect(content.metadata).toBe(contentMetadata); - } - ); - }); - }); - }, - "WebGL" -);