@babylonjs/lite 1.4.0 → 1.5.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 (122) hide show
  1. package/dist/index.js +381 -375
  2. package/dist/index.js.map +1 -1
  3. package/index.d.ts +757 -0
  4. package/lib/audio/analyzer.js +65 -0
  5. package/lib/audio/analyzer.js.map +1 -0
  6. package/lib/audio/audio-bus.js +38 -0
  7. package/lib/audio/audio-bus.js.map +1 -0
  8. package/lib/audio/audio-engine.js +188 -0
  9. package/lib/audio/audio-engine.js.map +1 -0
  10. package/lib/audio/audio-fetch.js +18 -0
  11. package/lib/audio/audio-fetch.js.map +1 -0
  12. package/lib/audio/audio-param.js +96 -0
  13. package/lib/audio/audio-param.js.map +1 -0
  14. package/lib/audio/audio-signal.js +46 -0
  15. package/lib/audio/audio-signal.js.map +1 -0
  16. package/lib/audio/bus.js +33 -0
  17. package/lib/audio/bus.js.map +1 -0
  18. package/lib/audio/host-types.js +2 -0
  19. package/lib/audio/host-types.js.map +1 -0
  20. package/lib/audio/index.js +12 -0
  21. package/lib/audio/index.js.map +1 -0
  22. package/lib/audio/sound-buffer.js +59 -0
  23. package/lib/audio/sound-buffer.js.map +1 -0
  24. package/lib/audio/sound-source.js +57 -0
  25. package/lib/audio/sound-source.js.map +1 -0
  26. package/lib/audio/sound-sub-graph.js +72 -0
  27. package/lib/audio/sound-sub-graph.js.map +1 -0
  28. package/lib/audio/spatial.js +466 -0
  29. package/lib/audio/spatial.js.map +1 -0
  30. package/lib/audio/static-sound.js +313 -0
  31. package/lib/audio/static-sound.js.map +1 -0
  32. package/lib/audio/stereo.js +40 -0
  33. package/lib/audio/stereo.js.map +1 -0
  34. package/lib/audio/streaming-sound.js +377 -0
  35. package/lib/audio/streaming-sound.js.map +1 -0
  36. package/lib/audio/unmute-ui.js +72 -0
  37. package/lib/audio/unmute-ui.js.map +1 -0
  38. package/lib/audio/visualizer.js +101 -0
  39. package/lib/audio/visualizer.js.map +1 -0
  40. package/lib/engine/engine.js +1 -1
  41. package/lib/index.js +11 -0
  42. package/lib/index.js.map +1 -1
  43. package/lib/light/types.js.map +1 -1
  44. package/lib/loader-gltf/animation-pointer-basecolor.js +25 -0
  45. package/lib/loader-gltf/animation-pointer-basecolor.js.map +1 -0
  46. package/lib/loader-gltf/animation-pointer-ext.js +244 -0
  47. package/lib/loader-gltf/animation-pointer-ext.js.map +1 -0
  48. package/lib/loader-gltf/animation-pointer-lights.js +46 -0
  49. package/lib/loader-gltf/animation-pointer-lights.js.map +1 -0
  50. package/lib/loader-gltf/animation-pointer.js +4 -1
  51. package/lib/loader-gltf/animation-pointer.js.map +1 -1
  52. package/lib/loader-gltf/gltf-animation.js +5 -3
  53. package/lib/loader-gltf/gltf-animation.js.map +1 -1
  54. package/lib/loader-gltf/gltf-color-normalize.js +10 -1
  55. package/lib/loader-gltf/gltf-color-normalize.js.map +1 -1
  56. package/lib/loader-gltf/gltf-feature-animation-pointer.js +67 -47
  57. package/lib/loader-gltf/gltf-feature-animation-pointer.js.map +1 -1
  58. package/lib/loader-gltf/gltf-feature-lights-punctual.js +51 -9
  59. package/lib/loader-gltf/gltf-feature-lights-punctual.js.map +1 -1
  60. package/lib/loader-gltf/gltf-feature-primitive.js +20 -0
  61. package/lib/loader-gltf/gltf-feature-primitive.js.map +1 -0
  62. package/lib/loader-gltf/gltf-feature-registry.js +25 -0
  63. package/lib/loader-gltf/gltf-feature-registry.js.map +1 -1
  64. package/lib/loader-gltf/gltf-feature-skeleton.js +18 -3
  65. package/lib/loader-gltf/gltf-feature-skeleton.js.map +1 -1
  66. package/lib/loader-gltf/gltf-interleave.js +3 -2
  67. package/lib/loader-gltf/gltf-interleave.js.map +1 -1
  68. package/lib/loader-gltf/gltf-light-pointer-state.js +18 -0
  69. package/lib/loader-gltf/gltf-light-pointer-state.js.map +1 -0
  70. package/lib/loader-gltf/gltf-parser.js +7 -1
  71. package/lib/loader-gltf/gltf-parser.js.map +1 -1
  72. package/lib/loader-gltf/gltf-pbr-builder-ext.js +1 -1
  73. package/lib/loader-gltf/gltf-pbr-builder-ext.js.map +1 -1
  74. package/lib/loader-gltf/gltf-pbr-builder.js +1 -1
  75. package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
  76. package/lib/loader-gltf/gltf-sampler-denorm.js +20 -0
  77. package/lib/loader-gltf/gltf-sampler-denorm.js.map +1 -0
  78. package/lib/loader-gltf/gltf-sampler-desc.js +11 -2
  79. package/lib/loader-gltf/gltf-sampler-desc.js.map +1 -1
  80. package/lib/loader-gltf/gltf-uv-denorm.js +28 -0
  81. package/lib/loader-gltf/gltf-uv-denorm.js.map +1 -0
  82. package/lib/loader-gltf/load-gltf.js +15 -6
  83. package/lib/loader-gltf/load-gltf.js.map +1 -1
  84. package/lib/material/material-rebuild.js +4 -0
  85. package/lib/material/material-rebuild.js.map +1 -1
  86. package/lib/material/mesh-features.js +8 -1
  87. package/lib/material/mesh-features.js.map +1 -1
  88. package/lib/material/pbr/fragments/reflectance-fragment.js +1 -1
  89. package/lib/material/pbr/fragments/reflectance-fragment.js.map +1 -1
  90. package/lib/material/pbr/fragments/refraction-rtt-fragment.js +1 -1
  91. package/lib/material/pbr/fragments/refraction-rtt-fragment.js.map +1 -1
  92. package/lib/material/pbr/pbr-pipeline.js +7 -3
  93. package/lib/material/pbr/pbr-pipeline.js.map +1 -1
  94. package/lib/material/pbr/pbr-primitive-resolver.js +34 -0
  95. package/lib/material/pbr/pbr-primitive-resolver.js.map +1 -0
  96. package/lib/material/pbr/pbr-renderable.js +1 -1
  97. package/lib/material/pbr/pbr-renderable.js.map +1 -1
  98. package/lib/material/shader/shader-material.js +9 -5
  99. package/lib/material/shader/shader-material.js.map +1 -1
  100. package/lib/material/shader/shader-thin-instance.js +1 -1
  101. package/lib/material/shader/shader-thin-instance.js.map +1 -1
  102. package/lib/material/standard/standard-renderable.js +1 -1
  103. package/lib/material/standard/standard-renderable.js.map +1 -1
  104. package/lib/mesh/mesh-dispose.js +1 -0
  105. package/lib/mesh/mesh-dispose.js.map +1 -1
  106. package/lib/mesh/thin-instance-cull-binding.js +15 -6
  107. package/lib/mesh/thin-instance-cull-binding.js.map +1 -1
  108. package/lib/scene/scene-core.js +1 -0
  109. package/lib/scene/scene-core.js.map +1 -1
  110. package/lib/scene/scene-material-swap.js +2 -0
  111. package/lib/scene/scene-material-swap.js.map +1 -1
  112. package/lib/shadow/csm-shadow-task-hooks.js +67 -9
  113. package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
  114. package/lib/sprite/sprite-2d.js +4 -0
  115. package/lib/sprite/sprite-2d.js.map +1 -1
  116. package/lib/sprite/sprite-pipeline.js +25 -22
  117. package/lib/sprite/sprite-pipeline.js.map +1 -1
  118. package/lib/text/_gpu/text-pipeline.js +1 -1
  119. package/lib/text/_gpu/text-pipeline.js.map +1 -1
  120. package/lib/text/text-renderer.js +3 -1
  121. package/lib/text/text-renderer.js.map +1 -1
  122. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"mesh-features.js","sources":["../../../src/material/mesh-features.ts"],"sourcesContent":["import type { Mesh } from \"../mesh/mesh.js\";\n\nexport const MSH_HAS_TANGENTS = 1 << 0;\nexport const MSH_HAS_SKELETON = 1 << 1;\nexport const MSH_HAS_SKELETON_8 = 1 << 2;\nexport const MSH_HAS_MORPH_TARGETS = 1 << 3;\nexport const MSH_HAS_THIN_INSTANCES = 1 << 4;\nexport const MSH_HAS_INSTANCE_COLOR = 1 << 5;\nexport const MSH_HAS_VERTEX_COLOR = 1 << 6;\nexport const MSH_HAS_UV2 = 1 << 7;\nexport const MSH_RECEIVE_SHADOWS = 1 << 8;\nexport const MSH_VAT = 1 << 9;\n/** Mesh has no NORMAL attribute → must be flat-shaded (glTF spec). */\nexport const MSH_FLAT_NORMAL = 1 << 10;\n\n/** @internal Compute mesh/pass feature bits shared by material renderers. */\nexport function _computeMeshFeatures(mesh: Mesh, receiveShadows = false): number {\n const gpu = mesh._gpu;\n let features = 0;\n if (gpu.tangentBuffer) {\n features |= MSH_HAS_TANGENTS;\n }\n if (mesh.vat) {\n // Baked vertex animation: the VAT vertex path replaces live skinning (still uses the 8-bone\n // joints1 attribute flag when present), so don't also set MSH_HAS_SKELETON.\n features |= MSH_VAT;\n if (mesh.vat.joints1Buffer) {\n features |= MSH_HAS_SKELETON_8;\n }\n } else if (mesh.skeleton) {\n features |= MSH_HAS_SKELETON;\n if (mesh.skeleton.joints1Buffer) {\n features |= MSH_HAS_SKELETON_8;\n }\n }\n if (mesh.morphTargets) {\n features |= MSH_HAS_MORPH_TARGETS;\n }\n if (mesh.thinInstances) {\n features |= MSH_HAS_THIN_INSTANCES;\n if (mesh.thinInstances.colors) {\n features |= MSH_HAS_INSTANCE_COLOR;\n }\n }\n if (gpu.colorBuffer) {\n features |= MSH_HAS_VERTEX_COLOR;\n }\n if (gpu.uv2Buffer) {\n features |= MSH_HAS_UV2;\n }\n if ((mesh as { _flatNormal?: boolean })._flatNormal) {\n features |= MSH_FLAT_NORMAL;\n }\n if (receiveShadows) {\n features |= MSH_RECEIVE_SHADOWS;\n }\n return features;\n}\n"],"names":[],"mappings":"AAEO,MAAM,mBAAmB,CAAA,IAAK;AAC9B,MAAM,mBAAmB,CAAA,IAAK;AAC9B,MAAM,qBAAqB,CAAA,IAAK;AAChC,MAAM,wBAAwB,CAAA,IAAK;AACnC,MAAM,yBAAyB,CAAA,IAAK;AACpC,MAAM,yBAAyB,CAAA,IAAK;AACpC,MAAM,uBAAuB,CAAA,IAAK;AAClC,MAAM,cAAc,CAAA,IAAK;AACzB,MAAM,sBAAsB,CAAA,IAAK;AACjC,MAAM,UAAU,CAAA,IAAK;AAErB,MAAM,kBAAkB,CAAA,IAAK;AAG7B,SAAS,oBAAA,CAAqB,IAAA,EAAY,cAAA,GAAiB,KAAA,EAAe;AAC7E,EAAA,MAAM,MAAM,IAAA,CAAK,IAAA;AACjB,EAAA,IAAI,QAAA,GAAW,CAAA;AACf,EAAA,IAAI,IAAI,aAAA,EAAe;AACnB,IAAA,QAAA,IAAY,gBAAA;AAAA,EAChB;AACA,EAAA,IAAI,KAAK,GAAA,EAAK;AAGV,IAAA,QAAA,IAAY,OAAA;AACZ,IAAA,IAAI,IAAA,CAAK,IAAI,aAAA,EAAe;AACxB,MAAA,QAAA,IAAY,kBAAA;AAAA,IAChB;AAAA,EACJ,CAAA,MAAA,IAAW,KAAK,QAAA,EAAU;AACtB,IAAA,QAAA,IAAY,gBAAA;AACZ,IAAA,IAAI,IAAA,CAAK,SAAS,aAAA,EAAe;AAC7B,MAAA,QAAA,IAAY,kBAAA;AAAA,IAChB;AAAA,EACJ;AACA,EAAA,IAAI,KAAK,YAAA,EAAc;AACnB,IAAA,QAAA,IAAY,qBAAA;AAAA,EAChB;AACA,EAAA,IAAI,KAAK,aAAA,EAAe;AACpB,IAAA,QAAA,IAAY,sBAAA;AACZ,IAAA,IAAI,IAAA,CAAK,cAAc,MAAA,EAAQ;AAC3B,MAAA,QAAA,IAAY,sBAAA;AAAA,IAChB;AAAA,EACJ;AACA,EAAA,IAAI,IAAI,WAAA,EAAa;AACjB,IAAA,QAAA,IAAY,oBAAA;AAAA,EAChB;AACA,EAAA,IAAI,IAAI,SAAA,EAAW;AACf,IAAA,QAAA,IAAY,WAAA;AAAA,EAChB;AACA,EAAA,IAAK,KAAmC,WAAA,EAAa;AACjD,IAAA,QAAA,IAAY,eAAA;AAAA,EAChB;AACA,EAAA,IAAI,cAAA,EAAgB;AAChB,IAAA,QAAA,IAAY,mBAAA;AAAA,EAChB;AACA,EAAA,OAAO,QAAA;AACX;;;;"}
