diff --git a/packages/model-viewer/src/features/scene-graph.ts b/packages/model-viewer/src/features/scene-graph.ts index 8142b26cf4..aa6092ef50 100644 --- a/packages/model-viewer/src/features/scene-graph.ts +++ b/packages/model-viewer/src/features/scene-graph.ts @@ -16,6 +16,7 @@ import {property} from 'lit/decorators.js'; import {CanvasTexture, Object3D, RepeatWrapping, SRGBColorSpace, Texture, VideoTexture} from 'three'; import {GLTFExporter, GLTFExporterOptions} from 'three/examples/jsm/exporters/GLTFExporter.js'; +import {decompress} from 'three/examples/jsm/utils/WebGLTextureUtils.js'; import ModelViewerElementBase, {$needsRender, $onModelLoad, $progressTracker, $renderer, $scene} from '../model-viewer-base.js'; import {GLTF} from '../three-components/gltf-instance/gltf-defaulted.js'; @@ -289,6 +290,13 @@ export const SceneGraphMixin = >( .register( (writer: any) => new GLTFExporterMaterialsVariantsExtension(writer)); + + exporter.setTextureUtils({ + decompress: (texture: Texture, maxTextureSize?: number) => { + return decompress(texture, maxTextureSize ?? Infinity, undefined); + } + }); + let exportTarget: Object3D; if (scene.models.length > 1) { exportTarget = new Object3D(); diff --git a/packages/model-viewer/src/test/features/scene-graph/texture-spec.ts b/packages/model-viewer/src/test/features/scene-graph/texture-spec.ts index 3ae7b5adb5..1f49399095 100644 --- a/packages/model-viewer/src/test/features/scene-graph/texture-spec.ts +++ b/packages/model-viewer/src/test/features/scene-graph/texture-spec.ts @@ -75,6 +75,37 @@ suite('scene-graph/texture', () => { .to.be.equal('image/png'); }); + test( + 'exports and re-imports a model with KTX2 compressed texture', + async () => { + const ktx2Texture = await element.createTexture(KTX2_TEXTURE_PATH); + element.model!.materials[0] + .pbrMetallicRoughness.baseColorTexture!.setTexture(ktx2Texture); + + const materialCount = element.model!.materials.length; + const dim = element.getDimensions(); + + const exported = await element.exportScene({binary: true}); + expect(exported).to.be.not.undefined; + expect(exported.size).to.be.greaterThan(500); + + // Verify scene is still intact after export (no renderer + // corruption). + expect(element.model).to.not.be.null; + expect(element.model!.materials.length).to.equal(materialCount); + const dimAfter = element.getDimensions(); + expect(dimAfter.x).to.be.closeTo(dim.x, 0.001); + expect(dimAfter.y).to.be.closeTo(dim.y, 0.001); + expect(dimAfter.z).to.be.closeTo(dim.z, 0.001); + + const url = URL.createObjectURL(exported); + element.src = url; + await waitForEvent(element, 'load'); + + expect(element.model).to.not.be.null; + expect(element.model!.materials.length).to.be.greaterThan(0); + }); + test('Verify legacy correlatedObjects are updated.', async () => { const newUUID: string|undefined = texture?.source[$threeTexture]?.uuid;