@aura3d/assets 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/AdvancedAssetCorpus.d.ts +124 -0
- package/dist/AdvancedAssetCorpus.d.ts.map +1 -0
- package/dist/AdvancedAssetCorpus.js +266 -0
- package/dist/AdvancedAssetCorpus.js.map +1 -0
- package/dist/AssetBundleCacheFixtures.d.ts +62 -0
- package/dist/AssetBundleCacheFixtures.d.ts.map +1 -0
- package/dist/AssetBundleCacheFixtures.js +222 -0
- package/dist/AssetBundleCacheFixtures.js.map +1 -0
- package/dist/AssetCache.d.ts +21 -0
- package/dist/AssetCache.d.ts.map +1 -0
- package/dist/AssetCache.js +54 -0
- package/dist/AssetCache.js.map +1 -0
- package/dist/AssetCompatibility.d.ts +54 -0
- package/dist/AssetCompatibility.d.ts.map +1 -0
- package/dist/AssetCompatibility.js +122 -0
- package/dist/AssetCompatibility.js.map +1 -0
- package/dist/AssetCorpus.d.ts +88 -0
- package/dist/AssetCorpus.d.ts.map +1 -0
- package/dist/AssetCorpus.js +215 -0
- package/dist/AssetCorpus.js.map +1 -0
- package/dist/AssetDependencyGraph.d.ts +12 -0
- package/dist/AssetDependencyGraph.d.ts.map +1 -0
- package/dist/AssetDependencyGraph.js +66 -0
- package/dist/AssetDependencyGraph.js.map +1 -0
- package/dist/AssetHandle.d.ts +26 -0
- package/dist/AssetHandle.d.ts.map +1 -0
- package/dist/AssetHandle.js +53 -0
- package/dist/AssetHandle.js.map +1 -0
- package/dist/AssetImportPreflight.d.ts +43 -0
- package/dist/AssetImportPreflight.d.ts.map +1 -0
- package/dist/AssetImportPreflight.js +117 -0
- package/dist/AssetImportPreflight.js.map +1 -0
- package/dist/AssetInspection.d.ts +183 -0
- package/dist/AssetInspection.d.ts.map +1 -0
- package/dist/AssetInspection.js +397 -0
- package/dist/AssetInspection.js.map +1 -0
- package/dist/AssetLoader.d.ts +26 -0
- package/dist/AssetLoader.d.ts.map +1 -0
- package/dist/AssetLoader.js +12 -0
- package/dist/AssetLoader.js.map +1 -0
- package/dist/AssetManager.d.ts +37 -0
- package/dist/AssetManager.d.ts.map +1 -0
- package/dist/AssetManager.js +161 -0
- package/dist/AssetManager.js.map +1 -0
- package/dist/AssetRegistry.d.ts +10 -0
- package/dist/AssetRegistry.d.ts.map +1 -0
- package/dist/AssetRegistry.js +34 -0
- package/dist/AssetRegistry.js.map +1 -0
- package/dist/AssetRenderDefaults.d.ts +13 -0
- package/dist/AssetRenderDefaults.d.ts.map +1 -0
- package/dist/AssetRenderDefaults.js +23 -0
- package/dist/AssetRenderDefaults.js.map +1 -0
- package/dist/AudioLoader.d.ts +17 -0
- package/dist/AudioLoader.d.ts.map +1 -0
- package/dist/AudioLoader.js +23 -0
- package/dist/AudioLoader.js.map +1 -0
- package/dist/BlenderExportValidation.d.ts +64 -0
- package/dist/BlenderExportValidation.d.ts.map +1 -0
- package/dist/BlenderExportValidation.js +143 -0
- package/dist/BlenderExportValidation.js.map +1 -0
- package/dist/CarConceptMaterialStability.d.ts +28 -0
- package/dist/CarConceptMaterialStability.d.ts.map +1 -0
- package/dist/CarConceptMaterialStability.js +1308 -0
- package/dist/CarConceptMaterialStability.js.map +1 -0
- package/dist/EXRLoader.d.ts +2 -0
- package/dist/EXRLoader.d.ts.map +1 -0
- package/dist/EXRLoader.js +2 -0
- package/dist/EXRLoader.js.map +1 -0
- package/dist/ExternalParityGLTFCorpus.d.ts +39 -0
- package/dist/ExternalParityGLTFCorpus.d.ts.map +1 -0
- package/dist/ExternalParityGLTFCorpus.js +32 -0
- package/dist/ExternalParityGLTFCorpus.js.map +1 -0
- package/dist/GLTFAnimationRuntime.d.ts +243 -0
- package/dist/GLTFAnimationRuntime.d.ts.map +1 -0
- package/dist/GLTFAnimationRuntime.js +954 -0
- package/dist/GLTFAnimationRuntime.js.map +1 -0
- package/dist/GLTFCompressionDecoders.d.ts +42 -0
- package/dist/GLTFCompressionDecoders.d.ts.map +1 -0
- package/dist/GLTFCompressionDecoders.js +99 -0
- package/dist/GLTFCompressionDecoders.js.map +1 -0
- package/dist/GLTFExtensionSupport.d.ts +33 -0
- package/dist/GLTFExtensionSupport.d.ts.map +1 -0
- package/dist/GLTFExtensionSupport.js +85 -0
- package/dist/GLTFExtensionSupport.js.map +1 -0
- package/dist/GLTFLoader.d.ts +361 -0
- package/dist/GLTFLoader.d.ts.map +1 -0
- package/dist/GLTFLoader.js +2735 -0
- package/dist/GLTFLoader.js.map +1 -0
- package/dist/GLTFRenderResources.d.ts +162 -0
- package/dist/GLTFRenderResources.d.ts.map +1 -0
- package/dist/GLTFRenderResources.js +1684 -0
- package/dist/GLTFRenderResources.js.map +1 -0
- package/dist/HDRLoader.d.ts +2 -0
- package/dist/HDRLoader.d.ts.map +1 -0
- package/dist/HDRLoader.js +2 -0
- package/dist/HDRLoader.js.map +1 -0
- package/dist/ImageLoader.d.ts +15 -0
- package/dist/ImageLoader.d.ts.map +1 -0
- package/dist/ImageLoader.js +36 -0
- package/dist/ImageLoader.js.map +1 -0
- package/dist/ImportPipeline.d.ts +39 -0
- package/dist/ImportPipeline.d.ts.map +1 -0
- package/dist/ImportPipeline.js +105 -0
- package/dist/ImportPipeline.js.map +1 -0
- package/dist/KTX2BasisTextureTranscoder.d.ts +9 -0
- package/dist/KTX2BasisTextureTranscoder.d.ts.map +1 -0
- package/dist/KTX2BasisTextureTranscoder.js +178 -0
- package/dist/KTX2BasisTextureTranscoder.js.map +1 -0
- package/dist/LoadContext.d.ts +20 -0
- package/dist/LoadContext.d.ts.map +1 -0
- package/dist/LoadContext.js +42 -0
- package/dist/LoadContext.js.map +1 -0
- package/dist/MaterialLoader.d.ts +17 -0
- package/dist/MaterialLoader.d.ts.map +1 -0
- package/dist/MaterialLoader.js +138 -0
- package/dist/MaterialLoader.js.map +1 -0
- package/dist/MeshOptimization.d.ts +20 -0
- package/dist/MeshOptimization.d.ts.map +1 -0
- package/dist/MeshOptimization.js +65 -0
- package/dist/MeshOptimization.js.map +1 -0
- package/dist/OBJLoader.d.ts +13 -0
- package/dist/OBJLoader.d.ts.map +1 -0
- package/dist/OBJLoader.js +492 -0
- package/dist/OBJLoader.js.map +1 -0
- package/dist/SceneAnalysisFixtures.d.ts +100 -0
- package/dist/SceneAnalysisFixtures.d.ts.map +1 -0
- package/dist/SceneAnalysisFixtures.js +331 -0
- package/dist/SceneAnalysisFixtures.js.map +1 -0
- package/dist/SceneLoader.d.ts +27 -0
- package/dist/SceneLoader.d.ts.map +1 -0
- package/dist/SceneLoader.js +40 -0
- package/dist/SceneLoader.js.map +1 -0
- package/dist/ShaderLoader.d.ts +12 -0
- package/dist/ShaderLoader.d.ts.map +1 -0
- package/dist/ShaderLoader.js +18 -0
- package/dist/ShaderLoader.js.map +1 -0
- package/dist/TextureLoader.d.ts +16 -0
- package/dist/TextureLoader.d.ts.map +1 -0
- package/dist/TextureLoader.js +17 -0
- package/dist/TextureLoader.js.map +1 -0
- package/dist/TexturePipeline.d.ts +24 -0
- package/dist/TexturePipeline.d.ts.map +1 -0
- package/dist/TexturePipeline.js +64 -0
- package/dist/TexturePipeline.js.map +1 -0
- package/dist/TextureStreaming.d.ts +10 -0
- package/dist/TextureStreaming.d.ts.map +1 -0
- package/dist/TextureStreaming.js +11 -0
- package/dist/TextureStreaming.js.map +1 -0
- package/dist/WorkerAssetJobs.d.ts +18 -0
- package/dist/WorkerAssetJobs.d.ts.map +1 -0
- package/dist/WorkerAssetJobs.js +37 -0
- package/dist/WorkerAssetJobs.js.map +1 -0
- package/dist/advanced-gallery/index.d.ts +3 -0
- package/dist/advanced-gallery/index.d.ts.map +1 -0
- package/dist/advanced-gallery/index.js +2 -0
- package/dist/advanced-gallery/index.js.map +1 -0
- package/dist/asset-corpus/GLTFSceneLoader.d.ts +3 -0
- package/dist/asset-corpus/GLTFSceneLoader.d.ts.map +1 -0
- package/dist/asset-corpus/GLTFSceneLoader.js +2 -0
- package/dist/asset-corpus/GLTFSceneLoader.js.map +1 -0
- package/dist/asset-corpus/ProductionAssetCorpus.d.ts +89 -0
- package/dist/asset-corpus/ProductionAssetCorpus.d.ts.map +1 -0
- package/dist/asset-corpus/ProductionAssetCorpus.js +116 -0
- package/dist/asset-corpus/ProductionAssetCorpus.js.map +1 -0
- package/dist/asset-corpus/ProductionAssetPipeline.d.ts +3 -0
- package/dist/asset-corpus/ProductionAssetPipeline.d.ts.map +1 -0
- package/dist/asset-corpus/ProductionAssetPipeline.js +3 -0
- package/dist/asset-corpus/ProductionAssetPipeline.js.map +1 -0
- package/dist/asset-corpus/ProductionGLTFRenderPipeline.d.ts +65 -0
- package/dist/asset-corpus/ProductionGLTFRenderPipeline.d.ts.map +1 -0
- package/dist/asset-corpus/ProductionGLTFRenderPipeline.js +110 -0
- package/dist/asset-corpus/ProductionGLTFRenderPipeline.js.map +1 -0
- package/dist/asset-corpus/ProductionHDRTextureLoader.d.ts +8 -0
- package/dist/asset-corpus/ProductionHDRTextureLoader.d.ts.map +1 -0
- package/dist/asset-corpus/ProductionHDRTextureLoader.js +2 -0
- package/dist/asset-corpus/ProductionHDRTextureLoader.js.map +1 -0
- package/dist/asset-corpus/ProductionKTX2TextureLoader.d.ts +7 -0
- package/dist/asset-corpus/ProductionKTX2TextureLoader.d.ts.map +1 -0
- package/dist/asset-corpus/ProductionKTX2TextureLoader.js +2 -0
- package/dist/asset-corpus/ProductionKTX2TextureLoader.js.map +1 -0
- package/dist/asset-corpus/ProductionTextureLoader.d.ts +7 -0
- package/dist/asset-corpus/ProductionTextureLoader.d.ts.map +1 -0
- package/dist/asset-corpus/ProductionTextureLoader.js +2 -0
- package/dist/asset-corpus/ProductionTextureLoader.js.map +1 -0
- package/dist/asset-corpus/index.d.ts +10 -0
- package/dist/asset-corpus/index.d.ts.map +1 -0
- package/dist/asset-corpus/index.js +8 -0
- package/dist/asset-corpus/index.js.map +1 -0
- package/dist/browser-index.d.ts +48 -0
- package/dist/browser-index.d.ts.map +1 -0
- package/dist/browser-index.js +26 -0
- package/dist/browser-index.js.map +1 -0
- package/dist/createRenderableScene.d.ts +23 -0
- package/dist/createRenderableScene.d.ts.map +1 -0
- package/dist/createRenderableScene.js +94 -0
- package/dist/createRenderableScene.js.map +1 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/loadRenderableAsset.d.ts +16 -0
- package/dist/loadRenderableAsset.d.ts.map +1 -0
- package/dist/loadRenderableAsset.js +50 -0
- package/dist/loadRenderableAsset.js.map +1 -0
- package/dist/loaders/CubeTextureLoader.d.ts +4 -0
- package/dist/loaders/CubeTextureLoader.d.ts.map +1 -0
- package/dist/loaders/CubeTextureLoader.js +9 -0
- package/dist/loaders/CubeTextureLoader.js.map +1 -0
- package/dist/loaders/EXRLoader.d.ts +4 -0
- package/dist/loaders/EXRLoader.d.ts.map +1 -0
- package/dist/loaders/EXRLoader.js +10 -0
- package/dist/loaders/EXRLoader.js.map +1 -0
- package/dist/loaders/HDRLoader.d.ts +4 -0
- package/dist/loaders/HDRLoader.d.ts.map +1 -0
- package/dist/loaders/HDRLoader.js +7 -0
- package/dist/loaders/HDRLoader.js.map +1 -0
- package/dist/loaders/KTX2Loader.d.ts +4 -0
- package/dist/loaders/KTX2Loader.d.ts.map +1 -0
- package/dist/loaders/KTX2Loader.js +7 -0
- package/dist/loaders/KTX2Loader.js.map +1 -0
- package/dist/loaders/LoaderDiagnostics.d.ts +18 -0
- package/dist/loaders/LoaderDiagnostics.d.ts.map +1 -0
- package/dist/loaders/LoaderDiagnostics.js +18 -0
- package/dist/loaders/LoaderDiagnostics.js.map +1 -0
- package/dist/loaders/MTLLoader.d.ts +10 -0
- package/dist/loaders/MTLLoader.d.ts.map +1 -0
- package/dist/loaders/MTLLoader.js +14 -0
- package/dist/loaders/MTLLoader.js.map +1 -0
- package/dist/loaders/OBJLoader.d.ts +12 -0
- package/dist/loaders/OBJLoader.d.ts.map +1 -0
- package/dist/loaders/OBJLoader.js +16 -0
- package/dist/loaders/OBJLoader.js.map +1 -0
- package/dist/loaders/TextureLoader.d.ts +6 -0
- package/dist/loaders/TextureLoader.d.ts.map +1 -0
- package/dist/loaders/TextureLoader.js +11 -0
- package/dist/loaders/TextureLoader.js.map +1 -0
- package/dist/loaders/ThreeCompatGLTFLoader.d.ts +10 -0
- package/dist/loaders/ThreeCompatGLTFLoader.d.ts.map +1 -0
- package/dist/loaders/ThreeCompatGLTFLoader.js +13 -0
- package/dist/loaders/ThreeCompatGLTFLoader.js.map +1 -0
- package/dist/loaders/index.d.ts +15 -0
- package/dist/loaders/index.d.ts.map +1 -0
- package/dist/loaders/index.js +10 -0
- package/dist/loaders/index.js.map +1 -0
- package/dist/threejs-compatibility/ThreeCompatAssetProvenance.d.ts +34 -0
- package/dist/threejs-compatibility/ThreeCompatAssetProvenance.d.ts.map +1 -0
- package/dist/threejs-compatibility/ThreeCompatAssetProvenance.js +16 -0
- package/dist/threejs-compatibility/ThreeCompatAssetProvenance.js.map +1 -0
- package/dist/threejs-compatibility/ThreeCompatAssetRegistry.d.ts +29 -0
- package/dist/threejs-compatibility/ThreeCompatAssetRegistry.d.ts.map +1 -0
- package/dist/threejs-compatibility/ThreeCompatAssetRegistry.js +33 -0
- package/dist/threejs-compatibility/ThreeCompatAssetRegistry.js.map +1 -0
- package/dist/threejs-example-parity/index.d.ts +20 -0
- package/dist/threejs-example-parity/index.d.ts.map +1 -0
- package/dist/threejs-example-parity/index.js +218 -0
- package/dist/threejs-example-parity/index.js.map +1 -0
- package/package.json +23 -0
- package/src/AdvancedAssetCorpus.ts +454 -0
- package/src/AssetBundleCacheFixtures.ts +290 -0
- package/src/AssetCache.ts +76 -0
- package/src/AssetCompatibility.ts +224 -0
- package/src/AssetCorpus.ts +329 -0
- package/src/AssetDependencyGraph.ts +83 -0
- package/src/AssetHandle.ts +74 -0
- package/src/AssetImportPreflight.ts +179 -0
- package/src/AssetInspection.ts +706 -0
- package/src/AssetLoader.ts +36 -0
- package/src/AssetManager.ts +211 -0
- package/src/AssetRegistry.ts +44 -0
- package/src/AssetRenderDefaults.ts +36 -0
- package/src/AudioLoader.ts +41 -0
- package/src/BlenderExportValidation.ts +227 -0
- package/src/CarConceptMaterialStability.ts +1405 -0
- package/src/EXRLoader.ts +1 -0
- package/src/ExternalParityGLTFCorpus.ts +65 -0
- package/src/GLTFAnimationRuntime.ts +1221 -0
- package/src/GLTFCompressionDecoders.ts +190 -0
- package/src/GLTFExtensionSupport.ts +138 -0
- package/src/GLTFLoader.ts +4001 -0
- package/src/GLTFRenderResources.ts +2105 -0
- package/src/HDRLoader.ts +1 -0
- package/src/ImageLoader.ts +52 -0
- package/src/ImportPipeline.ts +148 -0
- package/src/KTX2BasisTextureTranscoder.ts +224 -0
- package/src/LoadContext.ts +60 -0
- package/src/MaterialLoader.ts +166 -0
- package/src/MeshOptimization.ts +93 -0
- package/src/OBJLoader.ts +551 -0
- package/src/SceneAnalysisFixtures.ts +438 -0
- package/src/SceneLoader.ts +62 -0
- package/src/ShaderLoader.ts +30 -0
- package/src/TextureLoader.ts +30 -0
- package/src/TexturePipeline.ts +96 -0
- package/src/TextureStreaming.ts +20 -0
- package/src/WorkerAssetJobs.ts +56 -0
- package/src/advanced-gallery/index.ts +18 -0
- package/src/asset-corpus/GLTFSceneLoader.ts +9 -0
- package/src/asset-corpus/ProductionAssetCorpus.ts +230 -0
- package/src/asset-corpus/ProductionAssetPipeline.ts +5 -0
- package/src/asset-corpus/ProductionGLTFRenderPipeline.ts +182 -0
- package/src/asset-corpus/ProductionHDRTextureLoader.ts +2 -0
- package/src/asset-corpus/ProductionKTX2TextureLoader.ts +2 -0
- package/src/asset-corpus/ProductionTextureLoader.ts +2 -0
- package/src/asset-corpus/index.ts +29 -0
- package/src/browser-index.ts +224 -0
- package/src/createRenderableScene.ts +128 -0
- package/src/index.ts +317 -0
- package/src/loadRenderableAsset.ts +67 -0
- package/src/loaders/CubeTextureLoader.ts +8 -0
- package/src/loaders/EXRLoader.ts +10 -0
- package/src/loaders/HDRLoader.ts +7 -0
- package/src/loaders/KTX2Loader.ts +7 -0
- package/src/loaders/LoaderDiagnostics.ts +36 -0
- package/src/loaders/MTLLoader.ts +20 -0
- package/src/loaders/OBJLoader.ts +24 -0
- package/src/loaders/TextureLoader.ts +14 -0
- package/src/loaders/ThreeCompatGLTFLoader.ts +19 -0
- package/src/loaders/index.ts +14 -0
- package/src/threejs-compatibility/ThreeCompatAssetProvenance.ts +51 -0
- package/src/threejs-compatibility/ThreeCompatAssetRegistry.ts +61 -0
- package/src/threejs-example-parity/index.ts +262 -0
- package/tests/assets.test.ts +311 -0
- package/tsconfig.json +7 -0
|
@@ -0,0 +1,1684 @@
|
|
|
1
|
+
import { Geometry, IndexBuffer, InstancedPBRMaterial, InstancedUnlitMaterial, Material, PBRMaterial, Sampler, SkinnedLitMaterial, Texture, TextureBinding, TexturedPBRMaterial, TexturedUnlitMaterial, UnlitMaterial, VertexBuffer, createExternalParityEnvironmentLighting, computePerspectiveCameraFrame, computeSkinnedMorphTargetEnvelopeBounds, VertexFormat, DEFAULT_PBR_ENVIRONMENT_INTENSITY, isTexturedPbrTextureSlotShaderActive, DEFAULT_TEXTURED_PBR_SHADER_NAME } from "@aura3d/rendering";
|
|
2
|
+
import { Bounds3 as SceneBounds3, multiplyMat4 } from "@aura3d/scene";
|
|
3
|
+
import { parseGLTFRuntimeMaterialKey } from "./GLTFLoader.js";
|
|
4
|
+
import { transcodeKTX2BasisTexture } from "./KTX2BasisTextureTranscoder.js";
|
|
5
|
+
const GLTF_DIAGNOSTIC_TEXTURE_BINDINGS = [
|
|
6
|
+
["baseColor", "u_baseColorTexture", "u_baseColorTextureEnabled"],
|
|
7
|
+
["normal", "u_normalTexture", "u_normalTextureEnabled"],
|
|
8
|
+
["metallicRoughness", "u_metallicRoughnessTexture", "u_metallicRoughnessTextureEnabled"],
|
|
9
|
+
["occlusion", "u_occlusionTexture", "u_occlusionTextureEnabled"],
|
|
10
|
+
["emissive", "u_emissiveTexture", "u_emissiveTextureEnabled"],
|
|
11
|
+
["clearcoat", "u_clearcoatTexture", "u_clearcoatTextureEnabled"],
|
|
12
|
+
["clearcoatRoughness", "u_clearcoatRoughnessTexture", "u_clearcoatRoughnessTextureEnabled"],
|
|
13
|
+
["clearcoatNormal", "u_clearcoatNormalTexture", "u_clearcoatNormalTextureEnabled"],
|
|
14
|
+
["transmission", "u_transmissionTexture", "u_transmissionTextureEnabled"],
|
|
15
|
+
["diffuseTransmission", "u_diffuseTransmissionTexture", "u_diffuseTransmissionTextureEnabled"],
|
|
16
|
+
["diffuseTransmissionColor", "u_diffuseTransmissionColorTexture", "u_diffuseTransmissionColorTextureEnabled"],
|
|
17
|
+
["volumeThickness", "u_volumeThicknessTexture", "u_volumeThicknessTextureEnabled"],
|
|
18
|
+
["specular", "u_specularTexture", "u_specularTextureEnabled"],
|
|
19
|
+
["specularColor", "u_specularColorTexture", "u_specularColorTextureEnabled"],
|
|
20
|
+
["sheenColor", "u_sheenColorTexture", "u_sheenColorTextureEnabled"],
|
|
21
|
+
["sheenRoughness", "u_sheenRoughnessTexture", "u_sheenRoughnessTextureEnabled"],
|
|
22
|
+
["anisotropy", "u_anisotropyTexture", "u_anisotropyTextureEnabled"],
|
|
23
|
+
["iridescence", "u_iridescenceTexture", "u_iridescenceTextureEnabled"],
|
|
24
|
+
["iridescenceThickness", "u_iridescenceThicknessTexture", "u_iridescenceThicknessTextureEnabled"]
|
|
25
|
+
];
|
|
26
|
+
export const DEFAULT_GLTF_RENDER_ENVIRONMENT_LIGHTING = {
|
|
27
|
+
color: [0.72, 0.74, 0.78],
|
|
28
|
+
intensity: 0.38,
|
|
29
|
+
proceduralMap: {
|
|
30
|
+
skyColor: [0.62, 0.72, 0.9],
|
|
31
|
+
horizonColor: [0.9, 0.82, 0.66],
|
|
32
|
+
groundColor: [0.16, 0.16, 0.18],
|
|
33
|
+
specularColor: [1, 0.92, 0.78],
|
|
34
|
+
intensity: 0.42,
|
|
35
|
+
specularIntensity: 0.7
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
export const DEFAULT_GLTF_STUDIO_PREVIEW_ENVIRONMENT_LIGHTING = {
|
|
39
|
+
color: [0.82, 0.84, 0.88],
|
|
40
|
+
intensity: 0.5,
|
|
41
|
+
proceduralMap: {
|
|
42
|
+
skyColor: [0.72, 0.82, 0.95],
|
|
43
|
+
horizonColor: [1, 0.9, 0.72],
|
|
44
|
+
groundColor: [0.12, 0.13, 0.15],
|
|
45
|
+
specularColor: [1, 0.95, 0.82],
|
|
46
|
+
intensity: 0.62,
|
|
47
|
+
specularIntensity: 1.15
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
export function createDefaultGLTFHdrStudioPreviewEnvironmentLighting() {
|
|
51
|
+
return createExternalParityEnvironmentLighting("studio").lighting;
|
|
52
|
+
}
|
|
53
|
+
export const DEFAULT_GLTF_STUDIO_PREVIEW_POSTPROCESS = {
|
|
54
|
+
targetFormat: "rgba8",
|
|
55
|
+
toneMapping: {
|
|
56
|
+
exposure: 1.18,
|
|
57
|
+
operator: "filmic",
|
|
58
|
+
inputColorSpace: "linear",
|
|
59
|
+
outputColorSpace: "srgb"
|
|
60
|
+
},
|
|
61
|
+
colorGrade: {
|
|
62
|
+
contrast: 1.08,
|
|
63
|
+
saturation: 1.06,
|
|
64
|
+
vibrance: 0.1,
|
|
65
|
+
vignette: 0.18,
|
|
66
|
+
sharpening: 0.28
|
|
67
|
+
},
|
|
68
|
+
bloom: {
|
|
69
|
+
threshold: 0.82,
|
|
70
|
+
intensity: 0.08,
|
|
71
|
+
radius: 1
|
|
72
|
+
},
|
|
73
|
+
fxaa: {
|
|
74
|
+
edgeThreshold: 0.08,
|
|
75
|
+
subpixelBlend: 0.55
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
export const DEFAULT_GLTF_HDR_STUDIO_PREVIEW_POSTPROCESS = {
|
|
79
|
+
targetFormat: "rgba16f",
|
|
80
|
+
toneMapping: {
|
|
81
|
+
exposure: 1.12,
|
|
82
|
+
whitePoint: 1.25,
|
|
83
|
+
operator: "filmic",
|
|
84
|
+
inputColorSpace: "linear",
|
|
85
|
+
outputColorSpace: "srgb"
|
|
86
|
+
},
|
|
87
|
+
colorGrade: {
|
|
88
|
+
contrast: 1.1,
|
|
89
|
+
saturation: 1.06,
|
|
90
|
+
vibrance: 0.12,
|
|
91
|
+
vignette: 0.16,
|
|
92
|
+
sharpening: 0.32
|
|
93
|
+
},
|
|
94
|
+
bloom: {
|
|
95
|
+
threshold: 0.9,
|
|
96
|
+
intensity: 0.12,
|
|
97
|
+
radius: 1
|
|
98
|
+
},
|
|
99
|
+
fxaa: {
|
|
100
|
+
edgeThreshold: 0.08,
|
|
101
|
+
subpixelBlend: 0.55
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
export const DEFAULT_GLTF_STUDIO_PREVIEW_FRAME = {
|
|
105
|
+
paddingRatio: 0.16,
|
|
106
|
+
yawRadians: -0.38,
|
|
107
|
+
pitchRadians: -0.16,
|
|
108
|
+
nearPadding: 0.18,
|
|
109
|
+
farPadding: 2.4
|
|
110
|
+
};
|
|
111
|
+
export async function createGLTFRenderResources(asset, options = {}) {
|
|
112
|
+
const geometryLibrary = new Map();
|
|
113
|
+
const materialLibrary = new Map();
|
|
114
|
+
const morphTargetLibrary = new Map();
|
|
115
|
+
const textureLibrary = new Map();
|
|
116
|
+
const textureByImage = new Map();
|
|
117
|
+
const scene = asset.createScene({
|
|
118
|
+
...(options.materialVariant ? { materialVariant: options.materialVariant } : {}),
|
|
119
|
+
...(options.sceneIndex !== undefined ? { sceneIndex: options.sceneIndex } : {}),
|
|
120
|
+
...(options.sceneName !== undefined ? { sceneName: options.sceneName } : {})
|
|
121
|
+
});
|
|
122
|
+
const getTexture = async (info, colorSpace) => {
|
|
123
|
+
const textureAsset = asset.textures[info.texture];
|
|
124
|
+
const image = asset.images[info.image];
|
|
125
|
+
if (!textureAsset || !image) {
|
|
126
|
+
throw new Error(`glTF material texture ${info.texture} references missing image ${info.image}`);
|
|
127
|
+
}
|
|
128
|
+
const cacheKey = textureCacheKey(info.image, colorSpace);
|
|
129
|
+
const existing = textureByImage.get(cacheKey);
|
|
130
|
+
if (existing) {
|
|
131
|
+
const texture = await existing;
|
|
132
|
+
setTextureLibraryEntry(textureLibrary, textureAsset.name, colorSpace, texture);
|
|
133
|
+
return texture;
|
|
134
|
+
}
|
|
135
|
+
const decoder = options.imageDecoder ?? ((sourceImage, imageIndex, sourceAsset) => decodeImageInBrowser(sourceImage, imageIndex, sourceAsset, options));
|
|
136
|
+
const texturePromise = (async () => {
|
|
137
|
+
const decoded = await decoder(image, info.image, asset);
|
|
138
|
+
return new Texture({
|
|
139
|
+
width: decoded.width,
|
|
140
|
+
height: decoded.height,
|
|
141
|
+
...(decoded.format ? { format: decoded.format } : {}),
|
|
142
|
+
colorSpace,
|
|
143
|
+
label: textureAsset.name,
|
|
144
|
+
...(decoded.mipLevels ? { mipLevels: decoded.mipLevels } : decoded.data ? { data: decoded.data } : { source: decoded.source }),
|
|
145
|
+
...(decoded.fallbackData ? { fallbackData: decoded.fallbackData } : {}),
|
|
146
|
+
...(decoded.fallbackMipLevels ? { fallbackMipLevels: decoded.fallbackMipLevels } : {})
|
|
147
|
+
});
|
|
148
|
+
})();
|
|
149
|
+
textureByImage.set(cacheKey, texturePromise);
|
|
150
|
+
try {
|
|
151
|
+
const texture = await texturePromise;
|
|
152
|
+
setTextureLibraryEntry(textureLibrary, textureAsset.name, colorSpace, texture);
|
|
153
|
+
return texture;
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
textureByImage.delete(cacheKey);
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
try {
|
|
161
|
+
for (const mesh of asset.meshes) {
|
|
162
|
+
geometryLibrary.set(mesh.name, createGeometry(mesh, materialForMesh(asset, mesh, options.materialVariant)));
|
|
163
|
+
if (mesh.morphTargets.length > 0) {
|
|
164
|
+
morphTargetLibrary.set(mesh.name, mesh.morphTargets.map((target) => ({
|
|
165
|
+
positions: target.positions,
|
|
166
|
+
normals: target.normals,
|
|
167
|
+
tangents: target.tangents
|
|
168
|
+
})));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const runtimeMaterialContracts = new Map();
|
|
172
|
+
for (const { renderable } of scene.collectRenderables()) {
|
|
173
|
+
const parsed = parseGLTFRuntimeMaterialKey(renderable.material);
|
|
174
|
+
runtimeMaterialContracts.set(renderable.material, {
|
|
175
|
+
material: parsed.material,
|
|
176
|
+
contract: {
|
|
177
|
+
...parsed.contract,
|
|
178
|
+
...(renderable.skinning ? { skinned: true } : {}),
|
|
179
|
+
...(renderable.instanceTransforms ? { instanced: true } : {})
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
const materialTasks = [];
|
|
184
|
+
for (const material of asset.materials) {
|
|
185
|
+
const runtimeKeys = [...runtimeMaterialContracts.entries()].filter(([, runtime]) => runtime.material === material.name);
|
|
186
|
+
if (runtimeKeys.length === 0) {
|
|
187
|
+
materialTasks.push(createMaterial(asset, material, getTexture, {}, options.materialRenderStateOverrides).then((runtimeMaterial) => {
|
|
188
|
+
materialLibrary.set(material.name, runtimeMaterial);
|
|
189
|
+
}));
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
for (const [key, runtime] of runtimeKeys) {
|
|
193
|
+
materialTasks.push(createMaterial(asset, material, getTexture, runtime.contract, options.materialRenderStateOverrides).then((runtimeMaterial) => {
|
|
194
|
+
materialLibrary.set(key, runtimeMaterial);
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
await Promise.all(materialTasks);
|
|
199
|
+
for (const mesh of asset.meshes) {
|
|
200
|
+
for (const [key, runtime] of runtimeMaterialContracts) {
|
|
201
|
+
if (runtime.material === mesh.material && !materialLibrary.has(key)) {
|
|
202
|
+
materialLibrary.set(key, createDefaultGLTFMaterial(mesh, runtime.contract));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (!materialLibrary.has(mesh.material)) {
|
|
206
|
+
materialLibrary.set(mesh.material, createDefaultGLTFMaterial(mesh));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
disposeGLTFRenderResourceMaps(geometryLibrary, textureLibrary);
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
const bounds = computeGLTFRenderResourceBounds(scene, geometryLibrary, morphTargetLibrary);
|
|
215
|
+
const renderableBindings = createGLTFRenderableBindings(asset, scene);
|
|
216
|
+
const materialFidelityDiagnostics = createGLTFMaterialFidelityDiagnostics(asset, renderableBindings, options.materialVariant);
|
|
217
|
+
return {
|
|
218
|
+
scene,
|
|
219
|
+
geometryLibrary,
|
|
220
|
+
materialLibrary,
|
|
221
|
+
renderableBindings,
|
|
222
|
+
materialFidelityDiagnostics,
|
|
223
|
+
morphTargetLibrary,
|
|
224
|
+
textureLibrary,
|
|
225
|
+
bounds,
|
|
226
|
+
collectMaterialOverrideTargets: (query = {}) => collectGLTFMaterialOverrideTargets(renderableBindings, materialLibrary, query),
|
|
227
|
+
createCameraFrame: (viewport, frameOptions = {}) => computePerspectiveCameraFrame(bounds, viewport, defaultGLTFCameraFrameOptions(bounds, frameOptions)),
|
|
228
|
+
toRenderSource: (sourceOptions = {}) => createGLTFRenderSource({
|
|
229
|
+
scene,
|
|
230
|
+
geometryLibrary,
|
|
231
|
+
materialLibrary,
|
|
232
|
+
morphTargetLibrary,
|
|
233
|
+
bounds
|
|
234
|
+
}, sourceOptions),
|
|
235
|
+
toRendererInput: (viewport, inputOptions = {}) => {
|
|
236
|
+
const { frame: frameOptions, ...sourceOptions } = inputOptions;
|
|
237
|
+
const qualityPreset = sourceOptions.qualityPreset ?? "studio-preview";
|
|
238
|
+
const frame = computePerspectiveCameraFrame(bounds, viewport, defaultGLTFCameraFrameOptions(bounds, frameOptions));
|
|
239
|
+
return {
|
|
240
|
+
source: createGLTFRenderSource({
|
|
241
|
+
scene,
|
|
242
|
+
geometryLibrary,
|
|
243
|
+
materialLibrary,
|
|
244
|
+
morphTargetLibrary,
|
|
245
|
+
bounds
|
|
246
|
+
}, {
|
|
247
|
+
...sourceOptions,
|
|
248
|
+
qualityPreset,
|
|
249
|
+
cameraPosition: sourceOptions.cameraPosition ?? frame.cameraPosition,
|
|
250
|
+
cameraPolicy: sourceOptions.cameraPolicy ?? "require"
|
|
251
|
+
}),
|
|
252
|
+
camera: {
|
|
253
|
+
viewProjectionMatrix: frame.viewProjectionMatrix,
|
|
254
|
+
viewMatrix: frame.viewMatrix,
|
|
255
|
+
projectionMatrix: frame.projectionMatrix
|
|
256
|
+
},
|
|
257
|
+
frame,
|
|
258
|
+
bounds
|
|
259
|
+
};
|
|
260
|
+
},
|
|
261
|
+
dispose: () => disposeGLTFRenderResourceMaps(geometryLibrary, textureLibrary)
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function createGLTFRenderableBindings(asset, scene) {
|
|
265
|
+
const meshByGeometry = new Map(asset.meshes.map((mesh) => [mesh.name, mesh]));
|
|
266
|
+
return scene.collectRenderables().map(({ node, renderable }) => {
|
|
267
|
+
const mesh = meshByGeometry.get(renderable.geometry);
|
|
268
|
+
const materialKey = renderable.material;
|
|
269
|
+
const parsedMaterial = parseGLTFRuntimeMaterialKey(materialKey);
|
|
270
|
+
return {
|
|
271
|
+
nodeName: node.name,
|
|
272
|
+
geometryKey: renderable.geometry,
|
|
273
|
+
materialKey,
|
|
274
|
+
sourceMaterialName: parsedMaterial.material,
|
|
275
|
+
...(mesh?.materialIndex !== undefined ? { sourceMaterialIndex: mesh.materialIndex } : {}),
|
|
276
|
+
...(mesh?.sourceMeshIndex !== undefined ? { sourceMeshIndex: mesh.sourceMeshIndex } : {}),
|
|
277
|
+
...(mesh?.primitiveIndex !== undefined ? { primitiveIndex: mesh.primitiveIndex } : {}),
|
|
278
|
+
materialVariants: mesh?.materialVariants ?? [],
|
|
279
|
+
skinned: Boolean(renderable.skinning),
|
|
280
|
+
instanced: Boolean(renderable.instanceTransforms)
|
|
281
|
+
};
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
function createGLTFMaterialFidelityDiagnostics(asset, bindings, materialVariant) {
|
|
285
|
+
const diagnostics = [];
|
|
286
|
+
const meshByGeometry = new Map(asset.meshes.map((mesh) => [mesh.name, mesh]));
|
|
287
|
+
for (const binding of bindings) {
|
|
288
|
+
const mesh = meshByGeometry.get(binding.geometryKey);
|
|
289
|
+
if (!mesh)
|
|
290
|
+
continue;
|
|
291
|
+
const material = materialForMesh(asset, mesh, materialVariant);
|
|
292
|
+
if (!material)
|
|
293
|
+
continue;
|
|
294
|
+
for (const { slot, info, tangentSpace } of materialTextureInfosBySlot(material)) {
|
|
295
|
+
const renderedTexCoord = renderTexCoord(info.texCoord);
|
|
296
|
+
if (info.texCoord > 1) {
|
|
297
|
+
diagnostics.push({
|
|
298
|
+
issue: "unsupported-texcoord-set",
|
|
299
|
+
slot,
|
|
300
|
+
texCoord: info.texCoord,
|
|
301
|
+
renderedTexCoord,
|
|
302
|
+
...materialFidelityBindingFields(binding),
|
|
303
|
+
detail: `glTF ${slot} texture requests TEXCOORD_${info.texCoord}, but current WebGL render resources only bind TEXCOORD_0 and TEXCOORD_1; the shader samples TEXCOORD_${renderedTexCoord}.`
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
if (tangentSpace && mesh.tangents.length === 0 && info.texCoord > 0) {
|
|
307
|
+
diagnostics.push({
|
|
308
|
+
issue: "generated-tangent-uv-mismatch",
|
|
309
|
+
slot,
|
|
310
|
+
texCoord: info.texCoord,
|
|
311
|
+
renderedTexCoord,
|
|
312
|
+
...materialFidelityBindingFields(binding),
|
|
313
|
+
detail: `glTF ${slot} texture samples TEXCOORD_${info.texCoord}, but generated tangents are derived from TEXCOORD_0 when source tangents are absent.`
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return diagnostics;
|
|
319
|
+
}
|
|
320
|
+
function materialFidelityBindingFields(binding) {
|
|
321
|
+
return {
|
|
322
|
+
nodeName: binding.nodeName,
|
|
323
|
+
geometryKey: binding.geometryKey,
|
|
324
|
+
materialKey: binding.materialKey,
|
|
325
|
+
sourceMaterialName: binding.sourceMaterialName,
|
|
326
|
+
...(binding.sourceMaterialIndex !== undefined ? { sourceMaterialIndex: binding.sourceMaterialIndex } : {}),
|
|
327
|
+
...(binding.sourceMeshIndex !== undefined ? { sourceMeshIndex: binding.sourceMeshIndex } : {}),
|
|
328
|
+
...(binding.primitiveIndex !== undefined ? { primitiveIndex: binding.primitiveIndex } : {})
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
function collectGLTFMaterialOverrideTargets(bindings, materialLibrary, query) {
|
|
332
|
+
const uniqueMaterials = query.uniqueMaterials ?? true;
|
|
333
|
+
const seen = new Set();
|
|
334
|
+
const targets = [];
|
|
335
|
+
for (const binding of bindings) {
|
|
336
|
+
if (!matchesGLTFMaterialOverrideQuery(binding, query))
|
|
337
|
+
continue;
|
|
338
|
+
if (uniqueMaterials && seen.has(binding.materialKey))
|
|
339
|
+
continue;
|
|
340
|
+
const material = materialLibrary.get(binding.materialKey);
|
|
341
|
+
if (!material)
|
|
342
|
+
continue;
|
|
343
|
+
seen.add(binding.materialKey);
|
|
344
|
+
targets.push({ ...binding, material });
|
|
345
|
+
}
|
|
346
|
+
return targets;
|
|
347
|
+
}
|
|
348
|
+
function matchesGLTFMaterialOverrideQuery(binding, query) {
|
|
349
|
+
if (query.nodeName && !matchesTextOrPattern(binding.nodeName, query.nodeName))
|
|
350
|
+
return false;
|
|
351
|
+
if (query.sourceMaterialName && !matchesTextOrPattern(binding.sourceMaterialName, query.sourceMaterialName))
|
|
352
|
+
return false;
|
|
353
|
+
if (query.materialKey && !matchesTextOrPattern(binding.materialKey, query.materialKey))
|
|
354
|
+
return false;
|
|
355
|
+
if (query.variant && !binding.materialVariants.some((variant) => variant.variant === query.variant))
|
|
356
|
+
return false;
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
function matchesTextOrPattern(value, matcher) {
|
|
360
|
+
return typeof matcher === "string" ? value === matcher : matcher.test(value);
|
|
361
|
+
}
|
|
362
|
+
export function createGLTFRenderSource(resources, options = {}) {
|
|
363
|
+
const qualityPreset = options.qualityPreset ?? "studio-preview";
|
|
364
|
+
const environmentLighting = options.environmentLighting === false
|
|
365
|
+
? false
|
|
366
|
+
: options.environmentLighting ?? cloneEnvironmentLighting(defaultEnvironmentLightingForPreset(qualityPreset));
|
|
367
|
+
const postprocess = options.postprocess !== undefined
|
|
368
|
+
? options.postprocess
|
|
369
|
+
: qualityPreset !== "default"
|
|
370
|
+
? cloneRendererPostprocess(defaultPostprocessForPreset(qualityPreset))
|
|
371
|
+
: undefined;
|
|
372
|
+
return {
|
|
373
|
+
scene: resources.scene,
|
|
374
|
+
geometryLibrary: resources.geometryLibrary,
|
|
375
|
+
materialLibrary: resources.materialLibrary,
|
|
376
|
+
morphTargetLibrary: resources.morphTargetLibrary,
|
|
377
|
+
...(options.renderItems ? { renderItems: options.renderItems } : {}),
|
|
378
|
+
...(environmentLighting !== undefined ? { environmentLighting } : {}),
|
|
379
|
+
...(options.shadowMap ? { shadowMap: options.shadowMap } : {}),
|
|
380
|
+
...(options.shadow !== undefined ? { shadow: options.shadow } : {}),
|
|
381
|
+
...(options.collectedLights ? { collectedLights: options.collectedLights } : {}),
|
|
382
|
+
...(postprocess !== undefined ? { postprocess } : {}),
|
|
383
|
+
...(options.cameraPolicy ? { cameraPolicy: options.cameraPolicy } : {}),
|
|
384
|
+
...(options.cameraFrameBounds ? { cameraFrameBounds: options.cameraFrameBounds } : { cameraFrameBounds: resources.bounds }),
|
|
385
|
+
...(options.cameraFrameOptions ? { cameraFrameOptions: options.cameraFrameOptions } : {}),
|
|
386
|
+
...(options.cameraPosition ? { cameraPosition: options.cameraPosition } : {}),
|
|
387
|
+
...(options.frustumCulling !== undefined ? { frustumCulling: options.frustumCulling } : {})
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
export function createGLTFRenderResourceDiagnostics(resources, options = {}) {
|
|
391
|
+
const label = options.label ?? "gltf-render-resources";
|
|
392
|
+
const textureBackedMaterialNames = new Set();
|
|
393
|
+
const textureSlotDiagnostics = new Map();
|
|
394
|
+
const textureContributionDiagnostics = new Map();
|
|
395
|
+
const suppressedTextureSlotDiagnostics = new Map();
|
|
396
|
+
const shaderActiveTextureSlotDiagnostics = new Map();
|
|
397
|
+
const shaderInactiveTextureSlotDiagnostics = new Map();
|
|
398
|
+
const fallbackWhiteMaterialNames = new Set();
|
|
399
|
+
const skinnedLabels = [];
|
|
400
|
+
const untexturedSkinnedLabels = [];
|
|
401
|
+
const fallbackWhiteLabels = [];
|
|
402
|
+
const missingGeometryLabels = [];
|
|
403
|
+
const missingMaterialLabels = [];
|
|
404
|
+
const suspectStaticLabels = [];
|
|
405
|
+
let drawItems = 0;
|
|
406
|
+
let skinnedDrawItems = 0;
|
|
407
|
+
let texturedDrawItems = 0;
|
|
408
|
+
let baseColorTextureDrawItems = 0;
|
|
409
|
+
let colorBearingTextureDrawItems = 0;
|
|
410
|
+
let surfaceDetailTextureDrawItems = 0;
|
|
411
|
+
let effectiveTextureBackedDrawItems = 0;
|
|
412
|
+
let texturedSkinnedDrawItems = 0;
|
|
413
|
+
let missingGeometryDrawItems = 0;
|
|
414
|
+
let missingMaterialDrawItems = 0;
|
|
415
|
+
resources.scene.updateWorldTransforms();
|
|
416
|
+
for (const { node, renderable } of resources.scene.collectRenderables()) {
|
|
417
|
+
const itemLabel = `${node.name}:${renderable.geometry}`;
|
|
418
|
+
const geometry = resources.geometryLibrary.get(renderable.geometry);
|
|
419
|
+
const material = resources.materialLibrary.get(renderable.material);
|
|
420
|
+
if (!geometry) {
|
|
421
|
+
missingGeometryDrawItems += 1;
|
|
422
|
+
missingGeometryLabels.push(itemLabel);
|
|
423
|
+
}
|
|
424
|
+
if (!material) {
|
|
425
|
+
missingMaterialDrawItems += 1;
|
|
426
|
+
missingMaterialLabels.push(itemLabel);
|
|
427
|
+
}
|
|
428
|
+
if (!geometry || !material)
|
|
429
|
+
continue;
|
|
430
|
+
drawItems += 1;
|
|
431
|
+
const isSkinned = Boolean(renderable.skinning);
|
|
432
|
+
const validTextureSlots = GLTF_DIAGNOSTIC_TEXTURE_BINDINGS.filter(([, textureParameter, enabledParameter]) => materialHasValidTextureBinding(material, textureParameter, enabledParameter));
|
|
433
|
+
const hasAnyTexture = validTextureSlots.length > 0;
|
|
434
|
+
const hasBaseColorTexture = materialHasValidTextureBinding(material, "u_baseColorTexture", "u_baseColorTextureEnabled");
|
|
435
|
+
if (isSkinned) {
|
|
436
|
+
skinnedDrawItems += 1;
|
|
437
|
+
skinnedLabels.push(itemLabel);
|
|
438
|
+
}
|
|
439
|
+
if (hasAnyTexture) {
|
|
440
|
+
texturedDrawItems += 1;
|
|
441
|
+
textureBackedMaterialNames.add(material.name);
|
|
442
|
+
}
|
|
443
|
+
let hasEffectiveBaseColorTexture = false;
|
|
444
|
+
let hasColorBearingTexture = false;
|
|
445
|
+
let hasSurfaceDetailTexture = false;
|
|
446
|
+
for (const [slot] of validTextureSlots) {
|
|
447
|
+
addTextureSlotDiagnostic(textureSlotDiagnostics, slot, material.name, itemLabel);
|
|
448
|
+
const shaderActive = materialSamplesTextureSlot(material, slot);
|
|
449
|
+
const shaderSlotMap = shaderActive ? shaderActiveTextureSlotDiagnostics : shaderInactiveTextureSlotDiagnostics;
|
|
450
|
+
addTextureSlotDiagnostic(shaderSlotMap, slot, material.name, itemLabel);
|
|
451
|
+
const contribution = shaderActive ? textureContributionForSlot(material, slot) : "suppressed";
|
|
452
|
+
if (contribution === "color-bearing") {
|
|
453
|
+
hasColorBearingTexture = true;
|
|
454
|
+
if (slot === "baseColor")
|
|
455
|
+
hasEffectiveBaseColorTexture = true;
|
|
456
|
+
addTextureContributionDiagnostic(textureContributionDiagnostics, contribution, slot, material.name, itemLabel);
|
|
457
|
+
}
|
|
458
|
+
else if (contribution === "surface-detail") {
|
|
459
|
+
hasSurfaceDetailTexture = true;
|
|
460
|
+
addTextureContributionDiagnostic(textureContributionDiagnostics, contribution, slot, material.name, itemLabel);
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
addTextureContributionDiagnostic(suppressedTextureSlotDiagnostics, contribution, slot, material.name, itemLabel);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (hasEffectiveBaseColorTexture)
|
|
467
|
+
baseColorTextureDrawItems += 1;
|
|
468
|
+
if (hasColorBearingTexture)
|
|
469
|
+
colorBearingTextureDrawItems += 1;
|
|
470
|
+
if (hasSurfaceDetailTexture)
|
|
471
|
+
surfaceDetailTextureDrawItems += 1;
|
|
472
|
+
if (hasColorBearingTexture || hasSurfaceDetailTexture)
|
|
473
|
+
effectiveTextureBackedDrawItems += 1;
|
|
474
|
+
if (isSkinned && hasBaseColorTexture)
|
|
475
|
+
texturedSkinnedDrawItems += 1;
|
|
476
|
+
if (isSkinned && !hasBaseColorTexture)
|
|
477
|
+
untexturedSkinnedLabels.push(itemLabel);
|
|
478
|
+
if (isFallbackWhiteRuntimeMaterial(material)) {
|
|
479
|
+
fallbackWhiteLabels.push(itemLabel);
|
|
480
|
+
fallbackWhiteMaterialNames.add(material.name);
|
|
481
|
+
}
|
|
482
|
+
if (!isSkinned && options.suspectStaticNodePattern?.test(node.name))
|
|
483
|
+
suspectStaticLabels.push(itemLabel);
|
|
484
|
+
}
|
|
485
|
+
return {
|
|
486
|
+
label,
|
|
487
|
+
drawItems,
|
|
488
|
+
skinnedDrawItems,
|
|
489
|
+
texturedDrawItems,
|
|
490
|
+
baseColorTextureDrawItems,
|
|
491
|
+
colorBearingTextureDrawItems,
|
|
492
|
+
surfaceDetailTextureDrawItems,
|
|
493
|
+
effectiveTextureBackedDrawItems,
|
|
494
|
+
unsupportedTexCoordDrawItems: countDistinctMaterialFidelityDrawItems(resources.materialFidelityDiagnostics, "unsupported-texcoord-set"),
|
|
495
|
+
generatedTangentUvMismatchDrawItems: countDistinctMaterialFidelityDrawItems(resources.materialFidelityDiagnostics, "generated-tangent-uv-mismatch"),
|
|
496
|
+
texturedSkinnedDrawItems,
|
|
497
|
+
untexturedSkinnedDrawItems: untexturedSkinnedLabels.length,
|
|
498
|
+
fallbackWhiteDrawItems: fallbackWhiteLabels.length,
|
|
499
|
+
missingGeometryDrawItems,
|
|
500
|
+
missingMaterialDrawItems,
|
|
501
|
+
materialCount: resources.materialLibrary.size,
|
|
502
|
+
textureCount: resources.textureLibrary?.size ?? 0,
|
|
503
|
+
textureBackedMaterialNames: [...textureBackedMaterialNames].sort(),
|
|
504
|
+
textureSlotDiagnostics: [...textureSlotDiagnostics.entries()]
|
|
505
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
506
|
+
.map(([slot, diagnostics]) => ({
|
|
507
|
+
slot: slot,
|
|
508
|
+
drawItems: diagnostics.drawItems,
|
|
509
|
+
materialNames: [...diagnostics.materialNames].sort(),
|
|
510
|
+
labels: [...diagnostics.labels].sort()
|
|
511
|
+
})),
|
|
512
|
+
textureContributionDiagnostics: mapTextureContributionDiagnostics(textureContributionDiagnostics),
|
|
513
|
+
suppressedTextureSlotDiagnostics: mapTextureContributionDiagnostics(suppressedTextureSlotDiagnostics),
|
|
514
|
+
materialFidelityDiagnostics: resources.materialFidelityDiagnostics ?? [],
|
|
515
|
+
shaderActiveTextureSlotDiagnostics: [...shaderActiveTextureSlotDiagnostics.entries()]
|
|
516
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
517
|
+
.map(([slot, diagnostics]) => ({
|
|
518
|
+
slot: slot,
|
|
519
|
+
drawItems: diagnostics.drawItems,
|
|
520
|
+
materialNames: [...diagnostics.materialNames].sort(),
|
|
521
|
+
labels: [...diagnostics.labels].sort()
|
|
522
|
+
})),
|
|
523
|
+
shaderInactiveTextureSlotDiagnostics: [...shaderInactiveTextureSlotDiagnostics.entries()]
|
|
524
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
525
|
+
.map(([slot, diagnostics]) => ({
|
|
526
|
+
slot: slot,
|
|
527
|
+
drawItems: diagnostics.drawItems,
|
|
528
|
+
materialNames: [...diagnostics.materialNames].sort(),
|
|
529
|
+
labels: [...diagnostics.labels].sort()
|
|
530
|
+
})),
|
|
531
|
+
fallbackWhiteMaterialNames: [...fallbackWhiteMaterialNames].sort(),
|
|
532
|
+
skinnedLabels,
|
|
533
|
+
untexturedSkinnedLabels,
|
|
534
|
+
fallbackWhiteLabels,
|
|
535
|
+
missingGeometryLabels,
|
|
536
|
+
missingMaterialLabels,
|
|
537
|
+
suspectStaticLabels
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function defaultEnvironmentLightingForPreset(preset) {
|
|
541
|
+
if (preset === "hdr-studio-preview")
|
|
542
|
+
return createDefaultGLTFHdrStudioPreviewEnvironmentLighting();
|
|
543
|
+
if (preset === "studio-preview")
|
|
544
|
+
return DEFAULT_GLTF_STUDIO_PREVIEW_ENVIRONMENT_LIGHTING;
|
|
545
|
+
return DEFAULT_GLTF_RENDER_ENVIRONMENT_LIGHTING;
|
|
546
|
+
}
|
|
547
|
+
function addTextureSlotDiagnostic(diagnosticsBySlot, slot, materialName, itemLabel) {
|
|
548
|
+
let diagnostics = diagnosticsBySlot.get(slot);
|
|
549
|
+
if (!diagnostics) {
|
|
550
|
+
diagnostics = { drawItems: 0, materialNames: new Set(), labels: [] };
|
|
551
|
+
diagnosticsBySlot.set(slot, diagnostics);
|
|
552
|
+
}
|
|
553
|
+
diagnostics.drawItems += 1;
|
|
554
|
+
diagnostics.materialNames.add(materialName);
|
|
555
|
+
diagnostics.labels.push(itemLabel);
|
|
556
|
+
}
|
|
557
|
+
function addTextureContributionDiagnostic(diagnosticsByContributionSlot, contribution, slot, materialName, itemLabel) {
|
|
558
|
+
addTextureSlotDiagnostic(diagnosticsByContributionSlot, `${contribution}:${slot}`, materialName, itemLabel);
|
|
559
|
+
}
|
|
560
|
+
function mapTextureContributionDiagnostics(diagnosticsByContributionSlot) {
|
|
561
|
+
return [...diagnosticsByContributionSlot.entries()]
|
|
562
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
563
|
+
.map(([key, diagnostics]) => {
|
|
564
|
+
const [contribution, slot] = key.split(":");
|
|
565
|
+
return {
|
|
566
|
+
contribution,
|
|
567
|
+
slot,
|
|
568
|
+
drawItems: diagnostics.drawItems,
|
|
569
|
+
materialNames: [...diagnostics.materialNames].sort(),
|
|
570
|
+
labels: [...diagnostics.labels].sort()
|
|
571
|
+
};
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
function countDistinctMaterialFidelityDrawItems(diagnostics, issue) {
|
|
575
|
+
if (!diagnostics)
|
|
576
|
+
return 0;
|
|
577
|
+
const labels = new Set();
|
|
578
|
+
for (const diagnostic of diagnostics) {
|
|
579
|
+
if (diagnostic.issue !== issue)
|
|
580
|
+
continue;
|
|
581
|
+
labels.add(`${diagnostic.nodeName}:${diagnostic.geometryKey}:${diagnostic.materialKey}`);
|
|
582
|
+
}
|
|
583
|
+
return labels.size;
|
|
584
|
+
}
|
|
585
|
+
function textureContributionForSlot(material, slot) {
|
|
586
|
+
switch (slot) {
|
|
587
|
+
case "baseColor":
|
|
588
|
+
case "diffuseTransmissionColor":
|
|
589
|
+
case "specularColor":
|
|
590
|
+
case "sheenColor":
|
|
591
|
+
return "color-bearing";
|
|
592
|
+
case "emissive":
|
|
593
|
+
return materialHasEmissiveContribution(material) ? "color-bearing" : "suppressed";
|
|
594
|
+
case "normal":
|
|
595
|
+
return numericMaterialParameter(material, "u_normalScale", 1) > 0.001 ? "surface-detail" : "suppressed";
|
|
596
|
+
case "occlusion":
|
|
597
|
+
return numericMaterialParameter(material, "u_occlusionStrength", 1) > 0.001 ? "surface-detail" : "suppressed";
|
|
598
|
+
default:
|
|
599
|
+
return "surface-detail";
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
function numericMaterialParameter(material, name, fallback) {
|
|
603
|
+
const value = material.getParameter(name);
|
|
604
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
605
|
+
}
|
|
606
|
+
function materialHasEmissiveContribution(material) {
|
|
607
|
+
const strength = numericMaterialParameter(material, "u_emissiveStrength", 1);
|
|
608
|
+
const color = material.getParameter("u_emissiveColor");
|
|
609
|
+
if (strength <= 0.001)
|
|
610
|
+
return false;
|
|
611
|
+
if ((Array.isArray(color) || ArrayBuffer.isView(color)) && color.length >= 3) {
|
|
612
|
+
return Math.max(Number(color[0]) || 0, Number(color[1]) || 0, Number(color[2]) || 0) > 0.001;
|
|
613
|
+
}
|
|
614
|
+
return true;
|
|
615
|
+
}
|
|
616
|
+
function materialSamplesTextureSlot(material, slot) {
|
|
617
|
+
if (material.shaderKey !== DEFAULT_TEXTURED_PBR_SHADER_NAME)
|
|
618
|
+
return true;
|
|
619
|
+
return isTexturedPbrTextureSlotShaderActive(slot, material.shaderVariant);
|
|
620
|
+
}
|
|
621
|
+
function materialHasValidTextureBinding(material, textureParameter, enabledParameter) {
|
|
622
|
+
const enabled = material.getParameter(enabledParameter);
|
|
623
|
+
const binding = material.getParameter(textureParameter);
|
|
624
|
+
const enabledByMaterial = enabled === undefined || enabled === 1;
|
|
625
|
+
return enabledByMaterial
|
|
626
|
+
&& binding instanceof TextureBinding
|
|
627
|
+
&& Boolean(binding.texture)
|
|
628
|
+
&& !isGeneratedFallbackTexture(binding.texture)
|
|
629
|
+
&& binding.validate().ok;
|
|
630
|
+
}
|
|
631
|
+
function isFallbackWhiteRuntimeMaterial(material) {
|
|
632
|
+
const baseColor = material.getParameter("u_baseColor");
|
|
633
|
+
const metallic = numericMaterialParameter(material, "u_metallic", 0);
|
|
634
|
+
const roughness = numericMaterialParameter(material, "u_roughness", 1);
|
|
635
|
+
const transmission = numericMaterialParameter(material, "u_transmissionFactor", 0)
|
|
636
|
+
+ numericMaterialParameter(material, "u_diffuseTransmissionFactor", 0);
|
|
637
|
+
const hasTexture = materialHasValidTextureBinding(material, "u_baseColorTexture", "u_baseColorTextureEnabled")
|
|
638
|
+
|| materialHasValidTextureBinding(material, "u_texture", "u_textureEnabled");
|
|
639
|
+
return !hasTexture
|
|
640
|
+
&& transmission <= 0.001
|
|
641
|
+
&& !(metallic >= 0.9 && roughness <= 0.25)
|
|
642
|
+
&& (Array.isArray(baseColor) || ArrayBuffer.isView(baseColor))
|
|
643
|
+
&& baseColor.length >= 4
|
|
644
|
+
&& baseColor[0] >= 0.98
|
|
645
|
+
&& baseColor[1] >= 0.98
|
|
646
|
+
&& baseColor[2] >= 0.98
|
|
647
|
+
&& baseColor[3] >= 0.98;
|
|
648
|
+
}
|
|
649
|
+
function isGeneratedFallbackTexture(texture) {
|
|
650
|
+
if (!texture)
|
|
651
|
+
return true;
|
|
652
|
+
return /^default-(?:white|linear-white|flat-normal|metallic-roughness|occlusion|emissive|clearcoat|transmission|diffuse-transmission|volume-thickness|specular|sheen|anisotropy|iridescence)/.test(texture.label);
|
|
653
|
+
}
|
|
654
|
+
function defaultPostprocessForPreset(preset) {
|
|
655
|
+
return preset === "hdr-studio-preview"
|
|
656
|
+
? DEFAULT_GLTF_HDR_STUDIO_PREVIEW_POSTPROCESS
|
|
657
|
+
: DEFAULT_GLTF_STUDIO_PREVIEW_POSTPROCESS;
|
|
658
|
+
}
|
|
659
|
+
function cloneEnvironmentLighting(environment) {
|
|
660
|
+
return {
|
|
661
|
+
color: [...environment.color],
|
|
662
|
+
intensity: environment.intensity,
|
|
663
|
+
...(environment.proceduralMap
|
|
664
|
+
? {
|
|
665
|
+
proceduralMap: {
|
|
666
|
+
skyColor: [...environment.proceduralMap.skyColor],
|
|
667
|
+
horizonColor: [...environment.proceduralMap.horizonColor],
|
|
668
|
+
groundColor: [...environment.proceduralMap.groundColor],
|
|
669
|
+
specularColor: [...environment.proceduralMap.specularColor],
|
|
670
|
+
intensity: environment.proceduralMap.intensity,
|
|
671
|
+
specularIntensity: environment.proceduralMap.specularIntensity
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
: {}),
|
|
675
|
+
...(environment.environmentMapTexture ? { environmentMapTexture: environment.environmentMapTexture } : {}),
|
|
676
|
+
...(environment.environmentCubeMapTexture ? { environmentCubeMapTexture: environment.environmentCubeMapTexture } : {}),
|
|
677
|
+
...(environment.environmentMapIntensity !== undefined ? { environmentMapIntensity: environment.environmentMapIntensity } : {}),
|
|
678
|
+
...(environment.environmentMapSpecularIntensity !== undefined ? { environmentMapSpecularIntensity: environment.environmentMapSpecularIntensity } : {}),
|
|
679
|
+
...(environment.environmentMapRotation !== undefined ? { environmentMapRotation: environment.environmentMapRotation } : {}),
|
|
680
|
+
...(environment.environmentMapMipCount !== undefined ? { environmentMapMipCount: environment.environmentMapMipCount } : {}),
|
|
681
|
+
...(environment.environmentMapEncoding ? { environmentMapEncoding: environment.environmentMapEncoding } : {}),
|
|
682
|
+
...(environment.environmentBrdfLutTexture ? { environmentBrdfLutTexture: environment.environmentBrdfLutTexture } : {})
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
function cloneRendererPostprocess(postprocess) {
|
|
686
|
+
return {
|
|
687
|
+
...(postprocess.targetFormat ? { targetFormat: postprocess.targetFormat } : {}),
|
|
688
|
+
...(postprocess.toneMapping !== undefined
|
|
689
|
+
? { toneMapping: typeof postprocess.toneMapping === "object" ? { ...postprocess.toneMapping } : postprocess.toneMapping }
|
|
690
|
+
: {}),
|
|
691
|
+
...(postprocess.colorGrade !== undefined
|
|
692
|
+
? { colorGrade: typeof postprocess.colorGrade === "object" ? { ...postprocess.colorGrade } : postprocess.colorGrade }
|
|
693
|
+
: {}),
|
|
694
|
+
...(postprocess.bloom !== undefined
|
|
695
|
+
? { bloom: typeof postprocess.bloom === "object" ? { ...postprocess.bloom } : postprocess.bloom }
|
|
696
|
+
: {}),
|
|
697
|
+
...(postprocess.chromaticAberration !== undefined
|
|
698
|
+
? { chromaticAberration: typeof postprocess.chromaticAberration === "object" ? { ...postprocess.chromaticAberration } : postprocess.chromaticAberration }
|
|
699
|
+
: {}),
|
|
700
|
+
...(postprocess.filmGrain !== undefined
|
|
701
|
+
? { filmGrain: typeof postprocess.filmGrain === "object" ? { ...postprocess.filmGrain } : postprocess.filmGrain }
|
|
702
|
+
: {}),
|
|
703
|
+
...(postprocess.depthOfField !== undefined
|
|
704
|
+
? { depthOfField: postprocess.depthOfField === false ? false : { ...postprocess.depthOfField } }
|
|
705
|
+
: {}),
|
|
706
|
+
...(postprocess.motionBlur !== undefined
|
|
707
|
+
? { motionBlur: postprocess.motionBlur === false ? false : { ...postprocess.motionBlur } }
|
|
708
|
+
: {}),
|
|
709
|
+
...(postprocess.ssao !== undefined
|
|
710
|
+
? { ssao: postprocess.ssao === false ? false : { ...postprocess.ssao } }
|
|
711
|
+
: {}),
|
|
712
|
+
...(postprocess.ssr !== undefined
|
|
713
|
+
? { ssr: postprocess.ssr === false ? false : { ...postprocess.ssr } }
|
|
714
|
+
: {}),
|
|
715
|
+
...(postprocess.taa !== undefined
|
|
716
|
+
? { taa: postprocess.taa === false ? false : { ...postprocess.taa } }
|
|
717
|
+
: {}),
|
|
718
|
+
...(postprocess.outline !== undefined
|
|
719
|
+
? { outline: typeof postprocess.outline === "object" ? { ...postprocess.outline } : postprocess.outline }
|
|
720
|
+
: {}),
|
|
721
|
+
...(postprocess.fxaa !== undefined
|
|
722
|
+
? { fxaa: typeof postprocess.fxaa === "object" ? { ...postprocess.fxaa } : postprocess.fxaa }
|
|
723
|
+
: {})
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
function defaultGLTFCameraMinDistance(bounds) {
|
|
727
|
+
const sizeX = Math.max(0, bounds.max[0] - bounds.min[0]);
|
|
728
|
+
const sizeY = Math.max(0, bounds.max[1] - bounds.min[1]);
|
|
729
|
+
const sizeZ = Math.max(0, bounds.max[2] - bounds.min[2]);
|
|
730
|
+
const diagonal = Math.hypot(sizeX, sizeY, sizeZ);
|
|
731
|
+
return Math.max(1.2, diagonal * 0.5);
|
|
732
|
+
}
|
|
733
|
+
function defaultGLTFCameraFrameOptions(bounds, overrides = {}) {
|
|
734
|
+
return {
|
|
735
|
+
...DEFAULT_GLTF_STUDIO_PREVIEW_FRAME,
|
|
736
|
+
minDistance: defaultGLTFCameraMinDistance(bounds),
|
|
737
|
+
...overrides
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
function computeGLTFRenderResourceBounds(scene, geometryLibrary, morphTargetLibrary) {
|
|
741
|
+
scene.updateWorldTransforms();
|
|
742
|
+
let bounds;
|
|
743
|
+
for (const { node, renderable } of scene.collectRenderables()) {
|
|
744
|
+
const geometry = geometryLibrary.get(renderable.geometry);
|
|
745
|
+
if (!geometry)
|
|
746
|
+
continue;
|
|
747
|
+
const envelope = computeSkinnedMorphTargetEnvelopeBounds(geometry, renderable.skinning, morphTargetLibrary.get(renderable.geometry));
|
|
748
|
+
const local = new SceneBounds3([envelope.min[0], envelope.min[1], envelope.min[2]], [envelope.max[0], envelope.max[1], envelope.max[2]]);
|
|
749
|
+
const worldBounds = renderable.instanceTransforms
|
|
750
|
+
? transformInstancedBounds(local, node.transform.worldMatrix, renderable.instanceTransforms)
|
|
751
|
+
: local.transform(node.transform.worldMatrix);
|
|
752
|
+
bounds = bounds ? bounds.union(worldBounds) : worldBounds;
|
|
753
|
+
}
|
|
754
|
+
if (!bounds || bounds.isEmpty()) {
|
|
755
|
+
return { min: [0, 0, 0], max: [0, 0, 0] };
|
|
756
|
+
}
|
|
757
|
+
return {
|
|
758
|
+
min: [bounds.min[0], bounds.min[1], bounds.min[2]],
|
|
759
|
+
max: [bounds.max[0], bounds.max[1], bounds.max[2]]
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
function transformInstancedBounds(local, modelMatrix, instanceTransforms) {
|
|
763
|
+
let bounds = new SceneBounds3();
|
|
764
|
+
for (let offset = 0; offset + 15 < instanceTransforms.length; offset += 16) {
|
|
765
|
+
bounds = bounds.union(local.transform(multiplyMat4(modelMatrix, toMat4(instanceTransforms.slice(offset, offset + 16)))));
|
|
766
|
+
}
|
|
767
|
+
return bounds;
|
|
768
|
+
}
|
|
769
|
+
function toMat4(values) {
|
|
770
|
+
const array = Array.from(values);
|
|
771
|
+
if (array.length !== 16 || array.some((value) => !Number.isFinite(value))) {
|
|
772
|
+
throw new Error("glTF render resource instance transform must be a finite mat4.");
|
|
773
|
+
}
|
|
774
|
+
return array;
|
|
775
|
+
}
|
|
776
|
+
function disposeGLTFRenderResourceMaps(geometryLibrary, textureLibrary) {
|
|
777
|
+
for (const geometry of geometryLibrary.values())
|
|
778
|
+
geometry.dispose();
|
|
779
|
+
for (const texture of textureLibrary.values())
|
|
780
|
+
texture.dispose();
|
|
781
|
+
}
|
|
782
|
+
function materialForMesh(asset, mesh, materialVariant) {
|
|
783
|
+
const materialIndex = materialVariant
|
|
784
|
+
? mesh.materialVariants.find((mapping) => mapping.variant === materialVariant)?.materialIndex ?? mesh.materialIndex
|
|
785
|
+
: mesh.materialIndex;
|
|
786
|
+
return materialIndex === undefined ? undefined : asset.materials[materialIndex];
|
|
787
|
+
}
|
|
788
|
+
function createGeometry(mesh, material) {
|
|
789
|
+
const usedTexCoordSets = usedRenderTexCoordSets(material);
|
|
790
|
+
const texcoords = selectRenderTexcoords(mesh, material, 0);
|
|
791
|
+
const texcoords1 = usedTexCoordSets.has(1) ? selectRenderTexcoords(mesh, material, 1) : [];
|
|
792
|
+
const needsUv = usedTexCoordSets.has(0) || texcoords.length > 0;
|
|
793
|
+
const needsUv1 = texcoords1.length > 0;
|
|
794
|
+
const needsNormal = mesh.normals.length > 0 || needsUv || materialNeedsNormals(material);
|
|
795
|
+
const needsTangent = mesh.tangents.length > 0 || (needsUv && (materialNeedsTangents(material) || (material !== undefined && !material.unlit)));
|
|
796
|
+
const needsColor = mesh.colors.length > 0;
|
|
797
|
+
const needsSkinning = mesh.skinIndex !== undefined || mesh.joints.length > 0 || mesh.weights.length > 0;
|
|
798
|
+
const format = vertexFormatForGLTFMesh(needsNormal, needsUv, needsTangent, needsUv1, needsColor, needsSkinning);
|
|
799
|
+
const renderNormals = needsNormal && mesh.normals.length === 0
|
|
800
|
+
? generateMeshNormals(mesh.positions, mesh.indices, mesh.topology)
|
|
801
|
+
: mesh.normals;
|
|
802
|
+
const renderTangents = needsTangent && mesh.tangents.length === 0
|
|
803
|
+
? generateMeshTangents(mesh.positions, texcoords, mesh.indices, mesh.topology, renderNormals)
|
|
804
|
+
: mesh.tangents;
|
|
805
|
+
const vertices = new VertexBuffer(format, mesh.positions.length);
|
|
806
|
+
for (let index = 0; index < mesh.positions.length; index += 1) {
|
|
807
|
+
vertices.setAttribute(index, "position", mesh.positions[index]);
|
|
808
|
+
if (format.hasAttribute("normal")) {
|
|
809
|
+
vertices.setAttribute(index, "normal", renderNormals[index] ?? [0, 0, 1]);
|
|
810
|
+
}
|
|
811
|
+
if (format.hasAttribute("tangent")) {
|
|
812
|
+
vertices.setAttribute(index, "tangent", renderTangents[index] ?? fallbackTangent(renderNormals[index]));
|
|
813
|
+
}
|
|
814
|
+
if (format.hasAttribute("uv")) {
|
|
815
|
+
vertices.setAttribute(index, "uv", texcoords[index] ?? [0, 0]);
|
|
816
|
+
}
|
|
817
|
+
if (format.hasAttribute("uv1")) {
|
|
818
|
+
vertices.setAttribute(index, "uv1", texcoords1[index] ?? texcoords[index] ?? [0, 0]);
|
|
819
|
+
}
|
|
820
|
+
if (format.hasAttribute("color")) {
|
|
821
|
+
vertices.setAttribute(index, "color", mesh.colors[index] ?? [1, 1, 1, 1]);
|
|
822
|
+
}
|
|
823
|
+
if (format.hasAttribute("joints")) {
|
|
824
|
+
vertices.setAttribute(index, "joints", mesh.joints[index] ?? [0, 0, 0, 0]);
|
|
825
|
+
vertices.setAttribute(index, "weights", mesh.weights[index] ?? [0, 0, 0, 0]);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
const indices = mesh.indices && mesh.indices.length > 0 ? new IndexBuffer(mesh.indices, mesh.positions.length) : null;
|
|
829
|
+
return new Geometry(vertices, indices, mesh.topology, mesh.geometry.bounds);
|
|
830
|
+
}
|
|
831
|
+
function generateMeshNormals(positions, indices, topology) {
|
|
832
|
+
const normals = Array.from({ length: positions.length }, () => [0, 0, 0]);
|
|
833
|
+
if (topology !== "triangles") {
|
|
834
|
+
return normals.map(() => [0, 0, 1]);
|
|
835
|
+
}
|
|
836
|
+
const triangleIndices = indices && indices.length > 0 ? indices : positions.map((_, index) => index);
|
|
837
|
+
for (let offset = 0; offset + 2 < triangleIndices.length; offset += 3) {
|
|
838
|
+
const ia = triangleIndices[offset];
|
|
839
|
+
const ib = triangleIndices[offset + 1];
|
|
840
|
+
const ic = triangleIndices[offset + 2];
|
|
841
|
+
const a = positions[ia];
|
|
842
|
+
const b = positions[ib];
|
|
843
|
+
const c = positions[ic];
|
|
844
|
+
if (!a || !b || !c)
|
|
845
|
+
continue;
|
|
846
|
+
const normal = cross3(subtract3(b, a), subtract3(c, a));
|
|
847
|
+
normals[ia] = add3(normals[ia], normal);
|
|
848
|
+
normals[ib] = add3(normals[ib], normal);
|
|
849
|
+
normals[ic] = add3(normals[ic], normal);
|
|
850
|
+
}
|
|
851
|
+
return normals.map((normal) => normalize3(normal));
|
|
852
|
+
}
|
|
853
|
+
function generateMeshTangents(positions, texcoords, indices, topology, normals) {
|
|
854
|
+
const tangents = Array.from({ length: positions.length }, () => [0, 0, 0]);
|
|
855
|
+
const bitangents = Array.from({ length: positions.length }, () => [0, 0, 0]);
|
|
856
|
+
if (topology !== "triangles" || texcoords.length === 0) {
|
|
857
|
+
return normals.map((normal) => fallbackTangent(normal));
|
|
858
|
+
}
|
|
859
|
+
const triangleIndices = indices && indices.length > 0 ? indices : positions.map((_, index) => index);
|
|
860
|
+
for (let offset = 0; offset + 2 < triangleIndices.length; offset += 3) {
|
|
861
|
+
const ia = triangleIndices[offset];
|
|
862
|
+
const ib = triangleIndices[offset + 1];
|
|
863
|
+
const ic = triangleIndices[offset + 2];
|
|
864
|
+
const a = positions[ia];
|
|
865
|
+
const b = positions[ib];
|
|
866
|
+
const c = positions[ic];
|
|
867
|
+
const uva = texcoords[ia];
|
|
868
|
+
const uvb = texcoords[ib];
|
|
869
|
+
const uvc = texcoords[ic];
|
|
870
|
+
if (!a || !b || !c || !uva || !uvb || !uvc)
|
|
871
|
+
continue;
|
|
872
|
+
const edge1 = subtract3(b, a);
|
|
873
|
+
const edge2 = subtract3(c, a);
|
|
874
|
+
const duv1 = [uvb[0] - uva[0], uvb[1] - uva[1]];
|
|
875
|
+
const duv2 = [uvc[0] - uva[0], uvc[1] - uva[1]];
|
|
876
|
+
const determinant = duv1[0] * duv2[1] - duv2[0] * duv1[1];
|
|
877
|
+
if (Math.abs(determinant) <= 1e-8)
|
|
878
|
+
continue;
|
|
879
|
+
const scale = 1 / determinant;
|
|
880
|
+
const tangent = scale3(subtract3(scale3(edge1, duv2[1]), scale3(edge2, duv1[1])), scale);
|
|
881
|
+
const bitangent = scale3(subtract3(scale3(edge2, duv1[0]), scale3(edge1, duv2[0])), scale);
|
|
882
|
+
tangents[ia] = add3(tangents[ia], tangent);
|
|
883
|
+
tangents[ib] = add3(tangents[ib], tangent);
|
|
884
|
+
tangents[ic] = add3(tangents[ic], tangent);
|
|
885
|
+
bitangents[ia] = add3(bitangents[ia], bitangent);
|
|
886
|
+
bitangents[ib] = add3(bitangents[ib], bitangent);
|
|
887
|
+
bitangents[ic] = add3(bitangents[ic], bitangent);
|
|
888
|
+
}
|
|
889
|
+
return tangents.map((tangent, index) => {
|
|
890
|
+
const normal = normals[index] ?? [0, 0, 1];
|
|
891
|
+
const orthogonal = subtract3(tangent, scale3(normal, dot3(normal, tangent)));
|
|
892
|
+
if (length3(orthogonal) <= 1e-8)
|
|
893
|
+
return fallbackTangent(normal);
|
|
894
|
+
const normalized = normalize3(orthogonal);
|
|
895
|
+
const handedness = dot3(cross3(normal, normalized), bitangents[index] ?? [0, 1, 0]) < 0 ? -1 : 1;
|
|
896
|
+
return [normalized[0], normalized[1], normalized[2], handedness];
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
function subtract3(left, right) {
|
|
900
|
+
return [left[0] - right[0], left[1] - right[1], left[2] - right[2]];
|
|
901
|
+
}
|
|
902
|
+
function add3(left, right) {
|
|
903
|
+
return [left[0] + right[0], left[1] + right[1], left[2] + right[2]];
|
|
904
|
+
}
|
|
905
|
+
function scale3(value, scalar) {
|
|
906
|
+
return [value[0] * scalar, value[1] * scalar, value[2] * scalar];
|
|
907
|
+
}
|
|
908
|
+
function dot3(left, right) {
|
|
909
|
+
return left[0] * right[0] + left[1] * right[1] + left[2] * right[2];
|
|
910
|
+
}
|
|
911
|
+
function cross3(left, right) {
|
|
912
|
+
return [
|
|
913
|
+
left[1] * right[2] - left[2] * right[1],
|
|
914
|
+
left[2] * right[0] - left[0] * right[2],
|
|
915
|
+
left[0] * right[1] - left[1] * right[0]
|
|
916
|
+
];
|
|
917
|
+
}
|
|
918
|
+
function length3(value) {
|
|
919
|
+
return Math.hypot(value[0], value[1], value[2]);
|
|
920
|
+
}
|
|
921
|
+
function normalize3(value) {
|
|
922
|
+
const length = length3(value);
|
|
923
|
+
if (length <= 1e-8)
|
|
924
|
+
return [0, 0, 1];
|
|
925
|
+
return [value[0] / length, value[1] / length, value[2] / length];
|
|
926
|
+
}
|
|
927
|
+
function fallbackTangent(normal) {
|
|
928
|
+
const n = normal ?? [0, 0, 1];
|
|
929
|
+
const reference = Math.abs(n[1]) < 0.9 ? [0, 1, 0] : [1, 0, 0];
|
|
930
|
+
const tangent = normalize3(cross3(reference, n));
|
|
931
|
+
return [tangent[0], tangent[1], tangent[2], 1];
|
|
932
|
+
}
|
|
933
|
+
function selectRenderTexcoords(mesh, material, setIndex) {
|
|
934
|
+
const selected = mesh.texcoordSets[setIndex];
|
|
935
|
+
if (selected && selected.length > 0)
|
|
936
|
+
return selected;
|
|
937
|
+
if (setIndex > 0) {
|
|
938
|
+
throw new Error(`glTF mesh ${mesh.name} material ${mesh.material} references missing TEXCOORD_${setIndex}`);
|
|
939
|
+
}
|
|
940
|
+
return mesh.texcoords;
|
|
941
|
+
}
|
|
942
|
+
function usedRenderTexCoordSets(material) {
|
|
943
|
+
const sets = new Set();
|
|
944
|
+
const infos = material ? materialTextureInfos(material) : [];
|
|
945
|
+
for (const info of infos) {
|
|
946
|
+
if (info.texCoord <= 1)
|
|
947
|
+
sets.add(info.texCoord);
|
|
948
|
+
}
|
|
949
|
+
if (sets.size === 0 && infos.length > 0)
|
|
950
|
+
sets.add(0);
|
|
951
|
+
return sets;
|
|
952
|
+
}
|
|
953
|
+
function materialTextureInfos(material) {
|
|
954
|
+
return materialTextureInfosBySlot(material).map(({ info }) => info);
|
|
955
|
+
}
|
|
956
|
+
function materialTextureInfosBySlot(material) {
|
|
957
|
+
return [
|
|
958
|
+
material.baseColorTexture ? { slot: "baseColor", info: material.baseColorTexture, tangentSpace: false } : undefined,
|
|
959
|
+
material.metallicRoughnessTexture ? { slot: "metallicRoughness", info: material.metallicRoughnessTexture, tangentSpace: false } : undefined,
|
|
960
|
+
material.normalTexture ? { slot: "normal", info: material.normalTexture, tangentSpace: true } : undefined,
|
|
961
|
+
material.occlusionTexture ? { slot: "occlusion", info: material.occlusionTexture, tangentSpace: false } : undefined,
|
|
962
|
+
material.emissiveTexture ? { slot: "emissive", info: material.emissiveTexture, tangentSpace: false } : undefined,
|
|
963
|
+
material.clearcoat?.texture ? { slot: "clearcoat", info: material.clearcoat.texture, tangentSpace: false } : undefined,
|
|
964
|
+
material.clearcoat?.roughnessTexture ? { slot: "clearcoatRoughness", info: material.clearcoat.roughnessTexture, tangentSpace: false } : undefined,
|
|
965
|
+
material.clearcoat?.normalTexture ? { slot: "clearcoatNormal", info: material.clearcoat.normalTexture, tangentSpace: true } : undefined,
|
|
966
|
+
material.transmission?.texture ? { slot: "transmission", info: material.transmission.texture, tangentSpace: false } : undefined,
|
|
967
|
+
material.diffuseTransmission?.texture ? { slot: "diffuseTransmission", info: material.diffuseTransmission.texture, tangentSpace: false } : undefined,
|
|
968
|
+
material.diffuseTransmission?.colorTexture ? { slot: "diffuseTransmissionColor", info: material.diffuseTransmission.colorTexture, tangentSpace: false } : undefined,
|
|
969
|
+
material.volume?.thicknessTexture ? { slot: "volumeThickness", info: material.volume.thicknessTexture, tangentSpace: false } : undefined,
|
|
970
|
+
material.specular?.texture ? { slot: "specular", info: material.specular.texture, tangentSpace: false } : undefined,
|
|
971
|
+
material.specular?.colorTexture ? { slot: "specularColor", info: material.specular.colorTexture, tangentSpace: false } : undefined,
|
|
972
|
+
material.sheen?.colorTexture ? { slot: "sheenColor", info: material.sheen.colorTexture, tangentSpace: false } : undefined,
|
|
973
|
+
material.sheen?.roughnessTexture ? { slot: "sheenRoughness", info: material.sheen.roughnessTexture, tangentSpace: false } : undefined,
|
|
974
|
+
material.anisotropy?.texture ? { slot: "anisotropy", info: material.anisotropy.texture, tangentSpace: false } : undefined,
|
|
975
|
+
material.iridescence?.texture ? { slot: "iridescence", info: material.iridescence.texture, tangentSpace: false } : undefined,
|
|
976
|
+
material.iridescence?.thicknessTexture ? { slot: "iridescenceThickness", info: material.iridescence.thicknessTexture, tangentSpace: false } : undefined
|
|
977
|
+
].filter((entry) => entry !== undefined);
|
|
978
|
+
}
|
|
979
|
+
function materialNeedsNormals(material) {
|
|
980
|
+
return material === undefined || !material.unlit;
|
|
981
|
+
}
|
|
982
|
+
function materialNeedsTangents(material) {
|
|
983
|
+
return Boolean(material?.normalTexture || material?.clearcoat?.normalTexture);
|
|
984
|
+
}
|
|
985
|
+
function vertexFormatForGLTFMesh(needsNormal, needsUv, needsTangent, needsUv1, needsColor, needsSkinning) {
|
|
986
|
+
if (!needsColor && !needsSkinning && !needsUv1) {
|
|
987
|
+
if (needsUv && needsTangent)
|
|
988
|
+
return VertexFormat.P3N3T4T2;
|
|
989
|
+
if (needsUv)
|
|
990
|
+
return needsNormal ? VertexFormat.P3N3T2 : new VertexFormat([
|
|
991
|
+
{ semantic: "position", components: 3, offset: 0 },
|
|
992
|
+
{ semantic: "uv", components: 2, offset: 12 }
|
|
993
|
+
], 20);
|
|
994
|
+
return needsNormal ? VertexFormat.P3N3 : VertexFormat.P3;
|
|
995
|
+
}
|
|
996
|
+
if (!needsColor && needsSkinning && !needsUv)
|
|
997
|
+
return needsNormal ? VertexFormat.P3N3J4W4 : VertexFormat.P3J4W4;
|
|
998
|
+
const attributes = [{ semantic: "position", components: 3, offset: 0 }];
|
|
999
|
+
let offset = 12;
|
|
1000
|
+
if (needsNormal) {
|
|
1001
|
+
attributes.push({ semantic: "normal", components: 3, offset });
|
|
1002
|
+
offset += 12;
|
|
1003
|
+
}
|
|
1004
|
+
if (needsTangent) {
|
|
1005
|
+
attributes.push({ semantic: "tangent", components: 4, offset });
|
|
1006
|
+
offset += 16;
|
|
1007
|
+
}
|
|
1008
|
+
if (needsUv) {
|
|
1009
|
+
attributes.push({ semantic: "uv", components: 2, offset });
|
|
1010
|
+
offset += 8;
|
|
1011
|
+
}
|
|
1012
|
+
if (needsUv1) {
|
|
1013
|
+
attributes.push({ semantic: "uv1", components: 2, offset });
|
|
1014
|
+
offset += 8;
|
|
1015
|
+
}
|
|
1016
|
+
if (needsColor) {
|
|
1017
|
+
attributes.push({ semantic: "color", components: 4, offset });
|
|
1018
|
+
offset += 16;
|
|
1019
|
+
}
|
|
1020
|
+
if (needsSkinning) {
|
|
1021
|
+
attributes.push({ semantic: "joints", components: 4, offset });
|
|
1022
|
+
offset += 16;
|
|
1023
|
+
attributes.push({ semantic: "weights", components: 4, offset });
|
|
1024
|
+
offset += 16;
|
|
1025
|
+
}
|
|
1026
|
+
return new VertexFormat(attributes, offset);
|
|
1027
|
+
}
|
|
1028
|
+
async function createMaterial(asset, material, getTexture, options = {}, renderStateOverrides = []) {
|
|
1029
|
+
const renderState = renderStateForGLTFMaterial(material, renderStateOverrides);
|
|
1030
|
+
if (options.skinned && !material.unlit) {
|
|
1031
|
+
const baseColorTexture = material.baseColorTexture
|
|
1032
|
+
? await createTextureBinding(asset, material.baseColorTexture, "srgb", getTexture, "u_baseColorTexture")
|
|
1033
|
+
: undefined;
|
|
1034
|
+
const normalTexture = material.normalTexture
|
|
1035
|
+
? await createTextureBinding(asset, material.normalTexture, "linear", getTexture, "u_normalTexture", createNormalSampler(asset, material))
|
|
1036
|
+
: undefined;
|
|
1037
|
+
const metallicRoughnessTexture = material.metallicRoughnessTexture
|
|
1038
|
+
? await createTextureBinding(asset, material.metallicRoughnessTexture, "linear", getTexture, "u_metallicRoughnessTexture")
|
|
1039
|
+
: undefined;
|
|
1040
|
+
const occlusionTexture = material.occlusionTexture
|
|
1041
|
+
? await createTextureBinding(asset, material.occlusionTexture, "linear", getTexture, "u_occlusionTexture")
|
|
1042
|
+
: undefined;
|
|
1043
|
+
const emissiveTexture = material.emissiveTexture
|
|
1044
|
+
? await createTextureBinding(asset, material.emissiveTexture, "srgb", getTexture, "u_emissiveTexture")
|
|
1045
|
+
: undefined;
|
|
1046
|
+
const runtimeMaterial = new SkinnedLitMaterial({
|
|
1047
|
+
name: material.name,
|
|
1048
|
+
renderState,
|
|
1049
|
+
baseColor: material.baseColorFactor,
|
|
1050
|
+
baseColorTexture,
|
|
1051
|
+
baseColorTextureOffset: material.baseColorTexture?.transform?.offset,
|
|
1052
|
+
baseColorTextureScale: material.baseColorTexture?.transform?.scale,
|
|
1053
|
+
baseColorTextureRotation: material.baseColorTexture?.transform?.rotation,
|
|
1054
|
+
normalTexture,
|
|
1055
|
+
normalScale: renderNormalScale(asset, material),
|
|
1056
|
+
metallicRoughnessTexture,
|
|
1057
|
+
occlusionTexture,
|
|
1058
|
+
occlusionStrength: material.occlusionTexture?.strength,
|
|
1059
|
+
emissiveTexture,
|
|
1060
|
+
metallic: material.metallicFactor,
|
|
1061
|
+
roughness: material.roughnessFactor,
|
|
1062
|
+
emissiveColor: material.emissiveFactor,
|
|
1063
|
+
emissiveStrength: material.emissiveStrength,
|
|
1064
|
+
...pbrExtensionScalarOptions(material)
|
|
1065
|
+
});
|
|
1066
|
+
applyAlphaCutoff(runtimeMaterial, material);
|
|
1067
|
+
await applyPBRExtensionParameters(asset, runtimeMaterial, material, getTexture);
|
|
1068
|
+
return runtimeMaterial;
|
|
1069
|
+
}
|
|
1070
|
+
if (options.instanced && material.unlit && !material.baseColorTexture) {
|
|
1071
|
+
const runtimeMaterial = new InstancedUnlitMaterial({
|
|
1072
|
+
name: material.name,
|
|
1073
|
+
color: material.baseColorFactor,
|
|
1074
|
+
renderState
|
|
1075
|
+
});
|
|
1076
|
+
applyAlphaCutoff(runtimeMaterial, material);
|
|
1077
|
+
await applyPBRExtensionParameters(asset, runtimeMaterial, material, getTexture);
|
|
1078
|
+
return runtimeMaterial;
|
|
1079
|
+
}
|
|
1080
|
+
if (material.unlit) {
|
|
1081
|
+
if (material.baseColorTexture) {
|
|
1082
|
+
const texture = await getTexture(material.baseColorTexture, "srgb");
|
|
1083
|
+
const runtimeMaterial = new TexturedUnlitMaterial({
|
|
1084
|
+
name: material.name,
|
|
1085
|
+
texture,
|
|
1086
|
+
sampler: createSampler(asset.textures[material.baseColorTexture.texture]),
|
|
1087
|
+
textureTransform: material.baseColorTexture.transform,
|
|
1088
|
+
color: material.baseColorFactor,
|
|
1089
|
+
renderState
|
|
1090
|
+
});
|
|
1091
|
+
applyAlphaCutoff(runtimeMaterial, material);
|
|
1092
|
+
await applyPBRExtensionParameters(asset, runtimeMaterial, material, getTexture);
|
|
1093
|
+
return runtimeMaterial;
|
|
1094
|
+
}
|
|
1095
|
+
const runtimeMaterial = new UnlitMaterial({
|
|
1096
|
+
name: material.name,
|
|
1097
|
+
color: material.baseColorFactor,
|
|
1098
|
+
renderState
|
|
1099
|
+
});
|
|
1100
|
+
applyAlphaCutoff(runtimeMaterial, material);
|
|
1101
|
+
await applyPBRExtensionParameters(asset, runtimeMaterial, material, getTexture);
|
|
1102
|
+
return runtimeMaterial;
|
|
1103
|
+
}
|
|
1104
|
+
if (options.instanced && !requiresTexturedPBRMaterial(material) && !material.baseColorTexture) {
|
|
1105
|
+
const runtimeMaterial = new InstancedPBRMaterial({
|
|
1106
|
+
name: material.name,
|
|
1107
|
+
renderState,
|
|
1108
|
+
baseColor: material.baseColorFactor,
|
|
1109
|
+
metallic: material.metallicFactor,
|
|
1110
|
+
roughness: material.roughnessFactor,
|
|
1111
|
+
emissiveColor: material.emissiveFactor,
|
|
1112
|
+
emissiveStrength: material.emissiveStrength
|
|
1113
|
+
});
|
|
1114
|
+
applyAlphaCutoff(runtimeMaterial, material);
|
|
1115
|
+
await applyPBRExtensionParameters(asset, runtimeMaterial, material, getTexture);
|
|
1116
|
+
return runtimeMaterial;
|
|
1117
|
+
}
|
|
1118
|
+
if (requiresTexturedPBRMaterial(material)) {
|
|
1119
|
+
const baseColorTexture = material.baseColorTexture ? await getTexture(material.baseColorTexture, "srgb") : undefined;
|
|
1120
|
+
const normalTexture = material.normalTexture ? await getTexture(material.normalTexture, "linear") : undefined;
|
|
1121
|
+
const metallicRoughnessTexture = material.metallicRoughnessTexture ? await getTexture(material.metallicRoughnessTexture, "linear") : undefined;
|
|
1122
|
+
const occlusionTexture = material.occlusionTexture ? await getTexture(material.occlusionTexture, "linear") : undefined;
|
|
1123
|
+
const emissiveTexture = material.emissiveTexture ? await getTexture(material.emissiveTexture, "srgb") : undefined;
|
|
1124
|
+
const extensionTextureOptions = await pbrExtensionTextureOptions(asset, material, getTexture);
|
|
1125
|
+
const runtimeMaterial = new TexturedPBRMaterial({
|
|
1126
|
+
name: material.name,
|
|
1127
|
+
renderState,
|
|
1128
|
+
baseColor: renderPbrBaseColorFactor(material),
|
|
1129
|
+
metallic: material.metallicFactor,
|
|
1130
|
+
roughness: renderPbrRoughnessFactor(material),
|
|
1131
|
+
emissiveColor: material.emissiveFactor,
|
|
1132
|
+
emissiveStrength: material.emissiveStrength,
|
|
1133
|
+
textureTexCoords: pbrTextureTexCoords(material),
|
|
1134
|
+
...pbrExtensionScalarOptions(material),
|
|
1135
|
+
...extensionTextureOptions,
|
|
1136
|
+
baseColorTexture,
|
|
1137
|
+
baseColorSampler: createSampler(material.baseColorTexture ? asset.textures[material.baseColorTexture.texture] : undefined),
|
|
1138
|
+
baseColorTextureTransform: material.baseColorTexture?.transform,
|
|
1139
|
+
normalTexture,
|
|
1140
|
+
normalSampler: createNormalSampler(asset, material),
|
|
1141
|
+
normalTextureTransform: material.normalTexture?.transform,
|
|
1142
|
+
normalScale: renderNormalScale(asset, material),
|
|
1143
|
+
metallicRoughnessTexture,
|
|
1144
|
+
metallicRoughnessSampler: createSampler(material.metallicRoughnessTexture ? asset.textures[material.metallicRoughnessTexture.texture] : undefined),
|
|
1145
|
+
metallicRoughnessTextureTransform: material.metallicRoughnessTexture?.transform,
|
|
1146
|
+
occlusionTexture,
|
|
1147
|
+
occlusionSampler: createSampler(material.occlusionTexture ? asset.textures[material.occlusionTexture.texture] : undefined),
|
|
1148
|
+
occlusionTextureTransform: material.occlusionTexture?.transform,
|
|
1149
|
+
occlusionStrength: material.occlusionTexture?.strength,
|
|
1150
|
+
emissiveTexture,
|
|
1151
|
+
emissiveSampler: createSampler(material.emissiveTexture ? asset.textures[material.emissiveTexture.texture] : undefined),
|
|
1152
|
+
emissiveTextureTransform: material.emissiveTexture?.transform
|
|
1153
|
+
});
|
|
1154
|
+
applyAlphaCutoff(runtimeMaterial, material);
|
|
1155
|
+
await applyPBRExtensionParameters(asset, runtimeMaterial, material, getTexture);
|
|
1156
|
+
return runtimeMaterial;
|
|
1157
|
+
}
|
|
1158
|
+
if (material.baseColorTexture) {
|
|
1159
|
+
const texture = await getTexture(material.baseColorTexture, "srgb");
|
|
1160
|
+
const runtimeMaterial = new TexturedUnlitMaterial({
|
|
1161
|
+
name: material.name,
|
|
1162
|
+
texture,
|
|
1163
|
+
sampler: createSampler(asset.textures[material.baseColorTexture.texture]),
|
|
1164
|
+
textureTransform: material.baseColorTexture.transform,
|
|
1165
|
+
color: material.baseColorFactor,
|
|
1166
|
+
renderState
|
|
1167
|
+
});
|
|
1168
|
+
applyAlphaCutoff(runtimeMaterial, material);
|
|
1169
|
+
await applyPBRExtensionParameters(asset, runtimeMaterial, material, getTexture);
|
|
1170
|
+
return runtimeMaterial;
|
|
1171
|
+
}
|
|
1172
|
+
const runtimeMaterial = new PBRMaterial({
|
|
1173
|
+
name: material.name,
|
|
1174
|
+
renderState,
|
|
1175
|
+
baseColor: renderPbrBaseColorFactor(material),
|
|
1176
|
+
metallic: material.metallicFactor,
|
|
1177
|
+
roughness: renderPbrRoughnessFactor(material),
|
|
1178
|
+
emissiveColor: material.emissiveFactor,
|
|
1179
|
+
emissiveStrength: material.emissiveStrength,
|
|
1180
|
+
...pbrExtensionScalarOptions(material)
|
|
1181
|
+
});
|
|
1182
|
+
applyAlphaCutoff(runtimeMaterial, material);
|
|
1183
|
+
await applyPBRExtensionParameters(asset, runtimeMaterial, material, getTexture);
|
|
1184
|
+
return runtimeMaterial;
|
|
1185
|
+
}
|
|
1186
|
+
function createDefaultGLTFMaterial(mesh, options = {}) {
|
|
1187
|
+
const defaults = { name: mesh.material, metallic: 0, roughness: 1, environmentIntensity: DEFAULT_PBR_ENVIRONMENT_INTENSITY };
|
|
1188
|
+
if (options.skinned) {
|
|
1189
|
+
return new SkinnedLitMaterial(defaults);
|
|
1190
|
+
}
|
|
1191
|
+
if (options.instanced) {
|
|
1192
|
+
return new InstancedPBRMaterial(defaults);
|
|
1193
|
+
}
|
|
1194
|
+
return new PBRMaterial(defaults);
|
|
1195
|
+
}
|
|
1196
|
+
function renderStateForGLTFMaterial(material, overrides = []) {
|
|
1197
|
+
const blend = requiresTransparentRenderState(material);
|
|
1198
|
+
const cullBack = usesUnbackedScalarTransmission(material) || usesOpaqueDoubleSidedClearcoatShell(material);
|
|
1199
|
+
const baseState = {
|
|
1200
|
+
cullMode: cullBack ? "back" : material.doubleSided ? "none" : "back",
|
|
1201
|
+
blend,
|
|
1202
|
+
depthWrite: !blend
|
|
1203
|
+
};
|
|
1204
|
+
const override = overrides.find((entry) => matchesTextOrPattern(material.name, entry.materialName));
|
|
1205
|
+
return override ? { ...baseState, ...override.renderState } : baseState;
|
|
1206
|
+
}
|
|
1207
|
+
function requiresTransparentRenderState(material) {
|
|
1208
|
+
if (material.alphaMode === "BLEND")
|
|
1209
|
+
return true;
|
|
1210
|
+
if (material.alphaMode !== "OPAQUE")
|
|
1211
|
+
return false;
|
|
1212
|
+
if (usesUnbackedScalarTransmission(material))
|
|
1213
|
+
return false;
|
|
1214
|
+
return (material.transmission?.factor ?? 0) > 0.001
|
|
1215
|
+
|| (material.diffuseTransmission?.factor ?? 0) > 0.001
|
|
1216
|
+
|| (material.volume?.thicknessFactor ?? 0) > 0.001
|
|
1217
|
+
|| material.volume?.thicknessTexture !== undefined;
|
|
1218
|
+
}
|
|
1219
|
+
function usesUnbackedScalarTransmission(material) {
|
|
1220
|
+
return material.alphaMode === "OPAQUE"
|
|
1221
|
+
&& (material.transmission?.factor ?? 0) > 0.001
|
|
1222
|
+
&& material.transmission?.texture === undefined
|
|
1223
|
+
&& material.diffuseTransmission === undefined
|
|
1224
|
+
&& material.volume === undefined;
|
|
1225
|
+
}
|
|
1226
|
+
function usesOpaqueDoubleSidedClearcoatShell(material) {
|
|
1227
|
+
return material.alphaMode === "OPAQUE"
|
|
1228
|
+
&& material.doubleSided
|
|
1229
|
+
&& (material.clearcoat?.factor ?? 0) > 0.001
|
|
1230
|
+
&& material.metallicFactor > 0.35
|
|
1231
|
+
&& material.roughnessFactor <= 0.42;
|
|
1232
|
+
}
|
|
1233
|
+
function renderPbrBaseColorFactor(material) {
|
|
1234
|
+
if (!usesUnbackedScalarTransmission(material))
|
|
1235
|
+
return material.baseColorFactor;
|
|
1236
|
+
const maxColor = Math.max(material.baseColorFactor[0], material.baseColorFactor[1], material.baseColorFactor[2]);
|
|
1237
|
+
if (maxColor < 0.8)
|
|
1238
|
+
return material.baseColorFactor;
|
|
1239
|
+
return [0.028, 0.036, 0.044, material.baseColorFactor[3]];
|
|
1240
|
+
}
|
|
1241
|
+
function renderPbrRoughnessFactor(material) {
|
|
1242
|
+
if (!usesUnbackedScalarTransmission(material))
|
|
1243
|
+
return material.roughnessFactor;
|
|
1244
|
+
return Math.max(material.roughnessFactor, 0.72);
|
|
1245
|
+
}
|
|
1246
|
+
function applyAlphaCutoff(runtimeMaterial, material) {
|
|
1247
|
+
runtimeMaterial.setParameter("u_alphaCutoff", material.alphaMode === "MASK" ? material.alphaCutoff : 0);
|
|
1248
|
+
}
|
|
1249
|
+
function renderNormalScale(asset, material) {
|
|
1250
|
+
return renderNormalMapScale(asset, material.normalTexture);
|
|
1251
|
+
}
|
|
1252
|
+
function createNormalSampler(asset, material) {
|
|
1253
|
+
const texture = material.normalTexture ? asset.textures[material.normalTexture.texture] : undefined;
|
|
1254
|
+
return createNormalMapSampler(texture);
|
|
1255
|
+
}
|
|
1256
|
+
function createNormalSamplerForInfo(asset, info) {
|
|
1257
|
+
const texture = info ? asset.textures[info.texture] : undefined;
|
|
1258
|
+
return createNormalMapSampler(texture);
|
|
1259
|
+
}
|
|
1260
|
+
function renderNormalMapScale(asset, info) {
|
|
1261
|
+
if (!info)
|
|
1262
|
+
return undefined;
|
|
1263
|
+
return info.scale;
|
|
1264
|
+
}
|
|
1265
|
+
function createNormalMapSampler(texture) {
|
|
1266
|
+
const sampler = createSampler(texture);
|
|
1267
|
+
if (!usesNearestSampler(texture))
|
|
1268
|
+
return sampler;
|
|
1269
|
+
return new Sampler({
|
|
1270
|
+
minFilter: "linear-mipmap-linear",
|
|
1271
|
+
magFilter: "linear",
|
|
1272
|
+
addressU: sampler.addressU,
|
|
1273
|
+
addressV: sampler.addressV,
|
|
1274
|
+
maxAnisotropy: sampler.maxAnisotropy
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
function usesNearestSampler(texture) {
|
|
1278
|
+
const sampler = createSampler(texture);
|
|
1279
|
+
return sampler.magFilter === "nearest" || sampler.minFilter.startsWith("nearest");
|
|
1280
|
+
}
|
|
1281
|
+
function pbrExtensionScalarOptions(material) {
|
|
1282
|
+
return {
|
|
1283
|
+
...(material.clearcoat ? {
|
|
1284
|
+
clearcoatFactor: material.clearcoat.factor,
|
|
1285
|
+
clearcoatRoughnessFactor: renderClearcoatRoughnessFactor(material)
|
|
1286
|
+
} : {}),
|
|
1287
|
+
...(material.transmission ? {
|
|
1288
|
+
transmissionFactor: usesUnbackedScalarTransmission(material) ? 0 : material.transmission.factor,
|
|
1289
|
+
transmissionFallbackEnergy: renderTransmissionFallbackEnergy(material)
|
|
1290
|
+
} : {}),
|
|
1291
|
+
...(material.diffuseTransmission ? {
|
|
1292
|
+
diffuseTransmissionFactor: material.diffuseTransmission.factor,
|
|
1293
|
+
diffuseTransmissionColorFactor: material.diffuseTransmission.colorFactor
|
|
1294
|
+
} : {}),
|
|
1295
|
+
...(material.volume ? {
|
|
1296
|
+
volumeThicknessFactor: material.volume.thicknessFactor,
|
|
1297
|
+
volumeAttenuationDistance: renderVolumeAttenuationDistance(material.volume.attenuationDistance),
|
|
1298
|
+
volumeAttenuationColor: material.volume.attenuationColor
|
|
1299
|
+
} : {}),
|
|
1300
|
+
...(material.ior !== undefined ? { ior: material.ior } : {}),
|
|
1301
|
+
...(material.specular ? {
|
|
1302
|
+
specularFactor: material.specular.factor,
|
|
1303
|
+
specularColorFactor: renderSpecularColorFactor(material.specular.colorFactor)
|
|
1304
|
+
} : {}),
|
|
1305
|
+
...(material.sheen ? {
|
|
1306
|
+
sheenColorFactor: material.sheen.colorFactor,
|
|
1307
|
+
sheenRoughnessFactor: material.sheen.roughnessFactor
|
|
1308
|
+
} : {}),
|
|
1309
|
+
...(material.anisotropy ? {
|
|
1310
|
+
anisotropyStrength: material.anisotropy.strength,
|
|
1311
|
+
anisotropyRotation: material.anisotropy.rotation
|
|
1312
|
+
} : {}),
|
|
1313
|
+
...(material.iridescence ? {
|
|
1314
|
+
iridescenceFactor: material.iridescence.factor,
|
|
1315
|
+
iridescenceIor: material.iridescence.ior,
|
|
1316
|
+
iridescenceThicknessMinimum: material.iridescence.thicknessMinimum,
|
|
1317
|
+
iridescenceThicknessMaximum: material.iridescence.thicknessMaximum
|
|
1318
|
+
} : {}),
|
|
1319
|
+
...(material.dispersion !== undefined ? {
|
|
1320
|
+
dispersion: material.dispersion
|
|
1321
|
+
} : {})
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
async function pbrExtensionTextureOptions(asset, material, getTexture) {
|
|
1325
|
+
const clearcoatTexture = material.clearcoat?.texture;
|
|
1326
|
+
const clearcoatRoughnessTexture = material.clearcoat?.roughnessTexture;
|
|
1327
|
+
const clearcoatNormalTexture = material.clearcoat?.normalTexture;
|
|
1328
|
+
const transmissionTexture = material.transmission?.texture;
|
|
1329
|
+
const diffuseTransmissionTexture = material.diffuseTransmission?.texture;
|
|
1330
|
+
const diffuseTransmissionColorTexture = material.diffuseTransmission?.colorTexture;
|
|
1331
|
+
const volumeThicknessTexture = material.volume?.thicknessTexture;
|
|
1332
|
+
const specularTexture = material.specular?.texture;
|
|
1333
|
+
const specularColorTexture = material.specular?.colorTexture;
|
|
1334
|
+
const sheenColorTexture = material.sheen?.colorTexture;
|
|
1335
|
+
const sheenRoughnessTexture = material.sheen?.roughnessTexture;
|
|
1336
|
+
const anisotropyTexture = material.anisotropy?.texture;
|
|
1337
|
+
const iridescenceTexture = material.iridescence?.texture;
|
|
1338
|
+
const iridescenceThicknessTexture = material.iridescence?.thicknessTexture;
|
|
1339
|
+
return {
|
|
1340
|
+
...(clearcoatTexture ? {
|
|
1341
|
+
clearcoatTexture: await getTexture(clearcoatTexture, "linear"),
|
|
1342
|
+
clearcoatSampler: createSamplerForInfo(asset, clearcoatTexture),
|
|
1343
|
+
clearcoatTextureTransform: clearcoatTexture.transform
|
|
1344
|
+
} : {}),
|
|
1345
|
+
...(clearcoatRoughnessTexture ? {
|
|
1346
|
+
clearcoatRoughnessTexture: await getTexture(clearcoatRoughnessTexture, "linear"),
|
|
1347
|
+
clearcoatRoughnessSampler: createSamplerForInfo(asset, clearcoatRoughnessTexture),
|
|
1348
|
+
clearcoatRoughnessTextureTransform: clearcoatRoughnessTexture.transform
|
|
1349
|
+
} : {}),
|
|
1350
|
+
...(clearcoatNormalTexture ? {
|
|
1351
|
+
clearcoatNormalTexture: await getTexture(clearcoatNormalTexture, "linear"),
|
|
1352
|
+
clearcoatNormalSampler: createNormalSamplerForInfo(asset, clearcoatNormalTexture),
|
|
1353
|
+
clearcoatNormalTextureTransform: clearcoatNormalTexture.transform,
|
|
1354
|
+
clearcoatNormalScale: renderNormalMapScale(asset, clearcoatNormalTexture)
|
|
1355
|
+
} : {}),
|
|
1356
|
+
...(transmissionTexture ? {
|
|
1357
|
+
transmissionTexture: await getTexture(transmissionTexture, "linear"),
|
|
1358
|
+
transmissionSampler: createSamplerForInfo(asset, transmissionTexture),
|
|
1359
|
+
transmissionTextureTransform: transmissionTexture.transform
|
|
1360
|
+
} : {}),
|
|
1361
|
+
...(diffuseTransmissionTexture ? {
|
|
1362
|
+
diffuseTransmissionTexture: await getTexture(diffuseTransmissionTexture, "linear"),
|
|
1363
|
+
diffuseTransmissionSampler: createSamplerForInfo(asset, diffuseTransmissionTexture),
|
|
1364
|
+
diffuseTransmissionTextureTransform: diffuseTransmissionTexture.transform
|
|
1365
|
+
} : {}),
|
|
1366
|
+
...(diffuseTransmissionColorTexture ? {
|
|
1367
|
+
diffuseTransmissionColorTexture: await getTexture(diffuseTransmissionColorTexture, "srgb"),
|
|
1368
|
+
diffuseTransmissionColorSampler: createSamplerForInfo(asset, diffuseTransmissionColorTexture),
|
|
1369
|
+
diffuseTransmissionColorTextureTransform: diffuseTransmissionColorTexture.transform
|
|
1370
|
+
} : {}),
|
|
1371
|
+
...(volumeThicknessTexture ? {
|
|
1372
|
+
volumeThicknessTexture: await getTexture(volumeThicknessTexture, "linear"),
|
|
1373
|
+
volumeThicknessSampler: createSamplerForInfo(asset, volumeThicknessTexture),
|
|
1374
|
+
volumeThicknessTextureTransform: volumeThicknessTexture.transform
|
|
1375
|
+
} : {}),
|
|
1376
|
+
...(specularTexture ? {
|
|
1377
|
+
specularTexture: await getTexture(specularTexture, "linear"),
|
|
1378
|
+
specularSampler: createSamplerForInfo(asset, specularTexture),
|
|
1379
|
+
specularTextureTransform: specularTexture.transform
|
|
1380
|
+
} : {}),
|
|
1381
|
+
...(specularColorTexture ? {
|
|
1382
|
+
specularColorTexture: await getTexture(specularColorTexture, "srgb"),
|
|
1383
|
+
specularColorSampler: createSamplerForInfo(asset, specularColorTexture),
|
|
1384
|
+
specularColorTextureTransform: specularColorTexture.transform
|
|
1385
|
+
} : {}),
|
|
1386
|
+
...(sheenColorTexture ? {
|
|
1387
|
+
sheenColorTexture: await getTexture(sheenColorTexture, "srgb"),
|
|
1388
|
+
sheenColorSampler: createSamplerForInfo(asset, sheenColorTexture),
|
|
1389
|
+
sheenColorTextureTransform: sheenColorTexture.transform
|
|
1390
|
+
} : {}),
|
|
1391
|
+
...(sheenRoughnessTexture ? {
|
|
1392
|
+
sheenRoughnessTexture: await getTexture(sheenRoughnessTexture, "linear"),
|
|
1393
|
+
sheenRoughnessSampler: createSamplerForInfo(asset, sheenRoughnessTexture),
|
|
1394
|
+
sheenRoughnessTextureTransform: sheenRoughnessTexture.transform
|
|
1395
|
+
} : {}),
|
|
1396
|
+
...(anisotropyTexture ? {
|
|
1397
|
+
anisotropyTexture: await getTexture(anisotropyTexture, "linear"),
|
|
1398
|
+
anisotropySampler: createSamplerForInfo(asset, anisotropyTexture),
|
|
1399
|
+
anisotropyTextureTransform: anisotropyTexture.transform
|
|
1400
|
+
} : {}),
|
|
1401
|
+
...(iridescenceTexture ? {
|
|
1402
|
+
iridescenceTexture: await getTexture(iridescenceTexture, "linear"),
|
|
1403
|
+
iridescenceSampler: createSamplerForInfo(asset, iridescenceTexture),
|
|
1404
|
+
iridescenceTextureTransform: iridescenceTexture.transform
|
|
1405
|
+
} : {}),
|
|
1406
|
+
...(iridescenceThicknessTexture ? {
|
|
1407
|
+
iridescenceThicknessTexture: await getTexture(iridescenceThicknessTexture, "linear"),
|
|
1408
|
+
iridescenceThicknessSampler: createSamplerForInfo(asset, iridescenceThicknessTexture),
|
|
1409
|
+
iridescenceThicknessTextureTransform: iridescenceThicknessTexture.transform
|
|
1410
|
+
} : {})
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
function renderTransmissionFallbackEnergy(material) {
|
|
1414
|
+
const usesUnbackedCutoutTransmission = material.alphaMode === "MASK" && material.transmission?.texture === undefined && material.volume === undefined;
|
|
1415
|
+
return usesUnbackedCutoutTransmission || usesUnbackedScalarTransmission(material) ? 0 : 0.08;
|
|
1416
|
+
}
|
|
1417
|
+
function pbrTextureTexCoords(material) {
|
|
1418
|
+
return {
|
|
1419
|
+
...(material.baseColorTexture ? { baseColor: renderTexCoord(material.baseColorTexture.texCoord) } : {}),
|
|
1420
|
+
...(material.normalTexture ? { normal: renderTexCoord(material.normalTexture.texCoord) } : {}),
|
|
1421
|
+
...(material.metallicRoughnessTexture ? { metallicRoughness: renderTexCoord(material.metallicRoughnessTexture.texCoord) } : {}),
|
|
1422
|
+
...(material.occlusionTexture ? { occlusion: renderTexCoord(material.occlusionTexture.texCoord) } : {}),
|
|
1423
|
+
...(material.emissiveTexture ? { emissive: renderTexCoord(material.emissiveTexture.texCoord) } : {}),
|
|
1424
|
+
...(material.clearcoat?.texture ? { clearcoat: renderTexCoord(material.clearcoat.texture.texCoord) } : {}),
|
|
1425
|
+
...(material.clearcoat?.roughnessTexture ? { clearcoatRoughness: renderTexCoord(material.clearcoat.roughnessTexture.texCoord) } : {}),
|
|
1426
|
+
...(material.clearcoat?.normalTexture ? { clearcoatNormal: renderTexCoord(material.clearcoat.normalTexture.texCoord) } : {}),
|
|
1427
|
+
...(material.transmission?.texture ? { transmission: renderTexCoord(material.transmission.texture.texCoord) } : {}),
|
|
1428
|
+
...(material.diffuseTransmission?.texture ? { diffuseTransmission: renderTexCoord(material.diffuseTransmission.texture.texCoord) } : {}),
|
|
1429
|
+
...(material.diffuseTransmission?.colorTexture ? { diffuseTransmissionColor: renderTexCoord(material.diffuseTransmission.colorTexture.texCoord) } : {}),
|
|
1430
|
+
...(material.volume?.thicknessTexture ? { volumeThickness: renderTexCoord(material.volume.thicknessTexture.texCoord) } : {}),
|
|
1431
|
+
...(material.specular?.texture ? { specular: renderTexCoord(material.specular.texture.texCoord) } : {}),
|
|
1432
|
+
...(material.specular?.colorTexture ? { specularColor: renderTexCoord(material.specular.colorTexture.texCoord) } : {}),
|
|
1433
|
+
...(material.sheen?.colorTexture ? { sheenColor: renderTexCoord(material.sheen.colorTexture.texCoord) } : {}),
|
|
1434
|
+
...(material.sheen?.roughnessTexture ? { sheenRoughness: renderTexCoord(material.sheen.roughnessTexture.texCoord) } : {}),
|
|
1435
|
+
...(material.anisotropy?.texture ? { anisotropy: renderTexCoord(material.anisotropy.texture.texCoord) } : {}),
|
|
1436
|
+
...(material.iridescence?.texture ? { iridescence: renderTexCoord(material.iridescence.texture.texCoord) } : {}),
|
|
1437
|
+
...(material.iridescence?.thicknessTexture ? { iridescenceThickness: renderTexCoord(material.iridescence.thicknessTexture.texCoord) } : {})
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
function renderTexCoord(texCoord) {
|
|
1441
|
+
return texCoord === 1 ? 1 : 0;
|
|
1442
|
+
}
|
|
1443
|
+
async function applyPBRExtensionParameters(asset, runtimeMaterial, material, getTexture) {
|
|
1444
|
+
if (material.clearcoat) {
|
|
1445
|
+
runtimeMaterial.setParameter("u_clearcoatFactor", material.clearcoat.factor);
|
|
1446
|
+
runtimeMaterial.setParameter("u_clearcoatRoughnessFactor", renderClearcoatRoughnessFactor(material));
|
|
1447
|
+
if (material.clearcoat.texture) {
|
|
1448
|
+
await setTextureParameter(asset, runtimeMaterial, "u_clearcoatTexture", material.clearcoat.texture, "linear", getTexture);
|
|
1449
|
+
}
|
|
1450
|
+
if (material.clearcoat.roughnessTexture) {
|
|
1451
|
+
await setTextureParameter(asset, runtimeMaterial, "u_clearcoatRoughnessTexture", material.clearcoat.roughnessTexture, "linear", getTexture);
|
|
1452
|
+
}
|
|
1453
|
+
if (material.clearcoat.normalTexture) {
|
|
1454
|
+
await setTextureParameter(asset, runtimeMaterial, "u_clearcoatNormalTexture", material.clearcoat.normalTexture, "linear", getTexture);
|
|
1455
|
+
runtimeMaterial.setParameter("u_clearcoatNormalScale", renderNormalMapScale(asset, material.clearcoat.normalTexture) ?? material.clearcoat.normalTexture.scale);
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
if (material.transmission) {
|
|
1459
|
+
runtimeMaterial.setParameter("u_transmissionFactor", usesUnbackedScalarTransmission(material) ? 0 : material.transmission.factor);
|
|
1460
|
+
if (material.transmission.texture) {
|
|
1461
|
+
await setTextureParameter(asset, runtimeMaterial, "u_transmissionTexture", material.transmission.texture, "linear", getTexture);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
if (material.diffuseTransmission) {
|
|
1465
|
+
runtimeMaterial.setParameter("u_diffuseTransmissionFactor", material.diffuseTransmission.factor);
|
|
1466
|
+
runtimeMaterial.setParameter("u_diffuseTransmissionColorFactor", material.diffuseTransmission.colorFactor);
|
|
1467
|
+
if (material.diffuseTransmission.texture) {
|
|
1468
|
+
await setTextureParameter(asset, runtimeMaterial, "u_diffuseTransmissionTexture", material.diffuseTransmission.texture, "linear", getTexture);
|
|
1469
|
+
}
|
|
1470
|
+
if (material.diffuseTransmission.colorTexture) {
|
|
1471
|
+
await setTextureParameter(asset, runtimeMaterial, "u_diffuseTransmissionColorTexture", material.diffuseTransmission.colorTexture, "srgb", getTexture);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
if (material.volume) {
|
|
1475
|
+
runtimeMaterial.setParameter("u_volumeThicknessFactor", material.volume.thicknessFactor);
|
|
1476
|
+
runtimeMaterial.setParameter("u_volumeAttenuationDistance", renderVolumeAttenuationDistance(material.volume.attenuationDistance));
|
|
1477
|
+
runtimeMaterial.setParameter("u_volumeAttenuationColor", material.volume.attenuationColor);
|
|
1478
|
+
if (material.volume.thicknessTexture) {
|
|
1479
|
+
await setTextureParameter(asset, runtimeMaterial, "u_volumeThicknessTexture", material.volume.thicknessTexture, "linear", getTexture);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
if (material.ior !== undefined) {
|
|
1483
|
+
runtimeMaterial.setParameter("u_ior", material.ior);
|
|
1484
|
+
}
|
|
1485
|
+
if (material.specular) {
|
|
1486
|
+
runtimeMaterial.setParameter("u_specularFactor", material.specular.factor);
|
|
1487
|
+
runtimeMaterial.setParameter("u_specularColorFactor", renderSpecularColorFactor(material.specular.colorFactor));
|
|
1488
|
+
if (material.specular.texture) {
|
|
1489
|
+
await setTextureParameter(asset, runtimeMaterial, "u_specularTexture", material.specular.texture, "linear", getTexture);
|
|
1490
|
+
}
|
|
1491
|
+
if (material.specular.colorTexture) {
|
|
1492
|
+
await setTextureParameter(asset, runtimeMaterial, "u_specularColorTexture", material.specular.colorTexture, "srgb", getTexture);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
if (material.sheen) {
|
|
1496
|
+
runtimeMaterial.setParameter("u_sheenColorFactor", material.sheen.colorFactor);
|
|
1497
|
+
runtimeMaterial.setParameter("u_sheenRoughnessFactor", material.sheen.roughnessFactor);
|
|
1498
|
+
if (material.sheen.colorTexture) {
|
|
1499
|
+
await setTextureParameter(asset, runtimeMaterial, "u_sheenColorTexture", material.sheen.colorTexture, "srgb", getTexture);
|
|
1500
|
+
}
|
|
1501
|
+
if (material.sheen.roughnessTexture) {
|
|
1502
|
+
await setTextureParameter(asset, runtimeMaterial, "u_sheenRoughnessTexture", material.sheen.roughnessTexture, "linear", getTexture);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
if (material.anisotropy) {
|
|
1506
|
+
runtimeMaterial.setParameter("u_anisotropyStrength", material.anisotropy.strength);
|
|
1507
|
+
runtimeMaterial.setParameter("u_anisotropyRotation", material.anisotropy.rotation);
|
|
1508
|
+
if (material.anisotropy.texture) {
|
|
1509
|
+
await setTextureParameter(asset, runtimeMaterial, "u_anisotropyTexture", material.anisotropy.texture, "linear", getTexture);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
if (material.iridescence) {
|
|
1513
|
+
runtimeMaterial.setParameter("u_iridescenceFactor", material.iridescence.factor);
|
|
1514
|
+
runtimeMaterial.setParameter("u_iridescenceIor", material.iridescence.ior);
|
|
1515
|
+
runtimeMaterial.setParameter("u_iridescenceThicknessMinimum", material.iridescence.thicknessMinimum);
|
|
1516
|
+
runtimeMaterial.setParameter("u_iridescenceThicknessMaximum", material.iridescence.thicknessMaximum);
|
|
1517
|
+
if (material.iridescence.texture) {
|
|
1518
|
+
await setTextureParameter(asset, runtimeMaterial, "u_iridescenceTexture", material.iridescence.texture, "linear", getTexture);
|
|
1519
|
+
}
|
|
1520
|
+
if (material.iridescence.thicknessTexture) {
|
|
1521
|
+
await setTextureParameter(asset, runtimeMaterial, "u_iridescenceThicknessTexture", material.iridescence.thicknessTexture, "linear", getTexture);
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
if (material.dispersion !== undefined) {
|
|
1525
|
+
runtimeMaterial.setParameter("u_dispersion", material.dispersion);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
function renderClearcoatRoughnessFactor(material) {
|
|
1529
|
+
return material.clearcoat?.roughnessFactor ?? 0;
|
|
1530
|
+
}
|
|
1531
|
+
async function setTextureParameter(asset, runtimeMaterial, uniformName, info, colorSpace, getTexture, sampler) {
|
|
1532
|
+
runtimeMaterial.setParameter(uniformName, await createTextureBinding(asset, info, colorSpace, getTexture, uniformName, sampler));
|
|
1533
|
+
runtimeMaterial.setParameter(`${uniformName}Offset`, info.transform?.offset ?? [0, 0]);
|
|
1534
|
+
runtimeMaterial.setParameter(`${uniformName}Scale`, info.transform?.scale ?? [1, 1]);
|
|
1535
|
+
runtimeMaterial.setParameter(`${uniformName}Rotation`, info.transform?.rotation ?? 0);
|
|
1536
|
+
runtimeMaterial.setParameter(`${uniformName}TexCoord`, renderTexCoord(info.texCoord));
|
|
1537
|
+
}
|
|
1538
|
+
async function createTextureBinding(asset, info, colorSpace, getTexture, uniformName = `gltf-texture-${info.texture}`, sampler) {
|
|
1539
|
+
return new TextureBinding({
|
|
1540
|
+
name: uniformName,
|
|
1541
|
+
texture: await getTexture(info, colorSpace),
|
|
1542
|
+
sampler: sampler ?? createSampler(asset.textures[info.texture]),
|
|
1543
|
+
required: true,
|
|
1544
|
+
expectedColorSpace: colorSpace,
|
|
1545
|
+
transform: info.transform
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
function requiresTexturedPBRMaterial(material) {
|
|
1549
|
+
return Boolean(material.baseColorTexture ||
|
|
1550
|
+
material.normalTexture ||
|
|
1551
|
+
material.metallicRoughnessTexture ||
|
|
1552
|
+
material.occlusionTexture ||
|
|
1553
|
+
material.emissiveTexture ||
|
|
1554
|
+
material.clearcoat?.texture ||
|
|
1555
|
+
material.clearcoat?.roughnessTexture ||
|
|
1556
|
+
material.clearcoat?.normalTexture ||
|
|
1557
|
+
material.transmission?.texture ||
|
|
1558
|
+
material.diffuseTransmission?.texture ||
|
|
1559
|
+
material.diffuseTransmission?.colorTexture ||
|
|
1560
|
+
material.volume?.thicknessTexture ||
|
|
1561
|
+
material.specular?.texture ||
|
|
1562
|
+
material.specular?.colorTexture ||
|
|
1563
|
+
material.sheen?.colorTexture ||
|
|
1564
|
+
material.sheen?.roughnessTexture ||
|
|
1565
|
+
material.anisotropy?.texture ||
|
|
1566
|
+
material.iridescence?.texture ||
|
|
1567
|
+
material.iridescence?.thicknessTexture);
|
|
1568
|
+
}
|
|
1569
|
+
function renderVolumeAttenuationDistance(distance) {
|
|
1570
|
+
return distance === Number.POSITIVE_INFINITY ? 1_000_000 : distance;
|
|
1571
|
+
}
|
|
1572
|
+
function renderSpecularColorFactor(value) {
|
|
1573
|
+
return [clampNonNegative(value[0]), clampNonNegative(value[1]), clampNonNegative(value[2])];
|
|
1574
|
+
}
|
|
1575
|
+
function clampUnit(value) {
|
|
1576
|
+
return Math.max(0, Math.min(1, value));
|
|
1577
|
+
}
|
|
1578
|
+
function clampNonNegative(value) {
|
|
1579
|
+
return Math.max(0, value);
|
|
1580
|
+
}
|
|
1581
|
+
function textureCacheKey(imageIndex, colorSpace) {
|
|
1582
|
+
return `${imageIndex}:${colorSpace}`;
|
|
1583
|
+
}
|
|
1584
|
+
function setTextureLibraryEntry(textureLibrary, textureName, colorSpace, texture) {
|
|
1585
|
+
const existing = textureLibrary.get(textureName);
|
|
1586
|
+
if (!existing) {
|
|
1587
|
+
textureLibrary.set(textureName, texture);
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
if (existing === texture)
|
|
1591
|
+
return;
|
|
1592
|
+
const keyedName = textureLibraryKey(textureLibrary, textureName, colorSpace);
|
|
1593
|
+
if (textureLibrary.get(keyedName) !== texture) {
|
|
1594
|
+
textureLibrary.set(keyedName, texture);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
function textureLibraryKey(textureLibrary, textureName, colorSpace) {
|
|
1598
|
+
if (!textureLibrary.has(textureName))
|
|
1599
|
+
return textureName;
|
|
1600
|
+
return `${textureName}:${colorSpace}`;
|
|
1601
|
+
}
|
|
1602
|
+
function createSampler(texture) {
|
|
1603
|
+
const descriptor = texture?.samplerDescriptor;
|
|
1604
|
+
const samplerDescriptor = descriptor
|
|
1605
|
+
? {
|
|
1606
|
+
minFilter: descriptor.minFilter,
|
|
1607
|
+
magFilter: descriptor.magFilter,
|
|
1608
|
+
addressU: descriptor.addressU,
|
|
1609
|
+
addressV: descriptor.addressV,
|
|
1610
|
+
maxAnisotropy: 8
|
|
1611
|
+
}
|
|
1612
|
+
: {
|
|
1613
|
+
minFilter: "linear-mipmap-linear",
|
|
1614
|
+
magFilter: "linear",
|
|
1615
|
+
addressU: "repeat",
|
|
1616
|
+
addressV: "repeat",
|
|
1617
|
+
maxAnisotropy: 8
|
|
1618
|
+
};
|
|
1619
|
+
return new Sampler(samplerDescriptor);
|
|
1620
|
+
}
|
|
1621
|
+
async function decodeImageInBrowser(image, _imageIndex, asset, options = {}) {
|
|
1622
|
+
if (isKTX2BasisImage(image)) {
|
|
1623
|
+
const bytes = await readImageBytes(asset, image);
|
|
1624
|
+
return transcodeKTX2BasisTexture(bytes, {
|
|
1625
|
+
...options.ktx2BasisTranscoderOptions,
|
|
1626
|
+
targetFormat: options.ktx2BasisTargetFormat ?? options.ktx2BasisTranscoderOptions?.targetFormat
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
if (typeof createImageBitmap === "function") {
|
|
1630
|
+
const blob = image.data
|
|
1631
|
+
? new Blob([image.data], { type: image.mimeType ?? "application/octet-stream" })
|
|
1632
|
+
: await fetchImageBlob(asset, image);
|
|
1633
|
+
const bitmap = await createImageBitmap(blob, {
|
|
1634
|
+
colorSpaceConversion: "none",
|
|
1635
|
+
premultiplyAlpha: "none"
|
|
1636
|
+
});
|
|
1637
|
+
return { width: bitmap.width, height: bitmap.height, source: bitmap, colorSpace: "srgb" };
|
|
1638
|
+
}
|
|
1639
|
+
const ImageCtor = globalThis.Image;
|
|
1640
|
+
if (!ImageCtor || !image.uri) {
|
|
1641
|
+
throw new Error("glTF image decoding requires createImageBitmap, HTMLImageElement, or a custom imageDecoder");
|
|
1642
|
+
}
|
|
1643
|
+
const imageElement = new ImageCtor();
|
|
1644
|
+
const url = resolveImageUrl(asset.url, image.uri);
|
|
1645
|
+
return new Promise((resolve, reject) => {
|
|
1646
|
+
imageElement.onload = () => resolve({ width: imageElement.width, height: imageElement.height, source: imageElement, colorSpace: "srgb" });
|
|
1647
|
+
imageElement.onerror = () => reject(new Error(`glTF image decode failed for ${url}`));
|
|
1648
|
+
imageElement.src = url;
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
function createSamplerForInfo(asset, info) {
|
|
1652
|
+
return createSampler(asset.textures[info.texture]);
|
|
1653
|
+
}
|
|
1654
|
+
async function readImageBytes(asset, image) {
|
|
1655
|
+
if (image.data)
|
|
1656
|
+
return image.data.slice(0);
|
|
1657
|
+
const blob = await fetchImageBlob(asset, image);
|
|
1658
|
+
return blob.arrayBuffer();
|
|
1659
|
+
}
|
|
1660
|
+
async function fetchImageBlob(asset, image) {
|
|
1661
|
+
if (!image.uri) {
|
|
1662
|
+
throw new Error("glTF image has no uri or embedded data");
|
|
1663
|
+
}
|
|
1664
|
+
if (typeof fetch !== "function") {
|
|
1665
|
+
throw new Error("glTF image fetch requires fetch or a custom imageDecoder");
|
|
1666
|
+
}
|
|
1667
|
+
const response = await fetch(resolveImageUrl(asset.url, image.uri));
|
|
1668
|
+
if (!response.ok) {
|
|
1669
|
+
throw new Error(`glTF image request failed with ${response.status}`);
|
|
1670
|
+
}
|
|
1671
|
+
return response.blob();
|
|
1672
|
+
}
|
|
1673
|
+
function isKTX2BasisImage(image) {
|
|
1674
|
+
return image.mimeType === "image/ktx2" || /\.ktx2(?:[?#]|$)/i.test(image.uri ?? "");
|
|
1675
|
+
}
|
|
1676
|
+
function resolveImageUrl(assetUrl, imageUri) {
|
|
1677
|
+
if (/^(?:data:|blob:|https?:|file:)/i.test(imageUri))
|
|
1678
|
+
return imageUri;
|
|
1679
|
+
if (assetUrl.startsWith("data:")) {
|
|
1680
|
+
throw new Error(`Relative glTF image uri ${imageUri} cannot be resolved from a data URL asset`);
|
|
1681
|
+
}
|
|
1682
|
+
return new URL(imageUri, assetUrl).toString();
|
|
1683
|
+
}
|
|
1684
|
+
//# sourceMappingURL=GLTFRenderResources.js.map
|