1
+ {"version":3,"file":"mesh-features.js","sources":["../../../src/material/mesh-features.ts"],"sourcesContent":["import type { Mesh } from \"../mesh/mesh.js\";\n\nexport const MSH_HAS_TANGENTS = 1 << 0;\nexport const MSH_HAS_SKELETON = 1 << 1;\nexport const MSH_HAS_SKELETON_8 = 1 << 2;\nexport const MSH_HAS_MORPH_TARGETS = 1 << 3;\nexport const MSH_HAS_THIN_INSTANCES = 1 << 4;\nexport const MSH_HAS_INSTANCE_COLOR = 1 << 5;\nexport const MSH_HAS_VERTEX_COLOR = 1 << 6;\nexport const MSH_HAS_UV2 = 1 << 7;\nexport const MSH_RECEIVE_SHADOWS = 1 << 8;\nexport const MSH_VAT = 1 << 9;\n/** Mesh has no NORMAL attribute → must be flat-shaded (glTF spec). */\nexport const MSH_FLAT_NORMAL = 1 << 10;\n// Bits 11-15 (negative-winding + 3-bit topology index + uint32-strip flag) are owned by the lazy\n// glTF primitive feature: their constants live in pbr-primitive-resolver.ts and are encoded via the\n// `_meshFeatureExtra` hook below, so triangle-list positive-winding scenes never bundle that code.\n\n/** Extra mesh-feature encoder, installed only by the glTF primitive feature (topology +\n * negative-winding bits). Module-local with a single exported setter: when no such mesh is in the\n * bundle the setter tree-shakes, the bundler proves this is always null, and the `_meshFeatureExtra`\n * call below folds away — every common mesh keeps `_computeMeshFeatures` byte-identical. */\nlet _meshFeatureExtra: ((mesh: Mesh) => number) | null = null;\n/** @internal Install the extra mesh-feature encoder (called by the glTF primitive feature). */\nexport function _installMeshFeatureExtra(encode: (mesh: Mesh) => number): void {\n _meshFeatureExtra = encode;\n}\n\n/** @internal Compute mesh/pass feature bits shared by material renderers. */\nexport function _computeMeshFeatures(mesh: Mesh, receiveShadows = false): number {\n const gpu = mesh._gpu;\n let features = 0;\n if (gpu.tangentBuffer) {\n features |= MSH_HAS_TANGENTS;\n }\n if (mesh.vat) {\n // Baked vertex animation: the VAT vertex path replaces live skinning (still uses the 8-bone\n // joints1 attribute flag when present), so don't also set MSH_HAS_SKELETON.\n features |= MSH_VAT;\n if (mesh.vat.joints1Buffer) {\n features |= MSH_HAS_SKELETON_8;\n }\n } else if (mesh.skeleton) {\n features |= MSH_HAS_SKELETON;\n if (mesh.skeleton.joints1Buffer) {\n features |= MSH_HAS_SKELETON_8;\n }\n }\n if (mesh.morphTargets) {\n features |= MSH_HAS_MORPH_TARGETS;\n }\n if (mesh.thinInstances) {\n features |= MSH_HAS_THIN_INSTANCES;\n if (mesh.thinInstances.colors) {\n features |= MSH_HAS_INSTANCE_COLOR;\n }\n }\n if (gpu.colorBuffer) {\n features |= MSH_HAS_VERTEX_COLOR;\n }\n if (gpu.uv2Buffer) {\n features |= MSH_HAS_UV2;\n }\n if ((mesh as { _flatNormal?: boolean })._flatNormal) {\n features |= MSH_FLAT_NORMAL;\n }\n if (receiveShadows) {\n features |= MSH_RECEIVE_SHADOWS;\n }\n if (_meshFeatureExtra) {\n features |= _meshFeatureExtra(mesh);\n }\n return features;\n}\n"],"names":[],"mappings":"AAEO,MAAM,mBAAmB,CAAA,IAAK;AAC9B,MAAM,mBAAmB,CAAA,IAAK;AAC9B,MAAM,qBAAqB,CAAA,IAAK;AAChC,MAAM,wBAAwB,CAAA,IAAK;AACnC,MAAM,yBAAyB,CAAA,IAAK;AACpC,MAAM,yBAAyB,CAAA,IAAK;AACpC,MAAM,uBAAuB,CAAA,IAAK;AAClC,MAAM,cAAc,CAAA,IAAK;AACzB,MAAM,sBAAsB,CAAA,IAAK;AACjC,MAAM,UAAU,CAAA,IAAK;AAErB,MAAM,kBAAkB,CAAA,IAAK;AASpC,IAAI,iBAAA,GAAqD,IAAA;AAElD,SAAS,yBAAyB,MAAA,EAAsC;AAC3E,EAAA,iBAAA,GAAoB,MAAA;AACxB;AAGO,SAAS,oBAAA,CAAqB,IAAA,EAAY,cAAA,GAAiB,KAAA,EAAe;AAC7E,EAAA,MAAM,MAAM,IAAA,CAAK,IAAA;AACjB,EAAA,IAAI,QAAA,GAAW,CAAA;AACf,EAAA,IAAI,IAAI,aAAA,EAAe;AACnB,IAAA,QAAA,IAAY,gBAAA;AAAA,EAChB;AACA,EAAA,IAAI,KAAK,GAAA,EAAK;AAGV,IAAA,QAAA,IAAY,OAAA;AACZ,IAAA,IAAI,IAAA,CAAK,IAAI,aAAA,EAAe;AACxB,MAAA,QAAA,IAAY,kBAAA;AAAA,IAChB;AAAA,EACJ,CAAA,MAAA,IAAW,KAAK,QAAA,EAAU;AACtB,IAAA,QAAA,IAAY,gBAAA;AACZ,IAAA,IAAI,IAAA,CAAK,SAAS,aAAA,EAAe;AAC7B,MAAA,QAAA,IAAY,kBAAA;AAAA,IAChB;AAAA,EACJ;AACA,EAAA,IAAI,KAAK,YAAA,EAAc;AACnB,IAAA,QAAA,IAAY,qBAAA;AAAA,EAChB;AACA,EAAA,IAAI,KAAK,aAAA,EAAe;AACpB,IAAA,QAAA,IAAY,sBAAA;AACZ,IAAA,IAAI,IAAA,CAAK,cAAc,MAAA,EAAQ;AAC3B,MAAA,QAAA,IAAY,sBAAA;AAAA,IAChB;AAAA,EACJ;AACA,EAAA,IAAI,IAAI,WAAA,EAAa;AACjB,IAAA,QAAA,IAAY,oBAAA;AAAA,EAChB;AACA,EAAA,IAAI,IAAI,SAAA,EAAW;AACf,IAAA,QAAA,IAAY,WAAA;AAAA,EAChB;AACA,EAAA,IAAK,KAAmC,WAAA,EAAa;AACjD,IAAA,QAAA,IAAY,eAAA;AAAA,EAChB;AACA,EAAA,IAAI,cAAA,EAAgB;AAChB,IAAA,QAAA,IAAY,mBAAA;AAAA,EAChB;AACA,EAAA,IAAI,iBAAA,EAAmB;AACnB,IAAA,QAAA,IAAY,kBAAkB,IAAI,CAAA;AAAA,EACtC;AACA,EAAA,OAAO,QAAA;AACX;;;;"}
@@ -134,7 +134,7 @@ const pbrExt = {
134
134
  const hasNonDefaultF0 = m.metallicF0Factor != null && Math.abs(m.metallicF0Factor - 1) > 1e-6;
135
135
  const mrc = m.metallicReflectanceColor;
136
136
  const hasNonDefaultColor = mrc != null && (mrc[0] !== 1 || mrc[1] !== 1 || mrc[2] !== 1);
137
- if (hasNonDefaultF0 || hasNonDefaultColor) {
137
+ if (hasNonDefaultF0 || hasNonDefaultColor || m._occlStrengthAnimated) {
138
138
  f2 |= PBR2_HAS_REFLECTANCE_FACTORS;
139
139
  }
140
140
  }
@@ -1 +1 @@
1
- {"version":3,"file":"reflectance-fragment.js","sources":["../../../../../src/material/pbr/fragments/reflectance-fragment.ts"],"sourcesContent":["/**\n * Metallic Reflectance Fragment\n *\n * Advanced F0 computation with metallicReflectanceTexture and/or reflectanceTexture.\n * Only bundled when a scene uses these textures.\n *\n * Provides: UBO fields (occlusionStrength, metallicF0Factor, specularWeight, metallicReflectanceColor),\n * conditional texture bindings, F0 computation, and occlusion handling.\n */\n\nimport type { ShaderFragment, BindingDecl, UboField } from \"../../../shader/fragment-types.js\";\nimport type { PbrMaterialProps } from \"../pbr-material.js\";\nimport type { PbrExt } from \"../pbr-flags.js\";\nimport { PBR_HAS_METALLIC_REFLECTANCE_MAP, PBR_HAS_REFLECTANCE_MAP, PBR_HAS_USE_ALPHA_ONLY_MR, PBR2_HAS_REFLECTANCE_FACTORS, PBR2_HAS_UV2 } from \"../pbr-flag-bits.js\";\n\n// Reflectance-only features2 bit (reserved in pbr-flag-bits.ts). Defined here,\n// not in the shared flag module, for zero bundle movement on scenes that never\n// load this lazy fragment.\nconst PBR2_REFL_UV_TX = 1 << 26;\n\n// WebGPU shader stage constants\nconst STAGE_FRAGMENT = 0x2;\n\nconst reflUvExpr = (name: string): string => `(vec2<f32>(dot(material.${name}m.xy, input.uv), dot(material.${name}m.zw, input.uv)) + material.${name}t.xy)`;\n\n/** Write a 2x2 UV matrix (vec4) + translate (vec4) for a reflectance texture. */\nfunction writeReflUvTransform(\n data: Float32Array,\n offsets: ReadonlyMap<string, number>,\n name: string,\n tex: { uScale?: number; vScale?: number; uAng?: number; uOffset?: number; vOffset?: number } | undefined\n): void {\n const mOff = offsets.get(`${name}m`);\n const tOff = offsets.get(`${name}t`);\n if (mOff === undefined || tOff === undefined) {\n return;\n }\n const sx = tex?.uScale ?? 1;\n const sy = tex?.vScale ?? 1;\n const ang = tex?.uAng ?? 0;\n const mi = mOff / 4;\n if (ang === 0) {\n data[mi] = sx;\n data[mi + 1] = 0;\n data[mi + 2] = 0;\n data[mi + 3] = sy;\n } else {\n const c = Math.cos(ang);\n const s = Math.sin(ang);\n data[mi] = c * sx;\n data[mi + 1] = s * sy;\n data[mi + 2] = -s * sx;\n data[mi + 3] = c * sy;\n }\n const ti = tOff / 4;\n data[ti] = tex?.uOffset ?? 0;\n data[ti + 1] = tex?.vOffset ?? 0;\n}\n\n/** Write the reflectance-extension material-UBO slice\n * (occlusionStrength, metallicF0Factor, specularWeight, metallicReflectanceColor).\n * Gated by the presence of the `occlusionStrength` field in the UBO spec,\n * which is added only when a metallic-reflectance or reflectance texture\n * is in use. */\nexport function writeReflectanceUBO(data: Float32Array, material: PbrMaterialProps, offsets: ReadonlyMap<string, number>): void {\n if (!offsets.has(\"occlusionStrength\")) {\n return;\n }\n const off = offsets.get(\"occlusionStrength\")! / 4;\n data[off] = material.occlusionStrength ?? 1.0;\n data[off + 1] = material.metallicF0Factor ?? 1.0;\n data[off + 2] = material.specularWeight ?? material.metallicF0Factor ?? 1.0;\n const mrc = material.metallicReflectanceColor;\n data[off + 4] = mrc ? mrc[0]! : 1.0;\n data[off + 5] = mrc ? mrc[1]! : 1.0;\n data[off + 6] = mrc ? mrc[2]! : 1.0;\n\n writeReflUvTransform(data, offsets, \"reflUV\", material.reflectanceTexture);\n writeReflUvTransform(data, offsets, \"mrReflUV\", material.metallicReflectanceTexture);\n}\n\n/**\n * Create a metallic reflectance fragment.\n * @param hasMetallicReflectanceMap - Whether the material has a metallicReflectanceTexture.\n * @param hasReflectanceMap - Whether the material has a reflectanceTexture.\n * @param useAlphaOnlyMR - Whether to use only the alpha channel from the metallic reflectance map.\n */\nexport function createReflectanceFragment(\n hasMetallicReflectanceMap: boolean,\n hasReflectanceMap: boolean,\n useAlphaOnlyMR: boolean,\n hasOcclusionUv2: boolean = false,\n hasUvTx: boolean = false\n): ShaderFragment {\n const bindings: BindingDecl[] = [];\n if (hasMetallicReflectanceMap) {\n bindings.push(\n { _name: \"metallicReflectanceMap\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" }, _visibility: STAGE_FRAGMENT },\n { _name: \"metallicReflectanceMapSampler\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" }, _visibility: STAGE_FRAGMENT }\n );\n }\n if (hasReflectanceMap) {\n bindings.push(\n { _name: \"reflectanceMap\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" }, _visibility: STAGE_FRAGMENT },\n { _name: \"reflectanceMapSampler\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" }, _visibility: STAGE_FRAGMENT }\n );\n }\n\n const reflUv = hasUvTx ? reflUvExpr(\"reflUV\") : \"input.uv\";\n const mrReflUv = hasUvTx ? reflUvExpr(\"mrReflUV\") : \"input.uv\";\n\n // Build F0 computation code\n let f0Code = `var mrFactors = vec4<f32>(material.metallicReflectanceColor, material.metallicF0Factor);\nvar specularWeight = material.specularWeight;`;\n if (hasReflectanceMap) {\n f0Code += `\n{ let rSample = textureSample(reflectanceMap, reflectanceMapSampler, ${reflUv});\n let rLinear = pow(rSample.rgb, vec3<f32>(2.2));\n mrFactors = vec4<f32>(mrFactors.rgb * rLinear, mrFactors.a); }`;\n }\n if (hasMetallicReflectanceMap) {\n if (!useAlphaOnlyMR) {\n f0Code += `\n{ let mrSample = textureSample(metallicReflectanceMap, metallicReflectanceMapSampler, ${mrReflUv});\n let mrLinear = pow(mrSample.rgb, vec3<f32>(2.2));\n mrFactors = vec4<f32>(mrFactors.rgb * mrLinear, mrFactors.a * mrSample.a);\n specularWeight *= mrSample.a; }`;\n } else {\n f0Code += `\n{ let mrSample = textureSample(metallicReflectanceMap, metallicReflectanceMapSampler, ${mrReflUv});\n mrFactors = vec4<f32>(mrFactors.rgb, mrFactors.a * mrSample.a);\n specularWeight *= mrSample.a; }`;\n }\n }\n f0Code += `\nlet dielectricF0 = material.reflectance * mrFactors.a;\nlet surfaceReflectivityColor = mrFactors.rgb;\nlet dielectricColorF0 = vec3<f32>(dielectricF0) * surfaceReflectivityColor;\nlet metallicColorF0 = baseColor;\nvar colorF0 = mix(dielectricColorF0, metallicColorF0, metallic);\nlet colorF90 = vec3<f32>(mix(specularWeight, 1.0, metallic));\nlet surfaceAlbedo = baseColor * (vec3<f32>(1.0) - vec3<f32>(dielectricF0) * surfaceReflectivityColor) * (1.0 - metallic);`;\n\n const uboFields: UboField[] = [\n { _name: \"occlusionStrength\", _type: \"f32\" },\n { _name: \"metallicF0Factor\", _type: \"f32\" },\n { _name: \"specularWeight\", _type: \"f32\" },\n { _name: \"_mrPad1\", _type: \"f32\" },\n { _name: \"metallicReflectanceColor\", _type: \"vec3<f32>\" },\n { _name: \"_mrPad2\", _type: \"f32\" },\n ];\n if (hasUvTx) {\n if (hasReflectanceMap) {\n uboFields.push({ _name: \"reflUVm\", _type: \"vec4<f32>\" }, { _name: \"reflUVt\", _type: \"vec4<f32>\" });\n }\n if (hasMetallicReflectanceMap) {\n uboFields.push({ _name: \"mrReflUVm\", _type: \"vec4<f32>\" }, { _name: \"mrReflUVt\", _type: \"vec4<f32>\" });\n }\n }\n\n return {\n _id: hasUvTx ? \"reflectance-U\" : \"reflectance\",\n\n _uboFields: uboFields,\n\n _bindings: bindings,\n\n _fragmentSlots: {\n MF: f0Code,\n AT: hasOcclusionUv2\n ? `let occlusion = mix(1.0, textureSample(occlusionTexture, occlusionSampler_, input.uv2).r, material.occlusionStrength);`\n : `let occlusion = mix(1.0, orm.r, material.occlusionStrength);`,\n },\n };\n}\n\n/** Create the reflectance PBR extension (group 1, fragment phase). */\nexport const pbrExt: PbrExt = {\n id: \"reflectance\",\n phase: \"fragment\",\n detect(mat) {\n const m = mat as PbrMaterialProps;\n let f = 0;\n let f2 = 0;\n if (m.metallicReflectanceTexture) {\n f |= PBR_HAS_METALLIC_REFLECTANCE_MAP;\n }\n if (m.reflectanceTexture) {\n f |= PBR_HAS_REFLECTANCE_MAP;\n }\n if (f === 0) {\n const hasNonDefaultF0 = m.metallicF0Factor != null && Math.abs(m.metallicF0Factor - 1) > 1e-6;\n const mrc = m.metallicReflectanceColor;\n const hasNonDefaultColor = mrc != null && (mrc[0] !== 1 || mrc[1] !== 1 || mrc[2] !== 1);\n if (hasNonDefaultF0 || hasNonDefaultColor) {\n f2 |= PBR2_HAS_REFLECTANCE_FACTORS;\n }\n }\n if ((f !== 0 || f2 & PBR2_HAS_REFLECTANCE_FACTORS) && m.useOnlyMetallicFromMetallicReflectanceTexture) {\n f |= PBR_HAS_USE_ALPHA_ONLY_MR;\n }\n const refHasTx = (t: { _hasTx?: boolean } | undefined): boolean => !!t?._hasTx;\n if (f !== 0 && (refHasTx(m.reflectanceTexture as { _hasTx?: boolean } | undefined) || refHasTx(m.metallicReflectanceTexture as { _hasTx?: boolean } | undefined))) {\n f2 |= PBR2_REFL_UV_TX;\n }\n return { f, f2 };\n },\n frag(ctx) {\n const hasMR = (ctx._features & PBR_HAS_METALLIC_REFLECTANCE_MAP) !== 0;\n const hasR = (ctx._features & PBR_HAS_REFLECTANCE_MAP) !== 0;\n const hasFactors = (ctx._features2 & PBR2_HAS_REFLECTANCE_FACTORS) !== 0;\n if (!hasMR && !hasR && !hasFactors) {\n return null;\n }\n return createReflectanceFragment(\n hasMR,\n hasR,\n (ctx._features & PBR_HAS_USE_ALPHA_ONLY_MR) !== 0,\n (ctx._features2 & PBR2_HAS_UV2) !== 0,\n (ctx._features2 & PBR2_REFL_UV_TX) !== 0\n );\n },\n writeUbo: writeReflectanceUBO as PbrExt[\"writeUbo\"],\n bind(ctx, entries, b) {\n if ((ctx._features & (PBR_HAS_METALLIC_REFLECTANCE_MAP | PBR_HAS_REFLECTANCE_MAP)) === 0) {\n return b;\n }\n const m = ctx._material as PbrMaterialProps;\n if (m.metallicReflectanceTexture) {\n entries.push({ binding: b++, resource: m.metallicReflectanceTexture.view });\n entries.push({ binding: b++, resource: m.metallicReflectanceTexture.sampler });\n }\n if (m.reflectanceTexture) {\n entries.push({ binding: b++, resource: m.reflectanceTexture.view });\n entries.push({ binding: b++, resource: m.reflectanceTexture.sampler });\n }\n return b;\n },\n textures(mat, t) {\n const m = mat as PbrMaterialProps;\n if (m.metallicReflectanceTexture) {\n t.push(m.metallicReflectanceTexture);\n }\n if (m.reflectanceTexture) {\n t.push(m.reflectanceTexture);\n }\n },\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reflectance-fragment.js","sources":["../../../../../src/material/pbr/fragments/reflectance-fragment.ts"],"sourcesContent":["/**\n * Metallic Reflectance Fragment\n *\n * Advanced F0 computation with metallicReflectanceTexture and/or reflectanceTexture.\n * Only bundled when a scene uses these textures.\n *\n * Provides: UBO fields (occlusionStrength, metallicF0Factor, specularWeight, metallicReflectanceColor),\n * conditional texture bindings, F0 computation, and occlusion handling.\n */\n\nimport type { ShaderFragment, BindingDecl, UboField } from \"../../../shader/fragment-types.js\";\nimport type { PbrMaterialProps } from \"../pbr-material.js\";\nimport type { PbrExt } from \"../pbr-flags.js\";\nimport { PBR_HAS_METALLIC_REFLECTANCE_MAP, PBR_HAS_REFLECTANCE_MAP, PBR_HAS_USE_ALPHA_ONLY_MR, PBR2_HAS_REFLECTANCE_FACTORS, PBR2_HAS_UV2 } from \"../pbr-flag-bits.js\";\n\n// Reflectance-only features2 bit (reserved in pbr-flag-bits.ts). Defined here,\n// not in the shared flag module, for zero bundle movement on scenes that never\n// load this lazy fragment.\nconst PBR2_REFL_UV_TX = 1 << 26;\n\n// WebGPU shader stage constants\nconst STAGE_FRAGMENT = 0x2;\n\nconst reflUvExpr = (name: string): string => `(vec2<f32>(dot(material.${name}m.xy, input.uv), dot(material.${name}m.zw, input.uv)) + material.${name}t.xy)`;\n\n/** Write a 2x2 UV matrix (vec4) + translate (vec4) for a reflectance texture. */\nfunction writeReflUvTransform(\n data: Float32Array,\n offsets: ReadonlyMap<string, number>,\n name: string,\n tex: { uScale?: number; vScale?: number; uAng?: number; uOffset?: number; vOffset?: number } | undefined\n): void {\n const mOff = offsets.get(`${name}m`);\n const tOff = offsets.get(`${name}t`);\n if (mOff === undefined || tOff === undefined) {\n return;\n }\n const sx = tex?.uScale ?? 1;\n const sy = tex?.vScale ?? 1;\n const ang = tex?.uAng ?? 0;\n const mi = mOff / 4;\n if (ang === 0) {\n data[mi] = sx;\n data[mi + 1] = 0;\n data[mi + 2] = 0;\n data[mi + 3] = sy;\n } else {\n const c = Math.cos(ang);\n const s = Math.sin(ang);\n data[mi] = c * sx;\n data[mi + 1] = s * sy;\n data[mi + 2] = -s * sx;\n data[mi + 3] = c * sy;\n }\n const ti = tOff / 4;\n data[ti] = tex?.uOffset ?? 0;\n data[ti + 1] = tex?.vOffset ?? 0;\n}\n\n/** Write the reflectance-extension material-UBO slice\n * (occlusionStrength, metallicF0Factor, specularWeight, metallicReflectanceColor).\n * Gated by the presence of the `occlusionStrength` field in the UBO spec,\n * which is added only when a metallic-reflectance or reflectance texture\n * is in use. */\nexport function writeReflectanceUBO(data: Float32Array, material: PbrMaterialProps, offsets: ReadonlyMap<string, number>): void {\n if (!offsets.has(\"occlusionStrength\")) {\n return;\n }\n const off = offsets.get(\"occlusionStrength\")! / 4;\n data[off] = material.occlusionStrength ?? 1.0;\n data[off + 1] = material.metallicF0Factor ?? 1.0;\n data[off + 2] = material.specularWeight ?? material.metallicF0Factor ?? 1.0;\n const mrc = material.metallicReflectanceColor;\n data[off + 4] = mrc ? mrc[0]! : 1.0;\n data[off + 5] = mrc ? mrc[1]! : 1.0;\n data[off + 6] = mrc ? mrc[2]! : 1.0;\n\n writeReflUvTransform(data, offsets, \"reflUV\", material.reflectanceTexture);\n writeReflUvTransform(data, offsets, \"mrReflUV\", material.metallicReflectanceTexture);\n}\n\n/**\n * Create a metallic reflectance fragment.\n * @param hasMetallicReflectanceMap - Whether the material has a metallicReflectanceTexture.\n * @param hasReflectanceMap - Whether the material has a reflectanceTexture.\n * @param useAlphaOnlyMR - Whether to use only the alpha channel from the metallic reflectance map.\n */\nexport function createReflectanceFragment(\n hasMetallicReflectanceMap: boolean,\n hasReflectanceMap: boolean,\n useAlphaOnlyMR: boolean,\n hasOcclusionUv2: boolean = false,\n hasUvTx: boolean = false\n): ShaderFragment {\n const bindings: BindingDecl[] = [];\n if (hasMetallicReflectanceMap) {\n bindings.push(\n { _name: \"metallicReflectanceMap\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" }, _visibility: STAGE_FRAGMENT },\n { _name: \"metallicReflectanceMapSampler\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" }, _visibility: STAGE_FRAGMENT }\n );\n }\n if (hasReflectanceMap) {\n bindings.push(\n { _name: \"reflectanceMap\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" }, _visibility: STAGE_FRAGMENT },\n { _name: \"reflectanceMapSampler\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" }, _visibility: STAGE_FRAGMENT }\n );\n }\n\n const reflUv = hasUvTx ? reflUvExpr(\"reflUV\") : \"input.uv\";\n const mrReflUv = hasUvTx ? reflUvExpr(\"mrReflUV\") : \"input.uv\";\n\n // Build F0 computation code\n let f0Code = `var mrFactors = vec4<f32>(material.metallicReflectanceColor, material.metallicF0Factor);\nvar specularWeight = material.specularWeight;`;\n if (hasReflectanceMap) {\n f0Code += `\n{ let rSample = textureSample(reflectanceMap, reflectanceMapSampler, ${reflUv});\n let rLinear = pow(rSample.rgb, vec3<f32>(2.2));\n mrFactors = vec4<f32>(mrFactors.rgb * rLinear, mrFactors.a); }`;\n }\n if (hasMetallicReflectanceMap) {\n if (!useAlphaOnlyMR) {\n f0Code += `\n{ let mrSample = textureSample(metallicReflectanceMap, metallicReflectanceMapSampler, ${mrReflUv});\n let mrLinear = pow(mrSample.rgb, vec3<f32>(2.2));\n mrFactors = vec4<f32>(mrFactors.rgb * mrLinear, mrFactors.a * mrSample.a);\n specularWeight *= mrSample.a; }`;\n } else {\n f0Code += `\n{ let mrSample = textureSample(metallicReflectanceMap, metallicReflectanceMapSampler, ${mrReflUv});\n mrFactors = vec4<f32>(mrFactors.rgb, mrFactors.a * mrSample.a);\n specularWeight *= mrSample.a; }`;\n }\n }\n f0Code += `\nlet dielectricF0 = material.reflectance * mrFactors.a;\nlet surfaceReflectivityColor = mrFactors.rgb;\nlet dielectricColorF0 = vec3<f32>(dielectricF0) * surfaceReflectivityColor;\nlet metallicColorF0 = baseColor;\nvar colorF0 = mix(dielectricColorF0, metallicColorF0, metallic);\nlet colorF90 = vec3<f32>(mix(specularWeight, 1.0, metallic));\nlet surfaceAlbedo = baseColor * (vec3<f32>(1.0) - vec3<f32>(dielectricF0) * surfaceReflectivityColor) * (1.0 - metallic);`;\n\n const uboFields: UboField[] = [\n { _name: \"occlusionStrength\", _type: \"f32\" },\n { _name: \"metallicF0Factor\", _type: \"f32\" },\n { _name: \"specularWeight\", _type: \"f32\" },\n { _name: \"_mrPad1\", _type: \"f32\" },\n { _name: \"metallicReflectanceColor\", _type: \"vec3<f32>\" },\n { _name: \"_mrPad2\", _type: \"f32\" },\n ];\n if (hasUvTx) {\n if (hasReflectanceMap) {\n uboFields.push({ _name: \"reflUVm\", _type: \"vec4<f32>\" }, { _name: \"reflUVt\", _type: \"vec4<f32>\" });\n }\n if (hasMetallicReflectanceMap) {\n uboFields.push({ _name: \"mrReflUVm\", _type: \"vec4<f32>\" }, { _name: \"mrReflUVt\", _type: \"vec4<f32>\" });\n }\n }\n\n return {\n _id: hasUvTx ? \"reflectance-U\" : \"reflectance\",\n\n _uboFields: uboFields,\n\n _bindings: bindings,\n\n _fragmentSlots: {\n MF: f0Code,\n AT: hasOcclusionUv2\n ? `let occlusion = mix(1.0, textureSample(occlusionTexture, occlusionSampler_, input.uv2).r, material.occlusionStrength);`\n : `let occlusion = mix(1.0, orm.r, material.occlusionStrength);`,\n },\n };\n}\n\n/** Create the reflectance PBR extension (group 1, fragment phase). */\nexport const pbrExt: PbrExt = {\n id: \"reflectance\",\n phase: \"fragment\",\n detect(mat) {\n const m = mat as PbrMaterialProps;\n let f = 0;\n let f2 = 0;\n if (m.metallicReflectanceTexture) {\n f |= PBR_HAS_METALLIC_REFLECTANCE_MAP;\n }\n if (m.reflectanceTexture) {\n f |= PBR_HAS_REFLECTANCE_MAP;\n }\n if (f === 0) {\n const hasNonDefaultF0 = m.metallicF0Factor != null && Math.abs(m.metallicF0Factor - 1) > 1e-6;\n const mrc = m.metallicReflectanceColor;\n const hasNonDefaultColor = mrc != null && (mrc[0] !== 1 || mrc[1] !== 1 || mrc[2] !== 1);\n // `_occlStrengthAnimated` (set lazily by the animation-pointer feature) routes an\n // animated occlusionTexture.strength through this ext's occlusion mix slot. Reflectance\n // factors stay default, so F0/albedo is identical to the base template path — only the\n // `mix(1, orm.r, occlusionStrength)` is added. Non-animated scenes never set the flag.\n if (hasNonDefaultF0 || hasNonDefaultColor || (m as { _occlStrengthAnimated?: boolean })._occlStrengthAnimated) {\n f2 |= PBR2_HAS_REFLECTANCE_FACTORS;\n }\n }\n if ((f !== 0 || f2 & PBR2_HAS_REFLECTANCE_FACTORS) && m.useOnlyMetallicFromMetallicReflectanceTexture) {\n f |= PBR_HAS_USE_ALPHA_ONLY_MR;\n }\n const refHasTx = (t: { _hasTx?: boolean } | undefined): boolean => !!t?._hasTx;\n if (f !== 0 && (refHasTx(m.reflectanceTexture as { _hasTx?: boolean } | undefined) || refHasTx(m.metallicReflectanceTexture as { _hasTx?: boolean } | undefined))) {\n f2 |= PBR2_REFL_UV_TX;\n }\n return { f, f2 };\n },\n frag(ctx) {\n const hasMR = (ctx._features & PBR_HAS_METALLIC_REFLECTANCE_MAP) !== 0;\n const hasR = (ctx._features & PBR_HAS_REFLECTANCE_MAP) !== 0;\n const hasFactors = (ctx._features2 & PBR2_HAS_REFLECTANCE_FACTORS) !== 0;\n if (!hasMR && !hasR && !hasFactors) {\n return null;\n }\n return createReflectanceFragment(\n hasMR,\n hasR,\n (ctx._features & PBR_HAS_USE_ALPHA_ONLY_MR) !== 0,\n (ctx._features2 & PBR2_HAS_UV2) !== 0,\n (ctx._features2 & PBR2_REFL_UV_TX) !== 0\n );\n },\n writeUbo: writeReflectanceUBO as PbrExt[\"writeUbo\"],\n bind(ctx, entries, b) {\n if ((ctx._features & (PBR_HAS_METALLIC_REFLECTANCE_MAP | PBR_HAS_REFLECTANCE_MAP)) === 0) {\n return b;\n }\n const m = ctx._material as PbrMaterialProps;\n if (m.metallicReflectanceTexture) {\n entries.push({ binding: b++, resource: m.metallicReflectanceTexture.view });\n entries.push({ binding: b++, resource: m.metallicReflectanceTexture.sampler });\n }\n if (m.reflectanceTexture) {\n entries.push({ binding: b++, resource: m.reflectanceTexture.view });\n entries.push({ binding: b++, resource: m.reflectanceTexture.sampler });\n }\n return b;\n },\n textures(mat, t) {\n const m = mat as PbrMaterialProps;\n if (m.metallicReflectanceTexture) {\n t.push(m.metallicReflectanceTexture);\n }\n if (m.reflectanceTexture) {\n t.push(m.reflectanceTexture);\n }\n },\n};\n"],"names":[],"mappings":"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"}
@@ -112,7 +112,7 @@ function writeRefractionUBO(data, mat, offsets) {
112
112
  const ior = refr.indexOfRefraction ?? 1.5;
113
113
  const thick = ss.thickness;
114
114
  data[o + 1] = 1 / (refr.useThicknessAsDepth && thick?.max ? ior : 1);
115
- data[o + 2] = refr.useThicknessAsDepth ? thick?.max ?? 0 : 1;
115
+ data[o + 2] = refr.useThicknessAsDepth ? thick?.max ?? 0 : 0;
116
116
  data[o + 3] = 1 / ior;
117
117
  const vOff = offsets.get("volumeParams");
118
118
  if (vOff !== void 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"refraction-rtt-fragment.js","sources":["../../../../../src/material/pbr/fragments/refraction-rtt-fragment.ts"],"sourcesContent":["import type { ShaderFragment, UboField } from \"../../../shader/fragment-types.js\";\nimport type { PbrMaterialProps, SubSurfaceProps } from \"../pbr-material.js\";\nimport type { PbrExt } from \"../pbr-flags.js\";\nimport { getTrilinearAnisotropicSampler } from \"../../../resource/trilinear-anisotropic-sampler.js\";\nimport {\n PBR_HAS_THICKNESS_MAP,\n PBR2_HAS_DISPERSION,\n PBR2_HAS_REFRACTION,\n PBR2_HAS_REFRACTION_MAP,\n PBR2_HAS_THICKNESS_GLTF_CHANNEL,\n PBR2_HAS_VOLUME,\n PBR2_LINEAR_IMAGE_PROCESSING,\n} from \"../pbr-flag-bits.js\";\n\ntype TransmissionMat = PbrMaterialProps & { _linearImageProcessing?: boolean };\nconst LINEAR_IMAGE_PROCESSING_SLOTS = { NI: `if(scene.vImageInfos.w>=0.0){`, BC: `}` };\n\nfunction makeRefractionMod(\n hasVolume: boolean,\n hasMap: boolean,\n hasThicknessMap: boolean,\n useGltfThicknessChannel: boolean,\n hasDispersion: boolean,\n dispersionSampleWgsl: string | undefined\n): string {\n const thicknessScaleLine = hasVolume || hasThicknessMap ? `let ts=max(length(mesh.world[0].xyz),max(length(mesh.world[1].xyz),length(mesh.world[2].xyz)));` : ``;\n const mapUvDecl = hasMap\n ? `let refractionMapUV=vec2<f32>(dot(material.refractionMapUVm.xy,input.uv),dot(material.refractionMapUVm.zw,input.uv))+material.refractionMapUVt.xy;\\n`\n : ``;\n const thickUvDecl = hasThicknessMap\n ? `let thicknessUV=vec2<f32>(dot(material.thicknessUVm.xy,input.uv),dot(material.thicknessUVm.zw,input.uv))+material.thicknessUVt.xy;\\n`\n : ``;\n const thicknessLine = hasThicknessMap\n ? `let ths=textureSample(thicknessTexture_,thicknessSampler_,thicknessUV).${useGltfThicknessChannel ? \"g\" : \"r\"};\nlet th=(material.thicknessParams.x+ths*material.thicknessParams.y)*ts;`\n : hasVolume\n ? `let th=material.refractionParams.z*ts;`\n : `let th=material.refractionParams.z;`;\n const textureLine = hasMap\n ? `let ri=material.refractionParams.x*textureSample(refractionMapTexture,refractionMapSampler,refractionMapUV).r;`\n : `let ri=material.refractionParams.x;`;\n const absorptionLine = hasVolume ? `let ab=exp(material.volumeParams.rgb*th);` : ``;\n const refractionLine = hasVolume\n ? `let fr=er*surfaceAlbedo*(ri*ab)*(vec3<f32>(1.0)-colorSpecularEnvReflectance.rgb);`\n : `let fr=er*surfaceAlbedo*ri*(vec3<f32>(1.0)-colorSpecularEnvReflectance.rgb);`;\n\n // Refracted environment sample. Dispersion splits the refracted ray into\n // per-RGB index-of-refraction offsets (chromatic aberration); that 3-ray WGSL\n // is injected from a dynamically-imported module (see refraction-dispersion-wgsl.ts)\n // so non-dispersion transmission scenes keep the lean single-ray path below.\n const sampleLines =\n hasDispersion && dispersionSampleWgsl\n ? dispersionSampleWgsl\n : `let rd=refract(-V,N,material.refractionParams.y);\nlet cp=scene.viewProjection*vec4<f32>(input.worldPos+rd*th,1.0);\nlet ruv=(cp.xy/cp.w)*vec2<f32>(0.5,-0.5)+vec2<f32>(0.5,0.5);\nlet er=textureSampleLevel(refractionTexture,refractionSampler_,ruv,lv).rgb*material.environmentIntensity;`;\n\n return `{\n${thicknessScaleLine}\n${mapUvDecl}${thickUvDecl}${textureLine}\n${thicknessLine}\nlet ro=1.0-ri;\nlet ra=mix(alphaG,0.0,clamp(material.refractionParams.w*3.0-2.0,0.0,1.0));\nlet lv=clamp(log2(f32(textureDimensions(refractionTexture).x)*ra)-4.0,0.0,f32(textureNumLevels(refractionTexture)-1));\n${sampleLines}\n${absorptionLine}\n${refractionLine}\ncolor=finalIrradiance*ro*ro+finalRadianceScaled+finalSpecularScaled+directDiffuse*ro*ro+fr+emissive;\n}`;\n}\n\nfunction createRefractionRttFragment(\n hasVolume: boolean,\n hasMap: boolean,\n hasThicknessMap: boolean,\n useGltfThicknessChannel: boolean,\n linearImageProcessing: boolean,\n hasDispersion: boolean,\n dispersionSampleWgsl: string | undefined\n): ShaderFragment {\n const uboFields: UboField[] = [{ _name: \"refractionParams\", _type: \"vec4<f32>\" as const }];\n if (hasVolume) {\n uboFields.push({ _name: \"volumeParams\", _type: \"vec4<f32>\" as const });\n }\n if (hasThicknessMap) {\n uboFields.push({ _name: \"thicknessParams\", _type: \"vec4<f32>\" as const });\n }\n // Per-texture UV transforms (KHR_texture_transform on transmissionTexture / thicknessTexture),\n // animatable via KHR_animation_pointer. Emitted whenever the map is present; identity when the\n // texture carries no transform (sample at input.uv), so non-transformed scenes are unchanged.\n if (hasMap) {\n uboFields.push({ _name: \"refractionMapUVm\", _type: \"vec4<f32>\" as const }, { _name: \"refractionMapUVt\", _type: \"vec4<f32>\" as const });\n }\n if (hasThicknessMap) {\n uboFields.push({ _name: \"thicknessUVm\", _type: \"vec4<f32>\" as const }, { _name: \"thicknessUVt\", _type: \"vec4<f32>\" as const });\n }\n const bindings = [\n { _name: \"refractionTexture\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" } as const, _visibility: 2 },\n { _name: \"refractionSampler_\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" } as const, _visibility: 2 },\n ];\n if (hasMap) {\n bindings.push(\n { _name: \"refractionMapTexture\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" } as const, _visibility: 2 },\n { _name: \"refractionMapSampler\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" } as const, _visibility: 2 }\n );\n }\n if (hasThicknessMap) {\n bindings.push(\n { _name: \"thicknessTexture_\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" } as const, _visibility: 2 },\n { _name: \"thicknessSampler_\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" } as const, _visibility: 2 }\n );\n }\n return {\n _id: \"refraction\",\n _dependencies: [\"ibl\"],\n _uboFields: uboFields,\n _bindings: bindings,\n _fragmentSlots: linearImageProcessing\n ? { AI: makeRefractionMod(hasVolume, hasMap, hasThicknessMap, useGltfThicknessChannel, hasDispersion, dispersionSampleWgsl), ...LINEAR_IMAGE_PROCESSING_SLOTS }\n : { AI: makeRefractionMod(hasVolume, hasMap, hasThicknessMap, useGltfThicknessChannel, hasDispersion, dispersionSampleWgsl) },\n };\n}\n\nfunction writeRefractionUvTransform(\n data: Float32Array,\n offsets: ReadonlyMap<string, number>,\n name: string,\n tex: { uScale?: number; vScale?: number; uAng?: number; uOffset?: number; vOffset?: number } | undefined\n): void {\n const mOff = offsets.get(`${name}m`);\n const tOff = offsets.get(`${name}t`);\n if (mOff === undefined || tOff === undefined) {\n return;\n }\n const mi = mOff / 4;\n const ti = tOff / 4;\n const sx = tex?.uScale ?? 1;\n const sy = tex?.vScale ?? 1;\n const ang = tex?.uAng ?? 0;\n if (ang === 0) {\n data[mi] = sx;\n data[mi + 1] = 0;\n data[mi + 2] = 0;\n data[mi + 3] = sy;\n } else {\n const c = Math.cos(ang);\n const s = Math.sin(ang);\n data[mi] = c * sx;\n data[mi + 1] = s * sy;\n data[mi + 2] = -s * sx;\n data[mi + 3] = c * sy;\n }\n data[ti] = tex?.uOffset ?? 0;\n data[ti + 1] = tex?.vOffset ?? 0;\n data[ti + 2] = 0;\n data[ti + 3] = 0;\n}\n\nfunction writeRefractionUBO(data: Float32Array, mat: PbrMaterialProps, offsets: ReadonlyMap<string, number>): void {\n const ss = mat.subsurface as SubSurfaceProps | undefined;\n const refr = ss?.refraction;\n if (!refr) {\n return;\n }\n const off = offsets.get(\"refractionParams\");\n if (off === undefined) {\n return;\n }\n const o = off / 4;\n data[o] = refr.intensity ?? 0;\n const ior = refr.indexOfRefraction ?? 1.5;\n const thick = ss!.thickness;\n data[o + 1] = 1.0 / (refr.useThicknessAsDepth && thick?.max ? ior : 1.0);\n data[o + 2] = refr.useThicknessAsDepth ? (thick?.max ?? 0.0) : 1.0;\n data[o + 3] = 1.0 / ior;\n\n const vOff = offsets.get(\"volumeParams\");\n if (vOff !== undefined) {\n const vo = vOff / 4;\n const tint = ss!.tint?.color ?? [1, 1, 1];\n const dist = Math.max(ss!.tint?.atDistance ?? 1, 0.0001);\n data[vo] = Math.log(Math.max(tint[0]!, 1e-6)) / dist;\n data[vo + 1] = Math.log(Math.max(tint[1]!, 1e-6)) / dist;\n data[vo + 2] = Math.log(Math.max(tint[2]!, 1e-6)) / dist;\n // w carries the chromatic dispersion strength (0 when no KHR_materials_dispersion).\n data[vo + 3] = refr.dispersion ?? 0;\n }\n\n const tOff = offsets.get(\"thicknessParams\");\n if (tOff !== undefined) {\n const to = tOff / 4;\n const min = thick?.min ?? 0;\n const max = thick?.max ?? 1;\n data[to] = min;\n data[to + 1] = max - min;\n }\n\n writeRefractionUvTransform(data, offsets, \"refractionMapUV\", refr.texture);\n writeRefractionUvTransform(data, offsets, \"thicknessUV\", thick?.texture);\n}\n\n/** Build the PBR refraction/transmission extension. When the scene contains a\n * dispersive material, `dispersionSampleWgsl` carries the per-RGB 3-ray sample\n * WGSL (dynamically imported, scene-isolated); otherwise it is undefined and the\n * lean single-ray refraction path is emitted. */\nexport function makeRefractionRttExt(dispersionSampleWgsl?: string): PbrExt {\n return {\n id: \"refraction\",\n phase: \"fragment\",\n detect(mat) {\n const m = mat as TransmissionMat;\n const ss = m.subsurface as SubSurfaceProps | undefined;\n const refr = ss?.refraction;\n const linearImageProcessing = m._linearImageProcessing ? PBR2_LINEAR_IMAGE_PROCESSING : 0;\n const intensity = m.transmissive ? (refr?.intensity ?? 0) : 0;\n if (intensity <= 0) {\n return { f: 0, f2: linearImageProcessing };\n }\n let f = 0;\n let f2 = linearImageProcessing | PBR2_HAS_REFRACTION;\n if (refr?.texture) {\n f2 |= PBR2_HAS_REFRACTION_MAP;\n }\n if (ss?.thickness?.texture) {\n f |= PBR_HAS_THICKNESS_MAP;\n }\n if (ss?.thickness?.useGlTFChannel) {\n f2 |= PBR2_HAS_THICKNESS_GLTF_CHANNEL;\n }\n if (ss?.tint?.atDistance !== undefined) {\n f2 |= PBR2_HAS_VOLUME;\n // Dispersion requires the volume path (per-channel etas + volumeParams.w storage).\n if (refr?.dispersion) {\n f2 |= PBR2_HAS_DISPERSION;\n }\n }\n return { f, f2 };\n },\n frag(ctx) {\n const linearImageProcessing = (ctx._features2 & PBR2_LINEAR_IMAGE_PROCESSING) !== 0;\n if (!(ctx._features2 & PBR2_HAS_REFRACTION)) {\n return linearImageProcessing ? { _id: \"linear\", _fragmentSlots: LINEAR_IMAGE_PROCESSING_SLOTS } : null;\n }\n return createRefractionRttFragment(\n (ctx._features2 & PBR2_HAS_VOLUME) !== 0,\n (ctx._features2 & PBR2_HAS_REFRACTION_MAP) !== 0,\n (ctx._features & PBR_HAS_THICKNESS_MAP) !== 0,\n (ctx._features2 & PBR2_HAS_THICKNESS_GLTF_CHANNEL) !== 0,\n linearImageProcessing,\n (ctx._features2 & PBR2_HAS_DISPERSION) !== 0,\n dispersionSampleWgsl\n );\n },\n writeUbo(data, mat, offsets) {\n writeRefractionUBO(data, mat as PbrMaterialProps, offsets);\n },\n bind(ctx, entries, b) {\n if (!(ctx._features2 & PBR2_HAS_REFRACTION)) {\n return b;\n }\n const texture = ctx._refractionTexture;\n if (!texture) {\n throw new Error(\"PBR transmission requires a frame-graph refraction texture.\");\n }\n entries.push({ binding: b++, resource: texture.view });\n entries.push({ binding: b++, resource: texture.sampler });\n if ((ctx._features2 & PBR2_HAS_REFRACTION_MAP) !== 0) {\n const map = ((ctx._material as PbrMaterialProps).subsurface?.refraction as SubSurfaceProps[\"refraction\"] | undefined)?.texture!;\n entries.push({ binding: b++, resource: map.view });\n entries.push({ binding: b++, resource: getTrilinearAnisotropicSampler(ctx._engine) });\n }\n if ((ctx._features & PBR_HAS_THICKNESS_MAP) !== 0) {\n const thickness = (ctx._material as PbrMaterialProps).subsurface?.thickness?.texture!;\n entries.push({ binding: b++, resource: thickness.view });\n entries.push({ binding: b++, resource: thickness.sampler });\n }\n return b;\n },\n textures(mat, out) {\n const tex = (mat as PbrMaterialProps).subsurface?.refraction?.texture;\n if (tex) {\n out.push(tex);\n }\n const thickness = (mat as PbrMaterialProps).subsurface?.thickness?.texture;\n if (thickness) {\n out.push(thickness);\n }\n },\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"refraction-rtt-fragment.js","sources":["../../../../../src/material/pbr/fragments/refraction-rtt-fragment.ts"],"sourcesContent":["import type { ShaderFragment, UboField } from \"../../../shader/fragment-types.js\";\nimport type { PbrMaterialProps, SubSurfaceProps } from \"../pbr-material.js\";\nimport type { PbrExt } from \"../pbr-flags.js\";\nimport { getTrilinearAnisotropicSampler } from \"../../../resource/trilinear-anisotropic-sampler.js\";\nimport {\n PBR_HAS_THICKNESS_MAP,\n PBR2_HAS_DISPERSION,\n PBR2_HAS_REFRACTION,\n PBR2_HAS_REFRACTION_MAP,\n PBR2_HAS_THICKNESS_GLTF_CHANNEL,\n PBR2_HAS_VOLUME,\n PBR2_LINEAR_IMAGE_PROCESSING,\n} from \"../pbr-flag-bits.js\";\n\ntype TransmissionMat = PbrMaterialProps & { _linearImageProcessing?: boolean };\nconst LINEAR_IMAGE_PROCESSING_SLOTS = { NI: `if(scene.vImageInfos.w>=0.0){`, BC: `}` };\n\nfunction makeRefractionMod(\n hasVolume: boolean,\n hasMap: boolean,\n hasThicknessMap: boolean,\n useGltfThicknessChannel: boolean,\n hasDispersion: boolean,\n dispersionSampleWgsl: string | undefined\n): string {\n const thicknessScaleLine = hasVolume || hasThicknessMap ? `let ts=max(length(mesh.world[0].xyz),max(length(mesh.world[1].xyz),length(mesh.world[2].xyz)));` : ``;\n const mapUvDecl = hasMap\n ? `let refractionMapUV=vec2<f32>(dot(material.refractionMapUVm.xy,input.uv),dot(material.refractionMapUVm.zw,input.uv))+material.refractionMapUVt.xy;\\n`\n : ``;\n const thickUvDecl = hasThicknessMap\n ? `let thicknessUV=vec2<f32>(dot(material.thicknessUVm.xy,input.uv),dot(material.thicknessUVm.zw,input.uv))+material.thicknessUVt.xy;\\n`\n : ``;\n const thicknessLine = hasThicknessMap\n ? `let ths=textureSample(thicknessTexture_,thicknessSampler_,thicknessUV).${useGltfThicknessChannel ? \"g\" : \"r\"};\nlet th=(material.thicknessParams.x+ths*material.thicknessParams.y)*ts;`\n : hasVolume\n ? `let th=material.refractionParams.z*ts;`\n : `let th=material.refractionParams.z;`;\n const textureLine = hasMap\n ? `let ri=material.refractionParams.x*textureSample(refractionMapTexture,refractionMapSampler,refractionMapUV).r;`\n : `let ri=material.refractionParams.x;`;\n const absorptionLine = hasVolume ? `let ab=exp(material.volumeParams.rgb*th);` : ``;\n const refractionLine = hasVolume\n ? `let fr=er*surfaceAlbedo*(ri*ab)*(vec3<f32>(1.0)-colorSpecularEnvReflectance.rgb);`\n : `let fr=er*surfaceAlbedo*ri*(vec3<f32>(1.0)-colorSpecularEnvReflectance.rgb);`;\n\n // Refracted environment sample. Dispersion splits the refracted ray into\n // per-RGB index-of-refraction offsets (chromatic aberration); that 3-ray WGSL\n // is injected from a dynamically-imported module (see refraction-dispersion-wgsl.ts)\n // so non-dispersion transmission scenes keep the lean single-ray path below.\n const sampleLines =\n hasDispersion && dispersionSampleWgsl\n ? dispersionSampleWgsl\n : `let rd=refract(-V,N,material.refractionParams.y);\nlet cp=scene.viewProjection*vec4<f32>(input.worldPos+rd*th,1.0);\nlet ruv=(cp.xy/cp.w)*vec2<f32>(0.5,-0.5)+vec2<f32>(0.5,0.5);\nlet er=textureSampleLevel(refractionTexture,refractionSampler_,ruv,lv).rgb*material.environmentIntensity;`;\n\n return `{\n${thicknessScaleLine}\n${mapUvDecl}${thickUvDecl}${textureLine}\n${thicknessLine}\nlet ro=1.0-ri;\nlet ra=mix(alphaG,0.0,clamp(material.refractionParams.w*3.0-2.0,0.0,1.0));\nlet lv=clamp(log2(f32(textureDimensions(refractionTexture).x)*ra)-4.0,0.0,f32(textureNumLevels(refractionTexture)-1));\n${sampleLines}\n${absorptionLine}\n${refractionLine}\ncolor=finalIrradiance*ro*ro+finalRadianceScaled+finalSpecularScaled+directDiffuse*ro*ro+fr+emissive;\n}`;\n}\n\nfunction createRefractionRttFragment(\n hasVolume: boolean,\n hasMap: boolean,\n hasThicknessMap: boolean,\n useGltfThicknessChannel: boolean,\n linearImageProcessing: boolean,\n hasDispersion: boolean,\n dispersionSampleWgsl: string | undefined\n): ShaderFragment {\n const uboFields: UboField[] = [{ _name: \"refractionParams\", _type: \"vec4<f32>\" as const }];\n if (hasVolume) {\n uboFields.push({ _name: \"volumeParams\", _type: \"vec4<f32>\" as const });\n }\n if (hasThicknessMap) {\n uboFields.push({ _name: \"thicknessParams\", _type: \"vec4<f32>\" as const });\n }\n // Per-texture UV transforms (KHR_texture_transform on transmissionTexture / thicknessTexture),\n // animatable via KHR_animation_pointer. Emitted whenever the map is present; identity when the\n // texture carries no transform (sample at input.uv), so non-transformed scenes are unchanged.\n if (hasMap) {\n uboFields.push({ _name: \"refractionMapUVm\", _type: \"vec4<f32>\" as const }, { _name: \"refractionMapUVt\", _type: \"vec4<f32>\" as const });\n }\n if (hasThicknessMap) {\n uboFields.push({ _name: \"thicknessUVm\", _type: \"vec4<f32>\" as const }, { _name: \"thicknessUVt\", _type: \"vec4<f32>\" as const });\n }\n const bindings = [\n { _name: \"refractionTexture\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" } as const, _visibility: 2 },\n { _name: \"refractionSampler_\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" } as const, _visibility: 2 },\n ];\n if (hasMap) {\n bindings.push(\n { _name: \"refractionMapTexture\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" } as const, _visibility: 2 },\n { _name: \"refractionMapSampler\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" } as const, _visibility: 2 }\n );\n }\n if (hasThicknessMap) {\n bindings.push(\n { _name: \"thicknessTexture_\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" } as const, _visibility: 2 },\n { _name: \"thicknessSampler_\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" } as const, _visibility: 2 }\n );\n }\n return {\n _id: \"refraction\",\n _dependencies: [\"ibl\"],\n _uboFields: uboFields,\n _bindings: bindings,\n _fragmentSlots: linearImageProcessing\n ? { AI: makeRefractionMod(hasVolume, hasMap, hasThicknessMap, useGltfThicknessChannel, hasDispersion, dispersionSampleWgsl), ...LINEAR_IMAGE_PROCESSING_SLOTS }\n : { AI: makeRefractionMod(hasVolume, hasMap, hasThicknessMap, useGltfThicknessChannel, hasDispersion, dispersionSampleWgsl) },\n };\n}\n\nfunction writeRefractionUvTransform(\n data: Float32Array,\n offsets: ReadonlyMap<string, number>,\n name: string,\n tex: { uScale?: number; vScale?: number; uAng?: number; uOffset?: number; vOffset?: number } | undefined\n): void {\n const mOff = offsets.get(`${name}m`);\n const tOff = offsets.get(`${name}t`);\n if (mOff === undefined || tOff === undefined) {\n return;\n }\n const mi = mOff / 4;\n const ti = tOff / 4;\n const sx = tex?.uScale ?? 1;\n const sy = tex?.vScale ?? 1;\n const ang = tex?.uAng ?? 0;\n if (ang === 0) {\n data[mi] = sx;\n data[mi + 1] = 0;\n data[mi + 2] = 0;\n data[mi + 3] = sy;\n } else {\n const c = Math.cos(ang);\n const s = Math.sin(ang);\n data[mi] = c * sx;\n data[mi + 1] = s * sy;\n data[mi + 2] = -s * sx;\n data[mi + 3] = c * sy;\n }\n data[ti] = tex?.uOffset ?? 0;\n data[ti + 1] = tex?.vOffset ?? 0;\n data[ti + 2] = 0;\n data[ti + 3] = 0;\n}\n\nfunction writeRefractionUBO(data: Float32Array, mat: PbrMaterialProps, offsets: ReadonlyMap<string, number>): void {\n const ss = mat.subsurface as SubSurfaceProps | undefined;\n const refr = ss?.refraction;\n if (!refr) {\n return;\n }\n const off = offsets.get(\"refractionParams\");\n if (off === undefined) {\n return;\n }\n const o = off / 4;\n data[o] = refr.intensity ?? 0;\n const ior = refr.indexOfRefraction ?? 1.5;\n const thick = ss!.thickness;\n data[o + 1] = 1.0 / (refr.useThicknessAsDepth && thick?.max ? ior : 1.0);\n data[o + 2] = refr.useThicknessAsDepth ? (thick?.max ?? 0.0) : 0.0;\n data[o + 3] = 1.0 / ior;\n\n const vOff = offsets.get(\"volumeParams\");\n if (vOff !== undefined) {\n const vo = vOff / 4;\n const tint = ss!.tint?.color ?? [1, 1, 1];\n const dist = Math.max(ss!.tint?.atDistance ?? 1, 0.0001);\n data[vo] = Math.log(Math.max(tint[0]!, 1e-6)) / dist;\n data[vo + 1] = Math.log(Math.max(tint[1]!, 1e-6)) / dist;\n data[vo + 2] = Math.log(Math.max(tint[2]!, 1e-6)) / dist;\n // w carries the chromatic dispersion strength (0 when no KHR_materials_dispersion).\n data[vo + 3] = refr.dispersion ?? 0;\n }\n\n const tOff = offsets.get(\"thicknessParams\");\n if (tOff !== undefined) {\n const to = tOff / 4;\n const min = thick?.min ?? 0;\n const max = thick?.max ?? 1;\n data[to] = min;\n data[to + 1] = max - min;\n }\n\n writeRefractionUvTransform(data, offsets, \"refractionMapUV\", refr.texture);\n writeRefractionUvTransform(data, offsets, \"thicknessUV\", thick?.texture);\n}\n\n/** Build the PBR refraction/transmission extension. When the scene contains a\n * dispersive material, `dispersionSampleWgsl` carries the per-RGB 3-ray sample\n * WGSL (dynamically imported, scene-isolated); otherwise it is undefined and the\n * lean single-ray refraction path is emitted. */\nexport function makeRefractionRttExt(dispersionSampleWgsl?: string): PbrExt {\n return {\n id: \"refraction\",\n phase: \"fragment\",\n detect(mat) {\n const m = mat as TransmissionMat;\n const ss = m.subsurface as SubSurfaceProps | undefined;\n const refr = ss?.refraction;\n const linearImageProcessing = m._linearImageProcessing ? PBR2_LINEAR_IMAGE_PROCESSING : 0;\n const intensity = m.transmissive ? (refr?.intensity ?? 0) : 0;\n if (intensity <= 0) {\n return { f: 0, f2: linearImageProcessing };\n }\n let f = 0;\n let f2 = linearImageProcessing | PBR2_HAS_REFRACTION;\n if (refr?.texture) {\n f2 |= PBR2_HAS_REFRACTION_MAP;\n }\n if (ss?.thickness?.texture) {\n f |= PBR_HAS_THICKNESS_MAP;\n }\n if (ss?.thickness?.useGlTFChannel) {\n f2 |= PBR2_HAS_THICKNESS_GLTF_CHANNEL;\n }\n if (ss?.tint?.atDistance !== undefined) {\n f2 |= PBR2_HAS_VOLUME;\n // Dispersion requires the volume path (per-channel etas + volumeParams.w storage).\n if (refr?.dispersion) {\n f2 |= PBR2_HAS_DISPERSION;\n }\n }\n return { f, f2 };\n },\n frag(ctx) {\n const linearImageProcessing = (ctx._features2 & PBR2_LINEAR_IMAGE_PROCESSING) !== 0;\n if (!(ctx._features2 & PBR2_HAS_REFRACTION)) {\n return linearImageProcessing ? { _id: \"linear\", _fragmentSlots: LINEAR_IMAGE_PROCESSING_SLOTS } : null;\n }\n return createRefractionRttFragment(\n (ctx._features2 & PBR2_HAS_VOLUME) !== 0,\n (ctx._features2 & PBR2_HAS_REFRACTION_MAP) !== 0,\n (ctx._features & PBR_HAS_THICKNESS_MAP) !== 0,\n (ctx._features2 & PBR2_HAS_THICKNESS_GLTF_CHANNEL) !== 0,\n linearImageProcessing,\n (ctx._features2 & PBR2_HAS_DISPERSION) !== 0,\n dispersionSampleWgsl\n );\n },\n writeUbo(data, mat, offsets) {\n writeRefractionUBO(data, mat as PbrMaterialProps, offsets);\n },\n bind(ctx, entries, b) {\n if (!(ctx._features2 & PBR2_HAS_REFRACTION)) {\n return b;\n }\n const texture = ctx._refractionTexture;\n if (!texture) {\n throw new Error(\"PBR transmission requires a frame-graph refraction texture.\");\n }\n entries.push({ binding: b++, resource: texture.view });\n entries.push({ binding: b++, resource: texture.sampler });\n if ((ctx._features2 & PBR2_HAS_REFRACTION_MAP) !== 0) {\n const map = ((ctx._material as PbrMaterialProps).subsurface?.refraction as SubSurfaceProps[\"refraction\"] | undefined)?.texture!;\n entries.push({ binding: b++, resource: map.view });\n entries.push({ binding: b++, resource: getTrilinearAnisotropicSampler(ctx._engine) });\n }\n if ((ctx._features & PBR_HAS_THICKNESS_MAP) !== 0) {\n const thickness = (ctx._material as PbrMaterialProps).subsurface?.thickness?.texture!;\n entries.push({ binding: b++, resource: thickness.view });\n entries.push({ binding: b++, resource: thickness.sampler });\n }\n return b;\n },\n textures(mat, out) {\n const tex = (mat as PbrMaterialProps).subsurface?.refraction?.texture;\n if (tex) {\n out.push(tex);\n }\n const thickness = (mat as PbrMaterialProps).subsurface?.thickness?.texture;\n if (thickness) {\n out.push(thickness);\n }\n },\n };\n}\n"],"names":[],"mappings":"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"}
