@babylonjs/lite 1.11.0 → 1.13.0

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.
Files changed (105) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/index.js +444 -368
  3. package/dist/index.js.map +1 -1
  4. package/index.d.ts +208 -6
  5. package/lib/asset-container.js.map +1 -1
  6. package/lib/audio/index.js +1 -0
  7. package/lib/audio/index.js.map +1 -1
  8. package/lib/audio/media-stream-output.js +44 -0
  9. package/lib/audio/media-stream-output.js.map +1 -0
  10. package/lib/engine/engine.js +1 -1
  11. package/lib/frame-graph/render-task.js +1 -1
  12. package/lib/frame-graph/render-task.js.map +1 -1
  13. package/lib/frame-graph/shadow-inputs.js +10 -1
  14. package/lib/frame-graph/shadow-inputs.js.map +1 -1
  15. package/lib/frame-graph/transmission.js +1 -16
  16. package/lib/frame-graph/transmission.js.map +1 -1
  17. package/lib/index.js +6 -3
  18. package/lib/index.js.map +1 -1
  19. package/lib/loader-gltf/gltf-json-asset.js +1 -1
  20. package/lib/loader-gltf/gltf-json-asset.js.map +1 -1
  21. package/lib/loader-gltf/gltf-multi-buffer.js +2 -10
  22. package/lib/loader-gltf/gltf-multi-buffer.js.map +1 -1
  23. package/lib/loader-gltf/gltf-pbr-builder-ext.js +4 -18
  24. package/lib/loader-gltf/gltf-pbr-builder-ext.js.map +1 -1
  25. package/lib/loader-gltf/gltf-pbr-builder.js +17 -14
  26. package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
  27. package/lib/loader-gltf/gltf-sampler-desc.js +3 -16
  28. package/lib/loader-gltf/gltf-sampler-desc.js.map +1 -1
  29. package/lib/material/node/blocks/ambient-occlusion-block.js +1 -4
  30. package/lib/material/node/blocks/ambient-occlusion-block.js.map +1 -1
  31. package/lib/material/node/blocks/biplanar-block.js +3 -6
  32. package/lib/material/node/blocks/biplanar-block.js.map +1 -1
  33. package/lib/material/node/blocks/image-source.js +2 -5
  34. package/lib/material/node/blocks/image-source.js.map +1 -1
  35. package/lib/material/node/blocks/input-block.js +5 -26
  36. package/lib/material/node/blocks/input-block.js.map +1 -1
  37. package/lib/material/node/blocks/pbr-mr-helper-full.js +5 -8
  38. package/lib/material/node/blocks/pbr-mr-helper-full.js.map +1 -1
  39. package/lib/material/node/blocks/reflection-texture-block.js +1 -4
  40. package/lib/material/node/blocks/reflection-texture-block.js.map +1 -1
  41. package/lib/material/node/blocks/texture-block.js +2 -5
  42. package/lib/material/node/blocks/texture-block.js.map +1 -1
  43. package/lib/material/node/blocks/triplanar-block.js +3 -6
  44. package/lib/material/node/blocks/triplanar-block.js.map +1 -1
  45. package/lib/material/node/node-emitter.js +24 -1
  46. package/lib/material/node/node-emitter.js.map +1 -1
  47. package/lib/material/node/node-geometry-renderable.js +2 -2
  48. package/lib/material/node/node-material.js +1 -22
  49. package/lib/material/node/node-material.js.map +1 -1
  50. package/lib/material/node/node-types.js.map +1 -1
  51. package/lib/material/pbr/fragments/shadow-only-fragment.js +68 -0
  52. package/lib/material/pbr/fragments/shadow-only-fragment.js.map +1 -0
  53. package/lib/material/pbr/pbr-flag-bits.js.map +1 -1
  54. package/lib/material/pbr/pbr-material.js.map +1 -1
  55. package/lib/material/pbr/pbr-primitive-resolver.js +2 -2
  56. package/lib/material/pbr/pbr-primitive-resolver.js.map +1 -1
  57. package/lib/material/pbr/pbr-renderable.js +3 -0
  58. package/lib/material/pbr/pbr-renderable.js.map +1 -1
  59. package/lib/material/pbr/pbr-template.js +1 -0
  60. package/lib/material/pbr/pbr-template.js.map +1 -1
  61. package/lib/mesh/GaussianSplatting/gaussian-splatting-mesh.js +2 -8
  62. package/lib/mesh/GaussianSplatting/gaussian-splatting-mesh.js.map +1 -1
  63. package/lib/mesh/get-mesh-geometry.js +24 -0
  64. package/lib/mesh/get-mesh-geometry.js.map +1 -0
  65. package/lib/mesh/mesh-dispose.js +2 -0
  66. package/lib/mesh/mesh-dispose.js.map +1 -1
  67. package/lib/mesh/mesh.js +2 -8
  68. package/lib/mesh/mesh.js.map +1 -1
  69. package/lib/mesh/thin-instance-cull-binding.js +54 -3
  70. package/lib/mesh/thin-instance-cull-binding.js.map +1 -1
  71. package/lib/mesh/thin-instance-gpu-culling.js +241 -24
  72. package/lib/mesh/thin-instance-gpu-culling.js.map +1 -1
  73. package/lib/mesh/thin-instance.js +112 -1
  74. package/lib/mesh/thin-instance.js.map +1 -1
  75. package/lib/picking/gpu-picker.js +4 -2
  76. package/lib/picking/gpu-picker.js.map +1 -1
  77. package/lib/picking/picking-pipeline.js +1 -1
  78. package/lib/picking/picking-pipeline.js.map +1 -1
  79. package/lib/picking/picking-shader.js +38 -16
  80. package/lib/picking/picking-shader.js.map +1 -1
  81. package/lib/scene/scene-core.js +7 -2
  82. package/lib/scene/scene-core.js.map +1 -1
  83. package/lib/scene/scene-node.js +2 -6
  84. package/lib/scene/scene-node.js.map +1 -1
  85. package/lib/scene/scene-remove.js +70 -1
  86. package/lib/scene/scene-remove.js.map +1 -1
  87. package/lib/scene/transform-node.js +3 -0
  88. package/lib/scene/transform-node.js.map +1 -1
  89. package/lib/scene/world-matrix-state.js +7 -1
  90. package/lib/scene/world-matrix-state.js.map +1 -1
  91. package/lib/shadow/csm-directional-shadow-generator.js +22 -1
  92. package/lib/shadow/csm-directional-shadow-generator.js.map +1 -1
  93. package/lib/shadow/csm-shadow-task-hooks.js +19 -11
  94. package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
  95. package/lib/shadow/esm-directional-shadow-generator.js +2 -51
  96. package/lib/shadow/esm-directional-shadow-generator.js.map +1 -1
  97. package/lib/shadow/pcf-directional-shadow-generator.js +2 -48
  98. package/lib/shadow/pcf-directional-shadow-generator.js.map +1 -1
  99. package/lib/shadow/shadow-base.js +48 -1
  100. package/lib/shadow/shadow-base.js.map +1 -1
  101. package/lib/text/text-renderable.js +2 -10
  102. package/lib/text/text-renderable.js.map +1 -1
  103. package/lib/texture/texture-array.js +96 -0
  104. package/lib/texture/texture-array.js.map +1 -0
  105. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"pbr-material.js","sources":["../../../../src/material/pbr/pbr-material.ts"],"sourcesContent":["/** PBR Material — user-facing props + factory.\n *\n * Same role as StandardMaterialProps for the standard pipeline.\n * Users can create a PbrMaterialProps manually or let loadGltf() build one. */\n\nimport type { Texture2D } from \"../../texture/texture-2d.js\";\nimport type { MeshGroupBuilder } from \"../../render/renderable.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { Material, StencilState } from \"../material.js\";\nimport type { MaterialPlugin } from \"../plugin/material-plugin.js\";\nimport { createSolidTexture2D } from \"../../texture/solid-texture.js\";\nimport { _installPbrFallbackResolver } from \"./pbr-pipeline.js\";\nimport {\n _getPbrExts,\n PBR2_HAS_BASE_COLOR_FACTOR,\n PBR2_HAS_UV_TRANSFORM,\n PBR2_HAS_UV2,\n PBR_HAS_ALPHA_TEST,\n PBR_HAS_ALPHA_BLEND,\n PBR_HAS_ANISOTROPY,\n PBR_HAS_DOUBLE_SIDED,\n PBR_HAS_EMISSIVE,\n PBR_HAS_EMISSIVE_COLOR,\n PBR_HAS_GAMMA_ALBEDO,\n PBR_HAS_NORMAL_MAP,\n PBR_HAS_OCCLUSION,\n PBR_HAS_SKYBOX,\n PBR_HAS_SPECULAR_AA,\n PBR_HAS_SPEC_GLOSS,\n} from \"./pbr-flags.js\";\n\n/** Lazily-created singleton PBR {@link MeshGroupBuilder}. Lazy-imports the PBR\n * renderable builder and builds the pipeline. Thin instances are handled by the\n * fragment composer automatically. Lazy-init keeps the module free of top-level\n * side effects so a scene that uses no PBR material tree-shakes it away. */\nlet _pbrGroupBuilder: MeshGroupBuilder | null = null;\nexport function getPbrGroupBuilder(): MeshGroupBuilder {\n if (_pbrGroupBuilder) {\n return _pbrGroupBuilder;\n }\n const builder: MeshGroupBuilder = async (scene, meshes) => {\n const envTex = (scene as SceneContext)._envTextures;\n const renderableMod = await import(\"./pbr-renderable.js\");\n const result = await renderableMod.buildPbrRenderables(scene, meshes, envTex);\n // Wire the per-mesh rebuild closure used by material swap + per-pass override.\n builder._rebuildSingle = result.rebuildSingle;\n return result;\n };\n builder._materialFamily = \"pbr\";\n return (_pbrGroupBuilder = builder);\n}\n\n/** User-facing properties for a physically based (metallic-roughness) material.\n * Create one manually via `createPbrMaterial()` or let `loadGltf()` build it.\n * Optional sub-feature objects (clearcoat, sheen, anisotropy, subsurface) are\n * only bundled when referenced. */\nexport interface PbrMaterialProps extends Material {\n /** Optional opt-in material plugins (custom WGSL + uniforms + samplers layered\n * on top of the built-in PBR pipeline). Attach via `material.plugins = [plugin]`,\n * then call `enableMaterialPlugins(scene)` before `registerScene`. */\n plugins?: MaterialPlugin[];\n baseColorTexture?: Texture2D;\n /** Linear RGB/A factor multiplied with the base-color texture (glTF baseColorFactor). Default [1,1,1,1]. */\n baseColorFactor?: [number, number, number, number];\n normalTexture?: Texture2D;\n /** Normal map scale (glTF normalTexture.scale). Default 1.0. */\n normalTextureScale?: number;\n /** Occlusion-Roughness-Metallic packed: R=occ, G=rough, B=metal. */\n ormTexture?: Texture2D;\n emissiveTexture?: Texture2D;\n /** Emissive color as float uniform (linear RGB). Used when no emissiveTexture.\n * If both set, emissiveColor multiplies emissiveTexture. */\n emissiveColor?: [number, number, number];\n /** KHR_materials_pbrSpecularGlossiness: RGB=specular, A=glossiness. */\n specGlossTexture?: Texture2D;\n /** Whether material is double-sided (disables back-face culling). */\n doubleSided?: boolean;\n /** Overall material alpha (0=fully transparent, 1=opaque). Default 1.0. */\n alpha?: number;\n /** Enable alpha blending (glTF alphaMode \"BLEND\"). Enables radianceOverAlpha + specularOverAlpha. */\n alphaBlend?: boolean;\n /** Alpha test cutoff (glTF alphaMode \"MASK\"). Fragments with base alpha * material alpha below this value are discarded. */\n alphaCutOff?: number;\n /** Scale factor for environment/IBL contribution. Default 1.0. */\n environmentIntensity?: number;\n /** Scale factor for direct light contribution. Default 1.0. */\n directIntensity?: number;\n /** Whether direct point/spot lights use physical inverse-square falloff.\n * Default true, matching Babylon.js PBRMaterial. Set false for Standard-style\n * linear range + spot exponent falloff (`usePhysicalLightFalloff = false`). */\n usePhysicalLightFalloff?: boolean;\n /** Dielectric F0 reflectance (default 0.04, glass ≈ 0.2). */\n reflectance?: number;\n /** glTF metallicFactor multiplier applied over ORM.b metallic channel. Default 1.0. */\n metallicFactor?: number;\n /** glTF roughnessFactor multiplier applied over ORM.g roughness channel. Default 1.0. */\n roughnessFactor?: number;\n /** Strength of ambient occlusion from ORM R channel. Default 1.0; 0.0 ignores R channel. */\n occlusionStrength?: number;\n /** glTF-derived UV set index for the occlusion texture: 0 = first UV set (TEXCOORD_0),\n * 1 = second UV set (TEXCOORD_1). Default 0. Populated only by the glTF loader paths\n * (gltf-pbr-builder-ext and KHR_texture_basisu). It selects WHICH UV set occlusion samples;\n * whether UV2 gets plumbed at all is gated by `_uv2Mask` (occlusion contributes bit 32),\n * which the slow path computes from this same value — so every occlusion-on-UV1 glTF\n * material also carries `_uv2Mask`. Setting this alone (without `_uv2Mask`) does not force\n * UV2 plumbing. */\n occlusionTexCoord?: number;\n /** @internal Per-channel UV1 (TEXCOORD_1) selection bitmask, precomputed at glTF build time by\n * the slow-path loader (gltf-pbr-builder-ext). Bit literals mirror pbr-template-ext's decode. */\n _uv2Mask?: number;\n /** Separate occlusion texture sampled with UV2 when occlusionTexCoord=1.\n * R channel is occlusion. When set, ORM.r is NOT used for occlusion. */\n occlusionTexture?: Texture2D;\n /** Scales dielectric F0 (default 1.0). Maps to BJS metallicF0Factor. */\n metallicF0Factor?: number;\n /** Grazing specular/F90 weight (default follows metallicF0Factor for legacy callers). */\n specularWeight?: number;\n /** Tints dielectric reflectance (linear RGB, default [1,1,1]). Maps to BJS metallicReflectanceColor. */\n metallicReflectanceColor?: [number, number, number];\n /** Texture whose RGB tints reflectance and A scales F0. Maps to BJS metallicReflectanceTexture. */\n metallicReflectanceTexture?: Texture2D;\n /** Texture whose RGB tints reflectance only. Maps to BJS reflectanceTexture. */\n reflectanceTexture?: Texture2D;\n /** When true + both reflectance textures set, metallicReflectanceTexture only contributes A (F0 scalar). */\n useOnlyMetallicFromMetallicReflectanceTexture?: boolean;\n /** Enable specular anti-aliasing on IBL alphaG (matches BJS SPECULARAA). Default false.\n * Set automatically by the glTF loader for materials loaded from glTF files. */\n enableSpecularAA?: boolean;\n /** Clearcoat layer configuration. When set with isEnabled=true, adds a glossy transparent\n * top layer (like car paint or lacquer). Tree-shakable — only bundled when used. */\n clearCoat?: ClearCoatProps;\n /** Sheen layer configuration. When set with isEnabled=true, adds a soft velvet-like\n * sheen layer (like fabric or cloth). Tree-shakable — only bundled when used. */\n sheen?: SheenProps;\n /** Iridescence thin-film configuration. When set with isEnabled=true, replaces\n * base-layer F0 with a wavelength-dependent thin-film Fresnel blend.\n * Maps to BJS PBRMaterial.iridescence and KHR_materials_iridescence.\n * Tree-shakable — only bundled when used. */\n iridescence?: IridescenceProps;\n /** When true, the albedo texture is in sRGB/gamma space (loaded as rgba8unorm)\n * and the shader applies pow(baseColor, 2.2) for sRGB→linear conversion.\n * Matches BJS PBRMaterial's Texture.gammaSpace=true behavior.\n * When false (default), assumes the texture already provides linear values\n * (e.g. rgba8unorm-srgb format or glTF sRGB textures). */\n gammaAlbedo?: boolean;\n /** Anisotropy layer configuration. When set with isEnabled=true, stretches specular\n * highlights along a preferred direction. Tree-shakable — only bundled when used. */\n anisotropy?: AnisotropyProps;\n /** Subsurface configuration. Presence of nested sub-features (translucency, scattering)\n * enables them — no isEnabled booleans needed. Tree-shakable — only bundled when used. */\n subsurface?: SubSurfaceProps;\n /** True transmissive surface: render task provides a scene-color refraction texture\n * just before this material draws. Set by KHR_materials_transmission. */\n transmissive?: boolean;\n /** When true, the material samples the environment cubemap using the view direction\n * (camera→fragment) instead of the reflected view direction. Used for PBR skybox boxes\n * where the mesh surrounds the camera and should display the environment directly.\n * Also zeroes SH irradiance — skybox is pure cubemap + BRDF only. */\n skyboxMode?: boolean;\n /** When true, the material is unlit — the base color is output directly,\n * bypassing all lighting, IBL, tonemap, and shading calculations.\n * Matches `KHR_materials_unlit` glTF extension. Alpha handling is preserved. */\n unlit?: boolean;\n /** Linear-RGB tint applied to baseColor when `unlit` is true (i.e. glTF\n * `baseColorFactor`). When omitted or [1,1,1], no tint is applied.\n * Only bundled/bound when the unlit extension is active. */\n unlitColor?: [number, number, number];\n /** @internal True when any of the material's textures carries `_hasTx=true`\n * (KHR_texture_transform). Stamped once by the glTF loader's slow path\n * so the renderer doesn't re-scan 5 textures per mesh. */\n _hasUvTx?: boolean;\n /** Optional stencil-test state baked into the main-pass pipeline. Lets this material write the stencil buffer\n * where it draws (mask) or discard where another material wrote it. Default none. See `StencilState`. */\n stencil?: StencilState;\n}\n\n/** @internal Compute PBR material-only feature bits. Mesh/pass bits are added per renderable. */\nexport function _computePbrMaterialFeatures(mat: PbrMaterialProps): { features: number; features2: number } {\n let features =\n (mat.emissiveTexture ? PBR_HAS_EMISSIVE : 0) |\n (mat.emissiveColor ? PBR_HAS_EMISSIVE_COLOR : 0) |\n (mat.normalTexture ? PBR_HAS_NORMAL_MAP : 0) |\n ((mat.alphaCutOff ?? 0) > 0 ? PBR_HAS_ALPHA_TEST : 0) |\n (mat.alphaBlend === true || ((mat.alphaCutOff ?? 0) <= 0 && mat.alpha! < 1) ? PBR_HAS_ALPHA_BLEND : 0) |\n (mat.specGlossTexture ? PBR_HAS_SPEC_GLOSS : 0) |\n (mat.doubleSided ? PBR_HAS_DOUBLE_SIDED : 0);\n if ((mat.occlusionStrength ?? 1.0) > 0) {\n features |= PBR_HAS_OCCLUSION;\n }\n if (mat.enableSpecularAA) {\n features |= PBR_HAS_SPECULAR_AA;\n }\n if (mat.gammaAlbedo) {\n features |= PBR_HAS_GAMMA_ALBEDO;\n }\n if (mat.anisotropy?.isEnabled) {\n features |= PBR_HAS_ANISOTROPY;\n }\n if (mat.skyboxMode) {\n features |= PBR_HAS_SKYBOX;\n }\n\n let features2 = 0;\n for (const ext of _getPbrExts().values()) {\n if (ext.detect) {\n const d = ext.detect(mat);\n features |= d.f;\n features2 |= d.f2;\n }\n }\n if ((mat as { _hasUvTx?: boolean })._hasUvTx) {\n features2 |= PBR2_HAS_UV_TRANSFORM;\n }\n // Per-channel UV set selection (glTF texCoord). `_uv2Mask` is precomputed once at glTF build\n // time by the lazy slow-path loader (gltf-pbr-builder-ext) — the only place a texture can carry\n // texCoord:1 (occlusion included, as bit 32) — so the always-loaded fast path pays just one read\n // here. This replaces master's `occlusionTexCoord` trigger: occlusion-on-UV1 always routes through\n // the slow path (any texCoord:1 in the material JSON forces it, incl. KHR_texture_basisu), so its\n // bit is already folded into `_uv2Mask`. Any channel on UV1 needs the uv2 vertex attribute +\n // varying threaded through.\n if ((mat as { _uv2Mask?: number })._uv2Mask) {\n features2 |= PBR2_HAS_UV2;\n }\n if (mat.baseColorFactor) {\n features2 |= PBR2_HAS_BASE_COLOR_FACTOR;\n }\n return { features, features2 };\n}\n\n/** Clearcoat layer properties. Maps to BJS PBRMaterial.clearCoat sub-object. */\nexport interface ClearCoatProps {\n /** Whether clearcoat is active. Default false. */\n isEnabled?: boolean;\n /** Clearcoat layer intensity (0=off, 1=full). Default 1.0. */\n intensity?: number;\n /** Clearcoat layer roughness. Default 0.0 (perfectly smooth). */\n roughness?: number;\n /** Index of refraction of the clearcoat layer. Default 1.5. */\n indexOfRefraction?: number;\n /** Optional clearcoat intensity texture (R channel). Multiplies `intensity`. */\n texture?: Texture2D;\n /** Optional clearcoat roughness texture (G channel). Multiplies `roughness`. */\n roughnessTexture?: Texture2D;\n /** Optional clearcoat normal map (tangent-space). Used to perturb the coat\n * layer normal independently of the base layer. */\n bumpTexture?: Texture2D;\n /** Clearcoat normal texture scale (glTF normalTexture.scale). Default 1.0. */\n bumpTextureScale?: number;\n /** Whether to remap base F0 across the clearcoat interface (CLEARCOAT_REMAP_F0).\n * Matches BJS PBRClearCoatConfiguration.remapF0OnInterfaceChange.\n * Default true. glTF loader sets this to false per KHR_materials_clearcoat. */\n useF0Remap?: boolean;\n}\n\n/** Sheen layer properties. Maps to BJS PBRMaterial.sheen sub-object. */\nexport interface SheenProps {\n /** Whether sheen is active. Default false. */\n isEnabled: boolean;\n /** Sheen color (linear RGB). Default [1, 1, 1]. */\n color?: [number, number, number];\n /** Sheen roughness. Default 0.0. */\n roughness?: number;\n /** Sheen intensity (0=off, 1=full). Default 1.0. */\n intensity?: number;\n /** Optional sheen tint texture (modulates sheen color). Loaded via loadTexture2D(). */\n texture?: Texture2D;\n /** Optional separate sheen roughness texture (KHR_materials_sheen sheenRoughnessTexture).\n * When present, sheen roughness is read from this texture's A channel at its own UV\n * (with its own KHR_texture_transform, animatable) instead of the color texture's A. */\n roughnessTexture?: Texture2D;\n /** When true (recommended for glTF), applies proper sheen albedo scaling\n * on the base layer and treats the sheen texture as already-linear (no pow).\n * When false (default, legacy), applies pow(rgb, 2.2) to the sheen texture\n * and uses a (1-F0) attenuation on the sheen lobe without base-layer scaling. */\n albedoScaling?: boolean;\n}\n\n/** Iridescence thin-film properties. Maps to BJS PBRMaterial.iridescence and KHR_materials_iridescence. */\nexport interface IridescenceProps {\n /** Whether iridescence is active. Default false. */\n isEnabled?: boolean;\n /** Iridescence blend intensity (0=off, 1=full). Default 1.0 for native PBR; glTF default is supplied by the loader. */\n intensity?: number;\n /** Thin-film index of refraction. Default 1.3. */\n indexOfRefraction?: number;\n /** Minimum film thickness in nanometres. Default 100. */\n minimumThickness?: number;\n /** Maximum film thickness in nanometres. Default 400. */\n maximumThickness?: number;\n /** Optional intensity texture; R channel multiplies intensity. */\n texture?: Texture2D;\n /** Optional thickness texture; G channel lerps minimum→maximum thickness. */\n thicknessTexture?: Texture2D;\n}\n\n/** Anisotropy layer properties. Maps to BJS PBRMaterial.anisotropy sub-object.\n * Stretches specular reflections along the tangent direction. */\nexport interface AnisotropyProps {\n /** Whether anisotropy is active. Default false. */\n isEnabled: boolean;\n /** Anisotropy strength (0=isotropic, 1=fully anisotropic). Default 1.0. */\n intensity?: number;\n /** Anisotropy direction in tangent space (u, v). Default [1, 0]. */\n direction?: [number, number];\n /** KHR_materials_anisotropy anisotropyTexture (linear). RG = per-texel direction\n * (×2-1, rotated by `direction`), B = per-texel strength (multiplies `intensity`).\n * May carry a KHR_texture_transform that an animation pointer can drive. */\n texture?: Texture2D;\n}\n\n/** Translucency sub-feature. Presence enables translucency (no isEnabled boolean). */\nexport interface TranslucencyProps {\n /** Translucency intensity (0=off, 1=full). Default 1.0. */\n intensity?: number;\n /** Translucency color (linear RGB). Tints the transmitted light. Default [1,1,1]. */\n color?: [number, number, number];\n /** Translucency color texture (sampled sRGB). RGB multiplies `color`.\n * KHR_materials_diffuse_transmission.diffuseTransmissionColorTexture. */\n colorTexture?: Texture2D;\n /** Translucency intensity texture. Alpha channel multiplies `intensity`.\n * KHR_materials_diffuse_transmission.diffuseTransmissionTexture. */\n intensityTexture?: Texture2D;\n /** Diffusion distance for the Burley transmittance BRDF. Controls how far\n * light travels through the material per RGB channel. Default [1,1,1]. */\n diffusionDistance?: [number, number, number];\n}\n\n/** Scattering sub-feature. Presence enables screen-space subsurface scattering.\n * NOTE: PrePass/SSS pipeline is not yet implemented — this type is reserved. */\nexport interface ScatteringProps {\n /** Per-channel scattering diffusion distance. */\n diffusionDistance?: [number, number, number];\n /** World-space scale factor for the diffusion kernel. Default 1.0. */\n metersPerUnit?: number;\n}\n\n/** Thickness sub-feature. Controls how thick the material is at each point. */\nexport interface ThicknessProps {\n /** Thickness map texture. R channel is sampled by default (matches\n * existing BJS non-glTF path). Set `useGlTFChannel=true` for G-channel\n * sampling as specified by KHR_materials_volume. */\n texture?: Texture2D;\n /** When true, sample the thickness texture's G channel (KHR_materials_volume).\n * Default false — samples R channel (BJS default). Set by the glTF loader. */\n useGlTFChannel?: boolean;\n /** Minimum thickness. Default 0. */\n min?: number;\n /** Maximum thickness. Default 1.0. */\n max?: number;\n}\n\n/** Refraction sub-feature (KHR_materials_transmission + _volume + _ior).\n * Presence enables frame-graph scene-texture transmission. */\nexport interface RefractionProps {\n /** Transmission factor (0=off, 1=fully transmissive). Default 0.\n * Maps to KHR_materials_transmission.transmissionFactor. */\n intensity?: number;\n /** Optional transmission texture (R channel). Multiplies `intensity`. */\n texture?: Texture2D;\n /** Index of refraction (KHR_materials_ior.ior). Default 1.5 (glass). */\n indexOfRefraction?: number;\n /** When true, the thickness value is also used as the refracted\n * sample offset depth (KHR_materials_volume — matches BJS\n * `useThicknessAsDepth`). Default true when volume is present. */\n useThicknessAsDepth?: boolean;\n /** Chromatic dispersion strength (KHR_materials_dispersion.dispersion).\n * Splits the refracted ray into per-RGB index-of-refraction offsets,\n * producing chromatic aberration. Requires volume. Default 0 (off). */\n dispersion?: number;\n}\n\n/** Tint sub-feature. Controls absorption tint color for transmittance. */\nexport interface TintProps {\n /** Tint color (linear RGB). Default [1,1,1]. */\n color?: [number, number, number];\n /** Distance at which the tint color is reached. Default 1.0. */\n atDistance?: number;\n}\n\n/** Subsurface configuration. Nested sub-features — presence = enabled. */\nexport interface SubSurfaceProps {\n /** Translucency: light passing through thin surfaces. */\n translucency?: TranslucencyProps;\n /** Scattering: screen-space subsurface scattering (PrePass). Reserved — not yet implemented. */\n scattering?: ScatteringProps;\n /** Thickness: per-texel thickness for transmittance. */\n thickness?: ThicknessProps;\n /** Tint: absorption tint color for transmittance. */\n tint?: TintProps;\n /** Refraction: physical light transmission through the surface\n * (KHR_materials_transmission + _volume + _ior). Presence enables it.\n * Requires the frame graph to produce a transmission refraction texture. */\n refraction?: RefractionProps;\n}\n\n/** Create a PbrMaterialProps with optional overrides. */\nexport function createPbrMaterial(props?: Partial<PbrMaterialProps>): PbrMaterialProps {\n // A material may be created without baseColor / ORM textures (only factors). Both\n // slots are always sampled, so install the resolver that lazily provides a shared\n // 1×1 white default (white ORM → metallic = metallicFactor, roughness =\n // roughnessFactor — the glTF defaults). Reachable only via createPbrMaterial, so\n // loader-only PBR scenes (e.g. BoomBox) tree-shake it entirely.\n _installPbrFallbackResolver((engine) => (engine._pbrFallbackTex ??= createSolidTexture2D(engine, 1, 1, 1)));\n const mat = {\n ...props,\n _buildGroup: getPbrGroupBuilder(),\n _uboVersion: 0,\n } as PbrMaterialProps;\n return mat;\n}\n\n/** Collect all non-null textures referenced by a PBR material (for acquire/release). */\nexport function collectPbrBoundTextures(mat: PbrMaterialProps): Texture2D[] {\n const t: Texture2D[] = [];\n if (mat.baseColorTexture) {\n t.push(mat.baseColorTexture);\n }\n if (mat.normalTexture) {\n t.push(mat.normalTexture);\n }\n if (mat.ormTexture) {\n t.push(mat.ormTexture);\n }\n if (mat.occlusionTexture) {\n t.push(mat.occlusionTexture);\n }\n if (mat.emissiveTexture) {\n t.push(mat.emissiveTexture);\n }\n if (mat.specGlossTexture) {\n t.push(mat.specGlossTexture);\n }\n for (const ext of _getPbrExts().values()) {\n ext.textures?.(mat, t);\n }\n return t;\n}\n"],"names":[],"mappings":";;;;;AAmCA,IAAI,gBAAA,GAA4C,IAAA;AACzC,SAAS,kBAAA,GAAuC;AACnD,EAAA,IAAI,gBAAA,EAAkB;AAClB,IAAA,OAAO,gBAAA;AAAA,EACX;AACA,EAAA,MAAM,OAAA,GAA4B,OAAO,KAAA,EAAO,MAAA,KAAW;AACvD,IAAA,MAAM,SAAU,KAAA,CAAuB,YAAA;AACvC,IAAA,MAAM,aAAA,GAAgB,MAAM,OAAO,qBAAqB,CAAA;AACxD,IAAA,MAAM,SAAS,MAAM,aAAA,CAAc,mBAAA,CAAoB,KAAA,EAAO,QAAQ,MAAM,CAAA;AAE5E,IAAA,OAAA,CAAQ,iBAAiB,MAAA,CAAO,aAAA;AAChC,IAAA,OAAO,MAAA;AAAA,EACX,CAAA;AACA,EAAA,OAAA,CAAQ,eAAA,GAAkB,KAAA;AAC1B,EAAA,OAAQ,gBAAA,GAAmB,OAAA;AAC/B;AA+HO,SAAS,4BAA4B,GAAA,EAAgE;AACxG,EAAA,IAAI,YACC,GAAA,CAAI,eAAA,GAAkB,gBAAA,GAAmB,CAAA,KACzC,IAAI,aAAA,GAAgB,sBAAA,GAAyB,CAAA,CAAA,IAC7C,GAAA,CAAI,gBAAgB,kBAAA,GAAqB,CAAA,CAAA,IAAA,CACxC,GAAA,CAAI,WAAA,IAAe,KAAK,CAAA,GAAI,kBAAA,GAAqB,CAAA,CAAA,IAClD,GAAA,CAAI,eAAe,IAAA,IAAA,CAAU,GAAA,CAAI,WAAA,IAAe,CAAA,KAAM,KAAK,GAAA,CAAI,KAAA,GAAS,CAAA,GAAK,mBAAA,GAAsB,MACnG,GAAA,CAAI,gBAAA,GAAmB,qBAAqB,CAAA,CAAA,IAC5C,GAAA,CAAI,cAAc,oBAAA,GAAuB,CAAA,CAAA;AAC9C,EAAA,IAAA,CAAK,GAAA,CAAI,iBAAA,IAAqB,CAAA,IAAO,CAAA,EAAG;AACpC,IAAA,QAAA,IAAY,iBAAA;AAAA,EAChB;AACA,EAAA,IAAI,IAAI,gBAAA,EAAkB;AACtB,IAAA,QAAA,IAAY,mBAAA;AAAA,EAChB;AACA,EAAA,IAAI,IAAI,WAAA,EAAa;AACjB,IAAA,QAAA,IAAY,oBAAA;AAAA,EAChB;AACA,EAAA,IAAI,GAAA,CAAI,YAAY,SAAA,EAAW;AAC3B,IAAA,QAAA,IAAY,kBAAA;AAAA,EAChB;AACA,EAAA,IAAI,IAAI,UAAA,EAAY;AAChB,IAAA,QAAA,IAAY,cAAA;AAAA,EAChB;AAEA,EAAA,IAAI,SAAA,GAAY,CAAA;AAChB,EAAA,KAAA,MAAW,GAAA,IAAO,WAAA,EAAY,CAAE,MAAA,EAAO,EAAG;AACtC,IAAA,IAAI,IAAI,MAAA,EAAQ;AACZ,MAAA,MAAM,CAAA,GAAI,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA;AACxB,MAAA,QAAA,IAAY,CAAA,CAAE,CAAA;AACd,MAAA,SAAA,IAAa,CAAA,CAAE,EAAA;AAAA,IACnB;AAAA,EACJ;AACA,EAAA,IAAK,IAA+B,QAAA,EAAU;AAC1C,IAAA,SAAA,IAAa,qBAAA;AAAA,EACjB;AAQA,EAAA,IAAK,IAA8B,QAAA,EAAU;AACzC,IAAA,SAAA,IAAa,YAAA;AAAA,EACjB;AACA,EAAA,IAAI,IAAI,eAAA,EAAiB;AACrB,IAAA,SAAA,IAAa,0BAAA;AAAA,EACjB;AACA,EAAA,OAAO,EAAE,UAAU,SAAA,EAAU;AACjC;AAyKO,SAAS,kBAAkB,KAAA,EAAqD;AAMnF,EAAA,2BAAA,CAA4B,CAAC,WAAY,MAAA,CAAO,eAAA,KAAoB,qBAAqB,MAAA,EAAQ,CAAA,EAAG,CAAA,EAAG,CAAC,CAAE,CAAA;AAC1G,EAAA,MAAM,GAAA,GAAM;AAAA,IACR,GAAG,KAAA;AAAA,IACH,aAAa,kBAAA,EAAmB;AAAA,IAChC,WAAA,EAAa;AAAA,GACjB;AACA,EAAA,OAAO,GAAA;AACX;AAGO,SAAS,wBAAwB,GAAA,EAAoC;AACxE,EAAA,MAAM,IAAiB,EAAC;AACxB,EAAA,IAAI,IAAI,gBAAA,EAAkB;AACtB,IAAA,CAAA,CAAE,IAAA,CAAK,IAAI,gBAAgB,CAAA;AAAA,EAC/B;AACA,EAAA,IAAI,IAAI,aAAA,EAAe;AACnB,IAAA,CAAA,CAAE,IAAA,CAAK,IAAI,aAAa,CAAA;AAAA,EAC5B;AACA,EAAA,IAAI,IAAI,UAAA,EAAY;AAChB,IAAA,CAAA,CAAE,IAAA,CAAK,IAAI,UAAU,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAI,gBAAA,EAAkB;AACtB,IAAA,CAAA,CAAE,IAAA,CAAK,IAAI,gBAAgB,CAAA;AAAA,EAC/B;AACA,EAAA,IAAI,IAAI,eAAA,EAAiB;AACrB,IAAA,CAAA,CAAE,IAAA,CAAK,IAAI,eAAe,CAAA;AAAA,EAC9B;AACA,EAAA,IAAI,IAAI,gBAAA,EAAkB;AACtB,IAAA,CAAA,CAAE,IAAA,CAAK,IAAI,gBAAgB,CAAA;AAAA,EAC/B;AACA,EAAA,KAAA,MAAW,GAAA,IAAO,WAAA,EAAY,CAAE,MAAA,EAAO,EAAG;AACtC,IAAA,GAAA,CAAI,QAAA,GAAW,KAAK,CAAC,CAAA;AAAA,EACzB;AACA,EAAA,OAAO,CAAA;AACX;;;;"}
