diff --git a/CHANGES.md b/CHANGES.md index b3751eaadc0f..15c3175e91b1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ - Fixed error when resetting `Cesium3DTileset.modelMatrix` to its initial value. [#12409](https://github.com/CesiumGS/cesium/pull/12409) - Fixed the parameter types of the `ClippingPolygon.equals` function, and fixed cases where parameters to `equals` functions had erroneously not been marked as 'optional'. [#12394](https://github.com/CesiumGS/cesium/pull/12394) - Fixed type of `ImageryLayer.fromProviderAsync`, to correctly show that the param `options` is optional. [#12400](https://github.com/CesiumGS/cesium/pull/12400) +- Fixed Draco decoding for vertex colors that are normalized `UNSIGNED_BYTE` or `UNSIGNED_SHORT`. [#12417](https://github.com/CesiumGS/cesium/pull/12417) ### 1.125 - 2025-01-02 diff --git a/packages/engine/Source/Scene/GltfDracoLoader.js b/packages/engine/Source/Scene/GltfDracoLoader.js index a1902e0ba848..b51fbe5b611e 100644 --- a/packages/engine/Source/Scene/GltfDracoLoader.js +++ b/packages/engine/Source/Scene/GltfDracoLoader.js @@ -1,9 +1,11 @@ import Check from "../Core/Check.js"; +import ComponentDatatype from "../Core/ComponentDatatype.js"; import defaultValue from "../Core/defaultValue.js"; import defined from "../Core/defined.js"; import DracoLoader from "./DracoLoader.js"; import ResourceLoader from "./ResourceLoader.js"; import ResourceLoaderState from "./ResourceLoaderState.js"; +import VertexAttributeSemantic from "./VertexAttributeSemantic.js"; /** * Load a draco buffer from a glTF. @@ -18,6 +20,7 @@ import ResourceLoaderState from "./ResourceLoaderState.js"; * @param {object} options Object with the following properties: * @param {ResourceCache} options.resourceCache The {@link ResourceCache} (to avoid circular dependencies). * @param {object} options.gltf The glTF JSON. + * @param {object} options.primitive The primitive containing the Draco extension. * @param {object} options.draco The Draco extension object. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to. @@ -29,6 +32,7 @@ function GltfDracoLoader(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); const resourceCache = options.resourceCache; const gltf = options.gltf; + const primitive = options.primitive; const draco = options.draco; const gltfResource = options.gltfResource; const baseResource = options.baseResource; @@ -37,6 +41,7 @@ function GltfDracoLoader(options) { //>>includeStart('debug', pragmas.debug); Check.typeOf.func("options.resourceCache", resourceCache); Check.typeOf.object("options.gltf", gltf); + Check.typeOf.object("options.primitive", primitive); Check.typeOf.object("options.draco", draco); Check.typeOf.object("options.gltfResource", gltfResource); Check.typeOf.object("options.baseResource", baseResource); @@ -46,6 +51,7 @@ function GltfDracoLoader(options) { this._gltfResource = gltfResource; this._baseResource = baseResource; this._gltf = gltf; + this._primitive = primitive; this._draco = draco; this._cacheKey = cacheKey; this._bufferViewLoader = undefined; @@ -169,6 +175,24 @@ async function processDecode(loader, decodePromise) { } } +const SemanticToDracoAttributeType = {}; +SemanticToDracoAttributeType[VertexAttributeSemantic.POSITION] = "POSITION"; +SemanticToDracoAttributeType[VertexAttributeSemantic.NORMAL] = "NORMAL"; +SemanticToDracoAttributeType[VertexAttributeSemantic.COLOR] = "COLOR"; +SemanticToDracoAttributeType[VertexAttributeSemantic.TEXCOORD] = "TEX_COORD"; + +function getDracoAttributeType(attribute) { + for (const semantic in SemanticToDracoAttributeType) { + if (SemanticToDracoAttributeType.hasOwnProperty(semantic)) { + if (attribute.startsWith(semantic)) { + return SemanticToDracoAttributeType[semantic]; + } + } + } + + return undefined; +} + /** * Processes the resource until it becomes ready. * @@ -203,12 +227,31 @@ GltfDracoLoader.prototype.process = function (frameState) { } const draco = this._draco; + const primitive = this._primitive; const gltf = this._gltf; const bufferViews = gltf.bufferViews; const bufferViewId = draco.bufferView; const bufferView = bufferViews[bufferViewId]; const compressedAttributes = draco.attributes; + // Skip de-quantization transform if present for floating point attributes. + // They will stay quantized in memory and be dequantized in the shader. + const attributesToSkipTransform = []; + + for (const attribute in primitive.attributes) { + if (primitive.attributes.hasOwnProperty(attribute)) { + const dracoAttributeType = getDracoAttributeType(attribute); + if (defined(dracoAttributeType)) { + const accessor = gltf.accessors[primitive.attributes[attribute]]; + if (accessor.componentType === ComponentDatatype.FLOAT) { + if (!attributesToSkipTransform.includes(dracoAttributeType)) { + attributesToSkipTransform.push(dracoAttributeType); + } + } + } + } + } + const decodeOptions = { // Need to make a copy of the typed array otherwise the underlying // ArrayBuffer may be accessed on both the worker and the main thread. This @@ -218,6 +261,7 @@ GltfDracoLoader.prototype.process = function (frameState) { bufferView: bufferView, compressedAttributes: compressedAttributes, dequantizeInShader: true, + attributesToSkipTransform: attributesToSkipTransform, }; const decodePromise = DracoLoader.decodeBufferView(decodeOptions); @@ -243,6 +287,7 @@ GltfDracoLoader.prototype.unload = function () { this._bufferViewTypedArray = undefined; this._decodedData = undefined; this._gltf = undefined; + this._primitive = undefined; }; export default GltfDracoLoader; diff --git a/packages/engine/Source/Scene/GltfIndexBufferLoader.js b/packages/engine/Source/Scene/GltfIndexBufferLoader.js index 5a46f8e43535..12731eb47fa7 100644 --- a/packages/engine/Source/Scene/GltfIndexBufferLoader.js +++ b/packages/engine/Source/Scene/GltfIndexBufferLoader.js @@ -27,6 +27,7 @@ import ResourceLoaderState from "./ResourceLoaderState.js"; * @param {number} options.accessorId The accessor ID corresponding to the index buffer. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to. + * @param {object} [options.primitive] The primitive containing the Draco extension. * @param {object} [options.draco] The Draco extension object. * @param {string} [options.cacheKey] The cache key of the resource. * @param {boolean} [options.asynchronous=true] Determines if WebGL resource creation will be spread out over several frames or block until all WebGL resources are created. @@ -41,6 +42,7 @@ function GltfIndexBufferLoader(options) { const accessorId = options.accessorId; const gltfResource = options.gltfResource; const baseResource = options.baseResource; + const primitive = options.primitive; const draco = options.draco; const cacheKey = options.cacheKey; const asynchronous = defaultValue(options.asynchronous, true); @@ -68,6 +70,7 @@ function GltfIndexBufferLoader(options) { this._gltf = gltf; this._accessorId = accessorId; this._indexDatatype = indexDatatype; + this._primitive = primitive; this._draco = draco; this._cacheKey = cacheKey; this._asynchronous = asynchronous; @@ -174,6 +177,7 @@ async function loadFromDraco(indexBufferLoader) { try { const dracoLoader = resourceCache.getDracoLoader({ gltf: indexBufferLoader._gltf, + primitive: indexBufferLoader._primitive, draco: indexBufferLoader._draco, gltfResource: indexBufferLoader._gltfResource, baseResource: indexBufferLoader._baseResource, @@ -411,6 +415,7 @@ GltfIndexBufferLoader.prototype.unload = function () { this._typedArray = undefined; this._buffer = undefined; this._gltf = undefined; + this._primitive = undefined; }; export default GltfIndexBufferLoader; diff --git a/packages/engine/Source/Scene/GltfLoader.js b/packages/engine/Source/Scene/GltfLoader.js index d853d90d73dc..35cdc7585012 100644 --- a/packages/engine/Source/Scene/GltfLoader.js +++ b/packages/engine/Source/Scene/GltfLoader.js @@ -685,6 +685,7 @@ function getVertexBufferLoader( loader, accessorId, semantic, + primitive, draco, loadBuffer, loadTypedArray, @@ -700,6 +701,7 @@ function getVertexBufferLoader( baseResource: loader._baseResource, frameState: frameState, bufferViewId: bufferViewId, + primitive: primitive, draco: draco, attributeSemantic: semantic, accessorId: accessorId, @@ -714,6 +716,7 @@ function getVertexBufferLoader( function getIndexBufferLoader( loader, accessorId, + primitive, draco, loadBuffer, loadTypedArray, @@ -725,6 +728,7 @@ function getIndexBufferLoader( gltfResource: loader._gltfResource, baseResource: loader._baseResource, frameState: frameState, + primitive: primitive, draco: draco, asynchronous: loader._asynchronous, loadBuffer: loadBuffer, @@ -1154,6 +1158,7 @@ function loadAttribute( loader, accessorId, semanticInfo, + primitive, draco, loadBuffer, loadTypedArray, @@ -1188,6 +1193,7 @@ function loadAttribute( loader, accessorId, gltfSemantic, + primitive, draco, loadBuffer, loadTypedArray, @@ -1232,6 +1238,7 @@ function loadVertexAttribute( loader, accessorId, semanticInfo, + primitive, draco, hasInstances, needsPostProcessing, @@ -1278,6 +1285,7 @@ function loadVertexAttribute( loader, accessorId, semanticInfo, + primitive, draco, loadBuffer, loadTypedArray, @@ -1345,12 +1353,13 @@ function loadInstancedAttribute( const loadTypedArray = loadAsTypedArrayOnly || loadTranslationAsTypedArray; - // Don't pass in draco object since instanced attributes can't be draco compressed + // Don't pass in primitive or draco object since instanced attributes can't be draco compressed return loadAttribute( loader, accessorId, semanticInfo, undefined, + undefined, loadBuffer, loadTypedArray, frameState, @@ -1360,6 +1369,7 @@ function loadInstancedAttribute( function loadIndices( loader, accessorId, + primitive, draco, hasFeatureIds, needsPostProcessing, @@ -1403,6 +1413,7 @@ function loadIndices( const indexBufferLoader = getIndexBufferLoader( loader, accessorId, + primitive, draco, loadBuffer, loadTypedArray, @@ -1865,7 +1876,8 @@ function loadMorphTarget( ) { const morphTarget = new MorphTarget(); - // Don't pass in draco object since morph targets can't be draco compressed + // Don't pass in primitive or draco object since morph targets can't be draco compressed + const primitive = undefined; const draco = undefined; const hasInstances = false; @@ -1885,6 +1897,7 @@ function loadMorphTarget( loader, accessorId, semanticInfo, + primitive, draco, hasInstances, needsPostProcessing, @@ -1970,6 +1983,7 @@ function loadPrimitive(loader, gltfPrimitive, hasInstances, frameState) { loader, accessorId, semanticInfo, + gltfPrimitive, draco, hasInstances, needsPostProcessing, @@ -2002,6 +2016,7 @@ function loadPrimitive(loader, gltfPrimitive, hasInstances, frameState) { const indicesPlan = loadIndices( loader, indices, + gltfPrimitive, draco, hasFeatureIds, needsPostProcessing, diff --git a/packages/engine/Source/Scene/GltfVertexBufferLoader.js b/packages/engine/Source/Scene/GltfVertexBufferLoader.js index 52f77e4505e1..39c4535ea3b2 100644 --- a/packages/engine/Source/Scene/GltfVertexBufferLoader.js +++ b/packages/engine/Source/Scene/GltfVertexBufferLoader.js @@ -26,6 +26,7 @@ import ResourceLoaderState from "./ResourceLoaderState.js"; * @param {Resource} options.gltfResource The {@link Resource} containing the glTF. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to. * @param {number} [options.bufferViewId] The bufferView ID corresponding to the vertex buffer. + * @param {object} [options.primitive] The primitive containing the Draco extension. * @param {object} [options.draco] The Draco extension object. * @param {string} [options.attributeSemantic] The attribute semantic, e.g. POSITION or NORMAL. * @param {number} [options.accessorId] The accessor id. @@ -47,6 +48,7 @@ function GltfVertexBufferLoader(options) { const gltfResource = options.gltfResource; const baseResource = options.baseResource; const bufferViewId = options.bufferViewId; + const primitive = options.primitive; const draco = options.draco; const attributeSemantic = options.attributeSemantic; const accessorId = options.accessorId; @@ -67,6 +69,7 @@ function GltfVertexBufferLoader(options) { } const hasBufferViewId = defined(bufferViewId); + const hasPrimitive = defined(primitive); const hasDraco = hasDracoCompression(draco, attributeSemantic); const hasAttributeSemantic = defined(attributeSemantic); const hasAccessorId = defined(accessorId); @@ -89,7 +92,14 @@ function GltfVertexBufferLoader(options) { ); } + if (hasDraco && !hasPrimitive) { + throw new DeveloperError( + "When options.draco is defined options.primitive must also be defined.", + ); + } + if (hasDraco) { + Check.typeOf.object("options.primitive", primitive); Check.typeOf.object("options.draco", draco); Check.typeOf.string("options.attributeSemantic", attributeSemantic); Check.typeOf.number("options.accessorId", accessorId); @@ -101,6 +111,7 @@ function GltfVertexBufferLoader(options) { this._baseResource = baseResource; this._gltf = gltf; this._bufferViewId = bufferViewId; + this._primitive = primitive; this._draco = draco; this._attributeSemantic = attributeSemantic; this._accessorId = accessorId; @@ -265,6 +276,7 @@ async function loadFromDraco(vertexBufferLoader) { try { const dracoLoader = resourceCache.getDracoLoader({ gltf: vertexBufferLoader._gltf, + primitive: vertexBufferLoader._primitive, draco: vertexBufferLoader._draco, gltfResource: vertexBufferLoader._gltfResource, baseResource: vertexBufferLoader._baseResource, @@ -467,6 +479,7 @@ GltfVertexBufferLoader.prototype.unload = function () { this._typedArray = undefined; this._buffer = undefined; this._gltf = undefined; + this._primitive = undefined; }; export default GltfVertexBufferLoader; diff --git a/packages/engine/Source/Scene/ResourceCache.js b/packages/engine/Source/Scene/ResourceCache.js index 8d6c2a6afab6..886adacdac1f 100644 --- a/packages/engine/Source/Scene/ResourceCache.js +++ b/packages/engine/Source/Scene/ResourceCache.js @@ -345,6 +345,7 @@ ResourceCache.getBufferViewLoader = function (options) { * * @param {object} options Object with the following properties: * @param {object} options.gltf The glTF JSON. + * @param {object} options.primitive The primitive containing the Draco extension. * @param {object} options.draco The Draco extension object. * @param {Resource} options.gltfResource The {@link Resource} containing the glTF. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to. @@ -354,10 +355,11 @@ ResourceCache.getBufferViewLoader = function (options) { */ ResourceCache.getDracoLoader = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const { gltf, draco, gltfResource, baseResource } = options; + const { gltf, primitive, draco, gltfResource, baseResource } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); + Check.typeOf.object("options.primitive", primitive); Check.typeOf.object("options.draco", draco); Check.typeOf.object("options.gltfResource", gltfResource); Check.typeOf.object("options.baseResource", baseResource); @@ -378,6 +380,7 @@ ResourceCache.getDracoLoader = function (options) { dracoLoader = new GltfDracoLoader({ resourceCache: ResourceCache, gltf: gltf, + primitive: primitive, draco: draco, gltfResource: gltfResource, baseResource: baseResource, @@ -396,6 +399,7 @@ ResourceCache.getDracoLoader = function (options) { * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to. * @param {FrameState} options.frameState The frame state. * @param {number} [options.bufferViewId] The bufferView ID corresponding to the vertex buffer. + * @param {object} [options.primitive] The primitive containing the Draco extension. * @param {object} [options.draco] The Draco extension object. * @param {string} [options.attributeSemantic] The attribute semantic, e.g. POSITION or NORMAL. * @param {number} [options.accessorId] The accessor ID. @@ -418,6 +422,7 @@ ResourceCache.getVertexBufferLoader = function (options) { baseResource, frameState, bufferViewId, + primitive, draco, attributeSemantic, accessorId, @@ -439,6 +444,7 @@ ResourceCache.getVertexBufferLoader = function (options) { } const hasBufferViewId = defined(bufferViewId); + const hasPrimitive = defined(primitive); const hasDraco = hasDracoCompression(draco, attributeSemantic); const hasAttributeSemantic = defined(attributeSemantic); const hasAccessorId = defined(accessorId); @@ -461,6 +467,12 @@ ResourceCache.getVertexBufferLoader = function (options) { ); } + if (hasDraco && !hasPrimitive) { + throw new DeveloperError( + "When options.draco is defined options.primitive must also be defined.", + ); + } + if (hasDraco) { Check.typeOf.object("options.draco", draco); Check.typeOf.string("options.attributeSemantic", attributeSemantic); @@ -492,6 +504,7 @@ ResourceCache.getVertexBufferLoader = function (options) { gltfResource: gltfResource, baseResource: baseResource, bufferViewId: bufferViewId, + primitive: primitive, draco: draco, attributeSemantic: attributeSemantic, accessorId: accessorId, @@ -522,6 +535,7 @@ function hasDracoCompression(draco, semantic) { * @param {Resource} options.gltfResource The {@link Resource} containing the glTF. * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to. * @param {FrameState} options.frameState The frame state. + * @param {object} [options.primitive] The primitive containing the Draco extension. * @param {object} [options.draco] The Draco extension object. * @param {boolean} [options.asynchronous=true] Determines if WebGL resource creation will be spread out over several frames or block until all WebGL resources are created. * @param {boolean} [options.loadBuffer=false] Load index buffer as a GPU index buffer. @@ -537,6 +551,7 @@ ResourceCache.getIndexBufferLoader = function (options) { gltfResource, baseResource, frameState, + primitive, draco, asynchronous = true, loadBuffer = false, @@ -578,6 +593,7 @@ ResourceCache.getIndexBufferLoader = function (options) { accessorId: accessorId, gltfResource: gltfResource, baseResource: baseResource, + primitive: primitive, draco: draco, cacheKey: cacheKey, asynchronous: asynchronous, diff --git a/packages/engine/Source/Workers/decodeDraco.js b/packages/engine/Source/Workers/decodeDraco.js index 7b32c1187955..5abe00986d1c 100644 --- a/packages/engine/Source/Workers/decodeDraco.js +++ b/packages/engine/Source/Workers/decodeDraco.js @@ -295,11 +295,11 @@ function decodePointCloud(parameters) { function decodePrimitive(parameters) { const dracoDecoder = new draco.Decoder(); - // Skip all parameter types except generic - const attributesToSkip = ["POSITION", "NORMAL", "COLOR", "TEX_COORD"]; if (parameters.dequantizeInShader) { - for (let i = 0; i < attributesToSkip.length; ++i) { - dracoDecoder.SkipAttributeTransform(draco[attributesToSkip[i]]); + for (let i = 0; i < parameters.attributesToSkipTransform.length; ++i) { + dracoDecoder.SkipAttributeTransform( + draco[parameters.attributesToSkipTransform[i]], + ); } } diff --git a/packages/engine/Specs/Scene/GltfDracoLoaderSpec.js b/packages/engine/Specs/Scene/GltfDracoLoaderSpec.js index d6aada9505b2..f6d750a82113 100644 --- a/packages/engine/Specs/Scene/GltfDracoLoaderSpec.js +++ b/packages/engine/Specs/Scene/GltfDracoLoaderSpec.js @@ -122,8 +122,8 @@ describe( ], }; - const dracoExtension = - gltfDraco.meshes[0].primitives[0].extensions.KHR_draco_mesh_compression; + const primitive = gltfDraco.meshes[0].primitives[0]; + const dracoExtension = primitive.extensions.KHR_draco_mesh_compression; let scene; @@ -144,6 +144,7 @@ describe( return new GltfDracoLoader({ resourceCache: undefined, gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: gltfResource, baseResource: gltfResource, @@ -156,6 +157,20 @@ describe( return new GltfDracoLoader({ resourceCache: ResourceCache, gltf: undefined, + primitive: primitive, + draco: dracoExtension, + gltfResource: gltfResource, + baseResource: gltfResource, + }); + }).toThrowDeveloperError(); + }); + + it("throws if primitive is undefined", function () { + expect(function () { + return new GltfDracoLoader({ + resourceCache: ResourceCache, + gltf: gltfDraco, + primitive: undefined, draco: dracoExtension, gltfResource: gltfResource, baseResource: gltfResource, @@ -168,6 +183,7 @@ describe( return new GltfDracoLoader({ resourceCache: ResourceCache, gltf: gltfDraco, + primitive: primitive, draco: undefined, gltfResource: gltfResource, baseResource: gltfResource, @@ -180,6 +196,7 @@ describe( return new GltfDracoLoader({ resourceCache: ResourceCache, gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: undefined, baseResource: gltfResource, @@ -192,6 +209,7 @@ describe( return new GltfDracoLoader({ resourceCache: ResourceCache, gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: gltfResource, baseResource: undefined, @@ -208,6 +226,7 @@ describe( const dracoLoader = new GltfDracoLoader({ resourceCache: ResourceCache, gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: gltfResource, baseResource: gltfResource, @@ -232,6 +251,7 @@ describe( const dracoLoader = new GltfDracoLoader({ resourceCache: ResourceCache, gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: gltfResource, baseResource: gltfResource, @@ -266,6 +286,7 @@ describe( const dracoLoader = new GltfDracoLoader({ resourceCache: ResourceCache, gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: gltfResource, baseResource: gltfResource, @@ -300,6 +321,7 @@ describe( const dracoLoader = new GltfDracoLoader({ resourceCache: ResourceCache, gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: gltfResource, baseResource: gltfResource, @@ -334,6 +356,7 @@ describe( const dracoLoader = new GltfDracoLoader({ resourceCache: ResourceCache, gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: gltfResource, baseResource: gltfResource, @@ -362,6 +385,7 @@ describe( const dracoLoader = new GltfDracoLoader({ resourceCache: ResourceCache, gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: gltfResource, baseResource: gltfResource, diff --git a/packages/engine/Specs/Scene/GltfIndexBufferLoaderSpec.js b/packages/engine/Specs/Scene/GltfIndexBufferLoaderSpec.js index 18baacf9f881..21e2ec796f5f 100644 --- a/packages/engine/Specs/Scene/GltfIndexBufferLoaderSpec.js +++ b/packages/engine/Specs/Scene/GltfIndexBufferLoaderSpec.js @@ -144,8 +144,8 @@ describe( ], }; - const dracoExtension = - gltfDraco.meshes[0].primitives[0].extensions.KHR_draco_mesh_compression; + const primitive = gltfDraco.meshes[0].primitives[0]; + const dracoExtension = primitive.extensions.KHR_draco_mesh_compression; const gltfUncompressed = { buffers: [ @@ -378,6 +378,7 @@ describe( accessorId: 2, gltfResource: gltfResource, baseResource: gltfResource, + primitive: primitive, draco: dracoExtension, loadBuffer: true, }); @@ -570,6 +571,7 @@ describe( accessorId: 2, gltfResource: gltfResource, baseResource: gltfResource, + primitive: primitive, draco: dracoExtension, loadBuffer: true, }); @@ -604,6 +606,7 @@ describe( accessorId: 2, gltfResource: gltfResource, baseResource: gltfResource, + primitive: primitive, draco: dracoExtension, loadBuffer: true, }); @@ -678,6 +681,7 @@ describe( accessorId: 2, gltfResource: gltfResource, baseResource: gltfResource, + primitive: primitive, draco: dracoExtension, loadBuffer: true, }); @@ -738,6 +742,7 @@ describe( accessorId: 2, gltfResource: gltfResource, baseResource: gltfResource, + primitive: primitive, draco: dracoExtension, loadBuffer: true, }); diff --git a/packages/engine/Specs/Scene/GltfVertexBufferLoaderSpec.js b/packages/engine/Specs/Scene/GltfVertexBufferLoaderSpec.js index 9e6670d5f5b2..59ed582c41b2 100644 --- a/packages/engine/Specs/Scene/GltfVertexBufferLoaderSpec.js +++ b/packages/engine/Specs/Scene/GltfVertexBufferLoaderSpec.js @@ -140,8 +140,8 @@ describe( ], }; - const dracoExtension = - gltfDraco.meshes[0].primitives[0].extensions.KHR_draco_mesh_compression; + const primitive = gltfDraco.meshes[0].primitives[0]; + const dracoExtension = primitive.extensions.KHR_draco_mesh_compression; const gltfUncompressed = { buffers: [ @@ -281,6 +281,7 @@ describe( gltfResource: gltfResource, baseResource: gltfResource, bufferViewId: 0, + primitive: primitive, draco: dracoExtension, attributeSemantic: "POSITION", accessorId: 0, @@ -308,6 +309,7 @@ describe( gltf: gltfDraco, gltfResource: gltfResource, baseResource: gltfResource, + primitive: primitive, draco: dracoExtension, attributeSemantic: undefined, accessorId: 0, @@ -323,6 +325,7 @@ describe( gltf: gltfDraco, gltfResource: gltfResource, baseResource: gltfResource, + primitive: primitive, draco: dracoExtension, attributeSemantic: "POSITION", accessorId: undefined, @@ -331,6 +334,22 @@ describe( }).toThrowDeveloperError(); }); + it("throws if draco is defined and primitive is not defined", function () { + expect(function () { + return new GltfVertexBufferLoader({ + resourceCache: ResourceCache, + gltf: gltfDraco, + gltfResource: gltfResource, + baseResource: gltfResource, + primitive: undefined, + draco: dracoExtension, + attributeSemantic: "POSITION", + accessorId: 0, + loadBuffer: true, + }); + }).toThrowDeveloperError(); + }); + it("throws if both loadBuffer and loadTypedArray are false", function () { expect(function () { return new GltfVertexBufferLoader({ @@ -380,6 +399,7 @@ describe( gltf: gltfDraco, gltfResource: gltfResource, baseResource: gltfResource, + primitive: primitive, draco: dracoExtension, attributeSemantic: "POSITION", accessorId: 0, @@ -553,6 +573,7 @@ describe( gltf: gltfDraco, gltfResource: gltfResource, baseResource: gltfResource, + primitive: primitive, draco: dracoExtension, attributeSemantic: "POSITION", accessorId: 0, @@ -600,6 +621,7 @@ describe( gltf: gltfDraco, gltfResource: gltfResource, baseResource: gltfResource, + primitive: primitive, draco: dracoExtension, attributeSemantic: "NORMAL", accessorId: 1, @@ -686,6 +708,7 @@ describe( gltf: gltfDraco, gltfResource: gltfResource, baseResource: gltfResource, + primitive: primitive, draco: dracoExtension, attributeSemantic: "POSITION", accessorId: 0, @@ -747,6 +770,7 @@ describe( gltf: gltfDraco, gltfResource: gltfResource, baseResource: gltfResource, + primitive: primitive, draco: dracoExtension, attributeSemantic: "POSITION", accessorId: 0, diff --git a/packages/engine/Specs/Scene/ResourceCacheSpec.js b/packages/engine/Specs/Scene/ResourceCacheSpec.js index bf1540d4e976..28ca0b2336b1 100644 --- a/packages/engine/Specs/Scene/ResourceCacheSpec.js +++ b/packages/engine/Specs/Scene/ResourceCacheSpec.js @@ -101,8 +101,8 @@ describe("ResourceCache", function () { ], }; - const dracoExtension = - gltfDraco.meshes[0].primitives[0].extensions.KHR_draco_mesh_compression; + const primitive = gltfDraco.meshes[0].primitives[0]; + const dracoExtension = primitive.extensions.KHR_draco_mesh_compression; const gltfUncompressed = { buffers: [ @@ -589,6 +589,7 @@ describe("ResourceCache", function () { }); const dracoLoader = ResourceCache.getDracoLoader({ gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: gltfResource, baseResource: gltfResource, @@ -603,6 +604,7 @@ describe("ResourceCache", function () { expect( ResourceCache.getDracoLoader({ gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: gltfResource, baseResource: gltfResource, @@ -616,6 +618,7 @@ describe("ResourceCache", function () { expect(() => ResourceCache.getDracoLoader({ gltf: undefined, + primitive: primitive, draco: dracoExtension, gltfResource: gltfResource, baseResource: gltfResource, @@ -627,6 +630,7 @@ describe("ResourceCache", function () { expect(() => ResourceCache.getDracoLoader({ gltf: gltfDraco, + primitive: primitive, draco: undefined, gltfResource: gltfResource, baseResource: gltfResource, @@ -634,10 +638,23 @@ describe("ResourceCache", function () { ).toThrowDeveloperError(); }); + it("getDracoLoader throws if primitive is undefined", function () { + expect(() => + ResourceCache.getDracoLoader({ + gltf: gltfDraco, + primitive: undefined, + draco: dracoExtension, + gltfResource: gltfResource, + baseResource: gltfResource, + }), + ).toThrowDeveloperError(); + }); + it("getDracoLoader throws if gltfResource is undefined", function () { expect(() => ResourceCache.getDracoLoader({ gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: undefined, baseResource: gltfResource, @@ -649,6 +666,7 @@ describe("ResourceCache", function () { expect(() => ResourceCache.getDracoLoader({ gltf: gltfDraco, + primitive: primitive, draco: dracoExtension, gltfResource: gltfResource, baseResource: undefined, @@ -710,6 +728,7 @@ describe("ResourceCache", function () { gltfResource: gltfResource, baseResource: gltfResource, frameState: mockFrameState, + primitive: primitive, draco: dracoExtension, attributeSemantic: "POSITION", accessorId: 0, @@ -728,6 +747,7 @@ describe("ResourceCache", function () { gltfResource: gltfResource, baseResource: gltfResource, frameState: mockFrameState, + primitive: primitive, draco: dracoExtension, attributeSemantic: "POSITION", accessorId: 0, @@ -825,6 +845,7 @@ describe("ResourceCache", function () { baseResource: gltfResource, frameState: mockFrameState, bufferViewId: 0, + primitive: primitive, draco: dracoExtension, attributeSemantic: "POSITION", accessorId: 0, @@ -852,6 +873,7 @@ describe("ResourceCache", function () { gltfResource: gltfResource, baseResource: gltfResource, frameState: mockFrameState, + primitive: primitive, draco: dracoExtension, attributeSemantic: undefined, accessorId: 0, @@ -867,6 +889,7 @@ describe("ResourceCache", function () { gltfResource: gltfResource, baseResource: gltfResource, frameState: mockFrameState, + primitive: primitive, draco: dracoExtension, attributeSemantic: "POSITION", accessorId: undefined, @@ -875,6 +898,22 @@ describe("ResourceCache", function () { ).toThrowDeveloperError(); }); + it("getVertexBufferLoader throws if draco is defined and primitive is not defined", function () { + expect(() => + ResourceCache.getVertexBufferLoader({ + gltf: gltfDraco, + gltfResource: gltfResource, + baseResource: gltfResource, + frameState: mockFrameState, + primitive: undefined, + draco: dracoExtension, + attributeSemantic: "POSITION", + accessorId: 0, + loadBuffer: true, + }), + ).toThrowDeveloperError(); + }); + it("getVertexBufferLoader throws if both loadBuffer and loadTypedArray are false", function () { expect(() => ResourceCache.getVertexBufferLoader({ @@ -943,6 +982,7 @@ describe("ResourceCache", function () { gltfResource: gltfResource, baseResource: gltfResource, frameState: mockFrameState, + primitive: primitive, draco: dracoExtension, loadBuffer: true, }); @@ -960,6 +1000,7 @@ describe("ResourceCache", function () { gltfResource: gltfResource, baseResource: gltfResource, frameState: mockFrameState, + primitive: primitive, draco: dracoExtension, loadBuffer: true, }),