@@ -13,6 +13,10 @@ let _pbrFallbackResolver = null;
13
13
  function _installPbrFallbackResolver(resolve) {
14
14
  _pbrFallbackResolver = resolve;
15
15
  }
16
+ let _primitiveResolver = null;
17
+ function _installPbrPrimitiveResolver(resolve) {
18
+ _primitiveResolver = resolve;
19
+ }
16
20
  const _bindingsCache = /* @__PURE__ */ new Map();
17
21
  let _cachedDevice = null;
18
22
  function ensureDevice(engine) {
@@ -62,7 +66,7 @@ function getOrCreatePbrPipeline(engine, sig, bindings) {
62
66
  return cached;
63
67
  }
64
68
  const device = engine._device;
65
- const { _features: features, _features2: features2, _composed: composed } = bindings;
69
+ const { _features: features, _features2: features2, _composed: composed, _meshFeatures: meshFeatures } = bindings;
66
70
  const esmShadowOutput = (features2 & PBR2_ESM_SHADOW_OUTPUT) !== 0;
67
71
  const hasAlpha = !esmShadowOutput && (features & PBR_HAS_ALPHA_BLEND) !== 0;
68
72
  const hasDoubleSided = (features & PBR_HAS_DOUBLE_SIDED) !== 0;
@@ -95,7 +99,7 @@ function getOrCreatePbrPipeline(engine, sig, bindings) {
95
99
  }
96
100
  } : {},