1
+ {"version":3,"file":"pbr-material.js","sources":["../../../../src/material/pbr/pbr-material.ts"],"sourcesContent":["/** PBR Material — user-facing props + factory.\n *\n * Same role as StandardMaterialProps for the standard pipeline.\n * Users can create a PbrMaterialProps manually or let loadGltf() build one. */\n\nimport type { Texture2D } from \"../../texture/texture-2d.js\";\nimport type { MeshGroupBuilder } from \"../../render/renderable.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { Material, StencilState } from \"../material.js\";\nimport type { MaterialPlugin } from \"../plugin/material-plugin.js\";\nimport { createSolidTexture2D } from \"../../texture/solid-texture.js\";\nimport { _installPbrFallbackResolver } from \"./pbr-pipeline.js\";\nimport {\n _getPbrExts,\n PBR2_HAS_BASE_COLOR_FACTOR,\n PBR2_HAS_UV_TRANSFORM,\n PBR2_HAS_UV2,\n PBR_HAS_ALPHA_TEST,\n PBR_HAS_ALPHA_BLEND,\n PBR_HAS_ANISOTROPY,\n PBR_HAS_DOUBLE_SIDED,\n PBR_HAS_EMISSIVE,\n PBR_HAS_EMISSIVE_COLOR,\n PBR_HAS_GAMMA_ALBEDO,\n PBR_HAS_NORMAL_MAP,\n PBR_HAS_OCCLUSION,\n PBR_HAS_SKYBOX,\n PBR_HAS_SPECULAR_AA,\n PBR_HAS_SPEC_GLOSS,\n} from \"./pbr-flags.js\";\n\n/** Lazily-created singleton PBR {@link MeshGroupBuilder}. Lazy-imports the PBR\n * renderable builder and builds the pipeline. Thin instances are handled by the\n * fragment composer automatically. Lazy-init keeps the module free of top-level\n * side effects so a scene that uses no PBR material tree-shakes it away. */\nlet _pbrGroupBuilder: MeshGroupBuilder | null = null;\nexport function getPbrGroupBuilder(): MeshGroupBuilder {\n if (_pbrGroupBuilder) {\n return _pbrGroupBuilder;\n }\n const builder: MeshGroupBuilder = async (scene, meshes) => {\n const envTex = (scene as SceneContext)._envTextures;\n const renderableMod = await import(\"./pbr-renderable.js\");\n const result = await renderableMod.buildPbrRenderables(scene, meshes, envTex);\n // Wire the per-mesh rebuild closure used by material swap + per-pass override.\n builder._rebuildSingle = result.rebuildSingle;\n return result;\n };\n builder._materialFamily = \"pbr\";\n return (_pbrGroupBuilder = builder);\n}\n\n/** User-facing properties for a physically based (metallic-roughness) material.\n * Create one manually via `createPbrMaterial()` or let `loadGltf()` build it.\n * Optional sub-feature objects (clearcoat, sheen, anisotropy, subsurface) are\n * only bundled when referenced. */\nexport interface PbrMaterialProps extends Material {\n /** Optional opt-in material plugins (custom WGSL + uniforms + samplers layered\n * on top of the built-in PBR pipeline). Attach via `material.plugins = [plugin]`,\n * then call `enableMaterialPlugins(scene)` before `registerScene`. */\n plugins?: MaterialPlugin[];\n baseColorTexture?: Texture2D;\n /** Linear RGB/A factor multiplied with the base-color texture (glTF baseColorFactor). Default [1,1,1,1]. */\n baseColorFactor?: [number, number, number, number];\n normalTexture?: Texture2D;\n /** Normal map scale (glTF normalTexture.scale). Default 1.0. */\n normalTextureScale?: number;\n /** Occlusion-Roughness-Metallic packed: R=occ, G=rough, B=metal. */\n ormTexture?: Texture2D;\n emissiveTexture?: Texture2D;\n /** Emissive color as float uniform (linear RGB). Used when no emissiveTexture.\n * If both set, emissiveColor multiplies emissiveTexture. */\n emissiveColor?: [number, number, number];\n /** KHR_materials_pbrSpecularGlossiness: RGB=specular, A=glossiness. */\n specGlossTexture?: Texture2D;\n /** Whether material is double-sided (disables back-face culling). */\n doubleSided?: boolean;\n /** Overall material alpha (0=fully transparent, 1=opaque). Default 1.0. */\n alpha?: number;\n /** Enable alpha blending (glTF alphaMode \"BLEND\"). Enables radianceOverAlpha + specularOverAlpha. */\n alphaBlend?: boolean;\n /** Alpha test cutoff (glTF alphaMode \"MASK\"). Fragments with base alpha * material alpha below this value are discarded. */\n alphaCutOff?: number;\n /** Scale factor for environment/IBL contribution. Default 1.0. */\n environmentIntensity?: number;\n /** Scale factor for direct light contribution. Default 1.0. */\n directIntensity?: number;\n /** Whether direct point/spot lights use physical inverse-square falloff.\n * Default true, matching Babylon.js PBRMaterial. Set false for Standard-style\n * linear range + spot exponent falloff (`usePhysicalLightFalloff = false`). */\n usePhysicalLightFalloff?: boolean;\n /** Dielectric F0 reflectance (default 0.04, glass ≈ 0.2). */\n reflectance?: number;\n /** glTF metallicFactor multiplier applied over ORM.b metallic channel. Default 1.0. */\n metallicFactor?: number;\n /** glTF roughnessFactor multiplier applied over ORM.g roughness channel. Default 1.0. */\n roughnessFactor?: number;\n /** Strength of ambient occlusion from ORM R channel. Default 1.0; 0.0 ignores R channel. */\n occlusionStrength?: number;\n /** glTF-derived UV set index for the occlusion texture: 0 = first UV set (TEXCOORD_0),\n * 1 = second UV set (TEXCOORD_1). Default 0. Populated only by the glTF loader paths\n * (gltf-pbr-builder-ext and KHR_texture_basisu). It selects WHICH UV set occlusion samples;\n * whether UV2 gets plumbed at all is gated by `_uv2Mask` (occlusion contributes bit 32),\n * which the slow path computes from this same value — so every occlusion-on-UV1 glTF\n * material also carries `_uv2Mask`. Setting this alone (without `_uv2Mask`) does not force\n * UV2 plumbing. */\n occlusionTexCoord?: number;\n /** @internal Per-channel UV1 (TEXCOORD_1) selection bitmask, precomputed at glTF build time by\n * the slow-path loader (gltf-pbr-builder-ext). Bit literals mirror pbr-template-ext's decode. */\n _uv2Mask?: number;\n /** Separate occlusion texture sampled with UV2 when occlusionTexCoord=1.\n * R channel is occlusion. When set, ORM.r is NOT used for occlusion. */\n occlusionTexture?: Texture2D;\n /** Scales dielectric F0 (default 1.0). Maps to BJS metallicF0Factor. */\n metallicF0Factor?: number;\n /** Grazing specular/F90 weight (default follows metallicF0Factor for legacy callers). */\n specularWeight?: number;\n /** Tints dielectric reflectance (linear RGB, default [1,1,1]). Maps to BJS metallicReflectanceColor. */\n metallicReflectanceColor?: [number, number, number];\n /** Texture whose RGB tints reflectance and A scales F0. Maps to BJS metallicReflectanceTexture. */\n metallicReflectanceTexture?: Texture2D;\n /** Texture whose RGB tints reflectance only. Maps to BJS reflectanceTexture. */\n reflectanceTexture?: Texture2D;\n /** When true + both reflectance textures set, metallicReflectanceTexture only contributes A (F0 scalar). */\n useOnlyMetallicFromMetallicReflectanceTexture?: boolean;\n /** Enable specular anti-aliasing on IBL alphaG (matches BJS SPECULARAA). Default false.\n * Set automatically by the glTF loader for materials loaded from glTF files. */\n enableSpecularAA?: boolean;\n /** Clearcoat layer configuration. When set with isEnabled=true, adds a glossy transparent\n * top layer (like car paint or lacquer). Tree-shakable — only bundled when used. */\n clearCoat?: ClearCoatProps;\n /** Sheen layer configuration. When set with isEnabled=true, adds a soft velvet-like\n * sheen layer (like fabric or cloth). Tree-shakable — only bundled when used. */\n sheen?: SheenProps;\n /** Iridescence thin-film configuration. When set with isEnabled=true, replaces\n * base-layer F0 with a wavelength-dependent thin-film Fresnel blend.\n * Maps to BJS PBRMaterial.iridescence and KHR_materials_iridescence.\n * Tree-shakable — only bundled when used. */\n iridescence?: IridescenceProps;\n /** When true, the albedo texture is in sRGB/gamma space (loaded as rgba8unorm)\n * and the shader applies pow(baseColor, 2.2) for sRGB→linear conversion.\n * Matches BJS PBRMaterial's Texture.gammaSpace=true behavior.\n * When false (default), assumes the texture already provides linear values\n * (e.g. rgba8unorm-srgb format or glTF sRGB textures). */\n gammaAlbedo?: boolean;\n /** Anisotropy layer configuration. When set with isEnabled=true, stretches specular\n * highlights along a preferred direction. Tree-shakable — only bundled when used. */\n anisotropy?: AnisotropyProps;\n /** Subsurface configuration. Presence of nested sub-features (translucency, scattering)\n * enables them — no isEnabled booleans needed. Tree-shakable — only bundled when used. */\n subsurface?: SubSurfaceProps;\n /** True transmissive surface: render task provides a scene-color refraction texture\n * just before this material draws. Set by KHR_materials_transmission. */\n transmissive?: boolean;\n /** When true, the material samples the environment cubemap using the view direction\n * (camera→fragment) instead of the reflected view direction. Used for PBR skybox boxes\n * where the mesh surrounds the camera and should display the environment directly.\n * Also zeroes SH irradiance — skybox is pure cubemap + BRDF only. */\n skyboxMode?: boolean;\n /** When true, the material is unlit — the base color is output directly,\n * bypassing all lighting, IBL, tonemap, and shading calculations.\n * Matches `KHR_materials_unlit` glTF extension. Alpha handling is preserved. */\n unlit?: boolean;\n /** Linear-RGB tint applied to baseColor when `unlit` is true (i.e. glTF\n * `baseColorFactor`). When omitted or [1,1,1], no tint is applied.\n * Only bundled/bound when the unlit extension is active. */\n unlitColor?: [number, number, number];\n /** When true, the material is a shadow-only receiver: the surface is invisible\n * except where a shadow is cast on it, where it appears in `shadowOnlyColor` (or\n * black when omitted). Mirrors BJS `BackgroundMaterial.shadowOnly`. Requires\n * `receiveShadows` on the mesh and at least one shadow-casting light in the scene.\n * Implies alpha-blended rendering. Only bundled/bound when at least one mesh in\n * the scene uses it. */\n shadowOnly?: boolean;\n /** Linear-RGB color shown where the shadow falls when `shadowOnly` is true.\n * Defaults to black (`[0, 0, 0]`). */\n shadowOnlyColor?: [number, number, number];\n /** Maximum opacity at the darkest part of the shadow (when `shadowOnly` is true).\n * Range [0, 1]. Default 1.0 (fully opaque at full shadow). Lower values produce\n * a lighter, more transparent shadow. Mirrors the `shadowLevel` parameter on BJS\n * `BackgroundMaterial.shadowOnly`. */\n shadowOnlyOpacity?: number;\n /** Falloff sharpness for the shadow's soft edges (when `shadowOnly` is true).\n * Default 1.0 (the natural ESM/PCF falloff from the shadow generator). Higher\n * values steepen the falloff (saturating closer to the model silhouette), giving\n * crisper visible edges. Mathematically: `alpha = saturate((1 - shadowFactor) * falloff) * opacity`. */\n shadowOnlyFalloff?: number;\n /** @internal True when any of the material's textures carries `_hasTx=true`\n * (KHR_texture_transform). Stamped once by the glTF loader's slow path\n * so the renderer doesn't re-scan 5 textures per mesh. */\n _hasUvTx?: boolean;\n /** Optional stencil-test state baked into the main-pass pipeline. Lets this material write the stencil buffer\n * where it draws (mask) or discard where another material wrote it. Default none. See `StencilState`. */\n stencil?: StencilState;\n}\n\n/** @internal Compute PBR material-only feature bits. Mesh/pass bits are added per renderable. */\nexport function _computePbrMaterialFeatures(mat: PbrMaterialProps): { features: number; features2: number } {\n let features =\n (mat.emissiveTexture ? PBR_HAS_EMISSIVE : 0) |\n (mat.emissiveColor ? PBR_HAS_EMISSIVE_COLOR : 0) |\n (mat.normalTexture ? PBR_HAS_NORMAL_MAP : 0) |\n ((mat.alphaCutOff ?? 0) > 0 ? PBR_HAS_ALPHA_TEST : 0) |\n (mat.alphaBlend === true || ((mat.alphaCutOff ?? 0) <= 0 && mat.alpha! < 1) ? PBR_HAS_ALPHA_BLEND : 0) |\n (mat.specGlossTexture ? PBR_HAS_SPEC_GLOSS : 0) |\n (mat.doubleSided ? PBR_HAS_DOUBLE_SIDED : 0);\n if ((mat.occlusionStrength ?? 1.0) > 0) {\n features |= PBR_HAS_OCCLUSION;\n }\n if (mat.enableSpecularAA) {\n features |= PBR_HAS_SPECULAR_AA;\n }\n if (mat.gammaAlbedo) {\n features |= PBR_HAS_GAMMA_ALBEDO;\n }\n if (mat.anisotropy?.isEnabled) {\n features |= PBR_HAS_ANISOTROPY;\n }\n if (mat.skyboxMode) {\n features |= PBR_HAS_SKYBOX;\n }\n\n let features2 = 0;\n for (const ext of _getPbrExts().values()) {\n if (ext.detect) {\n const d = ext.detect(mat);\n features |= d.f;\n features2 |= d.f2;\n }\n }\n if ((mat as { _hasUvTx?: boolean })._hasUvTx) {\n features2 |= PBR2_HAS_UV_TRANSFORM;\n }\n // Per-channel UV set selection (glTF texCoord). `_uv2Mask` is precomputed once at glTF build\n // time by the lazy slow-path loader (gltf-pbr-builder-ext) — the only place a texture can carry\n // texCoord:1 (occlusion included, as bit 32) — so the always-loaded fast path pays just one read\n // here. This replaces master's `occlusionTexCoord` trigger: occlusion-on-UV1 always routes through\n // the slow path (any texCoord:1 in the material JSON forces it, incl. KHR_texture_basisu), so its\n // bit is already folded into `_uv2Mask`. Any channel on UV1 needs the uv2 vertex attribute +\n // varying threaded through.\n if ((mat as { _uv2Mask?: number })._uv2Mask) {\n features2 |= PBR2_HAS_UV2;\n }\n if (mat.baseColorFactor) {\n features2 |= PBR2_HAS_BASE_COLOR_FACTOR;\n }\n return { features, features2 };\n}\n\n/** Clearcoat layer properties. Maps to BJS PBRMaterial.clearCoat sub-object. */\nexport interface ClearCoatProps {\n /** Whether clearcoat is active. Default false. */\n isEnabled?: boolean;\n /** Clearcoat layer intensity (0=off, 1=full). Default 1.0. */\n intensity?: number;\n /** Clearcoat layer roughness. Default 0.0 (perfectly smooth). */\n roughness?: number;\n /** Index of refraction of the clearcoat layer. Default 1.5. */\n indexOfRefraction?: number;\n /** Optional clearcoat intensity texture (R channel). Multiplies `intensity`. */\n texture?: Texture2D;\n /** Optional clearcoat roughness texture (G channel). Multiplies `roughness`. */\n roughnessTexture?: Texture2D;\n /** Optional clearcoat normal map (tangent-space). Used to perturb the coat\n * layer normal independently of the base layer. */\n bumpTexture?: Texture2D;\n /** Clearcoat normal texture scale (glTF normalTexture.scale). Default 1.0. */\n bumpTextureScale?: number;\n /** Whether to remap base F0 across the clearcoat interface (CLEARCOAT_REMAP_F0).\n * Matches BJS PBRClearCoatConfiguration.remapF0OnInterfaceChange.\n * Default true. glTF loader sets this to false per KHR_materials_clearcoat. */\n useF0Remap?: boolean;\n}\n\n/** Sheen layer properties. Maps to BJS PBRMaterial.sheen sub-object. */\nexport interface SheenProps {\n /** Whether sheen is active. Default false. */\n isEnabled: boolean;\n /** Sheen color (linear RGB). Default [1, 1, 1]. */\n color?: [number, number, number];\n /** Sheen roughness. Default 0.0. */\n roughness?: number;\n /** Sheen intensity (0=off, 1=full). Default 1.0. */\n intensity?: number;\n /** Optional sheen tint texture (modulates sheen color). Loaded via loadTexture2D(). */\n texture?: Texture2D;\n /** Optional separate sheen roughness texture (KHR_materials_sheen sheenRoughnessTexture).\n * When present, sheen roughness is read from this texture's A channel at its own UV\n * (with its own KHR_texture_transform, animatable) instead of the color texture's A. */\n roughnessTexture?: Texture2D;\n /** When true (recommended for glTF), applies proper sheen albedo scaling\n * on the base layer and treats the sheen texture as already-linear (no pow).\n * When false (default, legacy), applies pow(rgb, 2.2) to the sheen texture\n * and uses a (1-F0) attenuation on the sheen lobe without base-layer scaling. */\n albedoScaling?: boolean;\n}\n\n/** Iridescence thin-film properties. Maps to BJS PBRMaterial.iridescence and KHR_materials_iridescence. */\nexport interface IridescenceProps {\n /** Whether iridescence is active. Default false. */\n isEnabled?: boolean;\n /** Iridescence blend intensity (0=off, 1=full). Default 1.0 for native PBR; glTF default is supplied by the loader. */\n intensity?: number;\n /** Thin-film index of refraction. Default 1.3. */\n indexOfRefraction?: number;\n /** Minimum film thickness in nanometres. Default 100. */\n minimumThickness?: number;\n /** Maximum film thickness in nanometres. Default 400. */\n maximumThickness?: number;\n /** Optional intensity texture; R channel multiplies intensity. */\n texture?: Texture2D;\n /** Optional thickness texture; G channel lerps minimum→maximum thickness. */\n thicknessTexture?: Texture2D;\n}\n\n/** Anisotropy layer properties. Maps to BJS PBRMaterial.anisotropy sub-object.\n * Stretches specular reflections along the tangent direction. */\nexport interface AnisotropyProps {\n /** Whether anisotropy is active. Default false. */\n isEnabled: boolean;\n /** Anisotropy strength (0=isotropic, 1=fully anisotropic). Default 1.0. */\n intensity?: number;\n /** Anisotropy direction in tangent space (u, v). Default [1, 0]. */\n direction?: [number, number];\n /** KHR_materials_anisotropy anisotropyTexture (linear). RG = per-texel direction\n * (×2-1, rotated by `direction`), B = per-texel strength (multiplies `intensity`).\n * May carry a KHR_texture_transform that an animation pointer can drive. */\n texture?: Texture2D;\n}\n\n/** Translucency sub-feature. Presence enables translucency (no isEnabled boolean). */\nexport interface TranslucencyProps {\n /** Translucency intensity (0=off, 1=full). Default 1.0. */\n intensity?: number;\n /** Translucency color (linear RGB). Tints the transmitted light. Default [1,1,1]. */\n color?: [number, number, number];\n /** Translucency color texture (sampled sRGB). RGB multiplies `color`.\n * KHR_materials_diffuse_transmission.diffuseTransmissionColorTexture. */\n colorTexture?: Texture2D;\n /** Translucency intensity texture. Alpha channel multiplies `intensity`.\n * KHR_materials_diffuse_transmission.diffuseTransmissionTexture. */\n intensityTexture?: Texture2D;\n /** Diffusion distance for the Burley transmittance BRDF. Controls how far\n * light travels through the material per RGB channel. Default [1,1,1]. */\n diffusionDistance?: [number, number, number];\n}\n\n/** Scattering sub-feature. Presence enables screen-space subsurface scattering.\n * NOTE: PrePass/SSS pipeline is not yet implemented — this type is reserved. */\nexport interface ScatteringProps {\n /** Per-channel scattering diffusion distance. */\n diffusionDistance?: [number, number, number];\n /** World-space scale factor for the diffusion kernel. Default 1.0. */\n metersPerUnit?: number;\n}\n\n/** Thickness sub-feature. Controls how thick the material is at each point. */\nexport interface ThicknessProps {\n /** Thickness map texture. R channel is sampled by default (matches\n * existing BJS non-glTF path). Set `useGlTFChannel=true` for G-channel\n * sampling as specified by KHR_materials_volume. */\n texture?: Texture2D;\n /** When true, sample the thickness texture's G channel (KHR_materials_volume).\n * Default false — samples R channel (BJS default). Set by the glTF loader. */\n useGlTFChannel?: boolean;\n /** Minimum thickness. Default 0. */\n min?: number;\n /** Maximum thickness. Default 1.0. */\n max?: number;\n}\n\n/** Refraction sub-feature (KHR_materials_transmission + _volume + _ior).\n * Presence enables frame-graph scene-texture transmission. */\nexport interface RefractionProps {\n /** Transmission factor (0=off, 1=fully transmissive). Default 0.\n * Maps to KHR_materials_transmission.transmissionFactor. */\n intensity?: number;\n /** Optional transmission texture (R channel). Multiplies `intensity`. */\n texture?: Texture2D;\n /** Index of refraction (KHR_materials_ior.ior). Default 1.5 (glass). */\n indexOfRefraction?: number;\n /** When true, the thickness value is also used as the refracted\n * sample offset depth (KHR_materials_volume — matches BJS\n * `useThicknessAsDepth`). Default true when volume is present. */\n useThicknessAsDepth?: boolean;\n /** Chromatic dispersion strength (KHR_materials_dispersion.dispersion).\n * Splits the refracted ray into per-RGB index-of-refraction offsets,\n * producing chromatic aberration. Requires volume. Default 0 (off). */\n dispersion?: number;\n}\n\n/** Tint sub-feature. Controls absorption tint color for transmittance. */\nexport interface TintProps {\n /** Tint color (linear RGB). Default [1,1,1]. */\n color?: [number, number, number];\n /** Distance at which the tint color is reached. Default 1.0. */\n atDistance?: number;\n}\n\n/** Subsurface configuration. Nested sub-features — presence = enabled. */\nexport interface SubSurfaceProps {\n /** Translucency: light passing through thin surfaces. */\n translucency?: TranslucencyProps;\n /** Scattering: screen-space subsurface scattering (PrePass). Reserved — not yet implemented. */\n scattering?: ScatteringProps;\n /** Thickness: per-texel thickness for transmittance. */\n thickness?: ThicknessProps;\n /** Tint: absorption tint color for transmittance. */\n tint?: TintProps;\n /** Refraction: physical light transmission through the surface\n * (KHR_materials_transmission + _volume + _ior). Presence enables it.\n * Requires the frame graph to produce a transmission refraction texture. */\n refraction?: RefractionProps;\n}\n\n/** Create a PbrMaterialProps with optional overrides. */\nexport function createPbrMaterial(props?: Partial<PbrMaterialProps>): PbrMaterialProps {\n // A material may be created without baseColor / ORM textures (only factors). Both\n // slots are always sampled, so install the resolver that lazily provides a shared\n // 1×1 white default (white ORM → metallic = metallicFactor, roughness =\n // roughnessFactor — the glTF defaults). Reachable only via createPbrMaterial, so\n // loader-only PBR scenes (e.g. BoomBox) tree-shake it entirely.\n _installPbrFallbackResolver((engine) => (engine._pbrFallbackTex ??= createSolidTexture2D(engine, 1, 1, 1)));\n const mat = {\n ...props,\n _buildGroup: getPbrGroupBuilder(),\n _uboVersion: 0,\n } as PbrMaterialProps;\n return mat;\n}\n\n/** Collect all non-null textures referenced by a PBR material (for acquire/release). */\nexport function collectPbrBoundTextures(mat: PbrMaterialProps): Texture2D[] {\n const t: Texture2D[] = [];\n if (mat.baseColorTexture) {\n t.push(mat.baseColorTexture);\n }\n if (mat.normalTexture) {\n t.push(mat.normalTexture);\n }\n if (mat.ormTexture) {\n t.push(mat.ormTexture);\n }\n if (mat.occlusionTexture) {\n t.push(mat.occlusionTexture);\n }\n if (mat.emissiveTexture) {\n t.push(mat.emissiveTexture);\n }\n if (mat.specGlossTexture) {\n t.push(mat.specGlossTexture);\n }\n for (const ext of _getPbrExts().values()) {\n ext.textures?.(mat, t);\n }\n return t;\n}\n"],"names":[],"mappings":"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"}
@@ -27,8 +27,8 @@ _installPbrPrimitiveResolver((meshFeatures, hasDoubleSided) => {
27
27
  return {
28
28
  topology,
29
29
  ...stripIndexFormat ? { stripIndexFormat } : void 0,
30
- cullMode: noCull || hasDoubleSided ? "none" : reverseWinding ? "front" : "back",
31
- frontFace: "ccw"
30
+ cullMode: noCull || hasDoubleSided ? "none" : "back",
31
+ frontFace: reverseWinding ? "cw" : "ccw"
32
32
  };
33
33
  });