97
101
  multisample: { count: sig._sampleCount },
98
- primitive: { topology: "triangle-list", cullMode: hasDoubleSided ? "none" : "back", frontFace: "ccw" }
102
+ primitive: _primitiveResolver ? _primitiveResolver(meshFeatures, hasDoubleSided) : { topology: "triangle-list", cullMode: hasDoubleSided ? "none" : "back", frontFace: "ccw" }
99
103
  });
100
104
  bindings._pipelines.set(key, pipeline);
101
105
  return pipeline;
@@ -168,5 +172,5 @@ function createPbrMeshBindGroup(engine, bindings, composed, meshUBO, materialUBO
168
172
  return device.createBindGroup({ layout: bindings._meshBGL, entries });
169
173
  }
170
174
 
171
- export { _installPbrFallbackResolver, _installPbrStencilResolver, clearPbrPipelineCache, createPbrMeshBindGroup, getOrCreatePbrBindings, getOrCreatePbrPipeline };
175
+ export { _installPbrFallbackResolver, _installPbrPrimitiveResolver, _installPbrStencilResolver, clearPbrPipelineCache, createPbrMeshBindGroup, getOrCreatePbrBindings, getOrCreatePbrPipeline };
172
176
  //# sourceMappingURL=pbr-pipeline.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pbr-pipeline.js","sources":["../../../../src/material/pbr/pbr-pipeline.ts"],"sourcesContent":["/** Dynamic PBR pipeline builder — creates and caches GPU render pipelines\n * based on per-mesh PBR feature flags + ComposedShader from the fragment system.\n *\n * Two-tier cache:\n * - Shader bindings (BGLs + composed shader + per-sig pipeline cache) keyed by\n * `(features, features2)`. Sig-independent.\n * - Pipelines live inside each `_PbrShaderBindings`, keyed by `targetSignatureKey(sig)`.\n */\n\nimport { CW } from \"../../engine/gpu-flags.js\";\nimport type { PbrMaterialProps } from \"./pbr-material.js\";\nimport type { ResolvedStencil } from \"../stencil-state.js\";\nimport type { StencilState } from \"../material.js\";\nimport type { EnvironmentTextures } from \"../../loader-env/load-env.js\";\nimport type { ComposedShader } from \"../../shader/fragment-types.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\nimport type { Texture2D } from \"../../texture/texture-2d.js\";\nimport type { _PbrBindCtx, PbrExt } from \"./pbr-flags.js\";\nimport { _getPbrExtsSorted, PBR2_ESM_SHADOW_OUTPUT, PBR2_NO_COLOR_OUTPUT, PBR2_HAS_UV2 } from \"./pbr-flags.js\";\nimport { PBR_HAS_NORMAL_MAP, PBR_HAS_EMISSIVE, PBR_HAS_SPEC_GLOSS, PBR_HAS_DOUBLE_SIDED, PBR_HAS_ALPHA_BLEND } from \"./pbr-flags.js\";\nimport { MSH_HAS_TANGENTS, MSH_HAS_UV2 } from \"../mesh-features.js\";\nimport { REVERSE_DEPTH_COMPARE, targetSignatureKey } from \"../../engine/render-target.js\";\nimport { getSceneBindGroupLayout } from \"../../render/scene-helpers.js\";\n\n// ─── Shader Bindings (sig-independent) ──────────────────────────────\n\n/** Stencil resolver, installed only by `enableMaterialStencil`. Module-local with a single exported setter:\n * when `enableMaterialStencil` is absent from the bundle the setter tree-shakes, the bundler proves this is\n * always null, and every stencil branch below folds away — stencil-free PBR scenes stay byte-identical. */\nlet _stencilResolver: ((stencil: StencilState) => ResolvedStencil) | null = null;\n/** @internal Install the stencil resolver into the PBR pipeline (called by `enableMaterialStencil`). */\nexport function _installPbrStencilResolver(resolve: (stencil: StencilState) => ResolvedStencil): void {\n _stencilResolver = resolve;\n}\n\n/** Fallback-texture resolver, installed only by `createPbrMaterial` (called on every\n * use). Provides the shared 1×1 white default for a factor-only material's baseColor /\n * ORM slots (the shader always samples both). Module-local with a single exported setter:\n * glTF-only scenes never call `createPbrMaterial`, so the setter tree-shakes, the bundler\n * proves this is always null, and the `?? _pbrFallbackResolver?.(engine)` reads below fold\n * away — loader-driven PBR scenes (e.g. BoomBox) stay byte-identical. */\nlet _pbrFallbackResolver: ((engine: EngineContext) => Texture2D) | null = null;\n/** @internal Install the factor-only fallback-texture resolver (called by `createPbrMaterial`). */\nexport function _installPbrFallbackResolver(resolve: (engine: EngineContext) => Texture2D): void {\n _pbrFallbackResolver = resolve;\n}\n\ninterface _PbrShaderBindings {\n _features: number;\n _features2: number;\n _meshFeatures: number;\n _meshBGL: GPUBindGroupLayout;\n _shadowBGL: GPUBindGroupLayout | null;\n _composed: ComposedShader;\n /** Pre-baked partial depth-stencil descriptor for this material's stencil state. Present (and the cache\n * key carries the resolved `_key`) only when `enableMaterialStencil` was called — otherwise the field is\n * never assigned and the whole stencil path folds out of stencil-free bundles. */\n _stencil?: Partial<GPUDepthStencilState>;\n /** Per-sig pipeline cache. Key = `targetSignatureKey(sig)`. */\n _pipelines: Map<string, GPURenderPipeline>;\n}\n\n// ─── Caches ─────────────────────────────────────────────────────────\n\nconst _bindingsCache = new Map<string, _PbrShaderBindings>();\nlet _cachedDevice: GPUDevice | null = null;\n\nfunction ensureDevice(engine: EngineContext): void {\n if (_cachedDevice !== engine._device) {\n _bindingsCache.clear();\n _cachedDevice = engine._device;\n }\n}\n\n/** Clear the pipeline cache. Must be called when a GPU device is destroyed. */\nexport function clearPbrPipelineCache(): void {\n _bindingsCache.clear();\n _cachedDevice = null;\n}\n\n/** Get-or-build the sig-independent PBR shader bindings. Used at renderable build time\n * so per-mesh bind groups can be created BEFORE any sig is known. */\nexport function getOrCreatePbrBindings(\n engine: EngineContext,\n features: number,\n features2: number,\n meshFeatures: number,\n sceneFeatures: number,\n composed: ComposedShader,\n shaderKey = \"\",\n stencil: StencilState | null = null\n): _PbrShaderBindings {\n ensureDevice(engine);\n // Stencil state is baked into the GPU pipeline (no dynamic stencil ref), so two materials that differ only in\n // stencil must NOT share bindings/pipelines — fold the resolved stencil token into the cache key. Resolution\n // goes through the opt-in `_stencilResolver` hook, so non-stencil scenes fold this whole block away.\n const resolvedStencil = stencil && _stencilResolver ? _stencilResolver(stencil) : null;\n const key = `${features}:${features2}:${meshFeatures}:${sceneFeatures}:${shaderKey}${resolvedStencil ? resolvedStencil._key : \"\"}`;\n const cached = _bindingsCache.get(key);\n if (cached) {\n return cached;\n }\n\n const device = engine._device;\n const meshBGL = device.createBindGroupLayout(composed._meshBGLDescriptor);\n let shadowBGL: GPUBindGroupLayout | null = null;\n if (composed._shadowBGLDescriptor) {\n shadowBGL = device.createBindGroupLayout(composed._shadowBGLDescriptor);\n }\n const bindings: _PbrShaderBindings = {\n _features: features,\n _features2: features2,\n _meshFeatures: meshFeatures,\n _meshBGL: meshBGL,\n _shadowBGL: shadowBGL,\n _composed: composed,\n _pipelines: new Map(),\n };\n // Gated by the opt-in resolver so the field assignment folds out of stencil-free bundles entirely.\n if (resolvedStencil) {\n bindings._stencil = resolvedStencil._desc;\n }\n _bindingsCache.set(key, bindings);\n return bindings;\n}\n\n/** Get-or-build the sig-specific pipeline on top of a PBR shader bindings. Called at bind() time. */\nexport function getOrCreatePbrPipeline(engine: EngineContext, sig: RenderTargetSignature, bindings: _PbrShaderBindings): GPURenderPipeline {\n ensureDevice(engine);\n const key = targetSignatureKey(sig);\n const cached = bindings._pipelines.get(key);\n if (cached) {\n return cached;\n }\n\n const device = engine._device;\n const { _features: features, _features2: features2, _composed: composed } = bindings;\n const esmShadowOutput = (features2 & PBR2_ESM_SHADOW_OUTPUT) !== 0;\n const hasAlpha = !esmShadowOutput && (features & PBR_HAS_ALPHA_BLEND) !== 0;\n const hasDoubleSided = (features & PBR_HAS_DOUBLE_SIDED) !== 0;\n\n const sceneBGL = getSceneBindGroupLayout(engine);\n const bgls: GPUBindGroupLayout[] = bindings._shadowBGL ? [sceneBGL, bindings._meshBGL, bindings._shadowBGL] : [sceneBGL, bindings._meshBGL];\n\n const vertModule = device.createShaderModule({ code: composed._vertexWGSL });\n const noColorOutput = (features2 & PBR2_NO_COLOR_OUTPUT) !== 0;\n const fragModule = !sig._colorFormat && !noColorOutput ? null : device.createShaderModule({ code: composed._fragmentWGSL });\n\n const fragTarget: GPUColorTargetState | null = noColorOutput ? null : { format: sig._colorFormat!, writeMask: CW.ALL };\n if (hasAlpha && fragTarget) {\n fragTarget.blend = {\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one\", operation: \"add\" },\n };\n }\n\n const pipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({ bindGroupLayouts: bgls }),\n vertex: { module: vertModule, entryPoint: \"main\", buffers: composed._vertexBufferLayouts },\n ...(fragModule ? { fragment: { module: fragModule, entryPoint: \"main\", targets: fragTarget ? [fragTarget] : [] } } : {}),\n ...(sig._depthStencilFormat\n ? {\n depthStencil: {\n format: sig._depthStencilFormat,\n depthCompare: sig._depthCompare ?? REVERSE_DEPTH_COMPARE,\n depthWriteEnabled: noColorOutput || esmShadowOutput || !hasAlpha,\n // Pre-baked stencil sub-fields, applied only on a stencil-capable target — the same\n // material in the depth32float shadow/depth pass keeps plain depth state (no stencil → no\n // format mismatch). Gated on `_stencilResolver` (the opt-in hook) so the entire branch —\n // including the `bindings._stencil` reads — folds out of stencil-free bundles.\n ...(_stencilResolver && bindings._stencil && sig._depthStencilFormat.includes(\"stencil\") ? bindings._stencil : {}),\n },\n }\n : {}),\n multisample: { count: sig._sampleCount },\n primitive: { topology: \"triangle-list\", cullMode: hasDoubleSided ? (\"none\" as GPUCullMode) : \"back\", frontFace: \"ccw\" },\n });\n bindings._pipelines.set(key, pipeline);\n return pipeline;\n}\n\n// ─── Per-Mesh Bind Group ────────────────────────────────────────────\n\nexport function createPbrMeshBindGroup(\n engine: EngineContext,\n bindings: _PbrShaderBindings,\n composed: ComposedShader,\n meshUBO: GPUBuffer,\n materialUBO: GPUBuffer,\n material: PbrMaterialProps,\n env: EnvironmentTextures | null,\n meshCtx: { skeleton?: { boneTexture: GPUTexture } | null; morphTargets?: { deltasBuffer: GPUBuffer; weightsBuffer?: GPUBuffer } | null } | null,\n refractionTexture?: Texture2D | null\n): GPUBindGroup {\n const device = engine._device;\n const features = bindings._features;\n const features2 = bindings._features2;\n const meshFeatures = bindings._meshFeatures;\n const hasNormal = (features & PBR_HAS_NORMAL_MAP) !== 0 && (meshFeatures & MSH_HAS_TANGENTS) !== 0;\n const hasCotangentNormal = (features & PBR_HAS_NORMAL_MAP) !== 0 && (meshFeatures & MSH_HAS_TANGENTS) === 0;\n const hasAnyNormal = hasNormal || hasCotangentNormal;\n const hasEmissive = (features & PBR_HAS_EMISSIVE) !== 0;\n const hasSpecGloss = (features & PBR_HAS_SPEC_GLOSS) !== 0;\n const esmShadowOutput = (features2 & PBR2_ESM_SHADOW_OUTPUT) !== 0;\n\n const entries: GPUBindGroupEntry[] = [];\n let b = 0;\n const addTex = (t: { view: GPUTextureView; sampler: GPUSampler }) => {\n entries.push({ binding: b++, resource: t.view });\n entries.push({ binding: b++, resource: t.sampler });\n };\n\n const ctx: _PbrBindCtx = {\n _engine: engine,\n _features: features,\n _features2: features2,\n _meshFeatures: meshFeatures,\n _material: material,\n _mesh: meshCtx ?? undefined,\n _env: env,\n _refractionTexture: refractionTexture,\n };\n\n const sortedExts = _getPbrExtsSorted();\n\n const fragIds = composed._fragmentKey ? composed._fragmentKey.split(\"|\").filter((s) => s.length > 0) : [];\n\n entries.push({ binding: b++, resource: { buffer: meshUBO } });\n entries.push({ binding: b++, resource: { buffer: materialUBO } });\n for (const ext of sortedExts) {\n if (ext.phase === \"vertex\" && ext.bind) {\n b = ext.bind(ctx, entries, b);\n }\n }\n addTex(material.baseColorTexture ?? _pbrFallbackResolver?.(engine)!);\n if (hasAnyNormal) {\n addTex(material.normalTexture!);\n }\n addTex(material.ormTexture ?? _pbrFallbackResolver?.(engine)!);\n if ((features2 & PBR2_HAS_UV2) !== 0 && (meshFeatures & MSH_HAS_UV2) !== 0 && material.occlusionTexture) {\n addTex(material.occlusionTexture);\n }\n if (hasEmissive) {\n addTex(material.emissiveTexture!);\n }\n if (hasSpecGloss) {\n addTex(material.specGlossTexture!);\n }\n if (esmShadowOutput) {\n entries.push({\n binding: b++,\n resource: { buffer: (material as PbrMaterialProps & { readonly _esmShadowParamsUBO: GPUBuffer })._esmShadowParamsUBO },\n });\n }\n const seenExts: PbrExt[] = [];\n for (const fid of fragIds) {\n const ext = sortedExts.find((e) => e.id === fid || fid.startsWith(e.id + \"-\"));\n if (!ext || ext.phase === \"vertex\" || !ext.bind || seenExts.includes(ext)) {\n continue;\n }\n seenExts.push(ext);\n b = ext.bind(ctx, entries, b);\n }\n\n return device.createBindGroup({ layout: bindings._meshBGL, entries });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pbr-pipeline.js","sources":["../../../../src/material/pbr/pbr-pipeline.ts"],"sourcesContent":["/** Dynamic PBR pipeline builder — creates and caches GPU render pipelines\n * based on per-mesh PBR feature flags + ComposedShader from the fragment system.\n *\n * Two-tier cache:\n * - Shader bindings (BGLs + composed shader + per-sig pipeline cache) keyed by\n * `(features, features2)`. Sig-independent.\n * - Pipelines live inside each `_PbrShaderBindings`, keyed by `targetSignatureKey(sig)`.\n */\n\nimport { CW } from \"../../engine/gpu-flags.js\";\nimport type { PbrMaterialProps } from \"./pbr-material.js\";\nimport type { ResolvedStencil } from \"../stencil-state.js\";\nimport type { StencilState } from \"../material.js\";\nimport type { EnvironmentTextures } from \"../../loader-env/load-env.js\";\nimport type { ComposedShader } from \"../../shader/fragment-types.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\nimport type { Texture2D } from \"../../texture/texture-2d.js\";\nimport type { _PbrBindCtx, PbrExt } from \"./pbr-flags.js\";\nimport { _getPbrExtsSorted, PBR2_ESM_SHADOW_OUTPUT, PBR2_NO_COLOR_OUTPUT, PBR2_HAS_UV2 } from \"./pbr-flags.js\";\nimport { PBR_HAS_NORMAL_MAP, PBR_HAS_EMISSIVE, PBR_HAS_SPEC_GLOSS, PBR_HAS_DOUBLE_SIDED, PBR_HAS_ALPHA_BLEND } from \"./pbr-flags.js\";\nimport { MSH_HAS_TANGENTS, MSH_HAS_UV2 } from \"../mesh-features.js\";\nimport { REVERSE_DEPTH_COMPARE, targetSignatureKey } from \"../../engine/render-target.js\";\nimport { getSceneBindGroupLayout } from \"../../render/scene-helpers.js\";\n\n// ─── Shader Bindings (sig-independent) ──────────────────────────────\n\n/** Stencil resolver, installed only by `enableMaterialStencil`. Module-local with a single exported setter:\n * when `enableMaterialStencil` is absent from the bundle the setter tree-shakes, the bundler proves this is\n * always null, and every stencil branch below folds away — stencil-free PBR scenes stay byte-identical. */\nlet _stencilResolver: ((stencil: StencilState) => ResolvedStencil) | null = null;\n/** @internal Install the stencil resolver into the PBR pipeline (called by `enableMaterialStencil`). */\nexport function _installPbrStencilResolver(resolve: (stencil: StencilState) => ResolvedStencil): void {\n _stencilResolver = resolve;\n}\n\n/** Fallback-texture resolver, installed only by `createPbrMaterial` (called on every\n * use). Provides the shared 1×1 white default for a factor-only material's baseColor /\n * ORM slots (the shader always samples both). Module-local with a single exported setter:\n * glTF-only scenes never call `createPbrMaterial`, so the setter tree-shakes, the bundler\n * proves this is always null, and the `?? _pbrFallbackResolver?.(engine)` reads below fold\n * away — loader-driven PBR scenes (e.g. BoomBox) stay byte-identical. */\nlet _pbrFallbackResolver: ((engine: EngineContext) => Texture2D) | null = null;\n/** @internal Install the factor-only fallback-texture resolver (called by `createPbrMaterial`). */\nexport function _installPbrFallbackResolver(resolve: (engine: EngineContext) => Texture2D): void {\n _pbrFallbackResolver = resolve;\n}\n\n/** Primitive-state resolver, installed only by the glTF primitive feature (non-triangle topology\n * or negative-winding meshes). Module-local with a single exported setter: when no such mesh is in\n * the bundle the setter tree-shakes, the bundler proves this is always null, and the\n * `_primitiveResolver ? … : { topology: \"triangle-list\", … }` ternary below folds to the plain\n * triangle-list default — every triangle-list PBR scene (e.g. BoomBox) stays byte-identical. */\nlet _primitiveResolver: ((meshFeatures: number, hasDoubleSided: boolean) => GPUPrimitiveState) | null = null;\n/** @internal Install the primitive-state resolver (called by the glTF primitive feature). */\nexport function _installPbrPrimitiveResolver(resolve: (meshFeatures: number, hasDoubleSided: boolean) => GPUPrimitiveState): void {\n _primitiveResolver = resolve;\n}\n\ninterface _PbrShaderBindings {\n _features: number;\n _features2: number;\n _meshFeatures: number;\n _meshBGL: GPUBindGroupLayout;\n _shadowBGL: GPUBindGroupLayout | null;\n _composed: ComposedShader;\n /** Pre-baked partial depth-stencil descriptor for this material's stencil state. Present (and the cache\n * key carries the resolved `_key`) only when `enableMaterialStencil` was called — otherwise the field is\n * never assigned and the whole stencil path folds out of stencil-free bundles. */\n _stencil?: Partial<GPUDepthStencilState>;\n /** Per-sig pipeline cache. Key = `targetSignatureKey(sig)`. */\n _pipelines: Map<string, GPURenderPipeline>;\n}\n\n// ─── Caches ─────────────────────────────────────────────────────────\n\nconst _bindingsCache = new Map<string, _PbrShaderBindings>();\nlet _cachedDevice: GPUDevice | null = null;\n\nfunction ensureDevice(engine: EngineContext): void {\n if (_cachedDevice !== engine._device) {\n _bindingsCache.clear();\n _cachedDevice = engine._device;\n }\n}\n\n/** Clear the pipeline cache. Must be called when a GPU device is destroyed. */\nexport function clearPbrPipelineCache(): void {\n _bindingsCache.clear();\n _cachedDevice = null;\n}\n\n/** Get-or-build the sig-independent PBR shader bindings. Used at renderable build time\n * so per-mesh bind groups can be created BEFORE any sig is known. */\nexport function getOrCreatePbrBindings(\n engine: EngineContext,\n features: number,\n features2: number,\n meshFeatures: number,\n sceneFeatures: number,\n composed: ComposedShader,\n shaderKey = \"\",\n stencil: StencilState | null = null\n): _PbrShaderBindings {\n ensureDevice(engine);\n // Stencil state is baked into the GPU pipeline (no dynamic stencil ref), so two materials that differ only in\n // stencil must NOT share bindings/pipelines — fold the resolved stencil token into the cache key. Resolution\n // goes through the opt-in `_stencilResolver` hook, so non-stencil scenes fold this whole block away.\n const resolvedStencil = stencil && _stencilResolver ? _stencilResolver(stencil) : null;\n const key = `${features}:${features2}:${meshFeatures}:${sceneFeatures}:${shaderKey}${resolvedStencil ? resolvedStencil._key : \"\"}`;\n const cached = _bindingsCache.get(key);\n if (cached) {\n return cached;\n }\n\n const device = engine._device;\n const meshBGL = device.createBindGroupLayout(composed._meshBGLDescriptor);\n let shadowBGL: GPUBindGroupLayout | null = null;\n if (composed._shadowBGLDescriptor) {\n shadowBGL = device.createBindGroupLayout(composed._shadowBGLDescriptor);\n }\n const bindings: _PbrShaderBindings = {\n _features: features,\n _features2: features2,\n _meshFeatures: meshFeatures,\n _meshBGL: meshBGL,\n _shadowBGL: shadowBGL,\n _composed: composed,\n _pipelines: new Map(),\n };\n // Gated by the opt-in resolver so the field assignment folds out of stencil-free bundles entirely.\n if (resolvedStencil) {\n bindings._stencil = resolvedStencil._desc;\n }\n _bindingsCache.set(key, bindings);\n return bindings;\n}\n\n/** Get-or-build the sig-specific pipeline on top of a PBR shader bindings. Called at bind() time. */\nexport function getOrCreatePbrPipeline(engine: EngineContext, sig: RenderTargetSignature, bindings: _PbrShaderBindings): GPURenderPipeline {\n ensureDevice(engine);\n const key = targetSignatureKey(sig);\n const cached = bindings._pipelines.get(key);\n if (cached) {\n return cached;\n }\n\n const device = engine._device;\n const { _features: features, _features2: features2, _composed: composed, _meshFeatures: meshFeatures } = bindings;\n const esmShadowOutput = (features2 & PBR2_ESM_SHADOW_OUTPUT) !== 0;\n const hasAlpha = !esmShadowOutput && (features & PBR_HAS_ALPHA_BLEND) !== 0;\n const hasDoubleSided = (features & PBR_HAS_DOUBLE_SIDED) !== 0;\n\n const sceneBGL = getSceneBindGroupLayout(engine);\n const bgls: GPUBindGroupLayout[] = bindings._shadowBGL ? [sceneBGL, bindings._meshBGL, bindings._shadowBGL] : [sceneBGL, bindings._meshBGL];\n\n const vertModule = device.createShaderModule({ code: composed._vertexWGSL });\n const noColorOutput = (features2 & PBR2_NO_COLOR_OUTPUT) !== 0;\n const fragModule = !sig._colorFormat && !noColorOutput ? null : device.createShaderModule({ code: composed._fragmentWGSL });\n\n const fragTarget: GPUColorTargetState | null = noColorOutput ? null : { format: sig._colorFormat!, writeMask: CW.ALL };\n if (hasAlpha && fragTarget) {\n fragTarget.blend = {\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one\", operation: \"add\" },\n };\n }\n\n const pipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({ bindGroupLayouts: bgls }),\n vertex: { module: vertModule, entryPoint: \"main\", buffers: composed._vertexBufferLayouts },\n ...(fragModule ? { fragment: { module: fragModule, entryPoint: \"main\", targets: fragTarget ? [fragTarget] : [] } } : {}),\n ...(sig._depthStencilFormat\n ? {\n depthStencil: {\n format: sig._depthStencilFormat,\n depthCompare: sig._depthCompare ?? REVERSE_DEPTH_COMPARE,\n depthWriteEnabled: noColorOutput || esmShadowOutput || !hasAlpha,\n // Pre-baked stencil sub-fields, applied only on a stencil-capable target — the same\n // material in the depth32float shadow/depth pass keeps plain depth state (no stencil → no\n // format mismatch). Gated on `_stencilResolver` (the opt-in hook) so the entire branch —\n // including the `bindings._stencil` reads — folds out of stencil-free bundles.\n ...(_stencilResolver && bindings._stencil && sig._depthStencilFormat.includes(\"stencil\") ? bindings._stencil : {}),\n },\n }\n : {}),\n multisample: { count: sig._sampleCount },\n primitive: _primitiveResolver\n ? _primitiveResolver(meshFeatures, hasDoubleSided)\n : { topology: \"triangle-list\", cullMode: hasDoubleSided ? (\"none\" as GPUCullMode) : \"back\", frontFace: \"ccw\" },\n });\n bindings._pipelines.set(key, pipeline);\n return pipeline;\n}\n\n// ─── Per-Mesh Bind Group ────────────────────────────────────────────\n\nexport function createPbrMeshBindGroup(\n engine: EngineContext,\n bindings: _PbrShaderBindings,\n composed: ComposedShader,\n meshUBO: GPUBuffer,\n materialUBO: GPUBuffer,\n material: PbrMaterialProps,\n env: EnvironmentTextures | null,\n meshCtx: { skeleton?: { boneTexture: GPUTexture } | null; morphTargets?: { deltasBuffer: GPUBuffer; weightsBuffer?: GPUBuffer } | null } | null,\n refractionTexture?: Texture2D | null\n): GPUBindGroup {\n const device = engine._device;\n const features = bindings._features;\n const features2 = bindings._features2;\n const meshFeatures = bindings._meshFeatures;\n const hasNormal = (features & PBR_HAS_NORMAL_MAP) !== 0 && (meshFeatures & MSH_HAS_TANGENTS) !== 0;\n const hasCotangentNormal = (features & PBR_HAS_NORMAL_MAP) !== 0 && (meshFeatures & MSH_HAS_TANGENTS) === 0;\n const hasAnyNormal = hasNormal || hasCotangentNormal;\n const hasEmissive = (features & PBR_HAS_EMISSIVE) !== 0;\n const hasSpecGloss = (features & PBR_HAS_SPEC_GLOSS) !== 0;\n const esmShadowOutput = (features2 & PBR2_ESM_SHADOW_OUTPUT) !== 0;\n\n const entries: GPUBindGroupEntry[] = [];\n let b = 0;\n const addTex = (t: { view: GPUTextureView; sampler: GPUSampler }) => {\n entries.push({ binding: b++, resource: t.view });\n entries.push({ binding: b++, resource: t.sampler });\n };\n\n const ctx: _PbrBindCtx = {\n _engine: engine,\n _features: features,\n _features2: features2,\n _meshFeatures: meshFeatures,\n _material: material,\n _mesh: meshCtx ?? undefined,\n _env: env,\n _refractionTexture: refractionTexture,\n };\n\n const sortedExts = _getPbrExtsSorted();\n\n const fragIds = composed._fragmentKey ? composed._fragmentKey.split(\"|\").filter((s) => s.length > 0) : [];\n\n entries.push({ binding: b++, resource: { buffer: meshUBO } });\n entries.push({ binding: b++, resource: { buffer: materialUBO } });\n for (const ext of sortedExts) {\n if (ext.phase === \"vertex\" && ext.bind) {\n b = ext.bind(ctx, entries, b);\n }\n }\n addTex(material.baseColorTexture ?? _pbrFallbackResolver?.(engine)!);\n if (hasAnyNormal) {\n addTex(material.normalTexture!);\n }\n addTex(material.ormTexture ?? _pbrFallbackResolver?.(engine)!);\n if ((features2 & PBR2_HAS_UV2) !== 0 && (meshFeatures & MSH_HAS_UV2) !== 0 && material.occlusionTexture) {\n addTex(material.occlusionTexture);\n }\n if (hasEmissive) {\n addTex(material.emissiveTexture!);\n }\n if (hasSpecGloss) {\n addTex(material.specGlossTexture!);\n }\n if (esmShadowOutput) {\n entries.push({\n binding: b++,\n resource: { buffer: (material as PbrMaterialProps & { readonly _esmShadowParamsUBO: GPUBuffer })._esmShadowParamsUBO },\n });\n }\n const seenExts: PbrExt[] = [];\n for (const fid of fragIds) {\n const ext = sortedExts.find((e) => e.id === fid || fid.startsWith(e.id + \"-\"));\n if (!ext || ext.phase === \"vertex\" || !ext.bind || seenExts.includes(ext)) {\n continue;\n }\n seenExts.push(ext);\n b = ext.bind(ctx, entries, b);\n }\n\n return device.createBindGroup({ layout: bindings._meshBGL, entries });\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { _installMeshFeatureExtra } from '../mesh-features.js';
2
+ import { _installPbrPrimitiveResolver } from './pbr-pipeline.js';
3
+
4
+ const MSH_REVERSE_WINDING = 1 << 11;
5
+ const MSH_TOPOLOGY_SHIFT = 12;
6
+ const MSH_INDEX_U32 = 1 << 15;
7
+ _installMeshFeatureExtra((mesh) => {
8
+ let f = 0;
9
+ if (mesh._reverseWinding) {
10
+ f |= MSH_REVERSE_WINDING;
11
+ }
12
+ const topo = mesh._topology;
13
+ if (topo) {
14
+ f |= topo << MSH_TOPOLOGY_SHIFT;
15
+ if (topo >= 3 && mesh._gpu.indexFormat === "uint32") {
16
+ f |= MSH_INDEX_U32;
17
+ }
18
+ }
19
+ return f;
20
+ });
21
+ _installPbrPrimitiveResolver((meshFeatures, hasDoubleSided) => {
22
+ const reverseWinding = (meshFeatures & MSH_REVERSE_WINDING) !== 0;
23
+ const topoIdx = meshFeatures >> MSH_TOPOLOGY_SHIFT & 7;
24
+ const topology = topoIdx === 1 ? "point-list" : topoIdx === 2 ? "line-list" : topoIdx === 3 ? "line-strip" : topoIdx === 4 ? "triangle-strip" : "triangle-list";
25
+ const noCull = topoIdx >= 1 && topoIdx <= 3;
26
+ const stripIndexFormat = topoIdx >= 3 ? meshFeatures & MSH_INDEX_U32 ? "uint32" : "uint16" : void 0;
27
+ return {
28
+ topology,
29
+ ...stripIndexFormat ? { stripIndexFormat } : void 0,
30
+ cullMode: noCull || hasDoubleSided ? "none" : reverseWinding ? "front" : "back",
31
+ frontFace: "ccw"
32
+ };
33
+ });
34
+ //# sourceMappingURL=pbr-primitive-resolver.js.map
@@ -0,0 +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"}
@@ -372,7 +372,7 @@ async function buildPbrRenderables(scene, meshes, envTextures) {
372
372
  bind(eng, sig) {
373
373
  const pipeline = getOrCreatePbrPipeline(eng, sig, bindings);
374
374
  const materialBindGroup = needsTaskRefraction ? createPbrMeshBindGroup(engine, bindings, composed, meshUBO, materialUBO, mat, envTextures ?? null, mesh, sig._transmissionTexture) : materialBindGroupStatic;
375
- const cb = _cull?.tryBind(r, s, mesh, engine, hasTIColor, isTransparent || needsTaskRefraction, update);
375
+ const cb = _cull?.tryBind(r, s, mesh, engine, hasTIColor, isTransparent || needsTaskRefraction, update, sig);
376
376
  return {
377
377
  renderable: r,
378
378
  pipeline,