34
34
  //# sourceMappingURL=pbr-primitive-resolver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pbr-primitive-resolver.js","sources":["../../../../src/material/pbr/pbr-primitive-resolver.ts"],"sourcesContent":["/** Installs the PBR pipeline's primitive-state resolver AND the extra mesh-feature encoder, which\n * together handle non-triangle glTF topologies (POINTS / LINES / LINE_STRIP / TRIANGLE_STRIP) and\n * negative-determinant winding reversal. Imported for side effect only by the glTF primitive +\n * negative-winding features, so triangle-list positive-winding scenes (the overwhelming majority)\n * never bundle this code and keep their renderer + pipeline chunks byte-identical.\n *\n * These bit constants are deliberately defined locally (not exported from mesh-features.ts): a bit\n * used only inside this lazy module must not leak into the shared mesh-features chunk, or it would\n * grow every scene's bundle. */\nimport type { Mesh } from \"../../mesh/mesh.js\";\nimport { _installMeshFeatureExtra } from \"../mesh-features.js\";\nimport { _installPbrPrimitiveResolver } from \"./pbr-pipeline.js\";\n\n/** Mesh world transform has a positive determinant (mirrored vs the RH→LH root): its triangle\n * winding is reversed, so back-face culling must flip (cull \"front\"). */\nconst MSH_REVERSE_WINDING = 1 << 11;\n/** Non-triangle-list primitive topology, encoded as a 3-bit index in bits 12-14 (1=point-list,\n * 2=line-list, 3=line-strip, 4=triangle-strip; 0=triangle-list). */\nconst MSH_TOPOLOGY_SHIFT = 12;\n/** A line-strip / triangle-strip mesh uses a uint32 index buffer (vs uint16); WebGPU needs the\n * pipeline's `stripIndexFormat` to match the index buffer for indexed strip draws. */\nconst MSH_INDEX_U32 = 1 << 15;\n\n// Encode the topology + negative-winding bits from the per-mesh flags set by the loader/feature.\n_installMeshFeatureExtra((mesh: Mesh): number => {\n let f = 0;\n if ((mesh as { _reverseWinding?: boolean })._reverseWinding) {\n f |= MSH_REVERSE_WINDING;\n }\n const topo = (mesh as { _topology?: number })._topology;\n if (topo) {\n f |= topo << MSH_TOPOLOGY_SHIFT;\n // Strips need the pipeline stripIndexFormat to match the index buffer; flag uint32 so the\n // pipeline picks the right format. Lite always draws indexed.\n if (topo >= 3 && mesh._gpu.indexFormat === \"uint32\") {\n f |= MSH_INDEX_U32;\n }\n }\n return f;\n});\n\n_installPbrPrimitiveResolver((meshFeatures, hasDoubleSided): GPUPrimitiveState => {\n // A mirrored mesh (positive world determinant, e.g. KHR negative node scale) has reversed\n // triangle winding, so back-face culling must cull the FRONT face instead. Matches BJS, which\n // flips sideOrientation when the world matrix determinant is negative.\n const reverseWinding = (meshFeatures & MSH_REVERSE_WINDING) !== 0;\n // Non-triangle-list primitive topology. Points and lines have no faces to cull; for a strip the\n // material's culling still applies.\n const topoIdx = (meshFeatures >> MSH_TOPOLOGY_SHIFT) & 7;\n const topology: GPUPrimitiveTopology =\n topoIdx === 1 ? \"point-list\" : topoIdx === 2 ? \"line-list\" : topoIdx === 3 ? \"line-strip\" : topoIdx === 4 ? \"triangle-strip\" : \"triangle-list\";\n const noCull = topoIdx >= 1 && topoIdx <= 3;\n // Indexed strip draws need stripIndexFormat to match the index buffer.\n const stripIndexFormat: GPUIndexFormat | undefined = topoIdx >= 3 ? (meshFeatures & MSH_INDEX_U32 ? \"uint32\" : \"uint16\") : undefined;\n return {\n topology,\n ...(stripIndexFormat ? { stripIndexFormat } : undefined),\n cullMode: noCull || hasDoubleSided ? \"none\" : reverseWinding ? \"front\" : \"back\",\n frontFace: \"ccw\",\n };\n});\n"],"names":[],"mappings":";;;AAeA,MAAM,sBAAsB,CAAA,IAAK,EAAA;AAGjC,MAAM,kBAAA,GAAqB,EAAA;AAG3B,MAAM,gBAAgB,CAAA,IAAK,EAAA;AAG3B,wBAAA,CAAyB,CAAC,IAAA,KAAuB;AAC7C,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAK,KAAuC,eAAA,EAAiB;AACzD,IAAA,CAAA,IAAK,mBAAA;AAAA,EACT;AACA,EAAA,MAAM,OAAQ,IAAA,CAAgC,SAAA;AAC9C,EAAA,IAAI,IAAA,EAAM;AACN,IAAA,CAAA,IAAK,IAAA,IAAQ,kBAAA;AAGb,IAAA,IAAI,IAAA,IAAQ,CAAA,IAAK,IAAA,CAAK,IAAA,CAAK,gBAAgB,QAAA,EAAU;AACjD,MAAA,CAAA,IAAK,aAAA;AAAA,IACT;AAAA,EACJ;AACA,EAAA,OAAO,CAAA;AACX,CAAC,CAAA;AAED,4BAAA,CAA6B,CAAC,cAAc,cAAA,KAAsC;AAI9E,EAAA,MAAM,cAAA,GAAA,CAAkB,eAAe,mBAAA,MAAyB,CAAA;AAGhE,EAAA,MAAM,OAAA,GAAW,gBAAgB,kBAAA,GAAsB,CAAA;AACvD,EAAA,MAAM,QAAA,GACF,OAAA,KAAY,CAAA,GAAI,YAAA,GAAe,OAAA,KAAY,CAAA,GAAI,WAAA,GAAc,OAAA,KAAY,CAAA,GAAI,YAAA,GAAe,OAAA,KAAY,CAAA,GAAI,gBAAA,GAAmB,eAAA;AACnI,EAAA,MAAM,MAAA,GAAS,OAAA,IAAW,CAAA,IAAK,OAAA,IAAW,CAAA;AAE1C,EAAA,MAAM,mBAA+C,OAAA,IAAW,CAAA,GAAK,YAAA,GAAe,aAAA,GAAgB,WAAW,QAAA,GAAY,MAAA;AAC3H,EAAA,OAAO;AAAA,IACH,QAAA;AAAA,IACA,GAAI,gBAAA,GAAmB,EAAE,gBAAA,EAAiB,GAAI,MAAA;AAAA,IAC9C,QAAA,EAAU,MAAA,IAAU,cAAA,GAAiB,MAAA,GAAS,iBAAiB,OAAA,GAAU,MAAA;AAAA,IACzE,SAAA,EAAW;AAAA,GACf;AACJ,CAAC,CAAA"}
1
+ {"version":3,"file":"pbr-primitive-resolver.js","sources":["../../../../src/material/pbr/pbr-primitive-resolver.ts"],"sourcesContent":["/** Installs the PBR pipeline's primitive-state resolver AND the extra mesh-feature encoder, which\n * together handle non-triangle glTF topologies (POINTS / LINES / LINE_STRIP / TRIANGLE_STRIP) and\n * negative-determinant winding reversal. Imported for side effect only by the glTF primitive +\n * negative-winding features, so triangle-list positive-winding scenes (the overwhelming majority)\n * never bundle this code and keep their renderer + pipeline chunks byte-identical.\n *\n * These bit constants are deliberately defined locally (not exported from mesh-features.ts): a bit\n * used only inside this lazy module must not leak into the shared mesh-features chunk, or it would\n * grow every scene's bundle. */\nimport type { Mesh } from \"../../mesh/mesh.js\";\nimport { _installMeshFeatureExtra } from \"../mesh-features.js\";\nimport { _installPbrPrimitiveResolver } from \"./pbr-pipeline.js\";\n\n/** Mesh world transform has a positive determinant (mirrored vs the RH→LH root): its triangle\n * winding is reversed, so back-face culling must flip (cull \"front\"). */\nconst MSH_REVERSE_WINDING = 1 << 11;\n/** Non-triangle-list primitive topology, encoded as a 3-bit index in bits 12-14 (1=point-list,\n * 2=line-list, 3=line-strip, 4=triangle-strip; 0=triangle-list). */\nconst MSH_TOPOLOGY_SHIFT = 12;\n/** A line-strip / triangle-strip mesh uses a uint32 index buffer (vs uint16); WebGPU needs the\n * pipeline's `stripIndexFormat` to match the index buffer for indexed strip draws. */\nconst MSH_INDEX_U32 = 1 << 15;\n\n// Encode the topology + negative-winding bits from the per-mesh flags set by the loader/feature.\n_installMeshFeatureExtra((mesh: Mesh): number => {\n let f = 0;\n if ((mesh as { _reverseWinding?: boolean })._reverseWinding) {\n f |= MSH_REVERSE_WINDING;\n }\n const topo = (mesh as { _topology?: number })._topology;\n if (topo) {\n f |= topo << MSH_TOPOLOGY_SHIFT;\n // Strips need the pipeline stripIndexFormat to match the index buffer; flag uint32 so the\n // pipeline picks the right format. Lite always draws indexed.\n if (topo >= 3 && mesh._gpu.indexFormat === \"uint32\") {\n f |= MSH_INDEX_U32;\n }\n }\n return f;\n});\n\n_installPbrPrimitiveResolver((meshFeatures, hasDoubleSided): GPUPrimitiveState => {\n // `reverseWinding` marks a mesh mirrored relative to Lite's world space: the loader sets it when\n // the node's world-matrix determinant is positive. (Lite applies a RH→LH root flip with det < 0,\n // so an un-mirrored glTF node lands at a negative world determinant and a mirrored one — e.g. KHR\n // negative node scale — at a positive one.) A mirrored mesh has reversed triangle winding, so we\n // flip the pipeline's `frontFace` (ccw→cw) rather than the cull face: WebGPU derives\n // `@builtin(front_facing)` from `frontFace`, so this keeps the double-sided shader's front-facing\n // normal flip correct (a cullMode flip would leave front_facing evaluated against the un-mirrored\n // ccw winding, wrongly inverting the shading normal on the visible outer surface → black). BJS\n // handles the same case by flipping sideOrientation (the GL front-face winding); it states the\n // condition as a negative determinant because it measures the sign in its own opposite-handed space.\n const reverseWinding = (meshFeatures & MSH_REVERSE_WINDING) !== 0;\n // Non-triangle-list primitive topology. Points and lines have no faces to cull; for a strip the\n // material's culling still applies.\n const topoIdx = (meshFeatures >> MSH_TOPOLOGY_SHIFT) & 7;\n const topology: GPUPrimitiveTopology =\n topoIdx === 1 ? \"point-list\" : topoIdx === 2 ? \"line-list\" : topoIdx === 3 ? \"line-strip\" : topoIdx === 4 ? \"triangle-strip\" : \"triangle-list\";\n const noCull = topoIdx >= 1 && topoIdx <= 3;\n // Indexed strip draws need stripIndexFormat to match the index buffer.\n const stripIndexFormat: GPUIndexFormat | undefined = topoIdx >= 3 ? (meshFeatures & MSH_INDEX_U32 ? \"uint32\" : \"uint16\") : undefined;\n return {\n topology,\n ...(stripIndexFormat ? { stripIndexFormat } : undefined),\n cullMode: noCull || hasDoubleSided ? \"none\" : \"back\",\n frontFace: reverseWinding ? \"cw\" : \"ccw\",\n };\n});\n"],"names":[],"mappings":";;;AAeA,MAAM,sBAAsB,CAAA,IAAK,EAAA;AAGjC,MAAM,kBAAA,GAAqB,EAAA;AAG3B,MAAM,gBAAgB,CAAA,IAAK,EAAA;AAG3B,wBAAA,CAAyB,CAAC,IAAA,KAAuB;AAC7C,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAK,KAAuC,eAAA,EAAiB;AACzD,IAAA,CAAA,IAAK,mBAAA;AAAA,EACT;AACA,EAAA,MAAM,OAAQ,IAAA,CAAgC,SAAA;AAC9C,EAAA,IAAI,IAAA,EAAM;AACN,IAAA,CAAA,IAAK,IAAA,IAAQ,kBAAA;AAGb,IAAA,IAAI,IAAA,IAAQ,CAAA,IAAK,IAAA,CAAK,IAAA,CAAK,gBAAgB,QAAA,EAAU;AACjD,MAAA,CAAA,IAAK,aAAA;AAAA,IACT;AAAA,EACJ;AACA,EAAA,OAAO,CAAA;AACX,CAAC,CAAA;AAED,4BAAA,CAA6B,CAAC,cAAc,cAAA,KAAsC;AAW9E,EAAA,MAAM,cAAA,GAAA,CAAkB,eAAe,mBAAA,MAAyB,CAAA;AAGhE,EAAA,MAAM,OAAA,GAAW,gBAAgB,kBAAA,GAAsB,CAAA;AACvD,EAAA,MAAM,QAAA,GACF,OAAA,KAAY,CAAA,GAAI,YAAA,GAAe,OAAA,KAAY,CAAA,GAAI,WAAA,GAAc,OAAA,KAAY,CAAA,GAAI,YAAA,GAAe,OAAA,KAAY,CAAA,GAAI,gBAAA,GAAmB,eAAA;AACnI,EAAA,MAAM,MAAA,GAAS,OAAA,IAAW,CAAA,IAAK,OAAA,IAAW,CAAA;AAE1C,EAAA,MAAM,mBAA+C,OAAA,IAAW,CAAA,GAAK,YAAA,GAAe,aAAA,GAAgB,WAAW,QAAA,GAAY,MAAA;AAC3H,EAAA,OAAO;AAAA,IACH,QAAA;AAAA,IACA,GAAI,gBAAA,GAAmB,EAAE,gBAAA,EAAiB,GAAI,MAAA;AAAA,IAC9C,QAAA,EAAU,MAAA,IAAU,cAAA,GAAiB,MAAA,GAAS,MAAA;AAAA,IAC9C,SAAA,EAAW,iBAAiB,IAAA,GAAO;AAAA,GACvC;AACJ,CAAC,CAAA"}
@@ -57,6 +57,7 @@ async function buildPbrRenderables(scene, meshes, envTextures) {
57
57
  let hasSomeThinInstances = false;
58
58
  let hasCullingTI = false;
59
59
  let hasAnyUnlit = false;
60
+ let hasAnyShadowOnly = false;
60
61
  let hasAnyUvTransform = false;
61
62
  let hasAnyUv2 = false;
62
63
  let hasAnyVertexColor = false;
@@ -81,6 +82,7 @@ async function buildPbrRenderables(scene, meshes, envTextures) {
81
82
  hasSomeThinInstances ||= !!m.thinInstances;
82
83
  hasCullingTI ||= !!m.thinInstances?._gpuCullingEnabled;
83
84
  hasAnyUnlit ||= !!mat.unlit;
85
+ hasAnyShadowOnly ||= !!mat.shadowOnly;
84
86
  hasAnyUvTransform ||= !!mat._hasUvTx;
85
87
  hasAnyUv2 ||= !!m._gpu.uv2Buffer && !!mat._uv2Mask;
86
88
  hasAnyVertexColor ||= !!m._gpu.colorBuffer;
@@ -146,6 +148,7 @@ async function buildPbrRenderables(scene, meshes, envTextures) {
146
148
  await _drainPbrExts([
147
149
  [needsEmissiveColor, () => import('./fragments/emissive-fragment.js')],
148
150
  [hasAnyUnlit, () => import('./fragments/unlit-fragment.js')],
151
+ [hasAnyShadowOnly, () => import('./fragments/shadow-only-fragment.js')],
149
152
  [hasSomeSkeletons, () => import('./fragments/skeleton-fragment.js')],
150
153
  [hasSomeMorphs, () => import('./fragments/morph-fragment.js')],
151
154
  [hasAnyUvTransform, () => import('./fragments/uv-transform-fragment.js')]
@@ -1 +1 @@
1
- {"version":3,"file":"pbr-renderable.js","sources":["../../../../src/material/pbr/pbr-renderable.ts"],"sourcesContent":["/** PBR mesh renderable — builds Renderables from glTF PBR meshes + environment.\n *\n * `buildPbrRenderables` does shared per-scene setup (extension/fragment imports,\n * shader composer, scene bind group, multi-light UBO), then delegates per-mesh\n * work to `buildSinglePbrRenderable`. Both initial build and material-swap\n * rebuilds go through the same single-mesh function. */\n\nimport { F32 } from \"../../engine/typed-arrays.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { Mesh } from \"../../mesh/mesh.js\";\nimport type { PbrMaterialProps } from \"./pbr-material.js\";\nimport { collectPbrBoundTextures } from \"./pbr-material.js\";\nimport type { EnvironmentTextures } from \"../../loader-env/load-env.js\";\n\nimport type { Renderable, MeshGroupBuildResult } from \"../../render/renderable.js\";\nimport type { ShaderFragment } from \"../../shader/fragment-types.js\";\nimport { acquireTexture, releaseTexture, clearSamplerCache } from \"../../resource/gpu-pool.js\";\nimport { createUniformBuffer } from \"../../resource/gpu-buffers.js\";\nimport { getOrCreatePbrBindings, getOrCreatePbrPipeline, createPbrMeshBindGroup, clearPbrPipelineCache } from \"./pbr-pipeline.js\";\nimport {\n _registerPbrExt,\n _getPbrExts,\n PBR_HAS_NORMAL_MAP,\n PBR_HAS_ALPHA_BLEND,\n PBR2_NO_COLOR_OUTPUT,\n PBR2_HAS_REFRACTION,\n PBR2_HAS_UV2,\n PBR_HAS_ENV,\n PBR_HAS_TONEMAP,\n PBR_HAS_FOG,\n PBR2_ESM_SHADOW_OUTPUT,\n} from \"./pbr-flags.js\";\nimport type { PbrExt } from \"./pbr-flags.js\";\nimport { createPbrComposer } from \"./pbr-compose.js\";\nimport { StandardToneMapping } from \"./tone-mapping.js\";\nimport { _computePbrMaterialFeatures } from \"./pbr-material.js\";\nimport type { ShadowGenerator } from \"../../shadow/shadow-generator.js\";\nimport type { ThinInstanceData } from \"../../mesh/thin-instance.js\";\nimport type { PbrShadowLightSlot } from \"./fragments/pbr-shadow-fragment.js\";\nimport { writeMeshLightSelection } from \"../../render/lights-ubo.js\";\nimport type { PbrLightMode } from \"./pbr-compose.js\";\nimport type { Material, MaterialRenderFeatures } from \"../material.js\";\nimport { _computeMeshFeatures, MSH_HAS_INSTANCE_COLOR, MSH_HAS_THIN_INSTANCES, MSH_HAS_UV2, MSH_HAS_VERTEX_COLOR } from \"../mesh-features.js\";\nimport { packMat4IntoF32 } from \"../../math/pack-mat4-into-f32.js\";\n\ntype SingleLightType = \"hemispheric\" | \"directional\" | \"spot\" | \"point\";\ninterface SingleLightWgslModule {\n SINGLE_LIGHT_STRUCTS: string;\n getSingleLightBlock(): string;\n}\n\ntype SyncThinInstanceBuffers = (\n engine: EngineContext,\n ti: ThinInstanceData,\n pass: GPURenderPassEncoder | GPURenderBundleEncoder,\n slot: number,\n hasColor: boolean,\n drawBuffers?: import(\"../../mesh/thin-instance-gpu.js\").ThinInstanceDrawBuffers | null\n) => number;\n\n/** Build PBR Renderable(s) + a SceneUniformUpdater from PBR meshes. */\nexport async function buildPbrRenderables(scene: SceneContext, meshes: Mesh[], envTextures: EnvironmentTextures | undefined): Promise<MeshGroupBuildResult> {\n const engine = scene.surface.engine;\n const device = engine._device;\n // Per-size scratch buffers for material UBO re-writes (zero allocation per frame).\n const materialScratch = new Map<number, Float32Array>();\n const hasEnv = !!envTextures;\n const shadowLights: { lightIndex: number; shadowType: \"esm\" | \"pcf\" | \"csm\"; gen: ShadowGenerator }[] = [];\n for (let i = 0; i < scene.lights.length; i++) {\n const sg = scene.lights[i]!.shadowGenerator;\n if (sg) {\n shadowLights.push({ lightIndex: i, shadowType: sg._shadowType, gen: sg });\n }\n }\n const hasSomeShadows = shadowLights.length > 0;\n let hasAnyAffectedLight = false;\n let needsSingleLightPath = false;\n let needsMultiLightPath = false;\n const singleLightTypes: SingleLightType[] = [];\n for (const mesh of meshes) {\n const lr = writeMeshLightSelection(mesh, scene.lights);\n const affectedCount = lr > 0 ? 1 : -lr;\n hasAnyAffectedLight ||= affectedCount > 0;\n if (affectedCount === 1 && !(mesh.receiveShadows && hasSomeShadows)) {\n needsSingleLightPath = true;\n const type = getPackedSingleLightType(scene.lights, lr - 1);\n if (!singleLightTypes.includes(type)) {\n singleLightTypes.push(type);\n }\n } else if (affectedCount > 0) {\n needsMultiLightPath = true;\n }\n }\n\n // ── Single O(N) scan over meshes for all scene-wide feature flags ──\n // Flags are plain locals (not an object return) so terser can mangle their names.\n // Replaces ~11 sequential meshes.some() loops (was O(11N)).\n let hasSkybox = false;\n let hasMetallicReflectance = false;\n let hasClearcoat = false;\n let hasSheen = false;\n let hasIridescence = false;\n let hasAnyAnisotropy = false;\n let hasAnySubsurface = false;\n let hasAlphaTest = false;\n let hasTransmissionRefraction = false;\n let needsEmissiveColor = false;\n let hasSomeSkeletons = false;\n let hasSomeMorphs = false;\n let hasSomeThinInstances = false;\n let hasCullingTI = false;\n let hasAnyUnlit = false;\n let hasAnyUvTransform = false;\n let hasAnyUv2 = false;\n let hasAnyVertexColor = false;\n let hasAnyFlatNormal = false;\n let hasGammaAlbedo = false;\n for (let i = 0; i < meshes.length; i++) {\n const m = meshes[i]!;\n const mat = m.material as PbrMaterialProps & { _hasReflExt?: boolean; _hasUvTx?: boolean };\n const refractionIntensity = mat.subsurface?.refraction?.intensity ?? 0;\n hasSkybox ||= !!mat.skyboxMode;\n hasMetallicReflectance ||= !!(mat.metallicReflectanceTexture || mat.reflectanceTexture || mat._hasReflExt);\n hasClearcoat ||= !!mat.clearCoat?.isEnabled;\n hasSheen ||= !!mat.sheen?.isEnabled;\n hasIridescence ||= !!mat.iridescence?.isEnabled;\n hasAnyAnisotropy ||= !!mat.anisotropy?.isEnabled;\n hasAnySubsurface ||= !!mat.subsurface?.translucency;\n hasAlphaTest ||= mat.alphaCutOff! > 0;\n hasTransmissionRefraction ||= refractionIntensity > 0 && !!mat.transmissive;\n needsEmissiveColor ||= !!mat.emissiveColor;\n hasSomeSkeletons ||= !!m.skeleton;\n hasSomeMorphs ||= !!m.morphTargets;\n hasSomeThinInstances ||= !!m.thinInstances;\n hasCullingTI ||= !!m.thinInstances?._gpuCullingEnabled;\n hasAnyUnlit ||= !!mat.unlit;\n hasAnyUvTransform ||= !!mat._hasUvTx;\n // UV2 counts when ANY PBR channel samples texCoord 1 (occlusion included, via `_uv2Mask`\n // bit 32) — precomputed as `_uv2Mask` on the material by the glTF slow path (0/undefined on\n // the fast path). Occlusion-on-UV1 (incl. KHR_texture_basisu) always routes through that slow\n // path, so its UV2 usage is already reflected here without a separate occlusionTexCoord check.\n hasAnyUv2 ||= !!m._gpu.uv2Buffer && !!(mat as { _uv2Mask?: number })._uv2Mask;\n hasAnyVertexColor ||= !!m._gpu.colorBuffer;\n hasAnyFlatNormal ||= !!(m as { _flatNormal?: boolean })._flatNormal;\n hasGammaAlbedo ||= !!mat.gammaAlbedo;\n }\n\n // ── Dynamically import fragment creators based on scene capabilities ──\n\n // IBL fragment.\n let _iblSkyboxCalc = \"\";\n if (hasEnv) {\n const mod = await import(\"./fragments/ibl-fragment.js\");\n _registerPbrExt(mod.pbrExt);\n if (hasSkybox) {\n // Skybox-mode WGSL is only loaded when at least one mesh in the scene needs it.\n const sky = await import(\"./fragments/ibl-skybox-wgsl.js\");\n _iblSkyboxCalc = sky.IBL_SKYBOX_CALCULATION;\n }\n }\n\n // Flat-normal WGSL is only loaded when at least one mesh lacks a NORMAL attribute\n // (glTF flat-shading) — normal-having scenes bundle zero bytes.\n let _flatNormalWgsl = \"\";\n if (hasAnyFlatNormal) {\n const flatNormal = await import(\"./fragments/flat-normal-wgsl.js\");\n _flatNormalWgsl = flatNormal.FLAT_NORMAL_WGSL;\n }\n\n // Light/shadow helpers stay dynamic so single-light and non-shadow bundles stay lean.\n let _createPbrShadowFragment: ((slots: PbrShadowLightSlot[]) => ShaderFragment) | null = null;\n let _singleLightWGSL = \"\";\n let _getSingleLightBlock: ((type: string) => string) | null = null;\n const singleLightBlocks: Partial<Record<SingleLightType, () => string>> = {};\n let _multiLightWGSL = \"\";\n let _multiLightLoop = \"\";\n if (needsSingleLightPath) {\n for (const type of singleLightTypes) {\n const single = await importSingleLightWgsl(type);\n _singleLightWGSL = single.SINGLE_LIGHT_STRUCTS;\n singleLightBlocks[type] = single.getSingleLightBlock;\n }\n _getSingleLightBlock = (type) => singleLightBlocks[toSingleLightType(type)]?.() ?? \"\";\n }\n if (needsMultiLightPath) {\n const wgslMod = await import(\"./fragments/multilight-wgsl.js\");\n _multiLightWGSL = wgslMod.MULTI_LIGHT_STRUCTS() + wgslMod.COMPUTE_PBR_LIGHT;\n _multiLightLoop = wgslMod.getMultiLightLoop();\n }\n if (hasAnyAffectedLight && hasSomeShadows) {\n const shadowMod = await import(\"./fragments/pbr-shadow-fragment.js\");\n _createPbrShadowFragment = shadowMod.createPbrShadowFragment;\n }\n\n // ── Per-mesh fragment creators (imported if any mesh needs them) ──\n // Each optional PBR fragment module exports a uniform `pbrExt`, so registration\n // collapses to a single data-driven loop over [flag, loader] pairs. The `import()`\n // specifiers stay literal (required for Vite code-splitting) and the shared\n // `_registerPbrExt((await load()).pbrExt)` glue is emitted once instead of per\n // feature, keeping this management layer small as features are added.\n // Registration order is the iteration order consumed by `_getPbrExts().values()`\n // on the hot paths (composePbr, writeMaterialData, collectPbrBoundTextures).\n type PbrExtLoad = () => Promise<{ pbrExt: PbrExt }>;\n const _drainPbrExts = async (loaders: Array<readonly [boolean, PbrExtLoad]>) => {\n for (const [flag, load] of loaders) {\n if (flag) {\n _registerPbrExt((await load()).pbrExt);\n }\n }\n };\n\n await _drainPbrExts([\n [hasAlphaTest, () => import(\"./fragments/alpha-test-fragment.js\")],\n [hasMetallicReflectance, () => import(\"./fragments/reflectance-fragment.js\")],\n [hasClearcoat, () => import(\"./fragments/clearcoat-fragment.js\")],\n [hasSheen, () => import(\"./fragments/sheen-fragment.js\")],\n [hasIridescence, () => import(\"./fragments/iridescence-fragment.js\")],\n [hasAnySubsurface, () => import(\"./fragments/subsurface-fragment.js\")],\n ]);\n if (hasTransmissionRefraction) {\n const mod = await import(\"./pbr-refraction.js\");\n await mod.registerPbrRefraction(scene as SceneContext, engine, _registerPbrExt);\n }\n await _drainPbrExts([\n [needsEmissiveColor, () => import(\"./fragments/emissive-fragment.js\")],\n [hasAnyUnlit, () => import(\"./fragments/unlit-fragment.js\")],\n [hasSomeSkeletons, () => import(\"./fragments/skeleton-fragment.js\")],\n [hasSomeMorphs, () => import(\"./fragments/morph-fragment.js\")],\n [hasAnyUvTransform, () => import(\"./fragments/uv-transform-fragment.js\")],\n ]);\n\n // Anisotropy needs its module reference retained (for ANISO_BRDF_FUNCTIONS /\n // makeAnisotropyTBBlock / ANISO_DIRECT_DG / ANISO_BENT_NORMAL strings consumed\n // by the template below), so it keeps the full module binding.\n let _anisoExt: typeof import(\"./fragments/anisotropy-fragment.js\") | null = null;\n if (hasAnyAnisotropy) {\n _anisoExt = await import(\"./fragments/anisotropy-fragment.js\");\n _registerPbrExt(_anisoExt.pbrExt);\n }\n\n // Lazy-load pbr-template-ext when any advanced features are present.\n // Scene1 has none of these, so it won't pay the ~1.5KB cost.\n let _createPbrTemplateExt: typeof import(\"./pbr-template-ext.js\").createPbrTemplateExt | null = null;\n if (hasAnyUvTransform || hasAnyVertexColor || hasAnyUv2) {\n const extMod = await import(\"./pbr-template-ext.js\");\n _createPbrTemplateExt = extMod.createPbrTemplateExt;\n }\n\n const _gammaTemplate = hasGammaAlbedo ? await import(\"./pbr-template-gamma.js\") : null;\n\n let _createThinInstanceFragment: ((hasColor: boolean) => ShaderFragment) | null = null;\n let _syncThinInstanceBuffers: SyncThinInstanceBuffers | null = null;\n let _cull: typeof import(\"../../mesh/thin-instance-cull-binding.js\") | undefined;\n // Per-frame thin-instance matrix/color UPLOAD (no pass — just writeBuffer of the dirty range).\n // The bundle-recorded draw only re-binds the buffer; animated instances (e.g. wind-swayed flora)\n // mutate their matrices every frame, but the cached opaque bundle is NOT re-recorded each frame,\n // so the draw-time sync never runs on a steady frame. We therefore upload dirty thin-instance data\n // from the per-frame update() below (which always runs). It is version-gated, so static instances\n // cost nothing, and it never recreates the buffer for a same-capacity update — keeping the cached\n // bundle's setVertexBuffer reference valid.\n let _syncThinInstanceForDraw: ((engine: EngineContext, ti: ThinInstanceData, hasColor: boolean, indexCount: number) => GPUBuffer | null) | null = null;\n if (hasSomeThinInstances) {\n const mod = await import(\"../../shader/fragments/thin-instance-fragment.js\");\n _createThinInstanceFragment = mod.createThinInstanceFragment;\n const gpuMod = await import(\"../../mesh/thin-instance-gpu.js\");\n _syncThinInstanceBuffers = gpuMod.syncThinInstanceBuffers;\n if (hasCullingTI) {\n _cull = await import(\"../../mesh/thin-instance-cull-binding.js\");\n }\n _syncThinInstanceForDraw = gpuMod.syncThinInstanceForDraw;\n }\n\n // Tone mapping WGSL comes from the pluggable `imageProcessing.toneMapping` value, so a bundle only\n // carries the algorithm it references (e.g. AcesToneMapping's ~0.5 KB is bundled only when the app\n // imports it). When tone mapping is enabled but no algorithm was chosen, fall back to the default\n // StandardToneMapping — the single source of the standard exponential WGSL (pbr-template no longer\n // bakes its own copy).\n let _toneMappingHelpers = \"\";\n let _toneMappingCall = \"\";\n const hasTonemap = scene.imageProcessing.toneMappingEnabled;\n if (hasTonemap) {\n const toneMapping = scene.imageProcessing.toneMapping ?? StandardToneMapping;\n _toneMappingHelpers = toneMapping.helpersWGSL;\n _toneMappingCall = toneMapping.callWGSL;\n }\n\n // Fog WGSL is dynamically imported only when the scene has fog, so non-fog PBR scenes\n // bundle zero fog bytes (a static import would defeat tree-shaking — see pbr-fog-wgsl.ts).\n let _fogHelper = \"\";\n let _fogBlock = \"\";\n if (scene.fog) {\n const fogMod = await import(\"./pbr-fog-wgsl.js\");\n _fogHelper = fogMod.PBR_FOG_HELPER;\n _fogBlock = fogMod.PBR_FOG_BLOCK;\n }\n\n const composePbr = createPbrComposer({\n _singleLightWGSL,\n _getSingleLightBlock,\n _multiLightWGSL,\n _multiLightLoop,\n _toneMappingHelpers,\n _toneMappingCall,\n _fogHelper,\n _fogBlock,\n _createPbrTemplateExt,\n _anisoExt,\n _iblSkyboxCalc,\n _flatNormalWgsl,\n _gammaTemplate,\n _createPbrShadowFragment,\n _shadowLights: shadowLights,\n _createThinInstanceFragment,\n });\n\n const sceneFeatures = (hasEnv ? PBR_HAS_ENV : 0) | (hasTonemap ? PBR_HAS_TONEMAP : 0) | (scene.fog ? PBR_HAS_FOG : 0);\n // Shadow bind group cache — within one scene build, all receiving meshes share the\n // same shadowLights array, so a BG keyed by shadowBGL alone is correct.\n const shadowBGCache = new Map<GPUBindGroupLayout, GPUBindGroup>();\n const syncThinInstanceBuffers = _syncThinInstanceBuffers;\n const syncThinInstanceForDraw = _syncThinInstanceForDraw;\n\n // Closure used both for the initial per-mesh build below AND for later\n // material-swap / per-pass-override rebuilds (set on pbrGroupBuilder._rebuildSingle).\n // Captures the per-scene context — no separate WeakMap needed.\n const rebuildSingle = (s: SceneContext, mesh: Mesh, materialOverride?: Material): Renderable => {\n const materialInput = (materialOverride ?? mesh.material) as PbrMaterialProps;\n const mat = materialInput;\n const renderFeatures = (mat._renderFeatures ??= _computePbrMaterialFeatures(mat)) as MaterialRenderFeatures;\n const isOverride = materialOverride != null;\n const mi = mesh;\n\n const lr = writeMeshLightSelection(mesh, s.lights);\n const lightCount = lr > 0 ? 1 : -lr;\n const features = renderFeatures.features;\n const features2 = renderFeatures.features2 ?? 0;\n const shadowOutput = (features2 & (PBR2_NO_COLOR_OUTPUT | PBR2_ESM_SHADOW_OUTPUT)) !== 0;\n const receiveShadows = !shadowOutput && mesh.receiveShadows && hasSomeShadows;\n const lightMode: PbrLightMode = lightCount === 0 ? 0 : lightCount === 1 && !receiveShadows ? 1 : 2;\n const singleLightType = lightMode === 1 ? getPackedSingleLightType(s.lights, lr - 1) : \"\";\n const meshFeatures = _computeMeshFeatures(mesh, receiveShadows);\n const esmShadowDepthCode = (features2 & PBR2_ESM_SHADOW_OUTPUT) !== 0 ? (mat as PbrMaterialProps & { readonly _esmShadowDepthCode: string })._esmShadowDepthCode : \"\";\n\n // Genuine GPU interleaving. Tight meshes have `_vbLayout` undefined → vbKey \"\"\n // → composed shader, bindings, and pipeline cache keys are byte-identical to\n // today. Interleaved meshes carry a precomputed vbKey from the loader module.\n const vbLayout = mi._gpu._vbLayout;\n const vbKey = mi._gpu._vbKey ?? \"\";\n const uv2Mask = (mat as { _uv2Mask?: number })._uv2Mask ?? 0;\n\n const composed = composePbr(features, features2, meshFeatures, sceneFeatures, lightMode, singleLightType, esmShadowDepthCode, vbLayout, vbKey, uv2Mask);\n const bindings = getOrCreatePbrBindings(\n engine,\n features,\n features2,\n meshFeatures,\n sceneFeatures,\n composed,\n `${lightMode}:${singleLightType}${vbKey}:${uv2Mask}`,\n mat.stencil ?? null\n );\n\n // Mesh UBO (world matrix at offset 0; spec.totalBytes covers any extra fields).\n const meshUboData = new F32(composed._meshUboSpec._totalBytes / 4);\n const _packMeshWorld = engine._makePackMeshWorld?.(s as SceneContext) ?? packMat4IntoF32;\n _packMeshWorld(meshUboData, mesh.worldMatrix, 0, 0);\n writeMeshLightSelection(mesh, s.lights, meshUboData);\n const meshUBO = createUniformBuffer(engine, meshUboData);\n\n // Material UBO.\n const materialSpec = composed._materialUboSpec!;\n const matInitData = new F32(materialSpec._totalBytes / 4);\n _writeMaterialData(matInitData, mat, materialSpec);\n const materialUBO = createUniformBuffer(engine, matInitData);\n\n const needsTaskRefraction = !!mat.transmissive && (features2 & PBR2_HAS_REFRACTION) !== 0;\n const materialBindGroupStatic = needsTaskRefraction ? null : createPbrMeshBindGroup(engine, bindings, composed, meshUBO, materialUBO, mat, envTextures ?? null, mesh);\n\n // Shadow bind group (group 2) — shared across receiving meshes via shadowBGCache.\n let shadowBindGroup: GPUBindGroup | null = null;\n const meshShadowLights = receiveShadows ? shadowLights : [];\n if (meshShadowLights.length > 0 && bindings._shadowBGL) {\n let cached = shadowBGCache.get(bindings._shadowBGL);\n if (!cached) {\n const entries: GPUBindGroupEntry[] = [];\n let b = 0;\n for (const sl of meshShadowLights) {\n const sg = sl.gen;\n entries.push({ binding: b++, resource: sg._depthTexture.createView() });\n entries.push({ binding: b++, resource: sg._depthSampler });\n entries.push({ binding: b++, resource: { buffer: sg._shadowUBO } });\n }\n cached = device.createBindGroup({ layout: bindings._shadowBGL, entries });\n shadowBGCache.set(bindings._shadowBGL, cached);\n }\n shadowBindGroup = cached;\n }\n\n const boundTextures = collectPbrBoundTextures(mat);\n for (const t of boundTextures) {\n acquireTexture(t);\n }\n s._meshDisposables.set(mesh, [\n () => {\n meshUBO.destroy();\n materialUBO.destroy();\n },\n () => {\n for (const t of boundTextures) {\n releaseTexture(t);\n }\n },\n ]);\n\n const isTransparent = (features2 & (PBR2_NO_COLOR_OUTPUT | PBR2_ESM_SHADOW_OUTPUT)) === 0 && (features & PBR_HAS_ALPHA_BLEND) !== 0;\n const order = mesh.renderOrder ?? (isTransparent || needsTaskRefraction ? 150 : 100);\n\n const hasNormalMap = (features & PBR_HAS_NORMAL_MAP) !== 0;\n const hasUV2 = (features2 & PBR2_HAS_UV2) !== 0 && (meshFeatures & MSH_HAS_UV2) !== 0;\n const hasVertexColor = (meshFeatures & MSH_HAS_VERTEX_COLOR) !== 0;\n const hasTI = (meshFeatures & MSH_HAS_THIN_INSTANCES) !== 0;\n const hasTIColor = (meshFeatures & MSH_HAS_INSTANCE_COLOR) !== 0;\n\n let _lastWorldVersion = mesh.worldMatrixVersion;\n let _lastLightsCount = s.lights.length;\n let thinDrawArgs: GPUBuffer | null = null;\n const sortCenter = isTransparent || needsTaskRefraction ? ([mesh.worldMatrix[12]!, mesh.worldMatrix[13]!, mesh.worldMatrix[14]!] as [number, number, number]) : null;\n const _baseUpdate = (): void => {\n const worldVersion = mesh.worldMatrixVersion;\n if (worldVersion !== _lastWorldVersion || s.lights.length !== _lastLightsCount) {\n if (sortCenter) {\n sortCenter[0] = mesh.worldMatrix[12]!;\n sortCenter[1] = mesh.worldMatrix[13]!;\n sortCenter[2] = mesh.worldMatrix[14]!;\n }\n _packMeshWorld(meshUboData, mesh.worldMatrix, 0, 0);\n writeMeshLightSelection(mesh, s.lights, meshUboData);\n device.queue.writeBuffer(meshUBO, 0, meshUboData as Float32Array<ArrayBuffer>);\n _lastWorldVersion = worldVersion;\n _lastLightsCount = s.lights.length;\n }\n const uboVersion = mat._uboVersion;\n if (uboVersion !== _lastUboVersion) {\n _lastUboVersion = uboVersion;\n let data = materialScratch.get(materialSpec._totalBytes);\n if (!data) {\n data = new F32(materialSpec._totalBytes / 4);\n materialScratch.set(materialSpec._totalBytes, data);\n } else {\n data.fill(0);\n }\n _writeMaterialData(data, mat, materialSpec);\n device.queue.writeBuffer(materialUBO, 0, data.buffer, 0, data.byteLength);\n }\n // Upload any dirty thin-instance matrices/colors every frame (version-gated; see the\n // _syncThinInstanceForDraw declaration above). This is what makes per-frame animated\n // instance transforms (wind sway) actually reach the GPU despite the cached draw bundle.\n if (hasTI) {\n thinDrawArgs = syncThinInstanceForDraw!(engine, mesh.thinInstances!, hasTIColor, mesh._gpu.indexCount);\n }\n };\n // FO-version wrapper applied only when the engine has floating-origin\n // on (see standard-renderable for the rationale).\n const _invalidate = (): void => {\n _lastWorldVersion = -1;\n };\n const update = engine._wrapRenderableForFO?.(_baseUpdate, s as SceneContext, _invalidate) ?? _baseUpdate;\n\n const drawWith = (\n pass: GPURenderPassEncoder | GPURenderBundleEncoder,\n materialBindGroup: GPUBindGroup,\n cullBinding?: import(\"../../mesh/thin-instance-cull-binding.js\").TiCullBinding\n ): number => {\n if (!isOverride && mesh.material !== materialInput) {\n return 0;\n }\n const gpu = mi._gpu;\n pass.setBindGroup(1, materialBindGroup);\n if (shadowBindGroup) {\n pass.setBindGroup(2, shadowBindGroup);\n }\n let slot = 0;\n // Interleaved meshes share one GPU buffer across attributes; the per-attribute\n // byte offset is baked into the pipeline vertex layout (attributes[].offset), so\n // every slot binds at offset 0. This matches Babylon.js WebGPU and avoids a\n // non-zero setVertexBuffer bind offset, which corrupts vertex fetch on some\n // AMD (Renoir) / Dawn paths (interleaved ClearCoatTest labels went black/garbage).\n pass.setVertexBuffer(slot++, gpu.positionBuffer);\n pass.setVertexBuffer(slot++, gpu.normalBuffer);\n if (hasNormalMap && gpu.tangentBuffer) {\n pass.setVertexBuffer(slot++, gpu.tangentBuffer);\n }\n pass.setVertexBuffer(slot++, gpu.uvBuffer);\n if (hasUV2 && gpu.uv2Buffer) {\n pass.setVertexBuffer(slot++, gpu.uv2Buffer);\n }\n if (hasVertexColor && gpu.colorBuffer) {\n pass.setVertexBuffer(slot++, gpu.colorBuffer);\n }\n // Skinning vertex buffers: live skeleton OR baked VAT (same field names, mutually exclusive).\n const skin = mesh.skeleton ?? mesh.vat;\n if (skin) {\n pass.setVertexBuffer(slot++, skin.jointsBuffer);\n pass.setVertexBuffer(slot++, skin.weightsBuffer);\n if (skin.joints1Buffer && skin.weights1Buffer) {\n pass.setVertexBuffer(slot++, skin.joints1Buffer);\n pass.setVertexBuffer(slot++, skin.weights1Buffer);\n }\n }\n\n const ti = hasTI ? mesh.thinInstances : null;\n if (ti && syncThinInstanceBuffers) {\n slot = syncThinInstanceBuffers(engine, ti, pass, slot, hasTIColor, cullBinding?.cullDrawBufs);\n }\n\n pass.setIndexBuffer(gpu.indexBuffer, gpu.indexFormat);\n if (cullBinding) {\n cullBinding.draw(pass, gpu.indexCount, ti!.count);\n } else if (thinDrawArgs) {\n pass.drawIndexedIndirect(thinDrawArgs, 0);\n } else {\n pass.drawIndexed(gpu.indexCount, ti?.count);\n }\n return 1;\n };\n\n const r: Renderable = {\n order,\n isTransparent,\n _transmissive: needsTaskRefraction,\n mesh,\n bind(eng, sig) {\n const pipeline = getOrCreatePbrPipeline(eng as EngineContext, sig, bindings);\n const materialBindGroup = needsTaskRefraction\n ? createPbrMeshBindGroup(engine, bindings, composed, meshUBO, materialUBO, mat, envTextures ?? null, mesh, sig._transmissionTexture)\n : materialBindGroupStatic!;\n // Opaque-only GPU culling (opt-in): tryBind returns a per-binding lifecycle or undefined.\n const cb = _cull?.tryBind(r, s, mesh, engine, hasTIColor, isTransparent || needsTaskRefraction, update, sig);\n return {\n renderable: r,\n pipeline,\n ...(cb ? { _updateBatches: [cb._updateBatch] } : {}),\n update: cb ? cb.update : update,\n draw: (pass) => drawWith(pass, materialBindGroup, cb),\n };\n },\n };\n if (sortCenter) {\n r._worldCenter = sortCenter;\n }\n let _lastUboVersion = mat._uboVersion;\n return r;\n };\n\n const renderables = meshes.map((m) => rebuildSingle(scene, m));\n\n // Stash the per-scene PBR context on the scene so the PBR geometry-renderer\n // path can reuse the same composer / env / shadow setup without re-running\n // the scene-wide scan above. Stored on the scene (not on pbrGroupBuilder)\n // to avoid a static cycle: pbrGroupBuilder lives in pbr-material.ts which\n // already dynamic-imports this module.\n (scene as SceneContext & { _pbrGeomContext?: _PbrGeometryContext })._pbrGeomContext = {\n _composePbr: composePbr,\n _sceneFeatures: sceneFeatures,\n _envTextures: envTextures ?? null,\n _shadowLights: shadowLights,\n _syncThinInstanceBuffers: _syncThinInstanceBuffers,\n _syncThinInstanceForDraw,\n };\n\n scene._disposables.push(\n () => clearPbrPipelineCache(),\n () => clearSamplerCache(engine)\n );\n\n return { renderables, rebuildSingle };\n}\n\n/** @internal Per-scene PBR context stashed on the singleton `pbrGroupBuilder`\n * after `buildPbrRenderables` runs. Consumed by the PBR geometry-renderer\n * module — the only way to reuse the per-scene `composePbr` closure (env,\n * shadows, lights, anisotropy, sub-features) without duplicating the heavy\n * scene-wide dep-gathering scan. Overwritten on each scene build, matching\n * the same pattern used for `_rebuildSingle`. */\nexport interface _PbrGeometryContext {\n /** @internal */\n readonly _composePbr: ReturnType<typeof createPbrComposer>;\n /** @internal */\n readonly _sceneFeatures: number;\n /** @internal */\n readonly _envTextures: EnvironmentTextures | null;\n /** @internal */\n readonly _shadowLights: readonly { readonly lightIndex: number; readonly shadowType: \"esm\" | \"pcf\" | \"csm\"; readonly gen: ShadowGenerator }[];\n /** @internal */\n readonly _syncThinInstanceBuffers: SyncThinInstanceBuffers | null;\n /** @internal */\n readonly _syncThinInstanceForDraw: ((engine: EngineContext, ti: ThinInstanceData, hasColor: boolean, indexCount: number) => GPUBuffer | null) | null;\n}\n\nfunction toSingleLightType(type: string): SingleLightType {\n return type === \"hemispheric\" || type === \"directional\" || type === \"spot\" ? type : \"point\";\n}\n\nfunction getPackedSingleLightType(lights: SceneContext[\"lights\"], packedIndex: number): SingleLightType {\n let packed = 0;\n for (const light of lights) {\n if (!light._writeLightUbo) {\n continue;\n }\n if (packed === packedIndex) {\n return toSingleLightType(light.lightType);\n }\n packed++;\n }\n return \"point\";\n}\n\nasync function importSingleLightWgsl(type: SingleLightType): Promise<SingleLightWgslModule> {\n if (type === \"hemispheric\") {\n return import(\"./fragments/singlelight-hemispheric-wgsl.js\");\n }\n if (type === \"directional\") {\n return import(\"./fragments/singlelight-directional-wgsl.js\");\n }\n if (type === \"spot\") {\n return import(\"./fragments/singlelight-spot-wgsl.js\");\n }\n return import(\"./fragments/singlelight-point-wgsl.js\");\n}\n\n/** @internal Write material properties into a pre-allocated Float32Array.\n * Core fields only; per-extension slices are contributed by registered\n * writers. Exported for the PBR geometry-renderer path. */\nexport function _writeMaterialData(data: Float32Array, material: PbrMaterialProps, spec: import(\"../../shader/fragment-types.js\").UboSpec): void {\n data[0] = material.environmentIntensity ?? 1.0;\n data[1] = material.directIntensity ?? 1.0;\n data[2] = material.reflectance ?? 0.04;\n data[3] = material.alpha ?? 1.0;\n const baseColorFactorOffset = spec._offsets.get(\"baseColorFactor\");\n if (baseColorFactorOffset !== undefined) {\n const off = baseColorFactorOffset / 4;\n const factor = material.baseColorFactor;\n data[off] = factor ? factor[0]! : 1.0;\n data[off + 1] = factor ? factor[1]! : 1.0;\n data[off + 2] = factor ? factor[2]! : 1.0;\n data[off + 3] = factor ? factor[3]! : 1.0;\n }\n if (spec._offsets.has(\"metallicFactor\")) {\n const off = spec._offsets.get(\"metallicFactor\")! / 4;\n data[off] = material.metallicFactor ?? 1.0;\n data[off + 1] = material.roughnessFactor ?? 1.0;\n data[off + 2] = material.normalTextureScale ?? 1.0;\n data[off + 3] = material.usePhysicalLightFalloff === false ? 0 : 1;\n }\n for (const ext of _getPbrExts().values()) {\n if (ext.writeUbo) {\n ext.writeUbo(data, material, spec._offsets);\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pbr-renderable.js","sources":["../../../../src/material/pbr/pbr-renderable.ts"],"sourcesContent":["/** PBR mesh renderable — builds Renderables from glTF PBR meshes + environment.\n *\n * `buildPbrRenderables` does shared per-scene setup (extension/fragment imports,\n * shader composer, scene bind group, multi-light UBO), then delegates per-mesh\n * work to `buildSinglePbrRenderable`. Both initial build and material-swap\n * rebuilds go through the same single-mesh function. */\n\nimport { F32 } from \"../../engine/typed-arrays.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { Mesh } from \"../../mesh/mesh.js\";\nimport type { PbrMaterialProps } from \"./pbr-material.js\";\nimport { collectPbrBoundTextures } from \"./pbr-material.js\";\nimport type { EnvironmentTextures } from \"../../loader-env/load-env.js\";\n\nimport type { Renderable, MeshGroupBuildResult } from \"../../render/renderable.js\";\nimport type { ShaderFragment } from \"../../shader/fragment-types.js\";\nimport { acquireTexture, releaseTexture, clearSamplerCache } from \"../../resource/gpu-pool.js\";\nimport { createUniformBuffer } from \"../../resource/gpu-buffers.js\";\nimport { getOrCreatePbrBindings, getOrCreatePbrPipeline, createPbrMeshBindGroup, clearPbrPipelineCache } from \"./pbr-pipeline.js\";\nimport {\n _registerPbrExt,\n _getPbrExts,\n PBR_HAS_NORMAL_MAP,\n PBR_HAS_ALPHA_BLEND,\n PBR2_NO_COLOR_OUTPUT,\n PBR2_HAS_REFRACTION,\n PBR2_HAS_UV2,\n PBR_HAS_ENV,\n PBR_HAS_TONEMAP,\n PBR_HAS_FOG,\n PBR2_ESM_SHADOW_OUTPUT,\n} from \"./pbr-flags.js\";\nimport type { PbrExt } from \"./pbr-flags.js\";\nimport { createPbrComposer } from \"./pbr-compose.js\";\nimport { StandardToneMapping } from \"./tone-mapping.js\";\nimport { _computePbrMaterialFeatures } from \"./pbr-material.js\";\nimport type { ShadowGenerator } from \"../../shadow/shadow-generator.js\";\nimport type { ThinInstanceData } from \"../../mesh/thin-instance.js\";\nimport type { PbrShadowLightSlot } from \"./fragments/pbr-shadow-fragment.js\";\nimport { writeMeshLightSelection } from \"../../render/lights-ubo.js\";\nimport type { PbrLightMode } from \"./pbr-compose.js\";\nimport type { Material, MaterialRenderFeatures } from \"../material.js\";\nimport { _computeMeshFeatures, MSH_HAS_INSTANCE_COLOR, MSH_HAS_THIN_INSTANCES, MSH_HAS_UV2, MSH_HAS_VERTEX_COLOR } from \"../mesh-features.js\";\nimport { packMat4IntoF32 } from \"../../math/pack-mat4-into-f32.js\";\n\ntype SingleLightType = \"hemispheric\" | \"directional\" | \"spot\" | \"point\";\ninterface SingleLightWgslModule {\n SINGLE_LIGHT_STRUCTS: string;\n getSingleLightBlock(): string;\n}\n\ntype SyncThinInstanceBuffers = (\n engine: EngineContext,\n ti: ThinInstanceData,\n pass: GPURenderPassEncoder | GPURenderBundleEncoder,\n slot: number,\n hasColor: boolean,\n drawBuffers?: import(\"../../mesh/thin-instance-gpu.js\").ThinInstanceDrawBuffers | null\n) => number;\n\n/** Build PBR Renderable(s) + a SceneUniformUpdater from PBR meshes. */\nexport async function buildPbrRenderables(scene: SceneContext, meshes: Mesh[], envTextures: EnvironmentTextures | undefined): Promise<MeshGroupBuildResult> {\n const engine = scene.surface.engine;\n const device = engine._device;\n // Per-size scratch buffers for material UBO re-writes (zero allocation per frame).\n const materialScratch = new Map<number, Float32Array>();\n const hasEnv = !!envTextures;\n const shadowLights: { lightIndex: number; shadowType: \"esm\" | \"pcf\" | \"csm\"; gen: ShadowGenerator }[] = [];\n for (let i = 0; i < scene.lights.length; i++) {\n const sg = scene.lights[i]!.shadowGenerator;\n if (sg) {\n shadowLights.push({ lightIndex: i, shadowType: sg._shadowType, gen: sg });\n }\n }\n const hasSomeShadows = shadowLights.length > 0;\n let hasAnyAffectedLight = false;\n let needsSingleLightPath = false;\n let needsMultiLightPath = false;\n const singleLightTypes: SingleLightType[] = [];\n for (const mesh of meshes) {\n const lr = writeMeshLightSelection(mesh, scene.lights);\n const affectedCount = lr > 0 ? 1 : -lr;\n hasAnyAffectedLight ||= affectedCount > 0;\n if (affectedCount === 1 && !(mesh.receiveShadows && hasSomeShadows)) {\n needsSingleLightPath = true;\n const type = getPackedSingleLightType(scene.lights, lr - 1);\n if (!singleLightTypes.includes(type)) {\n singleLightTypes.push(type);\n }\n } else if (affectedCount > 0) {\n needsMultiLightPath = true;\n }\n }\n\n // ── Single O(N) scan over meshes for all scene-wide feature flags ──\n // Flags are plain locals (not an object return) so terser can mangle their names.\n // Replaces ~11 sequential meshes.some() loops (was O(11N)).\n let hasSkybox = false;\n let hasMetallicReflectance = false;\n let hasClearcoat = false;\n let hasSheen = false;\n let hasIridescence = false;\n let hasAnyAnisotropy = false;\n let hasAnySubsurface = false;\n let hasAlphaTest = false;\n let hasTransmissionRefraction = false;\n let needsEmissiveColor = false;\n let hasSomeSkeletons = false;\n let hasSomeMorphs = false;\n let hasSomeThinInstances = false;\n let hasCullingTI = false;\n let hasAnyUnlit = false;\n let hasAnyShadowOnly = false;\n let hasAnyUvTransform = false;\n let hasAnyUv2 = false;\n let hasAnyVertexColor = false;\n let hasAnyFlatNormal = false;\n let hasGammaAlbedo = false;\n for (let i = 0; i < meshes.length; i++) {\n const m = meshes[i]!;\n const mat = m.material as PbrMaterialProps & { _hasReflExt?: boolean; _hasUvTx?: boolean };\n const refractionIntensity = mat.subsurface?.refraction?.intensity ?? 0;\n hasSkybox ||= !!mat.skyboxMode;\n hasMetallicReflectance ||= !!(mat.metallicReflectanceTexture || mat.reflectanceTexture || mat._hasReflExt);\n hasClearcoat ||= !!mat.clearCoat?.isEnabled;\n hasSheen ||= !!mat.sheen?.isEnabled;\n hasIridescence ||= !!mat.iridescence?.isEnabled;\n hasAnyAnisotropy ||= !!mat.anisotropy?.isEnabled;\n hasAnySubsurface ||= !!mat.subsurface?.translucency;\n hasAlphaTest ||= mat.alphaCutOff! > 0;\n hasTransmissionRefraction ||= refractionIntensity > 0 && !!mat.transmissive;\n needsEmissiveColor ||= !!mat.emissiveColor;\n hasSomeSkeletons ||= !!m.skeleton;\n hasSomeMorphs ||= !!m.morphTargets;\n hasSomeThinInstances ||= !!m.thinInstances;\n hasCullingTI ||= !!m.thinInstances?._gpuCullingEnabled;\n hasAnyUnlit ||= !!mat.unlit;\n hasAnyShadowOnly ||= !!mat.shadowOnly;\n hasAnyUvTransform ||= !!mat._hasUvTx;\n // UV2 counts when ANY PBR channel samples texCoord 1 (occlusion included, via `_uv2Mask`\n // bit 32) — precomputed as `_uv2Mask` on the material by the glTF slow path (0/undefined on\n // the fast path). Occlusion-on-UV1 (incl. KHR_texture_basisu) always routes through that slow\n // path, so its UV2 usage is already reflected here without a separate occlusionTexCoord check.\n hasAnyUv2 ||= !!m._gpu.uv2Buffer && !!(mat as { _uv2Mask?: number })._uv2Mask;\n hasAnyVertexColor ||= !!m._gpu.colorBuffer;\n hasAnyFlatNormal ||= !!(m as { _flatNormal?: boolean })._flatNormal;\n hasGammaAlbedo ||= !!mat.gammaAlbedo;\n }\n\n // ── Dynamically import fragment creators based on scene capabilities ──\n\n // IBL fragment.\n let _iblSkyboxCalc = \"\";\n if (hasEnv) {\n const mod = await import(\"./fragments/ibl-fragment.js\");\n _registerPbrExt(mod.pbrExt);\n if (hasSkybox) {\n // Skybox-mode WGSL is only loaded when at least one mesh in the scene needs it.\n const sky = await import(\"./fragments/ibl-skybox-wgsl.js\");\n _iblSkyboxCalc = sky.IBL_SKYBOX_CALCULATION;\n }\n }\n\n // Flat-normal WGSL is only loaded when at least one mesh lacks a NORMAL attribute\n // (glTF flat-shading) — normal-having scenes bundle zero bytes.\n let _flatNormalWgsl = \"\";\n if (hasAnyFlatNormal) {\n const flatNormal = await import(\"./fragments/flat-normal-wgsl.js\");\n _flatNormalWgsl = flatNormal.FLAT_NORMAL_WGSL;\n }\n\n // Light/shadow helpers stay dynamic so single-light and non-shadow bundles stay lean.\n let _createPbrShadowFragment: ((slots: PbrShadowLightSlot[]) => ShaderFragment) | null = null;\n let _singleLightWGSL = \"\";\n let _getSingleLightBlock: ((type: string) => string) | null = null;\n const singleLightBlocks: Partial<Record<SingleLightType, () => string>> = {};\n let _multiLightWGSL = \"\";\n let _multiLightLoop = \"\";\n if (needsSingleLightPath) {\n for (const type of singleLightTypes) {\n const single = await importSingleLightWgsl(type);\n _singleLightWGSL = single.SINGLE_LIGHT_STRUCTS;\n singleLightBlocks[type] = single.getSingleLightBlock;\n }\n _getSingleLightBlock = (type) => singleLightBlocks[toSingleLightType(type)]?.() ?? \"\";\n }\n if (needsMultiLightPath) {\n const wgslMod = await import(\"./fragments/multilight-wgsl.js\");\n _multiLightWGSL = wgslMod.MULTI_LIGHT_STRUCTS() + wgslMod.COMPUTE_PBR_LIGHT;\n _multiLightLoop = wgslMod.getMultiLightLoop();\n }\n if (hasAnyAffectedLight && hasSomeShadows) {\n const shadowMod = await import(\"./fragments/pbr-shadow-fragment.js\");\n _createPbrShadowFragment = shadowMod.createPbrShadowFragment;\n }\n\n // ── Per-mesh fragment creators (imported if any mesh needs them) ──\n // Each optional PBR fragment module exports a uniform `pbrExt`, so registration\n // collapses to a single data-driven loop over [flag, loader] pairs. The `import()`\n // specifiers stay literal (required for Vite code-splitting) and the shared\n // `_registerPbrExt((await load()).pbrExt)` glue is emitted once instead of per\n // feature, keeping this management layer small as features are added.\n // Registration order is the iteration order consumed by `_getPbrExts().values()`\n // on the hot paths (composePbr, writeMaterialData, collectPbrBoundTextures).\n type PbrExtLoad = () => Promise<{ pbrExt: PbrExt }>;\n const _drainPbrExts = async (loaders: Array<readonly [boolean, PbrExtLoad]>) => {\n for (const [flag, load] of loaders) {\n if (flag) {\n _registerPbrExt((await load()).pbrExt);\n }\n }\n };\n\n await _drainPbrExts([\n [hasAlphaTest, () => import(\"./fragments/alpha-test-fragment.js\")],\n [hasMetallicReflectance, () => import(\"./fragments/reflectance-fragment.js\")],\n [hasClearcoat, () => import(\"./fragments/clearcoat-fragment.js\")],\n [hasSheen, () => import(\"./fragments/sheen-fragment.js\")],\n [hasIridescence, () => import(\"./fragments/iridescence-fragment.js\")],\n [hasAnySubsurface, () => import(\"./fragments/subsurface-fragment.js\")],\n ]);\n if (hasTransmissionRefraction) {\n const mod = await import(\"./pbr-refraction.js\");\n await mod.registerPbrRefraction(scene as SceneContext, engine, _registerPbrExt);\n }\n await _drainPbrExts([\n [needsEmissiveColor, () => import(\"./fragments/emissive-fragment.js\")],\n [hasAnyUnlit, () => import(\"./fragments/unlit-fragment.js\")],\n [hasAnyShadowOnly, () => import(\"./fragments/shadow-only-fragment.js\")],\n [hasSomeSkeletons, () => import(\"./fragments/skeleton-fragment.js\")],\n [hasSomeMorphs, () => import(\"./fragments/morph-fragment.js\")],\n [hasAnyUvTransform, () => import(\"./fragments/uv-transform-fragment.js\")],\n ]);\n\n // Anisotropy needs its module reference retained (for ANISO_BRDF_FUNCTIONS /\n // makeAnisotropyTBBlock / ANISO_DIRECT_DG / ANISO_BENT_NORMAL strings consumed\n // by the template below), so it keeps the full module binding.\n let _anisoExt: typeof import(\"./fragments/anisotropy-fragment.js\") | null = null;\n if (hasAnyAnisotropy) {\n _anisoExt = await import(\"./fragments/anisotropy-fragment.js\");\n _registerPbrExt(_anisoExt.pbrExt);\n }\n\n // Lazy-load pbr-template-ext when any advanced features are present.\n // Scene1 has none of these, so it won't pay the ~1.5KB cost.\n let _createPbrTemplateExt: typeof import(\"./pbr-template-ext.js\").createPbrTemplateExt | null = null;\n if (hasAnyUvTransform || hasAnyVertexColor || hasAnyUv2) {\n const extMod = await import(\"./pbr-template-ext.js\");\n _createPbrTemplateExt = extMod.createPbrTemplateExt;\n }\n\n const _gammaTemplate = hasGammaAlbedo ? await import(\"./pbr-template-gamma.js\") : null;\n\n let _createThinInstanceFragment: ((hasColor: boolean) => ShaderFragment) | null = null;\n let _syncThinInstanceBuffers: SyncThinInstanceBuffers | null = null;\n let _cull: typeof import(\"../../mesh/thin-instance-cull-binding.js\") | undefined;\n // Per-frame thin-instance matrix/color UPLOAD (no pass — just writeBuffer of the dirty range).\n // The bundle-recorded draw only re-binds the buffer; animated instances (e.g. wind-swayed flora)\n // mutate their matrices every frame, but the cached opaque bundle is NOT re-recorded each frame,\n // so the draw-time sync never runs on a steady frame. We therefore upload dirty thin-instance data\n // from the per-frame update() below (which always runs). It is version-gated, so static instances\n // cost nothing, and it never recreates the buffer for a same-capacity update — keeping the cached\n // bundle's setVertexBuffer reference valid.\n let _syncThinInstanceForDraw: ((engine: EngineContext, ti: ThinInstanceData, hasColor: boolean, indexCount: number) => GPUBuffer | null) | null = null;\n if (hasSomeThinInstances) {\n const mod = await import(\"../../shader/fragments/thin-instance-fragment.js\");\n _createThinInstanceFragment = mod.createThinInstanceFragment;\n const gpuMod = await import(\"../../mesh/thin-instance-gpu.js\");\n _syncThinInstanceBuffers = gpuMod.syncThinInstanceBuffers;\n if (hasCullingTI) {\n _cull = await import(\"../../mesh/thin-instance-cull-binding.js\");\n }\n _syncThinInstanceForDraw = gpuMod.syncThinInstanceForDraw;\n }\n\n // Tone mapping WGSL comes from the pluggable `imageProcessing.toneMapping` value, so a bundle only\n // carries the algorithm it references (e.g. AcesToneMapping's ~0.5 KB is bundled only when the app\n // imports it). When tone mapping is enabled but no algorithm was chosen, fall back to the default\n // StandardToneMapping — the single source of the standard exponential WGSL (pbr-template no longer\n // bakes its own copy).\n let _toneMappingHelpers = \"\";\n let _toneMappingCall = \"\";\n const hasTonemap = scene.imageProcessing.toneMappingEnabled;\n if (hasTonemap) {\n const toneMapping = scene.imageProcessing.toneMapping ?? StandardToneMapping;\n _toneMappingHelpers = toneMapping.helpersWGSL;\n _toneMappingCall = toneMapping.callWGSL;\n }\n\n // Fog WGSL is dynamically imported only when the scene has fog, so non-fog PBR scenes\n // bundle zero fog bytes (a static import would defeat tree-shaking — see pbr-fog-wgsl.ts).\n let _fogHelper = \"\";\n let _fogBlock = \"\";\n if (scene.fog) {\n const fogMod = await import(\"./pbr-fog-wgsl.js\");\n _fogHelper = fogMod.PBR_FOG_HELPER;\n _fogBlock = fogMod.PBR_FOG_BLOCK;\n }\n\n const composePbr = createPbrComposer({\n _singleLightWGSL,\n _getSingleLightBlock,\n _multiLightWGSL,\n _multiLightLoop,\n _toneMappingHelpers,\n _toneMappingCall,\n _fogHelper,\n _fogBlock,\n _createPbrTemplateExt,\n _anisoExt,\n _iblSkyboxCalc,\n _flatNormalWgsl,\n _gammaTemplate,\n _createPbrShadowFragment,\n _shadowLights: shadowLights,\n _createThinInstanceFragment,\n });\n\n const sceneFeatures = (hasEnv ? PBR_HAS_ENV : 0) | (hasTonemap ? PBR_HAS_TONEMAP : 0) | (scene.fog ? PBR_HAS_FOG : 0);\n // Shadow bind group cache — within one scene build, all receiving meshes share the\n // same shadowLights array, so a BG keyed by shadowBGL alone is correct.\n const shadowBGCache = new Map<GPUBindGroupLayout, GPUBindGroup>();\n const syncThinInstanceBuffers = _syncThinInstanceBuffers;\n const syncThinInstanceForDraw = _syncThinInstanceForDraw;\n\n // Closure used both for the initial per-mesh build below AND for later\n // material-swap / per-pass-override rebuilds (set on pbrGroupBuilder._rebuildSingle).\n // Captures the per-scene context — no separate WeakMap needed.\n const rebuildSingle = (s: SceneContext, mesh: Mesh, materialOverride?: Material): Renderable => {\n const materialInput = (materialOverride ?? mesh.material) as PbrMaterialProps;\n const mat = materialInput;\n const renderFeatures = (mat._renderFeatures ??= _computePbrMaterialFeatures(mat)) as MaterialRenderFeatures;\n const isOverride = materialOverride != null;\n const mi = mesh;\n\n const lr = writeMeshLightSelection(mesh, s.lights);\n const lightCount = lr > 0 ? 1 : -lr;\n const features = renderFeatures.features;\n const features2 = renderFeatures.features2 ?? 0;\n const shadowOutput = (features2 & (PBR2_NO_COLOR_OUTPUT | PBR2_ESM_SHADOW_OUTPUT)) !== 0;\n const receiveShadows = !shadowOutput && mesh.receiveShadows && hasSomeShadows;\n const lightMode: PbrLightMode = lightCount === 0 ? 0 : lightCount === 1 && !receiveShadows ? 1 : 2;\n const singleLightType = lightMode === 1 ? getPackedSingleLightType(s.lights, lr - 1) : \"\";\n const meshFeatures = _computeMeshFeatures(mesh, receiveShadows);\n const esmShadowDepthCode = (features2 & PBR2_ESM_SHADOW_OUTPUT) !== 0 ? (mat as PbrMaterialProps & { readonly _esmShadowDepthCode: string })._esmShadowDepthCode : \"\";\n\n // Genuine GPU interleaving. Tight meshes have `_vbLayout` undefined → vbKey \"\"\n // → composed shader, bindings, and pipeline cache keys are byte-identical to\n // today. Interleaved meshes carry a precomputed vbKey from the loader module.\n const vbLayout = mi._gpu._vbLayout;\n const vbKey = mi._gpu._vbKey ?? \"\";\n const uv2Mask = (mat as { _uv2Mask?: number })._uv2Mask ?? 0;\n\n const composed = composePbr(features, features2, meshFeatures, sceneFeatures, lightMode, singleLightType, esmShadowDepthCode, vbLayout, vbKey, uv2Mask);\n const bindings = getOrCreatePbrBindings(\n engine,\n features,\n features2,\n meshFeatures,\n sceneFeatures,\n composed,\n `${lightMode}:${singleLightType}${vbKey}:${uv2Mask}`,\n mat.stencil ?? null\n );\n\n // Mesh UBO (world matrix at offset 0; spec.totalBytes covers any extra fields).\n const meshUboData = new F32(composed._meshUboSpec._totalBytes / 4);\n const _packMeshWorld = engine._makePackMeshWorld?.(s as SceneContext) ?? packMat4IntoF32;\n _packMeshWorld(meshUboData, mesh.worldMatrix, 0, 0);\n writeMeshLightSelection(mesh, s.lights, meshUboData);\n const meshUBO = createUniformBuffer(engine, meshUboData);\n\n // Material UBO.\n const materialSpec = composed._materialUboSpec!;\n const matInitData = new F32(materialSpec._totalBytes / 4);\n _writeMaterialData(matInitData, mat, materialSpec);\n const materialUBO = createUniformBuffer(engine, matInitData);\n\n const needsTaskRefraction = !!mat.transmissive && (features2 & PBR2_HAS_REFRACTION) !== 0;\n const materialBindGroupStatic = needsTaskRefraction ? null : createPbrMeshBindGroup(engine, bindings, composed, meshUBO, materialUBO, mat, envTextures ?? null, mesh);\n\n // Shadow bind group (group 2) — shared across receiving meshes via shadowBGCache.\n let shadowBindGroup: GPUBindGroup | null = null;\n const meshShadowLights = receiveShadows ? shadowLights : [];\n if (meshShadowLights.length > 0 && bindings._shadowBGL) {\n let cached = shadowBGCache.get(bindings._shadowBGL);\n if (!cached) {\n const entries: GPUBindGroupEntry[] = [];\n let b = 0;\n for (const sl of meshShadowLights) {\n const sg = sl.gen;\n entries.push({ binding: b++, resource: sg._depthTexture.createView() });\n entries.push({ binding: b++, resource: sg._depthSampler });\n entries.push({ binding: b++, resource: { buffer: sg._shadowUBO } });\n }\n cached = device.createBindGroup({ layout: bindings._shadowBGL, entries });\n shadowBGCache.set(bindings._shadowBGL, cached);\n }\n shadowBindGroup = cached;\n }\n\n const boundTextures = collectPbrBoundTextures(mat);\n for (const t of boundTextures) {\n acquireTexture(t);\n }\n s._meshDisposables.set(mesh, [\n () => {\n meshUBO.destroy();\n materialUBO.destroy();\n },\n () => {\n for (const t of boundTextures) {\n releaseTexture(t);\n }\n },\n ]);\n\n const isTransparent = (features2 & (PBR2_NO_COLOR_OUTPUT | PBR2_ESM_SHADOW_OUTPUT)) === 0 && (features & PBR_HAS_ALPHA_BLEND) !== 0;\n const order = mesh.renderOrder ?? (isTransparent || needsTaskRefraction ? 150 : 100);\n\n const hasNormalMap = (features & PBR_HAS_NORMAL_MAP) !== 0;\n const hasUV2 = (features2 & PBR2_HAS_UV2) !== 0 && (meshFeatures & MSH_HAS_UV2) !== 0;\n const hasVertexColor = (meshFeatures & MSH_HAS_VERTEX_COLOR) !== 0;\n const hasTI = (meshFeatures & MSH_HAS_THIN_INSTANCES) !== 0;\n const hasTIColor = (meshFeatures & MSH_HAS_INSTANCE_COLOR) !== 0;\n\n let _lastWorldVersion = mesh.worldMatrixVersion;\n let _lastLightsCount = s.lights.length;\n let thinDrawArgs: GPUBuffer | null = null;\n const sortCenter = isTransparent || needsTaskRefraction ? ([mesh.worldMatrix[12]!, mesh.worldMatrix[13]!, mesh.worldMatrix[14]!] as [number, number, number]) : null;\n const _baseUpdate = (): void => {\n const worldVersion = mesh.worldMatrixVersion;\n if (worldVersion !== _lastWorldVersion || s.lights.length !== _lastLightsCount) {\n if (sortCenter) {\n sortCenter[0] = mesh.worldMatrix[12]!;\n sortCenter[1] = mesh.worldMatrix[13]!;\n sortCenter[2] = mesh.worldMatrix[14]!;\n }\n _packMeshWorld(meshUboData, mesh.worldMatrix, 0, 0);\n writeMeshLightSelection(mesh, s.lights, meshUboData);\n device.queue.writeBuffer(meshUBO, 0, meshUboData as Float32Array<ArrayBuffer>);\n _lastWorldVersion = worldVersion;\n _lastLightsCount = s.lights.length;\n }\n const uboVersion = mat._uboVersion;\n if (uboVersion !== _lastUboVersion) {\n _lastUboVersion = uboVersion;\n let data = materialScratch.get(materialSpec._totalBytes);\n if (!data) {\n data = new F32(materialSpec._totalBytes / 4);\n materialScratch.set(materialSpec._totalBytes, data);\n } else {\n data.fill(0);\n }\n _writeMaterialData(data, mat, materialSpec);\n device.queue.writeBuffer(materialUBO, 0, data.buffer, 0, data.byteLength);\n }\n // Upload any dirty thin-instance matrices/colors every frame (version-gated; see the\n // _syncThinInstanceForDraw declaration above). This is what makes per-frame animated\n // instance transforms (wind sway) actually reach the GPU despite the cached draw bundle.\n if (hasTI) {\n thinDrawArgs = syncThinInstanceForDraw!(engine, mesh.thinInstances!, hasTIColor, mesh._gpu.indexCount);\n }\n };\n // FO-version wrapper applied only when the engine has floating-origin\n // on (see standard-renderable for the rationale).\n const _invalidate = (): void => {\n _lastWorldVersion = -1;\n };\n const update = engine._wrapRenderableForFO?.(_baseUpdate, s as SceneContext, _invalidate) ?? _baseUpdate;\n\n const drawWith = (\n pass: GPURenderPassEncoder | GPURenderBundleEncoder,\n materialBindGroup: GPUBindGroup,\n cullBinding?: import(\"../../mesh/thin-instance-cull-binding.js\").TiCullBinding\n ): number => {\n if (!isOverride && mesh.material !== materialInput) {\n return 0;\n }\n const gpu = mi._gpu;\n pass.setBindGroup(1, materialBindGroup);\n if (shadowBindGroup) {\n pass.setBindGroup(2, shadowBindGroup);\n }\n let slot = 0;\n // Interleaved meshes share one GPU buffer across attributes; the per-attribute\n // byte offset is baked into the pipeline vertex layout (attributes[].offset), so\n // every slot binds at offset 0. This matches Babylon.js WebGPU and avoids a\n // non-zero setVertexBuffer bind offset, which corrupts vertex fetch on some\n // AMD (Renoir) / Dawn paths (interleaved ClearCoatTest labels went black/garbage).\n pass.setVertexBuffer(slot++, gpu.positionBuffer);\n pass.setVertexBuffer(slot++, gpu.normalBuffer);\n if (hasNormalMap && gpu.tangentBuffer) {\n pass.setVertexBuffer(slot++, gpu.tangentBuffer);\n }\n pass.setVertexBuffer(slot++, gpu.uvBuffer);\n if (hasUV2 && gpu.uv2Buffer) {\n pass.setVertexBuffer(slot++, gpu.uv2Buffer);\n }\n if (hasVertexColor && gpu.colorBuffer) {\n pass.setVertexBuffer(slot++, gpu.colorBuffer);\n }\n // Skinning vertex buffers: live skeleton OR baked VAT (same field names, mutually exclusive).\n const skin = mesh.skeleton ?? mesh.vat;\n if (skin) {\n pass.setVertexBuffer(slot++, skin.jointsBuffer);\n pass.setVertexBuffer(slot++, skin.weightsBuffer);\n if (skin.joints1Buffer && skin.weights1Buffer) {\n pass.setVertexBuffer(slot++, skin.joints1Buffer);\n pass.setVertexBuffer(slot++, skin.weights1Buffer);\n }\n }\n\n const ti = hasTI ? mesh.thinInstances : null;\n if (ti && syncThinInstanceBuffers) {\n slot = syncThinInstanceBuffers(engine, ti, pass, slot, hasTIColor, cullBinding?.cullDrawBufs);\n }\n\n pass.setIndexBuffer(gpu.indexBuffer, gpu.indexFormat);\n if (cullBinding) {\n cullBinding.draw(pass, gpu.indexCount, ti!.count);\n } else if (thinDrawArgs) {\n pass.drawIndexedIndirect(thinDrawArgs, 0);\n } else {\n pass.drawIndexed(gpu.indexCount, ti?.count);\n }\n return 1;\n };\n\n const r: Renderable = {\n order,\n isTransparent,\n _transmissive: needsTaskRefraction,\n mesh,\n bind(eng, sig) {\n const pipeline = getOrCreatePbrPipeline(eng as EngineContext, sig, bindings);\n const materialBindGroup = needsTaskRefraction\n ? createPbrMeshBindGroup(engine, bindings, composed, meshUBO, materialUBO, mat, envTextures ?? null, mesh, sig._transmissionTexture)\n : materialBindGroupStatic!;\n // Opaque-only GPU culling (opt-in): tryBind returns a per-binding lifecycle or undefined.\n const cb = _cull?.tryBind(r, s, mesh, engine, hasTIColor, isTransparent || needsTaskRefraction, update, sig);\n return {\n renderable: r,\n pipeline,\n ...(cb ? { _updateBatches: [cb._updateBatch] } : {}),\n update: cb ? cb.update : update,\n draw: (pass) => drawWith(pass, materialBindGroup, cb),\n };\n },\n };\n if (sortCenter) {\n r._worldCenter = sortCenter;\n }\n let _lastUboVersion = mat._uboVersion;\n return r;\n };\n\n const renderables = meshes.map((m) => rebuildSingle(scene, m));\n\n // Stash the per-scene PBR context on the scene so the PBR geometry-renderer\n // path can reuse the same composer / env / shadow setup without re-running\n // the scene-wide scan above. Stored on the scene (not on pbrGroupBuilder)\n // to avoid a static cycle: pbrGroupBuilder lives in pbr-material.ts which\n // already dynamic-imports this module.\n (scene as SceneContext & { _pbrGeomContext?: _PbrGeometryContext })._pbrGeomContext = {\n _composePbr: composePbr,\n _sceneFeatures: sceneFeatures,\n _envTextures: envTextures ?? null,\n _shadowLights: shadowLights,\n _syncThinInstanceBuffers: _syncThinInstanceBuffers,\n _syncThinInstanceForDraw,\n };\n\n scene._disposables.push(\n () => clearPbrPipelineCache(),\n () => clearSamplerCache(engine)\n );\n\n return { renderables, rebuildSingle };\n}\n\n/** @internal Per-scene PBR context stashed on the singleton `pbrGroupBuilder`\n * after `buildPbrRenderables` runs. Consumed by the PBR geometry-renderer\n * module — the only way to reuse the per-scene `composePbr` closure (env,\n * shadows, lights, anisotropy, sub-features) without duplicating the heavy\n * scene-wide dep-gathering scan. Overwritten on each scene build, matching\n * the same pattern used for `_rebuildSingle`. */\nexport interface _PbrGeometryContext {\n /** @internal */\n readonly _composePbr: ReturnType<typeof createPbrComposer>;\n /** @internal */\n readonly _sceneFeatures: number;\n /** @internal */\n readonly _envTextures: EnvironmentTextures | null;\n /** @internal */\n readonly _shadowLights: readonly { readonly lightIndex: number; readonly shadowType: \"esm\" | \"pcf\" | \"csm\"; readonly gen: ShadowGenerator }[];\n /** @internal */\n readonly _syncThinInstanceBuffers: SyncThinInstanceBuffers | null;\n /** @internal */\n readonly _syncThinInstanceForDraw: ((engine: EngineContext, ti: ThinInstanceData, hasColor: boolean, indexCount: number) => GPUBuffer | null) | null;\n}\n\nfunction toSingleLightType(type: string): SingleLightType {\n return type === \"hemispheric\" || type === \"directional\" || type === \"spot\" ? type : \"point\";\n}\n\nfunction getPackedSingleLightType(lights: SceneContext[\"lights\"], packedIndex: number): SingleLightType {\n let packed = 0;\n for (const light of lights) {\n if (!light._writeLightUbo) {\n continue;\n }\n if (packed === packedIndex) {\n return toSingleLightType(light.lightType);\n }\n packed++;\n }\n return \"point\";\n}\n\nasync function importSingleLightWgsl(type: SingleLightType): Promise<SingleLightWgslModule> {\n if (type === \"hemispheric\") {\n return import(\"./fragments/singlelight-hemispheric-wgsl.js\");\n }\n if (type === \"directional\") {\n return import(\"./fragments/singlelight-directional-wgsl.js\");\n }\n if (type === \"spot\") {\n return import(\"./fragments/singlelight-spot-wgsl.js\");\n }\n return import(\"./fragments/singlelight-point-wgsl.js\");\n}\n\n/** @internal Write material properties into a pre-allocated Float32Array.\n * Core fields only; per-extension slices are contributed by registered\n * writers. Exported for the PBR geometry-renderer path. */\nexport function _writeMaterialData(data: Float32Array, material: PbrMaterialProps, spec: import(\"../../shader/fragment-types.js\").UboSpec): void {\n data[0] = material.environmentIntensity ?? 1.0;\n data[1] = material.directIntensity ?? 1.0;\n data[2] = material.reflectance ?? 0.04;\n data[3] = material.alpha ?? 1.0;\n const baseColorFactorOffset = spec._offsets.get(\"baseColorFactor\");\n if (baseColorFactorOffset !== undefined) {\n const off = baseColorFactorOffset / 4;\n const factor = material.baseColorFactor;\n data[off] = factor ? factor[0]! : 1.0;\n data[off + 1] = factor ? factor[1]! : 1.0;\n data[off + 2] = factor ? factor[2]! : 1.0;\n data[off + 3] = factor ? factor[3]! : 1.0;\n }\n if (spec._offsets.has(\"metallicFactor\")) {\n const off = spec._offsets.get(\"metallicFactor\")! / 4;\n data[off] = material.metallicFactor ?? 1.0;\n data[off + 1] = material.roughnessFactor ?? 1.0;\n data[off + 2] = material.normalTextureScale ?? 1.0;\n data[off + 3] = material.usePhysicalLightFalloff === false ? 0 : 1;\n }\n for (const ext of _getPbrExts().values()) {\n if (ext.writeUbo) {\n ext.writeUbo(data, material, spec._offsets);\n }\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;AA8DA,eAAsB,mBAAA,CAAoB,KAAA,EAAqB,MAAA,EAAgB,WAAA,EAA6E;AACxJ,EAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,MAAA;AAC7B,EAAA,MAAM,SAAS,MAAA,CAAO,OAAA;AAEtB,EAAA,MAAM,eAAA,uBAAsB,GAAA,EAA0B;AACtD,EAAA,MAAM,MAAA,GAAS,CAAC,CAAC,WAAA;AACjB,EAAA,MAAM,eAAkG,EAAC;AACzG,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AAC1C,IAAA,MAAM,EAAA,GAAK,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,CAAG,eAAA;AAC5B,IAAA,IAAI,EAAA,EAAI;AACJ,MAAA,YAAA,CAAa,IAAA,CAAK,EAAE,UAAA,EAAY,CAAA,EAAG,YAAY,EAAA,CAAG,WAAA,EAAa,GAAA,EAAK,EAAA,EAAI,CAAA;AAAA,IAC5E;AAAA,EACJ;AACA,EAAA,MAAM,cAAA,GAAiB,aAAa,MAAA,GAAS,CAAA;AAC7C,EAAA,IAAI,mBAAA,GAAsB,KAAA;AAC1B,EAAA,IAAI,oBAAA,GAAuB,KAAA;AAC3B,EAAA,IAAI,mBAAA,GAAsB,KAAA;AAC1B,EAAA,MAAM,mBAAsC,EAAC;AAC7C,EAAA,KAAA,MAAW,QAAQ,MAAA,EAAQ;AACvB,IAAA,MAAM,EAAA,GAAK,uBAAA,CAAwB,IAAA,EAAM,KAAA,CAAM,MAAM,CAAA;AACrD,IAAA,MAAM,aAAA,GAAgB,EAAA,GAAK,CAAA,GAAI,CAAA,GAAI,CAAC,EAAA;AACpC,IAAA,mBAAA,KAAwB,aAAA,GAAgB,CAAA;AACxC,IAAA,IAAI,aAAA,KAAkB,CAAA,IAAK,EAAE,IAAA,CAAK,kBAAkB,cAAA,CAAA,EAAiB;AACjE,MAAA,oBAAA,GAAuB,IAAA;AACvB,MAAA,MAAM,IAAA,GAAO,wBAAA,CAAyB,KAAA,CAAM,MAAA,EAAQ,KAAK,CAAC,CAAA;AAC1D,MAAA,IAAI,CAAC,gBAAA,CAAiB,QAAA,CAAS,IAAI,CAAA,EAAG;AAClC,QAAA,gBAAA,CAAiB,KAAK,IAAI,CAAA;AAAA,MAC9B;AAAA,IACJ,CAAA,MAAA,IAAW,gBAAgB,CAAA,EAAG;AAC1B,MAAA,mBAAA,GAAsB,IAAA;AAAA,IAC1B;AAAA,EACJ;AAKA,EAAA,IAAI,SAAA,GAAY,KAAA;AAChB,EAAA,IAAI,sBAAA,GAAyB,KAAA;AAC7B,EAAA,IAAI,YAAA,GAAe,KAAA;AACnB,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,IAAI,cAAA,GAAiB,KAAA;AACrB,EAAA,IAAI,gBAAA,GAAmB,KAAA;AACvB,EAAA,IAAI,gBAAA,GAAmB,KAAA;AACvB,EAAA,IAAI,YAAA,GAAe,KAAA;AACnB,EAAA,IAAI,yBAAA,GAA4B,KAAA;AAChC,EAAA,IAAI,kBAAA,GAAqB,KAAA;AACzB,EAAA,IAAI,gBAAA,GAAmB,KAAA;AACvB,EAAA,IAAI,aAAA,GAAgB,KAAA;AACpB,EAAA,IAAI,oBAAA,GAAuB,KAAA;AAC3B,EAAA,IAAI,YAAA,GAAe,KAAA;AACnB,EAAA,IAAI,WAAA,GAAc,KAAA;AAClB,EAAA,IAAI,gBAAA,GAAmB,KAAA;AACvB,EAAA,IAAI,iBAAA,GAAoB,KAAA;AACxB,EAAA,IAAI,SAAA,GAAY,KAAA;AAChB,EAAA,IAAI,iBAAA,GAAoB,KAAA;AACxB,EAAA,IAAI,gBAAA,GAAmB,KAAA;AACvB,EAAA,IAAI,cAAA,GAAiB,KAAA;AACrB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACpC,IAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAClB,IAAA,MAAM,MAAM,CAAA,CAAE,QAAA;AACd,IAAA,MAAM,mBAAA,GAAsB,GAAA,CAAI,UAAA,EAAY,UAAA,EAAY,SAAA,IAAa,CAAA;AACrE,IAAA,SAAA,KAAc,CAAC,CAAC,GAAA,CAAI,UAAA;AACpB,IAAA,sBAAA,KAA2B,CAAC,EAAE,GAAA,CAAI,0BAAA,IAA8B,GAAA,CAAI,sBAAsB,GAAA,CAAI,WAAA,CAAA;AAC9F,IAAA,YAAA,KAAiB,CAAC,CAAC,GAAA,CAAI,SAAA,EAAW,SAAA;AAClC,IAAA,QAAA,KAAa,CAAC,CAAC,GAAA,CAAI,KAAA,EAAO,SAAA;AAC1B,IAAA,cAAA,KAAmB,CAAC,CAAC,GAAA,CAAI,WAAA,EAAa,SAAA;AACtC,IAAA,gBAAA,KAAqB,CAAC,CAAC,GAAA,CAAI,UAAA,EAAY,SAAA;AACvC,IAAA,gBAAA,KAAqB,CAAC,CAAC,GAAA,CAAI,UAAA,EAAY,YAAA;AACvC,IAAA,YAAA,KAAiB,IAAI,WAAA,GAAe,CAAA;AACpC,IAAA,yBAAA,KAA8B,mBAAA,GAAsB,CAAA,IAAK,CAAC,CAAC,GAAA,CAAI,YAAA;AAC/D,IAAA,kBAAA,KAAuB,CAAC,CAAC,GAAA,CAAI,aAAA;AAC7B,IAAA,gBAAA,KAAqB,CAAC,CAAC,CAAA,CAAE,QAAA;AACzB,IAAA,aAAA,KAAkB,CAAC,CAAC,CAAA,CAAE,YAAA;AACtB,IAAA,oBAAA,KAAyB,CAAC,CAAC,CAAA,CAAE,aAAA;AAC7B,IAAA,YAAA,KAAiB,CAAC,CAAC,CAAA,CAAE,aAAA,EAAe,kBAAA;AACpC,IAAA,WAAA,KAAgB,CAAC,CAAC,GAAA,CAAI,KAAA;AACtB,IAAA,gBAAA,KAAqB,CAAC,CAAC,GAAA,CAAI,UAAA;AAC3B,IAAA,iBAAA,KAAsB,CAAC,CAAC,GAAA,CAAI,QAAA;AAK5B,IAAA,SAAA,KAAc,CAAC,CAAC,CAAA,CAAE,KAAK,SAAA,IAAa,CAAC,CAAE,GAAA,CAA8B,QAAA;AACrE,IAAA,iBAAA,KAAsB,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,WAAA;AAC/B,IAAA,gBAAA,KAAqB,CAAC,CAAE,CAAA,CAAgC,WAAA;AACxD,IAAA,cAAA,KAAmB,CAAC,CAAC,GAAA,CAAI,WAAA;AAAA,EAC7B;AAKA,EAAA,IAAI,cAAA,GAAiB,EAAA;AACrB,EAAA,IAAI,MAAA,EAAQ;AACR,IAAA,MAAM,GAAA,GAAM,MAAM,OAAO,6BAA6B,CAAA;AACtD,IAAA,eAAA,CAAgB,IAAI,MAAM,CAAA;AAC1B,IAAA,IAAI,SAAA,EAAW;AAEX,MAAA,MAAM,GAAA,GAAM,MAAM,OAAO,gCAAgC,CAAA;AACzD,MAAA,cAAA,GAAiB,GAAA,CAAI,sBAAA;AAAA,IACzB;AAAA,EACJ;AAIA,EAAA,IAAI,eAAA,GAAkB,EAAA;AACtB,EAAA,IAAI,gBAAA,EAAkB;AAClB,IAAA,MAAM,UAAA,GAAa,MAAM,OAAO,iCAAiC,CAAA;AACjE,IAAA,eAAA,GAAkB,UAAA,CAAW,gBAAA;AAAA,EACjC;AAGA,EAAA,IAAI,wBAAA,GAAqF,IAAA;AACzF,EAAA,IAAI,gBAAA,GAAmB,EAAA;AACvB,EAAA,IAAI,oBAAA,GAA0D,IAAA;AAC9D,EAAA,MAAM,oBAAoE,EAAC;AAC3E,EAAA,IAAI,eAAA,GAAkB,EAAA;AACtB,EAAA,IAAI,eAAA,GAAkB,EAAA;AACtB,EAAA,IAAI,oBAAA,EAAsB;AACtB,IAAA,KAAA,MAAW,QAAQ,gBAAA,EAAkB;AACjC,MAAA,MAAM,MAAA,GAAS,MAAM,qBAAA,CAAsB,IAAI,CAAA;AAC/C,MAAA,gBAAA,GAAmB,MAAA,CAAO,oBAAA;AAC1B,MAAA,iBAAA,CAAkB,IAAI,IAAI,MAAA,CAAO,mBAAA;AAAA,IACrC;AACA,IAAA,oBAAA,GAAuB,CAAC,IAAA,KAAS,iBAAA,CAAkB,kBAAkB,IAAI,CAAC,KAAI,IAAK,EAAA;AAAA,EACvF;AACA,EAAA,IAAI,mBAAA,EAAqB;AACrB,IAAA,MAAM,OAAA,GAAU,MAAM,OAAO,gCAAgC,CAAA;AAC7D,IAAA,eAAA,GAAkB,OAAA,CAAQ,mBAAA,EAAoB,GAAI,OAAA,CAAQ,iBAAA;AAC1D,IAAA,eAAA,GAAkB,QAAQ,iBAAA,EAAkB;AAAA,EAChD;AACA,EAAA,IAAI,uBAAuB,cAAA,EAAgB;AACvC,IAAA,MAAM,SAAA,GAAY,MAAM,OAAO,oCAAoC,CAAA;AACnE,IAAA,wBAAA,GAA2B,SAAA,CAAU,uBAAA;AAAA,EACzC;AAWA,EAAA,MAAM,aAAA,GAAgB,OAAO,OAAA,KAAmD;AAC5E,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,IAAI,CAAA,IAAK,OAAA,EAAS;AAChC,MAAA,IAAI,IAAA,EAAM;AACN,QAAA,eAAA,CAAA,CAAiB,MAAM,IAAA,EAAK,EAAG,MAAM,CAAA;AAAA,MACzC;AAAA,IACJ;AAAA,EACJ,CAAA;AAEA,EAAA,MAAM,aAAA,CAAc;AAAA,IAChB,CAAC,YAAA,EAAc,MAAM,OAAO,oCAAoC,CAAC,CAAA;AAAA,IACjE,CAAC,sBAAA,EAAwB,MAAM,OAAO,qCAAqC,CAAC,CAAA;AAAA,IAC5E,CAAC,YAAA,EAAc,MAAM,OAAO,mCAAmC,CAAC,CAAA;AAAA,IAChE,CAAC,QAAA,EAAU,MAAM,OAAO,+BAA+B,CAAC,CAAA;AAAA,IACxD,CAAC,cAAA,EAAgB,MAAM,OAAO,qCAAqC,CAAC,CAAA;AAAA,IACpE,CAAC,gBAAA,EAAkB,MAAM,OAAO,oCAAoC,CAAC;AAAA,GACxE,CAAA;AACD,EAAA,IAAI,yBAAA,EAA2B;AAC3B,IAAA,MAAM,GAAA,GAAM,MAAM,OAAO,qBAAqB,CAAA;AAC9C,IAAA,MAAM,GAAA,CAAI,qBAAA,CAAsB,KAAA,EAAuB,MAAA,EAAQ,eAAe,CAAA;AAAA,EAClF;AACA,EAAA,MAAM,aAAA,CAAc;AAAA,IAChB,CAAC,kBAAA,EAAoB,MAAM,OAAO,kCAAkC,CAAC,CAAA;AAAA,IACrE,CAAC,WAAA,EAAa,MAAM,OAAO,+BAA+B,CAAC,CAAA;AAAA,IAC3D,CAAC,gBAAA,EAAkB,MAAM,OAAO,qCAAqC,CAAC,CAAA;AAAA,IACtE,CAAC,gBAAA,EAAkB,MAAM,OAAO,kCAAkC,CAAC,CAAA;AAAA,IACnE,CAAC,aAAA,EAAe,MAAM,OAAO,+BAA+B,CAAC,CAAA;AAAA,IAC7D,CAAC,iBAAA,EAAmB,MAAM,OAAO,sCAAsC,CAAC;AAAA,GAC3E,CAAA;AAKD,EAAA,IAAI,SAAA,GAAwE,IAAA;AAC5E,EAAA,IAAI,gBAAA,EAAkB;AAClB,IAAA,SAAA,GAAY,MAAM,OAAO,oCAAoC,CAAA;AAC7D,IAAA,eAAA,CAAgB,UAAU,MAAM,CAAA;AAAA,EACpC;AAIA,EAAA,IAAI,qBAAA,GAA4F,IAAA;AAChG,EAAA,IAAI,iBAAA,IAAqB,qBAAqB,SAAA,EAAW;AACrD,IAAA,MAAM,MAAA,GAAS,MAAM,OAAO,uBAAuB,CAAA;AACnD,IAAA,qBAAA,GAAwB,MAAA,CAAO,oBAAA;AAAA,EACnC;AAEA,EAAA,MAAM,cAAA,GAAiB,cAAA,GAAiB,MAAM,OAAO,yBAAyB,CAAA,GAAI,IAAA;AAElF,EAAA,IAAI,2BAAA,GAA8E,IAAA;AAClF,EAAA,IAAI,wBAAA,GAA2D,IAAA;AAC/D,EAAA,IAAI,KAAA;AAQJ,EAAA,IAAI,wBAAA,GAA8I,IAAA;AAClJ,EAAA,IAAI,oBAAA,EAAsB;AACtB,IAAA,MAAM,GAAA,GAAM,MAAM,OAAO,kDAAkD,CAAA;AAC3E,IAAA,2BAAA,GAA8B,GAAA,CAAI,0BAAA;AAClC,IAAA,MAAM,MAAA,GAAS,MAAM,OAAO,iCAAiC,CAAA;AAC7D,IAAA,wBAAA,GAA2B,MAAA,CAAO,uBAAA;AAClC,IAAA,IAAI,YAAA,EAAc;AACd,MAAA,KAAA,GAAQ,MAAM,OAAO,0CAA0C,CAAA;AAAA,IACnE;AACA,IAAA,wBAAA,GAA2B,MAAA,CAAO,uBAAA;AAAA,EACtC;AAOA,EAAA,IAAI,mBAAA,GAAsB,EAAA;AAC1B,EAAA,IAAI,gBAAA,GAAmB,EAAA;AACvB,EAAA,MAAM,UAAA,GAAa,MAAM,eAAA,CAAgB,kBAAA;AACzC,EAAA,IAAI,UAAA,EAAY;AACZ,IAAA,MAAM,WAAA,GAAc,KAAA,CAAM,eAAA,CAAgB,WAAA,IAAe,mBAAA;AACzD,IAAA,mBAAA,GAAsB,WAAA,CAAY,WAAA;AAClC,IAAA,gBAAA,GAAmB,WAAA,CAAY,QAAA;AAAA,EACnC;AAIA,EAAA,IAAI,UAAA,GAAa,EAAA;AACjB,EAAA,IAAI,SAAA,GAAY,EAAA;AAChB,EAAA,IAAI,MAAM,GAAA,EAAK;AACX,IAAA,MAAM,MAAA,GAAS,MAAM,OAAO,mBAAmB,CAAA;AAC/C,IAAA,UAAA,GAAa,MAAA,CAAO,cAAA;AACpB,IAAA,SAAA,GAAY,MAAA,CAAO,aAAA;AAAA,EACvB;AAEA,EAAA,MAAM,aAAa,iBAAA,CAAkB;AAAA,IACjC,gBAAA;AAAA,IACA,oBAAA;AAAA,IACA,eAAA;AAAA,IACA,eAAA;AAAA,IACA,mBAAA;AAAA,IACA,gBAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA;AAAA,IACA,qBAAA;AAAA,IACA,SAAA;AAAA,IACA,cAAA;AAAA,IACA,eAAA;AAAA,IACA,cAAA;AAAA,IACA,wBAAA;AAAA,IACA,aAAA,EAAe,YAAA;AAAA,IACf;AAAA,GACH,CAAA;AAED,EAAA,MAAM,aAAA,GAAA,CAAiB,SAAS,WAAA,GAAc,CAAA,KAAM,aAAa,eAAA,GAAkB,CAAA,CAAA,IAAM,KAAA,CAAM,GAAA,GAAM,WAAA,GAAc,CAAA,CAAA;AAGnH,EAAA,MAAM,aAAA,uBAAoB,GAAA,EAAsC;AAChE,EAAA,MAAM,uBAAA,GAA0B,wBAAA;AAChC,EAAA,MAAM,uBAAA,GAA0B,wBAAA;AAKhC,EAAA,MAAM,aAAA,GAAgB,CAAC,CAAA,EAAiB,IAAA,EAAY,gBAAA,KAA4C;AAC5F,IAAA,MAAM,aAAA,GAAiB,oBAAoB,IAAA,CAAK,QAAA;AAChD,IAAA,MAAM,GAAA,GAAM,aAAA;AACZ,IAAA,MAAM,cAAA,GAAkB,GAAA,CAAI,eAAA,KAAoB,2BAAA,CAA4B,GAAG,CAAA;AAC/E,IAAA,MAAM,aAAa,gBAAA,IAAoB,IAAA;AACvC,IAAA,MAAM,EAAA,GAAK,IAAA;AAEX,IAAA,MAAM,EAAA,GAAK,uBAAA,CAAwB,IAAA,EAAM,CAAA,CAAE,MAAM,CAAA;AACjD,IAAA,MAAM,UAAA,GAAa,EAAA,GAAK,CAAA,GAAI,CAAA,GAAI,CAAC,EAAA;AACjC,IAAA,MAAM,WAAW,cAAA,CAAe,QAAA;AAChC,IAAA,MAAM,SAAA,GAAY,eAAe,SAAA,IAAa,CAAA;AAC9C,IAAA,MAAM,YAAA,GAAA,CAAgB,SAAA,IAAa,oBAAA,GAAuB,sBAAA,CAAA,MAA6B,CAAA;AACvF,IAAA,MAAM,cAAA,GAAiB,CAAC,YAAA,IAAgB,IAAA,CAAK,cAAA,IAAkB,cAAA;AAC/D,IAAA,MAAM,SAAA,GAA0B,eAAe,CAAA,GAAI,CAAA,GAAI,eAAe,CAAA,IAAK,CAAC,iBAAiB,CAAA,GAAI,CAAA;AACjG,IAAA,MAAM,eAAA,GAAkB,cAAc,CAAA,GAAI,wBAAA,CAAyB,EAAE,MAAA,EAAQ,EAAA,GAAK,CAAC,CAAA,GAAI,EAAA;AACvF,IAAA,MAAM,YAAA,GAAe,oBAAA,CAAqB,IAAA,EAAM,cAAc,CAAA;AAC9D,IAAA,MAAM,kBAAA,GAAA,CAAsB,SAAA,GAAY,sBAAA,MAA4B,CAAA,GAAK,IAAoE,mBAAA,GAAsB,EAAA;AAKnK,IAAA,MAAM,QAAA,GAAW,GAAG,IAAA,CAAK,SAAA;AACzB,IAAA,MAAM,KAAA,GAAQ,EAAA,CAAG,IAAA,CAAK,MAAA,IAAU,EAAA;AAChC,IAAA,MAAM,OAAA,GAAW,IAA8B,QAAA,IAAY,CAAA;AAE3D,IAAA,MAAM,QAAA,GAAW,UAAA,CAAW,QAAA,EAAU,SAAA,EAAW,YAAA,EAAc,aAAA,EAAe,SAAA,EAAW,eAAA,EAAiB,kBAAA,EAAoB,QAAA,EAAU,KAAA,EAAO,OAAO,CAAA;AACtJ,IAAA,MAAM,QAAA,GAAW,sBAAA;AAAA,MACb,MAAA;AAAA,MACA,QAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAA;AAAA,MACA,aAAA;AAAA,MACA,QAAA;AAAA,MACA,GAAG,SAAS,CAAA,CAAA,EAAI,eAAe,CAAA,EAAG,KAAK,IAAI,OAAO,CAAA,CAAA;AAAA,MAClD,IAAI,OAAA,IAAW;AAAA,KACnB;AAGA,IAAA,MAAM,cAAc,IAAI,GAAA,CAAI,QAAA,CAAS,YAAA,CAAa,cAAc,CAAC,CAAA;AACjE,IAAA,MAAM,cAAA,GAAiB,MAAA,CAAO,kBAAA,GAAqB,CAAiB,CAAA,IAAK,eAAA;AACzE,IAAA,cAAA,CAAe,WAAA,EAAa,IAAA,CAAK,WAAA,EAAa,CAAA,EAAG,CAAC,CAAA;AAClD,IAAA,uBAAA,CAAwB,IAAA,EAAM,CAAA,CAAE,MAAA,EAAQ,WAAW,CAAA;AACnD,IAAA,MAAM,OAAA,GAAU,mBAAA,CAAoB,MAAA,EAAQ,WAAW,CAAA;AAGvD,IAAA,MAAM,eAAe,QAAA,CAAS,gBAAA;AAC9B,IAAA,MAAM,WAAA,GAAc,IAAI,GAAA,CAAI,YAAA,CAAa,cAAc,CAAC,CAAA;AACxD,IAAA,kBAAA,CAAmB,WAAA,EAAa,KAAK,YAAY,CAAA;AACjD,IAAA,MAAM,WAAA,GAAc,mBAAA,CAAoB,MAAA,EAAQ,WAAW,CAAA;AAE3D,IAAA,MAAM,sBAAsB,CAAC,CAAC,GAAA,CAAI,YAAA,IAAA,CAAiB,YAAY,mBAAA,MAAyB,CAAA;AACxF,IAAA,MAAM,uBAAA,GAA0B,mBAAA,GAAsB,IAAA,GAAO,sBAAA,CAAuB,MAAA,EAAQ,QAAA,EAAU,QAAA,EAAU,OAAA,EAAS,WAAA,EAAa,GAAA,EAAK,WAAA,IAAe,IAAA,EAAM,IAAI,CAAA;AAGpK,IAAA,IAAI,eAAA,GAAuC,IAAA;AAC3C,IAAA,MAAM,gBAAA,GAAmB,cAAA,GAAiB,YAAA,GAAe,EAAC;AAC1D,IAAA,IAAI,gBAAA,CAAiB,MAAA,GAAS,CAAA,IAAK,QAAA,CAAS,UAAA,EAAY;AACpD,MAAA,IAAI,MAAA,GAAS,aAAA,CAAc,GAAA,CAAI,QAAA,CAAS,UAAU,CAAA;AAClD,MAAA,IAAI,CAAC,MAAA,EAAQ;AACT,QAAA,MAAM,UAA+B,EAAC;AACtC,QAAA,IAAI,CAAA,GAAI,CAAA;AACR,QAAA,KAAA,MAAW,MAAM,gBAAA,EAAkB;AAC/B,UAAA,MAAM,KAAK,EAAA,CAAG,GAAA;AACd,UAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,OAAA,EAAS,CAAA,EAAA,EAAK,UAAU,EAAA,CAAG,aAAA,CAAc,UAAA,EAAW,EAAG,CAAA;AACtE,UAAA,OAAA,CAAQ,KAAK,EAAE,OAAA,EAAS,KAAK,QAAA,EAAU,EAAA,CAAG,eAAe,CAAA;AACzD,UAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,OAAA,EAAS,CAAA,EAAA,EAAK,QAAA,EAAU,EAAE,MAAA,EAAQ,EAAA,CAAG,UAAA,EAAW,EAAG,CAAA;AAAA,QACtE;AACA,QAAA,MAAA,GAAS,OAAO,eAAA,CAAgB,EAAE,QAAQ,QAAA,CAAS,UAAA,EAAY,SAAS,CAAA;AACxE,QAAA,aAAA,CAAc,GAAA,CAAI,QAAA,CAAS,UAAA,EAAY,MAAM,CAAA;AAAA,MACjD;AACA,MAAA,eAAA,GAAkB,MAAA;AAAA,IACtB;AAEA,IAAA,MAAM,aAAA,GAAgB,wBAAwB,GAAG,CAAA;AACjD,IAAA,KAAA,MAAW,KAAK,aAAA,EAAe;AAC3B,MAAA,cAAA,CAAe,CAAC,CAAA;AAAA,IACpB;AACA,IAAA,CAAA,CAAE,gBAAA,CAAiB,IAAI,IAAA,EAAM;AAAA,MACzB,MAAM;AACF,QAAA,OAAA,CAAQ,OAAA,EAAQ;AAChB,QAAA,WAAA,CAAY,OAAA,EAAQ;AAAA,MACxB,CAAA;AAAA,MACA,MAAM;AACF,QAAA,KAAA,MAAW,KAAK,aAAA,EAAe;AAC3B,UAAA,cAAA,CAAe,CAAC,CAAA;AAAA,QACpB;AAAA,MACJ;AAAA,KACH,CAAA;AAED,IAAA,MAAM,iBAAiB,SAAA,IAAa,oBAAA,GAAuB,sBAAA,CAAA,MAA6B,CAAA,IAAA,CAAM,WAAW,mBAAA,MAAyB,CAAA;AAClI,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,WAAA,KAAgB,aAAA,IAAiB,sBAAsB,GAAA,GAAM,GAAA,CAAA;AAEhF,IAAA,MAAM,YAAA,GAAA,CAAgB,WAAW,kBAAA,MAAwB,CAAA;AACzD,IAAA,MAAM,MAAA,GAAA,CAAU,SAAA,GAAY,YAAA,MAAkB,CAAA,IAAA,CAAM,eAAe,WAAA,MAAiB,CAAA;AACpF,IAAA,MAAM,cAAA,GAAA,CAAkB,eAAe,oBAAA,MAA0B,CAAA;AACjE,IAAA,MAAM,KAAA,GAAA,CAAS,eAAe,sBAAA,MAA4B,CAAA;AAC1D,IAAA,MAAM,UAAA,GAAA,CAAc,eAAe,sBAAA,MAA4B,CAAA;AAE/D,IAAA,IAAI,oBAAoB,IAAA,CAAK,kBAAA;AAC7B,IAAA,IAAI,gBAAA,GAAmB,EAAE,MAAA,CAAO,MAAA;AAChC,IAAA,IAAI,YAAA,GAAiC,IAAA;AACrC,IAAA,MAAM,aAAa,aAAA,IAAiB,mBAAA,GAAuB,CAAC,IAAA,CAAK,YAAY,EAAE,CAAA,EAAI,IAAA,CAAK,WAAA,CAAY,EAAE,CAAA,EAAI,IAAA,CAAK,WAAA,CAAY,EAAE,CAAE,CAAA,GAAiC,IAAA;AAChK,IAAA,MAAM,cAAc,MAAY;AAC5B,MAAA,MAAM,eAAe,IAAA,CAAK,kBAAA;AAC1B,MAAA,IAAI,YAAA,KAAiB,iBAAA,IAAqB,CAAA,CAAE,MAAA,CAAO,WAAW,gBAAA,EAAkB;AAC5E,QAAA,IAAI,UAAA,EAAY;AACZ,UAAA,UAAA,CAAW,CAAC,CAAA,GAAI,IAAA,CAAK,WAAA,CAAY,EAAE,CAAA;AACnC,UAAA,UAAA,CAAW,CAAC,CAAA,GAAI,IAAA,CAAK,WAAA,CAAY,EAAE,CAAA;AACnC,UAAA,UAAA,CAAW,CAAC,CAAA,GAAI,IAAA,CAAK,WAAA,CAAY,EAAE,CAAA;AAAA,QACvC;AACA,QAAA,cAAA,CAAe,WAAA,EAAa,IAAA,CAAK,WAAA,EAAa,CAAA,EAAG,CAAC,CAAA;AAClD,QAAA,uBAAA,CAAwB,IAAA,EAAM,CAAA,CAAE,MAAA,EAAQ,WAAW,CAAA;AACnD,QAAA,MAAA,CAAO,KAAA,CAAM,WAAA,CAAY,OAAA,EAAS,CAAA,EAAG,WAAwC,CAAA;AAC7E,QAAA,iBAAA,GAAoB,YAAA;AACpB,QAAA,gBAAA,GAAmB,EAAE,MAAA,CAAO,MAAA;AAAA,MAChC;AACA,MAAA,MAAM,aAAa,GAAA,CAAI,WAAA;AACvB,MAAA,IAAI,eAAe,eAAA,EAAiB;AAChC,QAAA,eAAA,GAAkB,UAAA;AAClB,QAAA,IAAI,IAAA,GAAO,eAAA,CAAgB,GAAA,CAAI,YAAA,CAAa,WAAW,CAAA;AACvD,QAAA,IAAI,CAAC,IAAA,EAAM;AACP,UAAA,IAAA,GAAO,IAAI,GAAA,CAAI,YAAA,CAAa,WAAA,GAAc,CAAC,CAAA;AAC3C,UAAA,eAAA,CAAgB,GAAA,CAAI,YAAA,CAAa,WAAA,EAAa,IAAI,CAAA;AAAA,QACtD,CAAA,MAAO;AACH,UAAA,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,QACf;AACA,QAAA,kBAAA,CAAmB,IAAA,EAAM,KAAK,YAAY,CAAA;AAC1C,QAAA,MAAA,CAAO,KAAA,CAAM,YAAY,WAAA,EAAa,CAAA,EAAG,KAAK,MAAA,EAAQ,CAAA,EAAG,KAAK,UAAU,CAAA;AAAA,MAC5E;AAIA,MAAA,IAAI,KAAA,EAAO;AACP,QAAA,YAAA,GAAe,wBAAyB,MAAA,EAAQ,IAAA,CAAK,eAAgB,UAAA,EAAY,IAAA,CAAK,KAAK,UAAU,CAAA;AAAA,MACzG;AAAA,IACJ,CAAA;AAGA,IAAA,MAAM,cAAc,MAAY;AAC5B,MAAA,iBAAA,GAAoB,EAAA;AAAA,IACxB,CAAA;AACA,IAAA,MAAM,SAAS,MAAA,CAAO,oBAAA,GAAuB,WAAA,EAAa,CAAA,EAAmB,WAAW,CAAA,IAAK,WAAA;AAE7F,IAAA,MAAM,QAAA,GAAW,CACb,IAAA,EACA,iBAAA,EACA,WAAA,KACS;AACT,MAAA,IAAI,CAAC,UAAA,IAAc,IAAA,CAAK,QAAA,KAAa,aAAA,EAAe;AAChD,QAAA,OAAO,CAAA;AAAA,MACX;AACA,MAAA,MAAM,MAAM,EAAA,CAAG,IAAA;AACf,MAAA,IAAA,CAAK,YAAA,CAAa,GAAG,iBAAiB,CAAA;AACtC,MAAA,IAAI,eAAA,EAAiB;AACjB,QAAA,IAAA,CAAK,YAAA,CAAa,GAAG,eAAe,CAAA;AAAA,MACxC;AACA,MAAA,IAAI,IAAA,GAAO,CAAA;AAMX,MAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,EAAA,EAAQ,GAAA,CAAI,cAAc,CAAA;AAC/C,MAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,EAAA,EAAQ,GAAA,CAAI,YAAY,CAAA;AAC7C,MAAA,IAAI,YAAA,IAAgB,IAAI,aAAA,EAAe;AACnC,QAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,EAAA,EAAQ,GAAA,CAAI,aAAa,CAAA;AAAA,MAClD;AACA,MAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,EAAA,EAAQ,GAAA,CAAI,QAAQ,CAAA;AACzC,MAAA,IAAI,MAAA,IAAU,IAAI,SAAA,EAAW;AACzB,QAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,EAAA,EAAQ,GAAA,CAAI,SAAS,CAAA;AAAA,MAC9C;AACA,MAAA,IAAI,cAAA,IAAkB,IAAI,WAAA,EAAa;AACnC,QAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,EAAA,EAAQ,GAAA,CAAI,WAAW,CAAA;AAAA,MAChD;AAEA,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,IAAY,IAAA,CAAK,GAAA;AACnC,MAAA,IAAI,IAAA,EAAM;AACN,QAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,EAAA,EAAQ,IAAA,CAAK,YAAY,CAAA;AAC9C,QAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,EAAA,EAAQ,IAAA,CAAK,aAAa,CAAA;AAC/C,QAAA,IAAI,IAAA,CAAK,aAAA,IAAiB,IAAA,CAAK,cAAA,EAAgB;AAC3C,UAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,EAAA,EAAQ,IAAA,CAAK,aAAa,CAAA;AAC/C,UAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,EAAA,EAAQ,IAAA,CAAK,cAAc,CAAA;AAAA,QACpD;AAAA,MACJ;AAEA,MAAA,MAAM,EAAA,GAAK,KAAA,GAAQ,IAAA,CAAK,aAAA,GAAgB,IAAA;AACxC,MAAA,IAAI,MAAM,uBAAA,EAAyB;AAC/B,QAAA,IAAA,GAAO,wBAAwB,MAAA,EAAQ,EAAA,EAAI,MAAM,IAAA,EAAM,UAAA,EAAY,aAAa,YAAY,CAAA;AAAA,MAChG;AAEA,MAAA,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,WAAA,EAAa,GAAA,CAAI,WAAW,CAAA;AACpD,MAAA,IAAI,WAAA,EAAa;AACb,QAAA,WAAA,CAAY,IAAA,CAAK,IAAA,EAAM,GAAA,CAAI,UAAA,EAAY,GAAI,KAAK,CAAA;AAAA,MACpD,WAAW,YAAA,EAAc;AACrB,QAAA,IAAA,CAAK,mBAAA,CAAoB,cAAc,CAAC,CAAA;AAAA,MAC5C,CAAA,MAAO;AACH,QAAA,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,UAAA,EAAY,EAAA,EAAI,KAAK,CAAA;AAAA,MAC9C;AACA,MAAA,OAAO,CAAA;AAAA,IACX,CAAA;AAEA,IAAA,MAAM,CAAA,GAAgB;AAAA,MAClB,KAAA;AAAA,MACA,aAAA;AAAA,MACA,aAAA,EAAe,mBAAA;AAAA,MACf,IAAA;AAAA,MACA,IAAA,CAAK,KAAK,GAAA,EAAK;AACX,QAAA,MAAM,QAAA,GAAW,sBAAA,CAAuB,GAAA,EAAsB,GAAA,EAAK,QAAQ,CAAA;AAC3E,QAAA,MAAM,iBAAA,GAAoB,mBAAA,GACpB,sBAAA,CAAuB,MAAA,EAAQ,UAAU,QAAA,EAAU,OAAA,EAAS,WAAA,EAAa,GAAA,EAAK,WAAA,IAAe,IAAA,EAAM,IAAA,EAAM,GAAA,CAAI,oBAAoB,CAAA,GACjI,uBAAA;AAEN,QAAA,MAAM,EAAA,GAAK,KAAA,EAAO,OAAA,CAAQ,CAAA,EAAG,CAAA,EAAG,IAAA,EAAM,MAAA,EAAQ,UAAA,EAAY,aAAA,IAAiB,mBAAA,EAAqB,MAAA,EAAQ,GAAG,CAAA;AAC3G,QAAA,OAAO;AAAA,UACH,UAAA,EAAY,CAAA;AAAA,UACZ,QAAA;AAAA,UACA,GAAI,KAAK,EAAE,cAAA,EAAgB,CAAC,EAAA,CAAG,YAAY,CAAA,EAAE,GAAI,EAAC;AAAA,UAClD,MAAA,EAAQ,EAAA,GAAK,EAAA,CAAG,MAAA,GAAS,MAAA;AAAA,UACzB,MAAM,CAAC,IAAA,KAAS,QAAA,CAAS,IAAA,EAAM,mBAAmB,EAAE;AAAA,SACxD;AAAA,MACJ;AAAA,KACJ;AACA,IAAA,IAAI,UAAA,EAAY;AACZ,MAAA,CAAA,CAAE,YAAA,GAAe,UAAA;AAAA,IACrB;AACA,IAAA,IAAI,kBAAkB,GAAA,CAAI,WAAA;AAC1B,IAAA,OAAO,CAAA;AAAA,EACX,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,OAAO,GAAA,CAAI,CAAC,MAAM,aAAA,CAAc,KAAA,EAAO,CAAC,CAAC,CAAA;AAO7D,EAAC,MAAmE,eAAA,GAAkB;AAAA,IAClF,WAAA,EAAa,UAAA;AAAA,IACb,cAAA,EAAgB,aAAA;AAAA,IAChB,cAAc,WAAA,IAAe,IAAA;AAAA,IAC7B,aAAA,EAAe,YAAA;AAAA,IACf,wBAAA;AAAA,IACA;AAAA,GACJ;AAEA,EAAA,KAAA,CAAM,YAAA,CAAa,IAAA;AAAA,IACf,MAAM,qBAAA,EAAsB;AAAA,IAC5B,MAAM,kBAAkB,MAAM;AAAA,GAClC;AAEA,EAAA,OAAO,EAAE,aAAa,aAAA,EAAc;AACxC;AAuBA,SAAS,kBAAkB,IAAA,EAA+B;AACtD,EAAA,OAAO,SAAS,aAAA,IAAiB,IAAA,KAAS,aAAA,IAAiB,IAAA,KAAS,SAAS,IAAA,GAAO,OAAA;AACxF;AAEA,SAAS,wBAAA,CAAyB,QAAgC,WAAA,EAAsC;AACpG,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AACxB,IAAA,IAAI,CAAC,MAAM,cAAA,EAAgB;AACvB,MAAA;AAAA,IACJ;AACA,IAAA,IAAI,WAAW,WAAA,EAAa;AACxB,MAAA,OAAO,iBAAA,CAAkB,MAAM,SAAS,CAAA;AAAA,IAC5C;AACA,IAAA,MAAA,EAAA;AAAA,EACJ;AACA,EAAA,OAAO,OAAA;AACX;AAEA,eAAe,sBAAsB,IAAA,EAAuD;AACxF,EAAA,IAAI,SAAS,aAAA,EAAe;AACxB,IAAA,OAAO,OAAO,6CAA6C,CAAA;AAAA,EAC/D;AACA,EAAA,IAAI,SAAS,aAAA,EAAe;AACxB,IAAA,OAAO,OAAO,6CAA6C,CAAA;AAAA,EAC/D;AACA,EAAA,IAAI,SAAS,MAAA,EAAQ;AACjB,IAAA,OAAO,OAAO,sCAAsC,CAAA;AAAA,EACxD;AACA,EAAA,OAAO,OAAO,uCAAuC,CAAA;AACzD;AAKO,SAAS,kBAAA,CAAmB,IAAA,EAAoB,QAAA,EAA4B,IAAA,EAA8D;AAC7I,EAAA,IAAA,CAAK,CAAC,CAAA,GAAI,QAAA,CAAS,oBAAA,IAAwB,CAAA;AAC3C,EAAA,IAAA,CAAK,CAAC,CAAA,GAAI,QAAA,CAAS,eAAA,IAAmB,CAAA;AACtC,EAAA,IAAA,CAAK,CAAC,CAAA,GAAI,QAAA,CAAS,WAAA,IAAe,IAAA;AAClC,EAAA,IAAA,CAAK,CAAC,CAAA,GAAI,QAAA,CAAS,KAAA,IAAS,CAAA;AAC5B,EAAA,MAAM,qBAAA,GAAwB,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,iBAAiB,CAAA;AACjE,EAAA,IAAI,0BAA0B,MAAA,EAAW;AACrC,IAAA,MAAM,MAAM,qBAAA,GAAwB,CAAA;AACpC,IAAA,MAAM,SAAS,QAAA,CAAS,eAAA;AACxB,IAAA,IAAA,CAAK,GAAG,CAAA,GAAI,MAAA,GAAS,MAAA,CAAO,CAAC,CAAA,GAAK,CAAA;AAClC,IAAA,IAAA,CAAK,MAAM,CAAC,CAAA,GAAI,MAAA,GAAS,MAAA,CAAO,CAAC,CAAA,GAAK,CAAA;AACtC,IAAA,IAAA,CAAK,MAAM,CAAC,CAAA,GAAI,MAAA,GAAS,MAAA,CAAO,CAAC,CAAA,GAAK,CAAA;AACtC,IAAA,IAAA,CAAK,MAAM,CAAC,CAAA,GAAI,MAAA,GAAS,MAAA,CAAO,CAAC,CAAA,GAAK,CAAA;AAAA,EAC1C;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,gBAAgB,CAAA,EAAG;AACrC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,gBAAgB,CAAA,GAAK,CAAA;AACnD,IAAA,IAAA,CAAK,GAAG,CAAA,GAAI,QAAA,CAAS,cAAA,IAAkB,CAAA;AACvC,IAAA,IAAA,CAAK,GAAA,GAAM,CAAC,CAAA,GAAI,QAAA,CAAS,eAAA,IAAmB,CAAA;AAC5C,IAAA,IAAA,CAAK,GAAA,GAAM,CAAC,CAAA,GAAI,QAAA,CAAS,kBAAA,IAAsB,CAAA;AAC/C,IAAA,IAAA,CAAK,MAAM,CAAC,CAAA,GAAI,QAAA,CAAS,uBAAA,KAA4B,QAAQ,CAAA,GAAI,CAAA;AAAA,EACrE;AACA,EAAA,KAAA,MAAW,GAAA,IAAO,WAAA,EAAY,CAAE,MAAA,EAAO,EAAG;AACtC,IAAA,IAAI,IAAI,QAAA,EAAU;AACd,MAAA,GAAA,CAAI,QAAA,CAAS,IAAA,EAAM,QAAA,EAAU,IAAA,CAAK,QAAQ,CAAA;AAAA,IAC9C;AAAA,EACJ;AACJ;;;;"}
@@ -233,6 +233,7 @@ var luminanceOverAlpha=0.0;
233
233
  /*BA*/
234
234
  luminanceOverAlpha+=dot(${_hasIbl ? `finalSpecularScaled` : `directSpecular`},vec3<f32>(0.2126,0.7152,0.0722));
235
235
  finalAlpha=saturate(finalAlpha+luminanceOverAlpha*luminanceOverAlpha);
236
+ /*FA*/
236
237
  return vec4<f32>(color,finalAlpha);` : `return vec4<f32>(color,alpha*material.materialAlpha);`;
237
238
  const doubleSidedEntry = _hasDoubleSided ? `@fragment fn main(input: FragmentInput, @builtin(front_facing) frontFacing: bool)${_noColorOutput ? "" : " -> @location(0) vec4<f32>"} {` : `@fragment fn main(input: FragmentInput)${_noColorOutput ? "" : " -> @location(0) vec4<f32>"} {`;
238
239
  const doubleSidedGeomFlip = _flatGeometricNormal ? "" : " N_geom = -N_geom;";