@babylonjs/lite 0.1.1 → 0.2.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 (197) hide show
  1. package/_mat4-storage-f64-Bvh5TymE.js +10 -0
  2. package/_mat4-storage-f64-Bvh5TymE.js.map +1 -0
  3. package/{alpha-test-fragment-CUiHCw7W.js → alpha-test-fragment-BCChpzaV.js} +2 -2
  4. package/{alpha-test-fragment-CUiHCw7W.js.map → alpha-test-fragment-BCChpzaV.js.map} +1 -1
  5. package/{background-dds-skybox-yHTqabU3.js → background-dds-skybox-ZjrSIxrT.js} +4 -4
  6. package/background-dds-skybox-ZjrSIxrT.js.map +1 -0
  7. package/{background-ground-DIw6D3qf.js → background-ground-B2Mie-MI.js} +3 -3
  8. package/background-ground-B2Mie-MI.js.map +1 -0
  9. package/{background-hdr-skybox-c4uuTmkP.js → background-hdr-skybox-DDRJYuT2.js} +3 -3
  10. package/background-hdr-skybox-DDRJYuT2.js.map +1 -0
  11. package/{background-solid-skybox-DPGBpPbm.js → background-solid-skybox-fjXlnWaD.js} +3 -3
  12. package/{background-solid-skybox-DPGBpPbm.js.map → background-solid-skybox-fjXlnWaD.js.map} +1 -1
  13. package/{billboard-renderable-D8mlVGCd.js → billboard-renderable-DKmlOgbM.js} +2 -2
  14. package/{billboard-renderable-D8mlVGCd.js.map → billboard-renderable-DKmlOgbM.js.map} +1 -1
  15. package/{clamp-block-BdII67hT.js → clamp-block-CxRBPlUq.js} +2 -2
  16. package/{clamp-block-BdII67hT.js.map → clamp-block-CxRBPlUq.js.map} +1 -1
  17. package/{clearcoat-fragment-LCiG98Rf.js → clearcoat-fragment-KbZAa0TA.js} +2 -2
  18. package/{clearcoat-fragment-LCiG98Rf.js.map → clearcoat-fragment-KbZAa0TA.js.map} +1 -1
  19. package/{create-skeleton-C9JdIJnb.js → create-skeleton-BBI5urcj.js} +2 -2
  20. package/{create-skeleton-C9JdIJnb.js.map → create-skeleton-BBI5urcj.js.map} +1 -1
  21. package/{cubemap-skybox-material-DvXMVc4k.js → cubemap-skybox-material-DvW81drX.js} +2 -2
  22. package/{cubemap-skybox-material-DvXMVc4k.js.map → cubemap-skybox-material-DvW81drX.js.map} +1 -1
  23. package/{curve-block-BlJpXVYv.js → curve-block-Dh_xdUj-.js} +2 -2
  24. package/{curve-block-BlJpXVYv.js.map → curve-block-Dh_xdUj-.js.map} +1 -1
  25. package/{emissive-fragment-BnNvbBCw.js → emissive-fragment-DD8cvHyx.js} +2 -2
  26. package/{emissive-fragment-BnNvbBCw.js.map → emissive-fragment-DD8cvHyx.js.map} +1 -1
  27. package/{esm-shadow-view-DGKdF1NI.js → esm-shadow-view-15S4JK6p.js} +2 -2
  28. package/{esm-shadow-view-DGKdF1NI.js.map → esm-shadow-view-15S4JK6p.js.map} +1 -1
  29. package/{esm-shadow-view-Dk9NFtLq.js → esm-shadow-view-DHVS9r7H.js} +2 -2
  30. package/{esm-shadow-view-Dk9NFtLq.js.map → esm-shadow-view-DHVS9r7H.js.map} +1 -1
  31. package/{esm-shadow-view-DN9HIaM4.js → esm-shadow-view-DYAc62Kl.js} +2 -2
  32. package/{esm-shadow-view-DN9HIaM4.js.map → esm-shadow-view-DYAc62Kl.js.map} +1 -1
  33. package/{gaussian-splatting-pipeline-sh-DgJl7l56.js → gaussian-splatting-pipeline-sh-BvkUhA9V.js} +2 -2
  34. package/{gaussian-splatting-pipeline-sh-DgJl7l56.js.map → gaussian-splatting-pipeline-sh-BvkUhA9V.js.map} +1 -1
  35. package/{gltf-animation-D7uyTyO3.js → gltf-animation-KnPzeOIY.js} +3 -3
  36. package/{gltf-animation-D7uyTyO3.js.map → gltf-animation-KnPzeOIY.js.map} +1 -1
  37. package/gltf-color-normalize-Qxl-9C48.js +29 -0
  38. package/gltf-color-normalize-Qxl-9C48.js.map +1 -0
  39. package/{gltf-ext-basisu-CPg5kPrx.js → gltf-ext-basisu-kmth3UWX.js} +7 -4
  40. package/gltf-ext-basisu-kmth3UWX.js.map +1 -0
  41. package/{gltf-ext-node-visibility-MafA9ot2.js → gltf-ext-node-visibility-BjRRd6si.js} +2 -2
  42. package/{gltf-ext-node-visibility-MafA9ot2.js.map → gltf-ext-node-visibility-BjRRd6si.js.map} +1 -1
  43. package/{gltf-ext-uv-transform-CE_-T1Tr.js → gltf-ext-uv-transform-MHmR-YyM.js} +2 -2
  44. package/{gltf-ext-uv-transform-CE_-T1Tr.js.map → gltf-ext-uv-transform-MHmR-YyM.js.map} +1 -1
  45. package/{gltf-feature-animation-pointer-BjpwOOqo.js → gltf-feature-animation-pointer-rFqLfbO_.js} +3 -3
  46. package/{gltf-feature-animation-pointer-BjpwOOqo.js.map → gltf-feature-animation-pointer-rFqLfbO_.js.map} +1 -1
  47. package/{gltf-feature-animations-CCizegp8.js → gltf-feature-animations-DikONdzi.js} +2 -2
  48. package/{gltf-feature-animations-CCizegp8.js.map → gltf-feature-animations-DikONdzi.js.map} +1 -1
  49. package/{gltf-feature-gpu-instancing-2e_CFQnl.js → gltf-feature-gpu-instancing-Cj1XjmM6.js} +5 -4
  50. package/gltf-feature-gpu-instancing-Cj1XjmM6.js.map +1 -0
  51. package/{gltf-feature-lights-punctual-DDDg4j0U.js → gltf-feature-lights-punctual-C-0SlGmD.js} +5 -5
  52. package/{gltf-feature-lights-punctual-DDDg4j0U.js.map → gltf-feature-lights-punctual-C-0SlGmD.js.map} +1 -1
  53. package/{gltf-feature-morph-CKCw6tkX.js → gltf-feature-morph-BAcY14XU.js} +3 -3
  54. package/{gltf-feature-morph-CKCw6tkX.js.map → gltf-feature-morph-BAcY14XU.js.map} +1 -1
  55. package/gltf-feature-registry-97sY_x5O.js +59 -0
  56. package/gltf-feature-registry-97sY_x5O.js.map +1 -0
  57. package/{gltf-feature-skeleton-D8hWLqi2.js → gltf-feature-skeleton-lVjkDfIU.js} +3 -3
  58. package/{gltf-feature-skeleton-D8hWLqi2.js.map → gltf-feature-skeleton-lVjkDfIU.js.map} +1 -1
  59. package/{gltf-feature-variants-Ds6v9byg.js → gltf-feature-variants-BphF4JmV.js} +2 -2
  60. package/{gltf-feature-variants-Ds6v9byg.js.map → gltf-feature-variants-BphF4JmV.js.map} +1 -1
  61. package/{gltf-interleave-DGnUlz28.js → gltf-interleave-C9eBqH_F.js} +2 -2
  62. package/{gltf-interleave-DGnUlz28.js.map → gltf-interleave-C9eBqH_F.js.map} +1 -1
  63. package/gltf-normals-b2h74380.js +37 -0
  64. package/gltf-normals-b2h74380.js.map +1 -0
  65. package/{gltf-pbr-builder-ext-BFOxOCnQ.js → gltf-pbr-builder-ext-DPC0zg_u.js} +2 -2
  66. package/{gltf-pbr-builder-ext-BFOxOCnQ.js.map → gltf-pbr-builder-ext-DPC0zg_u.js.map} +1 -1
  67. package/{gltf-variants-DFbr8EES.js → gltf-variants-CnBEZr0o.js} +4 -4
  68. package/{gltf-variants-DFbr8EES.js.map → gltf-variants-CnBEZr0o.js.map} +1 -1
  69. package/{gs-picking-pipeline-DzfMASL9.js → gs-picking-pipeline-Bx8LTav6.js} +2 -2
  70. package/{gs-picking-pipeline-DzfMASL9.js.map → gs-picking-pipeline-Bx8LTav6.js.map} +1 -1
  71. package/{index-C8HOR2sB.js → index-B7Qhw0xL.js} +3047 -1037
  72. package/index-B7Qhw0xL.js.map +1 -0
  73. package/index.d.ts +504 -17
  74. package/index.js +322 -304
  75. package/{input-block-DgAJBzN_.js → input-block-Coi_aZwl.js} +2 -2
  76. package/{input-block-DgAJBzN_.js.map → input-block-Coi_aZwl.js.map} +1 -1
  77. package/{iridescence-fragment-Gymp7or5.js → iridescence-fragment-DwZcCTdD.js} +2 -2
  78. package/{iridescence-fragment-Gymp7or5.js.map → iridescence-fragment-DwZcCTdD.js.map} +1 -1
  79. package/{light-block-B11ew7FA.js → light-block-Np_h5gPI.js} +2 -2
  80. package/{light-block-B11ew7FA.js.map → light-block-Np_h5gPI.js.map} +1 -1
  81. package/{loop-block-Bb23EOMb.js → loop-block-BFkLFYGm.js} +2 -2
  82. package/{loop-block-Bb23EOMb.js.map → loop-block-BFkLFYGm.js.map} +1 -1
  83. package/{mesh-features-BLENkYVt.js → mesh-features-BAJpbMog.js} +6 -3
  84. package/mesh-features-BAJpbMog.js.map +1 -0
  85. package/{morph-fragment-DOVo70gP.js → morph-fragment-DqH-w61u.js} +2 -2
  86. package/{morph-fragment-DOVo70gP.js.map → morph-fragment-DqH-w61u.js.map} +1 -1
  87. package/{multilight-wgsl-BGyiIOp3.js → multilight-wgsl-B9Mf9d-q.js} +4 -4
  88. package/{multilight-wgsl-BGyiIOp3.js.map → multilight-wgsl-B9Mf9d-q.js.map} +1 -1
  89. package/no-color-view-DsyLSL-W.js +8 -0
  90. package/no-color-view-DsyLSL-W.js.map +1 -0
  91. package/{node-registry-DwgC4yth.js → node-registry-Bd-AlrgC.js} +8 -8
  92. package/{node-registry-DwgC4yth.js.map → node-registry-Bd-AlrgC.js.map} +1 -1
  93. package/{node-registry-extra-compat-Dhrw8fDQ.js → node-registry-extra-compat-Ch7ApZHF.js} +2 -2
  94. package/{node-registry-extra-compat-Dhrw8fDQ.js.map → node-registry-extra-compat-Ch7ApZHF.js.map} +1 -1
  95. package/{node-registry-extra-math-CsAHvIZo.js → node-registry-extra-math-6ezzTkPj.js} +2 -2
  96. package/{node-registry-extra-math-CsAHvIZo.js.map → node-registry-extra-math-6ezzTkPj.js.map} +1 -1
  97. package/{node-renderable-DlLIdBmd.js → node-renderable-CS0CmsSp.js} +28 -11
  98. package/node-renderable-CS0CmsSp.js.map +1 -0
  99. package/{node-shadow-DKrcqmNg.js → node-shadow-CpnrdvtJ.js} +2 -2
  100. package/{node-shadow-DKrcqmNg.js.map → node-shadow-CpnrdvtJ.js.map} +1 -1
  101. package/{normal-map-fragment-DpsIXrJf.js → normal-map-fragment-DradEMl-.js} +3 -3
  102. package/{normal-map-fragment-DpsIXrJf.js.map → normal-map-fragment-DradEMl-.js.map} +1 -1
  103. package/pack-mat4-with-offset-BqB8Jqo7.js +37 -0
  104. package/pack-mat4-with-offset-BqB8Jqo7.js.map +1 -0
  105. package/package.json +3 -3
  106. package/{parse-camera-DM3oJJeT.js → parse-camera-CgV4bWc0.js} +2 -2
  107. package/{parse-camera-DM3oJJeT.js.map → parse-camera-CgV4bWc0.js.map} +1 -1
  108. package/pbr-fog-wgsl-BqdCid6r.js +8 -0
  109. package/pbr-fog-wgsl-BqdCid6r.js.map +1 -0
  110. package/{pbr-metallic-roughness-block-h_KAOZrW.js → pbr-metallic-roughness-block-BFwZj2Nw.js} +2 -2
  111. package/{pbr-metallic-roughness-block-h_KAOZrW.js.map → pbr-metallic-roughness-block-BFwZj2Nw.js.map} +1 -1
  112. package/{pbr-metallic-roughness-block-full-6vMm1Jk6.js → pbr-metallic-roughness-block-full-5t0HT3xl.js} +2 -2
  113. package/{pbr-metallic-roughness-block-full-6vMm1Jk6.js.map → pbr-metallic-roughness-block-full-5t0HT3xl.js.map} +1 -1
  114. package/{pbr-mr-helper-core-CIwm-T1G.js → pbr-mr-helper-core-R5tOZ8Ap.js} +2 -2
  115. package/{pbr-mr-helper-core-CIwm-T1G.js.map → pbr-mr-helper-core-R5tOZ8Ap.js.map} +1 -1
  116. package/{pbr-refraction-DGmMSa2v.js → pbr-refraction-Dd11HnaI.js} +2 -2
  117. package/{pbr-refraction-DGmMSa2v.js.map → pbr-refraction-Dd11HnaI.js.map} +1 -1
  118. package/{pbr-renderable-BJxUtPBb.js → pbr-renderable-BHAdF5Vw.js} +80 -38
  119. package/pbr-renderable-BHAdF5Vw.js.map +1 -0
  120. package/{pbr-shadow-fragment-LO9SlbJj.js → pbr-shadow-fragment-BxUrFJYZ.js} +6 -1
  121. package/pbr-shadow-fragment-BxUrFJYZ.js.map +1 -0
  122. package/{pbr-template-ext-8q7BcTDf.js → pbr-template-ext-CGgB2n2y.js} +3 -2
  123. package/{pbr-template-ext-8q7BcTDf.js.map → pbr-template-ext-CGgB2n2y.js.map} +1 -1
  124. package/{pbr-tracking-B3alzn91.js → pbr-tracking-D6i3yPb7.js} +2 -2
  125. package/{pbr-tracking-B3alzn91.js.map → pbr-tracking-D6i3yPb7.js.map} +1 -1
  126. package/pbr-transmission-ext-Dll8EYwE.js +190 -0
  127. package/pbr-transmission-ext-Dll8EYwE.js.map +1 -0
  128. package/{reflectance-fragment-BCrgPmrt.js → reflectance-fragment-ejMJ4O1o.js} +2 -2
  129. package/{reflectance-fragment-BCrgPmrt.js.map → reflectance-fragment-ejMJ4O1o.js.map} +1 -1
  130. package/{shader-renderable-D-6796KR.js → shader-renderable-BMf_vvO0.js} +41 -12
  131. package/shader-renderable-BMf_vvO0.js.map +1 -0
  132. package/shader-thin-instance-5_WUfi3m.js +150 -0
  133. package/shader-thin-instance-5_WUfi3m.js.map +1 -0
  134. package/shadow-fragment-core-DHN2G6FI.js.map +1 -1
  135. package/{sheen-fragment-Dze2f7XJ.js → sheen-fragment-CS6z29Fs.js} +2 -2
  136. package/{sheen-fragment-Dze2f7XJ.js.map → sheen-fragment-CS6z29Fs.js.map} +1 -1
  137. package/{singlelight-directional-wgsl-CmUDZxwz.js → singlelight-directional-wgsl-4MIgZMeC.js} +2 -2
  138. package/{singlelight-directional-wgsl-CmUDZxwz.js.map → singlelight-directional-wgsl-4MIgZMeC.js.map} +1 -1
  139. package/{singlelight-hemispheric-wgsl-t-83IP_s.js → singlelight-hemispheric-wgsl-CK-GUYWe.js} +2 -2
  140. package/{singlelight-hemispheric-wgsl-t-83IP_s.js.map → singlelight-hemispheric-wgsl-CK-GUYWe.js.map} +1 -1
  141. package/{singlelight-point-wgsl-CLzULIYV.js → singlelight-point-wgsl-CYtzqCbP.js} +2 -2
  142. package/{singlelight-point-wgsl-CLzULIYV.js.map → singlelight-point-wgsl-CYtzqCbP.js.map} +1 -1
  143. package/{singlelight-spot-wgsl-DEEUrfVM.js → singlelight-spot-wgsl-DVbaVufF.js} +2 -2
  144. package/{singlelight-spot-wgsl-DEEUrfVM.js.map → singlelight-spot-wgsl-DVbaVufF.js.map} +1 -1
  145. package/{skeleton-fragment-B_XlFbtx.js → skeleton-fragment-BOVmc8YS.js} +2 -2
  146. package/{skeleton-fragment-B_XlFbtx.js.map → skeleton-fragment-BOVmc8YS.js.map} +1 -1
  147. package/{skybox-renderable-DDwzu-PT.js → skybox-renderable-DDcCPSly.js} +3 -3
  148. package/{skybox-renderable-DDwzu-PT.js.map → skybox-renderable-DDcCPSly.js.map} +1 -1
  149. package/{standard-renderable-GjxL9xSf.js → standard-renderable-D1bhoF0K.js} +27 -81
  150. package/standard-renderable-D1bhoF0K.js.map +1 -0
  151. package/{std-ambient-fragment-BoUsD06w.js → std-ambient-fragment-C6WNm8dQ.js} +2 -2
  152. package/{std-ambient-fragment-BoUsD06w.js.map → std-ambient-fragment-C6WNm8dQ.js.map} +1 -1
  153. package/{std-cube-reflection-fragment-ulqc3bsP.js → std-cube-reflection-fragment-Bqutpy2q.js} +2 -2
  154. package/{std-cube-reflection-fragment-ulqc3bsP.js.map → std-cube-reflection-fragment-Bqutpy2q.js.map} +1 -1
  155. package/{std-emissive-fragment-DNGj1HdQ.js → std-emissive-fragment-B-A83rqX.js} +2 -2
  156. package/{std-emissive-fragment-DNGj1HdQ.js.map → std-emissive-fragment-B-A83rqX.js.map} +1 -1
  157. package/{std-lightmap-fragment-Bqj89aIe.js → std-lightmap-fragment-Df7KJezh.js} +2 -2
  158. package/{std-lightmap-fragment-Bqj89aIe.js.map → std-lightmap-fragment-Df7KJezh.js.map} +1 -1
  159. package/{std-opacity-fragment-KuPh5N2Z.js → std-opacity-fragment-D9et2jip.js} +2 -2
  160. package/{std-opacity-fragment-KuPh5N2Z.js.map → std-opacity-fragment-D9et2jip.js.map} +1 -1
  161. package/{std-reflection-fragment-BA5Ghn_M.js → std-reflection-fragment-DBJeT-yg.js} +2 -2
  162. package/{std-reflection-fragment-BA5Ghn_M.js.map → std-reflection-fragment-DBJeT-yg.js.map} +1 -1
  163. package/std-shadow-fragment-C6fD8rW-.js +13 -0
  164. package/std-shadow-fragment-C6fD8rW-.js.map +1 -0
  165. package/{std-specular-fragment-CE-6scqd.js → std-specular-fragment-C2ZOss-t.js} +2 -2
  166. package/{std-specular-fragment-CE-6scqd.js.map → std-specular-fragment-C2ZOss-t.js.map} +1 -1
  167. package/{std-tracking-CNKZ-hJN.js → std-tracking-C4L4nQGc.js} +2 -2
  168. package/{std-tracking-CNKZ-hJN.js.map → std-tracking-C4L4nQGc.js.map} +1 -1
  169. package/{subsurface-fragment-liM3y2-P.js → subsurface-fragment-C1H4ytqK.js} +2 -2
  170. package/{subsurface-fragment-liM3y2-P.js.map → subsurface-fragment-C1H4ytqK.js.map} +1 -1
  171. package/thin-instance-cull-binding-CCxrPNO6.js +310 -0
  172. package/thin-instance-cull-binding-CCxrPNO6.js.map +1 -0
  173. package/{thin-instance-gpu-C9Gv_Z1w.js → thin-instance-gpu-E8DBd8XL.js} +20 -3
  174. package/thin-instance-gpu-E8DBd8XL.js.map +1 -0
  175. package/{tracking-primitives-wgdBY85t.js → tracking-primitives-w4BVV9p9.js} +2 -2
  176. package/{tracking-primitives-wgdBY85t.js.map → tracking-primitives-w4BVV9p9.js.map} +1 -1
  177. package/{unlit-fragment-BIlhJpz6.js → unlit-fragment-DU9_mhzZ.js} +2 -2
  178. package/{unlit-fragment-BIlhJpz6.js.map → unlit-fragment-DU9_mhzZ.js.map} +1 -1
  179. package/{wgsl-helpers-DyzNzCeE.js → wgsl-helpers-D8sl1VVA.js} +4 -4
  180. package/{wgsl-helpers-DyzNzCeE.js.map → wgsl-helpers-D8sl1VVA.js.map} +1 -1
  181. package/background-dds-skybox-yHTqabU3.js.map +0 -1
  182. package/background-ground-DIw6D3qf.js.map +0 -1
  183. package/background-hdr-skybox-c4uuTmkP.js.map +0 -1
  184. package/gltf-ext-basisu-CPg5kPrx.js.map +0 -1
  185. package/gltf-feature-gpu-instancing-2e_CFQnl.js.map +0 -1
  186. package/index-C8HOR2sB.js.map +0 -1
  187. package/mesh-features-BLENkYVt.js.map +0 -1
  188. package/node-renderable-DlLIdBmd.js.map +0 -1
  189. package/pbr-renderable-BJxUtPBb.js.map +0 -1
  190. package/pbr-shadow-fragment-LO9SlbJj.js.map +0 -1
  191. package/pbr-transmission-ext-BxW4CEGu.js +0 -581
  192. package/pbr-transmission-ext-BxW4CEGu.js.map +0 -1
  193. package/shader-renderable-D-6796KR.js.map +0 -1
  194. package/standard-renderable-GjxL9xSf.js.map +0 -1
  195. package/std-shadow-fragment-FNQfrJuC.js +0 -8
  196. package/std-shadow-fragment-FNQfrJuC.js.map +0 -1
  197. package/thin-instance-gpu-C9Gv_Z1w.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { t as trackScalar, o as observableColor3, a as observableVec2 } from "./tracking-primitives-wgdBY85t.js";
1
+ import { t as trackScalar, o as observableColor3, a as observableVec2 } from "./tracking-primitives-w4BVV9p9.js";
2
2
  function installStdTracking(mat) {
3
3
  for (const key of ["alpha", "specularPower", "bumpLevel", "ambientTexLevel", "lightmapLevel", "opacityLevel", "alphaCutOff", "reflectionLevel"]) {
4
4
  trackScalar(mat, key);
@@ -12,4 +12,4 @@ function installStdTracking(mat) {
12
12
  export {
13
13
  installStdTracking
14
14
  };
15
- //# sourceMappingURL=std-tracking-CNKZ-hJN.js.map
15
+ //# sourceMappingURL=std-tracking-C4L4nQGc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"std-tracking-CNKZ-hJN.js","sources":["../src/material/tracking/std-tracking.ts"],"sourcesContent":["/** Standard material auto-dirty tracking. Dynamically imported by enableMaterialTracking(). */\n\nimport type { StandardMaterialProps } from \"../standard/standard-material.js\";\nimport { trackScalar, observableColor3, observableVec2 } from \"./tracking-primitives.js\";\n\nexport function installStdTracking(mat: StandardMaterialProps): void {\n for (const key of [\"alpha\", \"specularPower\", \"bumpLevel\", \"ambientTexLevel\", \"lightmapLevel\", \"opacityLevel\", \"alphaCutOff\", \"reflectionLevel\"]) {\n trackScalar(mat, key);\n }\n mat.diffuseColor = observableColor3(mat.diffuseColor[0], mat.diffuseColor[1], mat.diffuseColor[2], mat as any);\n mat.specularColor = observableColor3(mat.specularColor[0], mat.specularColor[1], mat.specularColor[2], mat as any);\n mat.emissiveColor = observableColor3(mat.emissiveColor[0], mat.emissiveColor[1], mat.emissiveColor[2], mat as any);\n mat.ambientColor = observableColor3(mat.ambientColor[0], mat.ambientColor[1], mat.ambientColor[2], mat as any);\n mat.uvScale = observableVec2(mat.uvScale[0], mat.uvScale[1], mat as any);\n}\n"],"names":[],"mappings":";AAKO,SAAS,mBAAmB,KAAkC;AACjE,aAAW,OAAO,CAAC,SAAS,iBAAiB,aAAa,mBAAmB,iBAAiB,gBAAgB,eAAe,iBAAiB,GAAG;AAC7I,gBAAY,KAAK,GAAG;AAAA,EACxB;AACA,MAAI,eAAe,iBAAiB,IAAI,aAAa,CAAC,GAAG,IAAI,aAAa,CAAC,GAAG,IAAI,aAAa,CAAC,GAAG,GAAU;AAC7G,MAAI,gBAAgB,iBAAiB,IAAI,cAAc,CAAC,GAAG,IAAI,cAAc,CAAC,GAAG,IAAI,cAAc,CAAC,GAAG,GAAU;AACjH,MAAI,gBAAgB,iBAAiB,IAAI,cAAc,CAAC,GAAG,IAAI,cAAc,CAAC,GAAG,IAAI,cAAc,CAAC,GAAG,GAAU;AACjH,MAAI,eAAe,iBAAiB,IAAI,aAAa,CAAC,GAAG,IAAI,aAAa,CAAC,GAAG,IAAI,aAAa,CAAC,GAAG,GAAU;AAC7G,MAAI,UAAU,eAAe,IAAI,QAAQ,CAAC,GAAG,IAAI,QAAQ,CAAC,GAAG,GAAU;AAC3E;"}
1
+ {"version":3,"file":"std-tracking-C4L4nQGc.js","sources":["../src/material/tracking/std-tracking.ts"],"sourcesContent":["/** Standard material auto-dirty tracking. Dynamically imported by enableMaterialTracking(). */\n\nimport type { StandardMaterialProps } from \"../standard/standard-material.js\";\nimport { trackScalar, observableColor3, observableVec2 } from \"./tracking-primitives.js\";\n\nexport function installStdTracking(mat: StandardMaterialProps): void {\n for (const key of [\"alpha\", \"specularPower\", \"bumpLevel\", \"ambientTexLevel\", \"lightmapLevel\", \"opacityLevel\", \"alphaCutOff\", \"reflectionLevel\"]) {\n trackScalar(mat, key);\n }\n mat.diffuseColor = observableColor3(mat.diffuseColor[0], mat.diffuseColor[1], mat.diffuseColor[2], mat as any);\n mat.specularColor = observableColor3(mat.specularColor[0], mat.specularColor[1], mat.specularColor[2], mat as any);\n mat.emissiveColor = observableColor3(mat.emissiveColor[0], mat.emissiveColor[1], mat.emissiveColor[2], mat as any);\n mat.ambientColor = observableColor3(mat.ambientColor[0], mat.ambientColor[1], mat.ambientColor[2], mat as any);\n mat.uvScale = observableVec2(mat.uvScale[0], mat.uvScale[1], mat as any);\n}\n"],"names":[],"mappings":";AAKO,SAAS,mBAAmB,KAAkC;AACjE,aAAW,OAAO,CAAC,SAAS,iBAAiB,aAAa,mBAAmB,iBAAiB,gBAAgB,eAAe,iBAAiB,GAAG;AAC7I,gBAAY,KAAK,GAAG;AAAA,EACxB;AACA,MAAI,eAAe,iBAAiB,IAAI,aAAa,CAAC,GAAG,IAAI,aAAa,CAAC,GAAG,IAAI,aAAa,CAAC,GAAG,GAAU;AAC7G,MAAI,gBAAgB,iBAAiB,IAAI,cAAc,CAAC,GAAG,IAAI,cAAc,CAAC,GAAG,IAAI,cAAc,CAAC,GAAG,GAAU;AACjH,MAAI,gBAAgB,iBAAiB,IAAI,cAAc,CAAC,GAAG,IAAI,cAAc,CAAC,GAAG,IAAI,cAAc,CAAC,GAAG,GAAU;AACjH,MAAI,eAAe,iBAAiB,IAAI,aAAa,CAAC,GAAG,IAAI,aAAa,CAAC,GAAG,IAAI,aAAa,CAAC,GAAG,GAAU;AAC7G,MAAI,UAAU,eAAe,IAAI,QAAQ,CAAC,GAAG,IAAI,QAAQ,CAAC,GAAG,GAAU;AAC3E;"}
@@ -1,4 +1,4 @@
1
- import { aH as PBR_HAS_THICKNESS_MAP, aI as PBR_HAS_SUBSURFACE, aJ as PBR2_HAS_THICKNESS_GLTF_CHANNEL } from "./index-C8HOR2sB.js";
1
+ import { av as PBR_HAS_THICKNESS_MAP, aw as PBR_HAS_SUBSURFACE, ax as PBR2_HAS_THICKNESS_GLTF_CHANNEL } from "./index-B7Qhw0xL.js";
2
2
  const SS_HELPERS = `
3
3
  fn transmittanceBRDF_Burley(tintColor: vec3<f32>, diffusionDistance: vec3<f32>, thickness: f32) -> vec3<f32> {
4
4
  let S = 1.0 / max(vec3<f32>(0.000001), diffusionDistance);
@@ -155,4 +155,4 @@ export {
155
155
  pbrExt,
156
156
  writeSubsurfaceUBO
157
157
  };
158
- //# sourceMappingURL=subsurface-fragment-liM3y2-P.js.map
158
+ //# sourceMappingURL=subsurface-fragment-C1H4ytqK.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"subsurface-fragment-liM3y2-P.js","sources":["../src/material/pbr/fragments/subsurface-fragment.ts"],"sourcesContent":["/**\n * Subsurface Fragment\n *\n * Adds translucency — light passing through thin surfaces.\n * Only bundled when a scene uses PbrMaterialProps.subsurface.\n *\n * Math follows BJS PBRSubSurfaceConfiguration:\n * - Burley transmittance BRDF: exp-based approximation\n * - Thickness from texture (.g channel, BJS glTF-style default)\n * - Direct: wrap-around diffuse scaled by transmittance\n * - IBL: irradiance reduced by (1 - intensity), transmittance-weighted contribution added\n */\n\nimport type { ShaderFragment } from \"../../../shader/fragment-types.js\";\nimport type { PbrMaterialProps, SubSurfaceProps } from \"../pbr-material.js\";\nimport type { Texture2D } from \"../../../texture/texture-2d.js\";\nimport type { PbrExt } from \"../pbr-flags.js\";\nimport { PBR_HAS_SUBSURFACE, PBR_HAS_THICKNESS_MAP, PBR2_HAS_THICKNESS_GLTF_CHANNEL } from \"../pbr-flag-bits.js\";\n\nconst SS_HELPERS = `\nfn transmittanceBRDF_Burley(tintColor: vec3<f32>, diffusionDistance: vec3<f32>, thickness: f32) -> vec3<f32> {\nlet S = 1.0 / max(vec3<f32>(0.000001), diffusionDistance);\nlet temp = exp((-0.333333333 * thickness) * S);\nreturn tintColor * 0.25 * (temp * temp * temp + 3.0 * temp);\n}\nfn computeWrappedDiffuseNdotL(NdotL: f32, w: f32) -> f32 {\nlet t = 1.0 + w;\nlet invt2 = 1.0 / (t * t);\nreturn saturate((NdotL + w) * invt2);\n}\n`;\n\n// SV: declare subsurface scope variables\nconst SS_SCOPE_VARS = `var translucencyDirect = vec3<f32>(0.0);\nvar ssTransmittance = vec3<f32>(0.0);\nvar ssIntensity = 0.0;`;\n\n// AT: sample thickness + compute transmittance.\n// Channel: R by default (matches existing non-glTF path); G when the glTF\n// KHR_materials_volume flag is on (spec mandates G channel).\nfunction makeThicknessBlock(hasThicknessMap: boolean, useGltfChannel: boolean): string {\n const chan = useGltfChannel ? \"g\" : \"r\";\n const texSample = hasThicknessMap ? `let thicknessSample = textureSample(thicknessTexture_, thicknessSampler_, input.uv).${chan};` : `let thicknessSample = 1.0;`;\n return `${texSample}\nlet ssThickness = max(material.subsurfaceParams.y + thicknessSample * material.subsurfaceParams.z, 0.000001);\nlet ssTranslucencyColor = material.subsurfaceParams3.rgb;\nlet ssDiffDist = material.subsurfaceParams2.rgb;\nssIntensity = material.subsurfaceParams.x;\nssTransmittance = transmittanceBRDF_Burley(ssTranslucencyColor, ssDiffDist, ssThickness) * ssIntensity;`;\n}\n\n// AD: direct-light translucency lobe (back-facing only, wrap 0.02, 1/PI diffuse BRDF).\n// BJS also scales the front-facing direct diffuse by (1 - ssIntensity); we cannot easily\n// modify `directDiffuse` at compute time, so compensate via `color -= directDiffuse * ssIntensity`\n// in the AI/NI slot below.\nconst SS_DIRECT = `{\nlet NdotLU = dot(N, L);\nif (NdotLU < 0.0) {\nlet wrapNdotL = computeWrappedDiffuseNdotL(abs(NdotLU), 0.02);\ntranslucencyDirect += (1.0 / PI) * wrapNdotL * ssTransmittance * lightAtten * lightColor * material.directIntensity;\n}\n}`;\n\n// AI: subsurface IBL modification (runs after IBL sets `color`).\n// BJS: finalIrradiance *= (1 - ssI); finalIrradiance += refractionIrradiance;\n// where refractionIrradiance = environmentIrradiance(-N) * transmittance (no albedo by default).\n// AO/occlusion applies to the full finalIrradiance in BJS.\n// Also: scale direct diffuse by (1-ssI) and add translucencyDirect lobe.\nconst SS_IBL_MOD = `{\nlet N_back = -N_env;\nlet envIrrBack = (scene.vSphericalL00.rgb\n + scene.vSphericalL1_1.rgb * N_back.y + scene.vSphericalL10.rgb * N_back.z + scene.vSphericalL11.rgb * N_back.x\n + scene.vSphericalL2_2.rgb * (N_back.y * N_back.x) + scene.vSphericalL2_1.rgb * (N_back.y * N_back.z)\n + scene.vSphericalL20.rgb * (3.0 * N_back.z * N_back.z - 1.0) + scene.vSphericalL21.rgb * (N_back.z * N_back.x)\n + scene.vSphericalL22.rgb * (N_back.x * N_back.x - N_back.y * N_back.y)) * material.environmentIntensity;\nlet refractionIrradiance = envIrrBack * ssTransmittance;\ncolor -= finalIrradiance * ssIntensity;\ncolor += refractionIrradiance * occlusion;\ncolor -= directDiffuse * ssIntensity;\ncolor += translucencyDirect * occlusion;\n}`;\n\n// NI: no-IBL path — just scale direct diffuse and add translucency lobe.\nconst SS_NO_IBL_MOD = `color -= directDiffuse * ssIntensity;\ncolor += translucencyDirect;`;\n\nconst STAGE_FRAGMENT = 0x2;\n\n/**\n * Create a subsurface translucency fragment.\n * @param hasThicknessMap - Whether the material has a thickness texture.\n * @param hasIbl - Whether the scene has IBL.\n * @param useGltfThicknessChannel - Sample the thickness texture's G channel\n * (KHR_materials_volume) instead of R (BJS default).\n */\nexport function createSubsurfaceFragment(hasThicknessMap: boolean, hasIbl: boolean, useGltfThicknessChannel: boolean): ShaderFragment {\n const bindings = hasThicknessMap\n ? [\n { _name: \"thicknessTexture_\", _type: { _kind: \"texture\" as const, _textureType: \"texture_2d<f32>\" as const }, _visibility: STAGE_FRAGMENT },\n { _name: \"thicknessSampler_\", _type: { _kind: \"sampler\" as const, _samplerType: \"sampler\" as const }, _visibility: STAGE_FRAGMENT },\n ]\n : [];\n\n const slots: Partial<Record<string, string>> = {\n SV: SS_SCOPE_VARS,\n AT: makeThicknessBlock(hasThicknessMap, useGltfThicknessChannel),\n AD: SS_DIRECT,\n };\n if (hasIbl) {\n slots.AI = SS_IBL_MOD;\n } else {\n slots.NI = SS_NO_IBL_MOD;\n }\n\n const deps: string[] = [];\n if (hasIbl) {\n deps.push(\"ibl\");\n }\n\n return {\n _id: \"subsurface\",\n _dependencies: deps.length > 0 ? deps : undefined,\n _bindings: bindings.length > 0 ? bindings : undefined,\n _uboFields: [\n { _name: \"subsurfaceParams\", _type: \"vec4<f32>\" as const },\n { _name: \"subsurfaceParams2\", _type: \"vec4<f32>\" as const },\n { _name: \"subsurfaceParams3\", _type: \"vec4<f32>\" as const },\n ],\n _helperFunctions: SS_HELPERS,\n _fragmentSlots: slots,\n };\n}\n\n/** Write subsurface UBO data. Called from pbr-renderable.ts only when subsurface is active. */\nexport function writeSubsurfaceUBO(data: Float32Array, ss: SubSurfaceProps, offsets: ReadonlyMap<string, number>): void {\n const trans = ss.translucency!;\n const thick = ss.thickness;\n\n const off = offsets.get(\"subsurfaceParams\")! / 4;\n data[off] = trans.intensity ?? 1.0;\n const minThick = thick?.min ?? 0;\n const maxThick = thick?.max ?? 1.0;\n data[off + 1] = minThick;\n data[off + 2] = maxThick - minThick;\n\n const off2 = offsets.get(\"subsurfaceParams2\")! / 4;\n const dd = trans.diffusionDistance ?? [1, 1, 1];\n data[off2] = dd[0]!;\n data[off2 + 1] = dd[1]!;\n data[off2 + 2] = dd[2]!;\n\n const off3 = offsets.get(\"subsurfaceParams3\")! / 4;\n const tc = trans.color ?? [1, 1, 1];\n data[off3] = tc[0]!;\n data[off3 + 1] = tc[1]!;\n data[off3 + 2] = tc[2]!;\n}\n\nexport const pbrExt: PbrExt = {\n id: \"subsurface\",\n phase: \"fragment\",\n detect(mat) {\n const m = mat as PbrMaterialProps;\n if (!m.subsurface?.translucency) {\n return { f: 0, f2: 0 };\n }\n let f = PBR_HAS_SUBSURFACE;\n let f2 = 0;\n if (m.subsurface.thickness?.texture) {\n f |= PBR_HAS_THICKNESS_MAP;\n }\n if (m.subsurface.thickness?.useGlTFChannel) {\n f2 |= PBR2_HAS_THICKNESS_GLTF_CHANNEL;\n }\n return { f, f2 };\n },\n frag(ctx) {\n if (!(ctx._features & PBR_HAS_SUBSURFACE)) {\n return null;\n }\n return createSubsurfaceFragment((ctx._features & PBR_HAS_THICKNESS_MAP) !== 0, ctx._hasIbl, (ctx._features2 & PBR2_HAS_THICKNESS_GLTF_CHANNEL) !== 0);\n },\n writeUbo(data, mat, offsets) {\n const m = mat as PbrMaterialProps;\n if (m.subsurface?.translucency && offsets.has(\"subsurfaceParams\")) {\n writeSubsurfaceUBO(data, m.subsurface as SubSurfaceProps, offsets);\n }\n },\n bind(ctx, entries, b) {\n if ((ctx._features & PBR_HAS_THICKNESS_MAP) !== 0) {\n const tex = (ctx._material as PbrMaterialProps).subsurface?.thickness?.texture as Texture2D | undefined;\n if (tex) {\n entries.push({ binding: b++, resource: tex.view });\n entries.push({ binding: b++, resource: tex.sampler });\n }\n }\n return b;\n },\n textures(mat, out) {\n const t = (mat as PbrMaterialProps).subsurface?.thickness?.texture;\n if (t) {\n out.push(t);\n }\n },\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subsurface-fragment-C1H4ytqK.js","sources":["../src/material/pbr/fragments/subsurface-fragment.ts"],"sourcesContent":["/**\n * Subsurface Fragment\n *\n * Adds translucency — light passing through thin surfaces.\n * Only bundled when a scene uses PbrMaterialProps.subsurface.\n *\n * Math follows BJS PBRSubSurfaceConfiguration:\n * - Burley transmittance BRDF: exp-based approximation\n * - Thickness from texture (.g channel, BJS glTF-style default)\n * - Direct: wrap-around diffuse scaled by transmittance\n * - IBL: irradiance reduced by (1 - intensity), transmittance-weighted contribution added\n */\n\nimport type { ShaderFragment } from \"../../../shader/fragment-types.js\";\nimport type { PbrMaterialProps, SubSurfaceProps } from \"../pbr-material.js\";\nimport type { Texture2D } from \"../../../texture/texture-2d.js\";\nimport type { PbrExt } from \"../pbr-flags.js\";\nimport { PBR_HAS_SUBSURFACE, PBR_HAS_THICKNESS_MAP, PBR2_HAS_THICKNESS_GLTF_CHANNEL } from \"../pbr-flag-bits.js\";\n\nconst SS_HELPERS = `\nfn transmittanceBRDF_Burley(tintColor: vec3<f32>, diffusionDistance: vec3<f32>, thickness: f32) -> vec3<f32> {\nlet S = 1.0 / max(vec3<f32>(0.000001), diffusionDistance);\nlet temp = exp((-0.333333333 * thickness) * S);\nreturn tintColor * 0.25 * (temp * temp * temp + 3.0 * temp);\n}\nfn computeWrappedDiffuseNdotL(NdotL: f32, w: f32) -> f32 {\nlet t = 1.0 + w;\nlet invt2 = 1.0 / (t * t);\nreturn saturate((NdotL + w) * invt2);\n}\n`;\n\n// SV: declare subsurface scope variables\nconst SS_SCOPE_VARS = `var translucencyDirect = vec3<f32>(0.0);\nvar ssTransmittance = vec3<f32>(0.0);\nvar ssIntensity = 0.0;`;\n\n// AT: sample thickness + compute transmittance.\n// Channel: R by default (matches existing non-glTF path); G when the glTF\n// KHR_materials_volume flag is on (spec mandates G channel).\nfunction makeThicknessBlock(hasThicknessMap: boolean, useGltfChannel: boolean): string {\n const chan = useGltfChannel ? \"g\" : \"r\";\n const texSample = hasThicknessMap ? `let thicknessSample = textureSample(thicknessTexture_, thicknessSampler_, input.uv).${chan};` : `let thicknessSample = 1.0;`;\n return `${texSample}\nlet ssThickness = max(material.subsurfaceParams.y + thicknessSample * material.subsurfaceParams.z, 0.000001);\nlet ssTranslucencyColor = material.subsurfaceParams3.rgb;\nlet ssDiffDist = material.subsurfaceParams2.rgb;\nssIntensity = material.subsurfaceParams.x;\nssTransmittance = transmittanceBRDF_Burley(ssTranslucencyColor, ssDiffDist, ssThickness) * ssIntensity;`;\n}\n\n// AD: direct-light translucency lobe (back-facing only, wrap 0.02, 1/PI diffuse BRDF).\n// BJS also scales the front-facing direct diffuse by (1 - ssIntensity); we cannot easily\n// modify `directDiffuse` at compute time, so compensate via `color -= directDiffuse * ssIntensity`\n// in the AI/NI slot below.\nconst SS_DIRECT = `{\nlet NdotLU = dot(N, L);\nif (NdotLU < 0.0) {\nlet wrapNdotL = computeWrappedDiffuseNdotL(abs(NdotLU), 0.02);\ntranslucencyDirect += (1.0 / PI) * wrapNdotL * ssTransmittance * lightAtten * lightColor * material.directIntensity;\n}\n}`;\n\n// AI: subsurface IBL modification (runs after IBL sets `color`).\n// BJS: finalIrradiance *= (1 - ssI); finalIrradiance += refractionIrradiance;\n// where refractionIrradiance = environmentIrradiance(-N) * transmittance (no albedo by default).\n// AO/occlusion applies to the full finalIrradiance in BJS.\n// Also: scale direct diffuse by (1-ssI) and add translucencyDirect lobe.\nconst SS_IBL_MOD = `{\nlet N_back = -N_env;\nlet envIrrBack = (scene.vSphericalL00.rgb\n + scene.vSphericalL1_1.rgb * N_back.y + scene.vSphericalL10.rgb * N_back.z + scene.vSphericalL11.rgb * N_back.x\n + scene.vSphericalL2_2.rgb * (N_back.y * N_back.x) + scene.vSphericalL2_1.rgb * (N_back.y * N_back.z)\n + scene.vSphericalL20.rgb * (3.0 * N_back.z * N_back.z - 1.0) + scene.vSphericalL21.rgb * (N_back.z * N_back.x)\n + scene.vSphericalL22.rgb * (N_back.x * N_back.x - N_back.y * N_back.y)) * material.environmentIntensity;\nlet refractionIrradiance = envIrrBack * ssTransmittance;\ncolor -= finalIrradiance * ssIntensity;\ncolor += refractionIrradiance * occlusion;\ncolor -= directDiffuse * ssIntensity;\ncolor += translucencyDirect * occlusion;\n}`;\n\n// NI: no-IBL path — just scale direct diffuse and add translucency lobe.\nconst SS_NO_IBL_MOD = `color -= directDiffuse * ssIntensity;\ncolor += translucencyDirect;`;\n\nconst STAGE_FRAGMENT = 0x2;\n\n/**\n * Create a subsurface translucency fragment.\n * @param hasThicknessMap - Whether the material has a thickness texture.\n * @param hasIbl - Whether the scene has IBL.\n * @param useGltfThicknessChannel - Sample the thickness texture's G channel\n * (KHR_materials_volume) instead of R (BJS default).\n */\nexport function createSubsurfaceFragment(hasThicknessMap: boolean, hasIbl: boolean, useGltfThicknessChannel: boolean): ShaderFragment {\n const bindings = hasThicknessMap\n ? [\n { _name: \"thicknessTexture_\", _type: { _kind: \"texture\" as const, _textureType: \"texture_2d<f32>\" as const }, _visibility: STAGE_FRAGMENT },\n { _name: \"thicknessSampler_\", _type: { _kind: \"sampler\" as const, _samplerType: \"sampler\" as const }, _visibility: STAGE_FRAGMENT },\n ]\n : [];\n\n const slots: Partial<Record<string, string>> = {\n SV: SS_SCOPE_VARS,\n AT: makeThicknessBlock(hasThicknessMap, useGltfThicknessChannel),\n AD: SS_DIRECT,\n };\n if (hasIbl) {\n slots.AI = SS_IBL_MOD;\n } else {\n slots.NI = SS_NO_IBL_MOD;\n }\n\n const deps: string[] = [];\n if (hasIbl) {\n deps.push(\"ibl\");\n }\n\n return {\n _id: \"subsurface\",\n _dependencies: deps.length > 0 ? deps : undefined,\n _bindings: bindings.length > 0 ? bindings : undefined,\n _uboFields: [\n { _name: \"subsurfaceParams\", _type: \"vec4<f32>\" as const },\n { _name: \"subsurfaceParams2\", _type: \"vec4<f32>\" as const },\n { _name: \"subsurfaceParams3\", _type: \"vec4<f32>\" as const },\n ],\n _helperFunctions: SS_HELPERS,\n _fragmentSlots: slots,\n };\n}\n\n/** Write subsurface UBO data. Called from pbr-renderable.ts only when subsurface is active. */\nexport function writeSubsurfaceUBO(data: Float32Array, ss: SubSurfaceProps, offsets: ReadonlyMap<string, number>): void {\n const trans = ss.translucency!;\n const thick = ss.thickness;\n\n const off = offsets.get(\"subsurfaceParams\")! / 4;\n data[off] = trans.intensity ?? 1.0;\n const minThick = thick?.min ?? 0;\n const maxThick = thick?.max ?? 1.0;\n data[off + 1] = minThick;\n data[off + 2] = maxThick - minThick;\n\n const off2 = offsets.get(\"subsurfaceParams2\")! / 4;\n const dd = trans.diffusionDistance ?? [1, 1, 1];\n data[off2] = dd[0]!;\n data[off2 + 1] = dd[1]!;\n data[off2 + 2] = dd[2]!;\n\n const off3 = offsets.get(\"subsurfaceParams3\")! / 4;\n const tc = trans.color ?? [1, 1, 1];\n data[off3] = tc[0]!;\n data[off3 + 1] = tc[1]!;\n data[off3 + 2] = tc[2]!;\n}\n\nexport const pbrExt: PbrExt = {\n id: \"subsurface\",\n phase: \"fragment\",\n detect(mat) {\n const m = mat as PbrMaterialProps;\n if (!m.subsurface?.translucency) {\n return { f: 0, f2: 0 };\n }\n let f = PBR_HAS_SUBSURFACE;\n let f2 = 0;\n if (m.subsurface.thickness?.texture) {\n f |= PBR_HAS_THICKNESS_MAP;\n }\n if (m.subsurface.thickness?.useGlTFChannel) {\n f2 |= PBR2_HAS_THICKNESS_GLTF_CHANNEL;\n }\n return { f, f2 };\n },\n frag(ctx) {\n if (!(ctx._features & PBR_HAS_SUBSURFACE)) {\n return null;\n }\n return createSubsurfaceFragment((ctx._features & PBR_HAS_THICKNESS_MAP) !== 0, ctx._hasIbl, (ctx._features2 & PBR2_HAS_THICKNESS_GLTF_CHANNEL) !== 0);\n },\n writeUbo(data, mat, offsets) {\n const m = mat as PbrMaterialProps;\n if (m.subsurface?.translucency && offsets.has(\"subsurfaceParams\")) {\n writeSubsurfaceUBO(data, m.subsurface as SubSurfaceProps, offsets);\n }\n },\n bind(ctx, entries, b) {\n if ((ctx._features & PBR_HAS_THICKNESS_MAP) !== 0) {\n const tex = (ctx._material as PbrMaterialProps).subsurface?.thickness?.texture as Texture2D | undefined;\n if (tex) {\n entries.push({ binding: b++, resource: tex.view });\n entries.push({ binding: b++, resource: tex.sampler });\n }\n }\n return b;\n },\n textures(mat, out) {\n const t = (mat as PbrMaterialProps).subsurface?.thickness?.texture;\n if (t) {\n out.push(t);\n }\n },\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,310 @@
1
+ import { b2 as getViewProjectionMatrix } from "./index-B7Qhw0xL.js";
2
+ import { syncThinInstanceGpuData } from "./thin-instance-gpu-E8DBd8XL.js";
3
+ const WORKGROUP_SIZE = 64;
4
+ const PARAM_BYTES = 192;
5
+ const COUNT_U32_OFFSET = 44;
6
+ const MESH_WORLD_FLOAT_OFFSET = 24;
7
+ const LOCAL_SPHERE_FLOAT_OFFSET = 40;
8
+ const INDIRECT_ARGS_BYTES = 20;
9
+ const CULL_WGSL_NO_COLOR = (
10
+ /* wgsl */
11
+ `
12
+ struct CullParams{planes:array<vec4<f32>,6>,meshWorld:mat4x4<f32>,localSphere:vec4<f32>,count:u32};
13
+ @group(0)@binding(0)var<storage,read> srcMatrices:array<mat4x4<f32>>;
14
+ @group(0)@binding(1)var<storage,read_write> dstMatrices:array<mat4x4<f32>>;
15
+ @group(0)@binding(2)var<storage,read_write> args:array<atomic<u32>>;
16
+ @group(0)@binding(3)var<uniform> params:CullParams;
17
+ fn visible(world:mat4x4<f32>)->bool{
18
+ let center=(world*vec4<f32>(params.localSphere.xyz,1.0)).xyz;
19
+ let sx=length(world[0].xyz);
20
+ let sy=length(world[1].xyz);
21
+ let sz=length(world[2].xyz);
22
+ let radius=params.localSphere.w*max(max(sx,sy),sz)+0.0001;
23
+ for(var i=0u;i<6u;i++){
24
+ let p=params.planes[i];
25
+ if(dot(p.xyz,center)+p.w < -radius){return false;}
26
+ }
27
+ return true;
28
+ }
29
+ @compute @workgroup_size(64)
30
+ fn main(@builtin(global_invocation_id) gid:vec3<u32>){
31
+ let i=gid.x;
32
+ if(i>=params.count){return;}
33
+ let world=params.meshWorld*srcMatrices[i];
34
+ if(!visible(world)){return;}
35
+ let outIndex=atomicAdd(&args[1],1u);
36
+ dstMatrices[outIndex]=srcMatrices[i];
37
+ }`
38
+ );
39
+ const CULL_WGSL_COLOR = `${CULL_WGSL_NO_COLOR}
40
+ @group(0)@binding(4)var<storage,read> srcColors:array<vec4<f32>>;
41
+ @group(0)@binding(5)var<storage,read_write> dstColors:array<vec4<f32>>;
42
+ @compute @workgroup_size(64)
43
+ fn mainColor(@builtin(global_invocation_id) gid:vec3<u32>){
44
+ let i=gid.x;
45
+ if(i>=params.count){return;}
46
+ let world=params.meshWorld*srcMatrices[i];
47
+ if(!visible(world)){return;}
48
+ let outIndex=atomicAdd(&args[1],1u);
49
+ dstMatrices[outIndex]=srcMatrices[i];
50
+ dstColors[outIndex]=srcColors[i];
51
+ }`;
52
+ let _cachedDevice = null;
53
+ let _pipelineNoColor = null;
54
+ let _pipelineColor = null;
55
+ function createTiCullState() {
56
+ const paramsBytes = new ArrayBuffer(PARAM_BYTES);
57
+ return {
58
+ _capacity: 0,
59
+ _visibleMatrixBuffer: null,
60
+ _visibleColorBuffer: null,
61
+ _argsBuffer: null,
62
+ _paramsBuffer: null,
63
+ _bindGroup: null,
64
+ _srcMatrixBuffer: null,
65
+ _srcColorBuffer: null,
66
+ _hasColor: false,
67
+ _localSphereReady: false,
68
+ _localSphere: new Float32Array(4),
69
+ _paramsBytes: paramsBytes,
70
+ _paramsF32: new Float32Array(paramsBytes),
71
+ _paramsU32: new Uint32Array(paramsBytes),
72
+ _argsData: new Uint32Array(5),
73
+ _drawBuffers: null
74
+ };
75
+ }
76
+ function destroyTiCullState(state) {
77
+ var _a, _b, _c, _d;
78
+ (_a = state._visibleMatrixBuffer) == null ? void 0 : _a.destroy();
79
+ (_b = state._visibleColorBuffer) == null ? void 0 : _b.destroy();
80
+ (_c = state._argsBuffer) == null ? void 0 : _c.destroy();
81
+ (_d = state._paramsBuffer) == null ? void 0 : _d.destroy();
82
+ state._visibleMatrixBuffer = null;
83
+ state._visibleColorBuffer = null;
84
+ state._argsBuffer = null;
85
+ state._paramsBuffer = null;
86
+ state._bindGroup = null;
87
+ state._drawBuffers = null;
88
+ }
89
+ function prepareTiCull(engine, state, mesh, gpu, ti, hasColor, context) {
90
+ const camera = context._camera;
91
+ if (!ti._gpuCullingEnabled || !camera || mesh.visible === false || ti.count === 0) {
92
+ state._drawBuffers = null;
93
+ return null;
94
+ }
95
+ if (hasColor && !ti.colors) {
96
+ state._drawBuffers = null;
97
+ return null;
98
+ }
99
+ if (!state._localSphereReady && !computeLocalSphere(mesh, state._localSphere)) {
100
+ state._drawBuffers = null;
101
+ return null;
102
+ }
103
+ state._localSphereReady = true;
104
+ syncThinInstanceGpuData(engine, ti, hasColor);
105
+ const sourceMatrixBuffer = ti._gpuBuffer;
106
+ const sourceColorBuffer = hasColor ? ti._colorGpuBuffer : null;
107
+ if (!sourceMatrixBuffer || hasColor && !sourceColorBuffer) {
108
+ state._drawBuffers = null;
109
+ return null;
110
+ }
111
+ ensureCullBuffers(engine, state, ti._capacity, hasColor);
112
+ const visibleMatrixBuffer = state._visibleMatrixBuffer;
113
+ const visibleColorBuffer = hasColor ? state._visibleColorBuffer : null;
114
+ const argsBuffer = state._argsBuffer;
115
+ const paramsBuffer = state._paramsBuffer;
116
+ const pipeline = getCullPipeline(engine, hasColor);
117
+ if (state._bindGroup === null || state._srcMatrixBuffer !== sourceMatrixBuffer || state._srcColorBuffer !== sourceColorBuffer || state._hasColor !== hasColor) {
118
+ const entries = [
119
+ { binding: 0, resource: { buffer: sourceMatrixBuffer } },
120
+ { binding: 1, resource: { buffer: visibleMatrixBuffer } },
121
+ { binding: 2, resource: { buffer: argsBuffer } },
122
+ { binding: 3, resource: { buffer: paramsBuffer } }
123
+ ];
124
+ if (hasColor) {
125
+ entries.push({ binding: 4, resource: { buffer: sourceColorBuffer } }, { binding: 5, resource: { buffer: visibleColorBuffer } });
126
+ }
127
+ state._bindGroup = engine._device.createBindGroup({ layout: pipeline.getBindGroupLayout(0), entries });
128
+ state._srcMatrixBuffer = sourceMatrixBuffer;
129
+ state._srcColorBuffer = sourceColorBuffer;
130
+ state._hasColor = hasColor;
131
+ }
132
+ const v = camera.viewport;
133
+ const aspect = context.targetWidth / context.targetHeight * (v ? v.width / v.height : 1);
134
+ writeCullParams(engine, state, mesh, gpu.indexCount, ti.count, camera, aspect);
135
+ const pass = engine._currentEncoder.beginComputePass();
136
+ pass.setPipeline(pipeline);
137
+ pass.setBindGroup(0, state._bindGroup);
138
+ pass.dispatchWorkgroups(Math.ceil(ti.count / WORKGROUP_SIZE));
139
+ pass.end();
140
+ state._drawBuffers = { matrixBuffer: visibleMatrixBuffer, colorBuffer: visibleColorBuffer };
141
+ return { drawBuffers: state._drawBuffers, argsBuffer };
142
+ }
143
+ function ensureCullBuffers(engine, state, capacity, hasColor) {
144
+ var _a, _b;
145
+ const device = engine._device;
146
+ if (state._capacity < capacity) {
147
+ (_a = state._visibleMatrixBuffer) == null ? void 0 : _a.destroy();
148
+ (_b = state._visibleColorBuffer) == null ? void 0 : _b.destroy();
149
+ state._visibleMatrixBuffer = device.createBuffer({
150
+ size: Math.max(capacity * 64, 4),
151
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE
152
+ });
153
+ state._visibleColorBuffer = hasColor ? device.createBuffer({
154
+ size: Math.max(capacity * 16, 4),
155
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE
156
+ }) : null;
157
+ state._capacity = capacity;
158
+ state._bindGroup = null;
159
+ state._drawBuffers = null;
160
+ } else if (hasColor && !state._visibleColorBuffer) {
161
+ state._visibleColorBuffer = device.createBuffer({
162
+ size: Math.max(state._capacity * 16, 4),
163
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE
164
+ });
165
+ state._bindGroup = null;
166
+ state._drawBuffers = null;
167
+ }
168
+ if (!state._argsBuffer) {
169
+ state._argsBuffer = device.createBuffer({
170
+ size: INDIRECT_ARGS_BYTES,
171
+ usage: GPUBufferUsage.INDIRECT | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
172
+ });
173
+ }
174
+ if (!state._paramsBuffer) {
175
+ state._paramsBuffer = device.createBuffer({
176
+ size: PARAM_BYTES,
177
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
178
+ });
179
+ }
180
+ }
181
+ function getCullPipeline(engine, hasColor) {
182
+ const device = engine._device;
183
+ if (_cachedDevice !== device) {
184
+ _cachedDevice = device;
185
+ _pipelineNoColor = null;
186
+ _pipelineColor = null;
187
+ }
188
+ if (hasColor) {
189
+ _pipelineColor ?? (_pipelineColor = device.createComputePipeline({
190
+ layout: "auto",
191
+ compute: { module: device.createShaderModule({ code: CULL_WGSL_COLOR }), entryPoint: "mainColor" }
192
+ }));
193
+ return _pipelineColor;
194
+ }
195
+ _pipelineNoColor ?? (_pipelineNoColor = device.createComputePipeline({
196
+ layout: "auto",
197
+ compute: { module: device.createShaderModule({ code: CULL_WGSL_NO_COLOR }), entryPoint: "main" }
198
+ }));
199
+ return _pipelineNoColor;
200
+ }
201
+ function writeCullParams(engine, state, mesh, indexCount, instanceCount, camera, aspect) {
202
+ const params = state._paramsF32;
203
+ const viewProjection = getViewProjectionMatrix(camera, aspect);
204
+ writeFrustumPlanes(params, viewProjection);
205
+ params.set(mesh.worldMatrix, MESH_WORLD_FLOAT_OFFSET);
206
+ params.set(state._localSphere, LOCAL_SPHERE_FLOAT_OFFSET);
207
+ state._paramsU32[COUNT_U32_OFFSET] = instanceCount;
208
+ const args = state._argsData;
209
+ args[0] = indexCount;
210
+ args[1] = 0;
211
+ args[2] = 0;
212
+ args[3] = 0;
213
+ args[4] = 0;
214
+ engine._device.queue.writeBuffer(state._argsBuffer, 0, args.buffer, args.byteOffset, args.byteLength);
215
+ engine._device.queue.writeBuffer(state._paramsBuffer, 0, state._paramsBytes);
216
+ }
217
+ function writeFrustumPlanes(out, m) {
218
+ writePlane(out, 0, m[3] + m[0], m[7] + m[4], m[11] + m[8], m[15] + m[12]);
219
+ writePlane(out, 4, m[3] - m[0], m[7] - m[4], m[11] - m[8], m[15] - m[12]);
220
+ writePlane(out, 8, m[3] + m[1], m[7] + m[5], m[11] + m[9], m[15] + m[13]);
221
+ writePlane(out, 12, m[3] - m[1], m[7] - m[5], m[11] - m[9], m[15] - m[13]);
222
+ writePlane(out, 16, m[2], m[6], m[10], m[14]);
223
+ writePlane(out, 20, m[3] - m[2], m[7] - m[6], m[11] - m[10], m[15] - m[14]);
224
+ }
225
+ function writePlane(out, offset, x, y, z, w) {
226
+ const invLen = 1 / Math.hypot(x, y, z);
227
+ out[offset] = x * invLen;
228
+ out[offset + 1] = y * invLen;
229
+ out[offset + 2] = z * invLen;
230
+ out[offset + 3] = w * invLen;
231
+ }
232
+ function computeLocalSphere(mesh, out) {
233
+ const positions = mesh._cpuPositions;
234
+ if (!positions || positions.length < 3) {
235
+ return false;
236
+ }
237
+ let minX = Infinity, minY = Infinity, minZ = Infinity;
238
+ let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
239
+ for (let i = 0; i < positions.length; i += 3) {
240
+ const x = positions[i];
241
+ const y = positions[i + 1];
242
+ const z = positions[i + 2];
243
+ if (x < minX) {
244
+ minX = x;
245
+ }
246
+ if (x > maxX) {
247
+ maxX = x;
248
+ }
249
+ if (y < minY) {
250
+ minY = y;
251
+ }
252
+ if (y > maxY) {
253
+ maxY = y;
254
+ }
255
+ if (z < minZ) {
256
+ minZ = z;
257
+ }
258
+ if (z > maxZ) {
259
+ maxZ = z;
260
+ }
261
+ }
262
+ if (!isFinite(minX)) {
263
+ return false;
264
+ }
265
+ const cx = (minX + maxX) * 0.5;
266
+ const cy = (minY + maxY) * 0.5;
267
+ const cz = (minZ + maxZ) * 0.5;
268
+ const dx = maxX - cx;
269
+ const dy = maxY - cy;
270
+ const dz = maxZ - cz;
271
+ out[0] = cx;
272
+ out[1] = cy;
273
+ out[2] = cz;
274
+ out[3] = Math.hypot(dx, dy, dz);
275
+ return true;
276
+ }
277
+ function tryBind(renderable, scene, mesh, engine, hasColor, excluded, baseUpdate) {
278
+ var _a;
279
+ const ti = mesh.thinInstances;
280
+ if (excluded || !(ti == null ? void 0 : ti._gpuCullingEnabled)) {
281
+ return void 0;
282
+ }
283
+ renderable._direct = true;
284
+ const state = createTiCullState();
285
+ (_a = scene._meshDisposables.get(mesh)) == null ? void 0 : _a.push(() => {
286
+ destroyTiCullState(state);
287
+ });
288
+ const binding = {
289
+ cullDrawBufs: null,
290
+ _args: null,
291
+ update(context) {
292
+ baseUpdate == null ? void 0 : baseUpdate(context);
293
+ const res = prepareTiCull(engine, state, mesh, mesh._gpu, ti, hasColor, context);
294
+ binding.cullDrawBufs = (res == null ? void 0 : res.drawBuffers) ?? null;
295
+ binding._args = (res == null ? void 0 : res.argsBuffer) ?? null;
296
+ },
297
+ draw(pass, indexCount, instanceCount) {
298
+ if (binding._args) {
299
+ pass.drawIndexedIndirect(binding._args, 0);
300
+ } else {
301
+ pass.drawIndexed(indexCount, instanceCount);
302
+ }
303
+ }
304
+ };
305
+ return binding;
306
+ }
307
+ export {
308
+ tryBind
309
+ };
310
+ //# sourceMappingURL=thin-instance-cull-binding-CCxrPNO6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thin-instance-cull-binding-CCxrPNO6.js","sources":["../src/mesh/thin-instance-gpu-culling.ts","../src/mesh/thin-instance-cull-binding.ts"],"sourcesContent":["/** GPU frustum culling for opt-in thin instances.\n *\n * Dynamically imported only when a scene enables thin-instance GPU culling.\n * Each render binding owns its own state so render tasks with different cameras\n * never clobber one another's compacted instance buffers or indirect args.\n */\n\nimport type { Camera } from \"../camera/camera.js\";\nimport { getViewProjectionMatrix } from \"../camera/camera.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { DrawUpdateContext } from \"../render/renderable.js\";\nimport type { Mat4 } from \"../math/types.js\";\nimport type { Mesh, MeshGPU } from \"./mesh.js\";\nimport type { ThinInstanceData } from \"./thin-instance.js\";\nimport { syncThinInstanceGpuData } from \"./thin-instance-gpu.js\";\nimport type { ThinInstanceDrawBuffers } from \"./thin-instance-gpu.js\";\n\nconst WORKGROUP_SIZE = 64;\nconst PARAM_BYTES = 192;\nconst COUNT_U32_OFFSET = 44;\nconst MESH_WORLD_FLOAT_OFFSET = 24;\nconst LOCAL_SPHERE_FLOAT_OFFSET = 40;\nconst INDIRECT_ARGS_BYTES = 20;\n\nconst CULL_WGSL_NO_COLOR = /* wgsl */ `\nstruct CullParams{planes:array<vec4<f32>,6>,meshWorld:mat4x4<f32>,localSphere:vec4<f32>,count:u32};\n@group(0)@binding(0)var<storage,read> srcMatrices:array<mat4x4<f32>>;\n@group(0)@binding(1)var<storage,read_write> dstMatrices:array<mat4x4<f32>>;\n@group(0)@binding(2)var<storage,read_write> args:array<atomic<u32>>;\n@group(0)@binding(3)var<uniform> params:CullParams;\nfn visible(world:mat4x4<f32>)->bool{\nlet center=(world*vec4<f32>(params.localSphere.xyz,1.0)).xyz;\nlet sx=length(world[0].xyz);\nlet sy=length(world[1].xyz);\nlet sz=length(world[2].xyz);\nlet radius=params.localSphere.w*max(max(sx,sy),sz)+0.0001;\nfor(var i=0u;i<6u;i++){\nlet p=params.planes[i];\nif(dot(p.xyz,center)+p.w < -radius){return false;}\n}\nreturn true;\n}\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) gid:vec3<u32>){\nlet i=gid.x;\nif(i>=params.count){return;}\nlet world=params.meshWorld*srcMatrices[i];\nif(!visible(world)){return;}\nlet outIndex=atomicAdd(&args[1],1u);\ndstMatrices[outIndex]=srcMatrices[i];\n}`;\n\nconst CULL_WGSL_COLOR = `${CULL_WGSL_NO_COLOR}\n@group(0)@binding(4)var<storage,read> srcColors:array<vec4<f32>>;\n@group(0)@binding(5)var<storage,read_write> dstColors:array<vec4<f32>>;\n@compute @workgroup_size(64)\nfn mainColor(@builtin(global_invocation_id) gid:vec3<u32>){\nlet i=gid.x;\nif(i>=params.count){return;}\nlet world=params.meshWorld*srcMatrices[i];\nif(!visible(world)){return;}\nlet outIndex=atomicAdd(&args[1],1u);\ndstMatrices[outIndex]=srcMatrices[i];\ndstColors[outIndex]=srcColors[i];\n}`;\n\n/** Per-render-binding GPU culling state. */\nexport interface ThinInstanceGpuCullState {\n /** @internal */\n _capacity: number;\n /** @internal */\n _visibleMatrixBuffer: GPUBuffer | null;\n /** @internal */\n _visibleColorBuffer: GPUBuffer | null;\n /** @internal */\n _argsBuffer: GPUBuffer | null;\n /** @internal */\n _paramsBuffer: GPUBuffer | null;\n /** @internal */\n _bindGroup: GPUBindGroup | null;\n /** @internal */\n _srcMatrixBuffer: GPUBuffer | null;\n /** @internal */\n _srcColorBuffer: GPUBuffer | null;\n /** @internal */\n _hasColor: boolean;\n /** @internal */\n _localSphereReady: boolean;\n /** @internal */\n _localSphere: Float32Array;\n /** @internal */\n _paramsBytes: ArrayBuffer;\n /** @internal */\n _paramsF32: Float32Array;\n /** @internal */\n _paramsU32: Uint32Array;\n /** @internal */\n _argsData: Uint32Array;\n /** @internal */\n _drawBuffers: ThinInstanceDrawBuffers | null;\n}\n\n/** Result consumed by a material draw closure after culling has run for the active pass. */\nexport interface ThinInstanceGpuCullResult {\n readonly drawBuffers: ThinInstanceDrawBuffers;\n readonly argsBuffer: GPUBuffer;\n}\n\nlet _cachedDevice: GPUDevice | null = null;\nlet _pipelineNoColor: GPUComputePipeline | null = null;\nlet _pipelineColor: GPUComputePipeline | null = null;\n\n/** Create per-binding culling state. */\nexport function createTiCullState(): ThinInstanceGpuCullState {\n const paramsBytes = new ArrayBuffer(PARAM_BYTES);\n return {\n _capacity: 0,\n _visibleMatrixBuffer: null,\n _visibleColorBuffer: null,\n _argsBuffer: null,\n _paramsBuffer: null,\n _bindGroup: null,\n _srcMatrixBuffer: null,\n _srcColorBuffer: null,\n _hasColor: false,\n _localSphereReady: false,\n _localSphere: new Float32Array(4),\n _paramsBytes: paramsBytes,\n _paramsF32: new Float32Array(paramsBytes),\n _paramsU32: new Uint32Array(paramsBytes),\n _argsData: new Uint32Array(5),\n _drawBuffers: null,\n };\n}\n\n/** Destroy GPU resources owned by a per-binding cull state. */\nexport function destroyTiCullState(state: ThinInstanceGpuCullState): void {\n state._visibleMatrixBuffer?.destroy();\n state._visibleColorBuffer?.destroy();\n state._argsBuffer?.destroy();\n state._paramsBuffer?.destroy();\n state._visibleMatrixBuffer = null;\n state._visibleColorBuffer = null;\n state._argsBuffer = null;\n state._paramsBuffer = null;\n state._bindGroup = null;\n state._drawBuffers = null;\n}\n\n/** Run culling for one render binding and return buffers for the subsequent indirect draw. */\nexport function prepareTiCull(\n engine: EngineContext,\n state: ThinInstanceGpuCullState,\n mesh: Mesh,\n gpu: MeshGPU,\n ti: ThinInstanceData,\n hasColor: boolean,\n context: DrawUpdateContext\n): ThinInstanceGpuCullResult | null {\n const camera = context._camera;\n if (!ti._gpuCullingEnabled || !camera || mesh.visible === false || ti.count === 0) {\n state._drawBuffers = null;\n return null;\n }\n if (hasColor && !ti.colors) {\n state._drawBuffers = null;\n return null;\n }\n if (!state._localSphereReady && !computeLocalSphere(mesh as Mesh, state._localSphere)) {\n state._drawBuffers = null;\n return null;\n }\n state._localSphereReady = true;\n\n syncThinInstanceGpuData(engine, ti, hasColor);\n const sourceMatrixBuffer = ti._gpuBuffer;\n const sourceColorBuffer = hasColor ? ti._colorGpuBuffer : null;\n if (!sourceMatrixBuffer || (hasColor && !sourceColorBuffer)) {\n state._drawBuffers = null;\n return null;\n }\n\n ensureCullBuffers(engine, state, ti._capacity, hasColor);\n const visibleMatrixBuffer = state._visibleMatrixBuffer!;\n const visibleColorBuffer = hasColor ? state._visibleColorBuffer! : null;\n const argsBuffer = state._argsBuffer!;\n const paramsBuffer = state._paramsBuffer!;\n const pipeline = getCullPipeline(engine, hasColor);\n\n if (state._bindGroup === null || state._srcMatrixBuffer !== sourceMatrixBuffer || state._srcColorBuffer !== sourceColorBuffer || state._hasColor !== hasColor) {\n const entries: GPUBindGroupEntry[] = [\n { binding: 0, resource: { buffer: sourceMatrixBuffer } },\n { binding: 1, resource: { buffer: visibleMatrixBuffer } },\n { binding: 2, resource: { buffer: argsBuffer } },\n { binding: 3, resource: { buffer: paramsBuffer } },\n ];\n if (hasColor) {\n entries.push({ binding: 4, resource: { buffer: sourceColorBuffer! } }, { binding: 5, resource: { buffer: visibleColorBuffer! } });\n }\n state._bindGroup = engine._device.createBindGroup({ layout: pipeline.getBindGroupLayout(0), entries });\n state._srcMatrixBuffer = sourceMatrixBuffer;\n state._srcColorBuffer = sourceColorBuffer;\n state._hasColor = hasColor;\n }\n\n const v = camera.viewport;\n const aspect = (context.targetWidth / context.targetHeight) * (v ? v.width / v.height : 1);\n writeCullParams(engine, state, mesh, gpu.indexCount, ti.count, camera, aspect);\n\n const pass = engine._currentEncoder.beginComputePass();\n pass.setPipeline(pipeline);\n pass.setBindGroup(0, state._bindGroup);\n pass.dispatchWorkgroups(Math.ceil(ti.count / WORKGROUP_SIZE));\n pass.end();\n\n state._drawBuffers = { matrixBuffer: visibleMatrixBuffer, colorBuffer: visibleColorBuffer };\n return { drawBuffers: state._drawBuffers, argsBuffer };\n}\n\nfunction ensureCullBuffers(engine: EngineContext, state: ThinInstanceGpuCullState, capacity: number, hasColor: boolean): void {\n const device = engine._device;\n if (state._capacity < capacity) {\n state._visibleMatrixBuffer?.destroy();\n state._visibleColorBuffer?.destroy();\n state._visibleMatrixBuffer = device.createBuffer({\n size: Math.max(capacity * 64, 4),\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE,\n });\n state._visibleColorBuffer = hasColor\n ? device.createBuffer({\n size: Math.max(capacity * 16, 4),\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE,\n })\n : null;\n state._capacity = capacity;\n state._bindGroup = null;\n state._drawBuffers = null;\n } else if (hasColor && !state._visibleColorBuffer) {\n state._visibleColorBuffer = device.createBuffer({\n size: Math.max(state._capacity * 16, 4),\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE,\n });\n state._bindGroup = null;\n state._drawBuffers = null;\n }\n if (!state._argsBuffer) {\n state._argsBuffer = device.createBuffer({\n size: INDIRECT_ARGS_BYTES,\n usage: GPUBufferUsage.INDIRECT | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n });\n }\n if (!state._paramsBuffer) {\n state._paramsBuffer = device.createBuffer({\n size: PARAM_BYTES,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n }\n}\n\nfunction getCullPipeline(engine: EngineContext, hasColor: boolean): GPUComputePipeline {\n const device = engine._device;\n if (_cachedDevice !== device) {\n _cachedDevice = device;\n _pipelineNoColor = null;\n _pipelineColor = null;\n }\n if (hasColor) {\n _pipelineColor ??= device.createComputePipeline({\n layout: \"auto\",\n compute: { module: device.createShaderModule({ code: CULL_WGSL_COLOR }), entryPoint: \"mainColor\" },\n });\n return _pipelineColor;\n }\n _pipelineNoColor ??= device.createComputePipeline({\n layout: \"auto\",\n compute: { module: device.createShaderModule({ code: CULL_WGSL_NO_COLOR }), entryPoint: \"main\" },\n });\n return _pipelineNoColor;\n}\n\nfunction writeCullParams(engine: EngineContext, state: ThinInstanceGpuCullState, mesh: Mesh, indexCount: number, instanceCount: number, camera: Camera, aspect: number): void {\n const params = state._paramsF32;\n const viewProjection = getViewProjectionMatrix(camera, aspect);\n writeFrustumPlanes(params, viewProjection);\n params.set(mesh.worldMatrix, MESH_WORLD_FLOAT_OFFSET);\n params.set(state._localSphere, LOCAL_SPHERE_FLOAT_OFFSET);\n state._paramsU32[COUNT_U32_OFFSET] = instanceCount;\n\n const args = state._argsData;\n args[0] = indexCount;\n args[1] = 0;\n args[2] = 0;\n args[3] = 0;\n args[4] = 0;\n\n engine._device.queue.writeBuffer(state._argsBuffer!, 0, args.buffer, args.byteOffset, args.byteLength);\n engine._device.queue.writeBuffer(state._paramsBuffer!, 0, state._paramsBytes);\n}\n\nfunction writeFrustumPlanes(out: Float32Array, m: Mat4): void {\n writePlane(out, 0, m[3]! + m[0]!, m[7]! + m[4]!, m[11]! + m[8]!, m[15]! + m[12]!);\n writePlane(out, 4, m[3]! - m[0]!, m[7]! - m[4]!, m[11]! - m[8]!, m[15]! - m[12]!);\n writePlane(out, 8, m[3]! + m[1]!, m[7]! + m[5]!, m[11]! + m[9]!, m[15]! + m[13]!);\n writePlane(out, 12, m[3]! - m[1]!, m[7]! - m[5]!, m[11]! - m[9]!, m[15]! - m[13]!);\n writePlane(out, 16, m[2]!, m[6]!, m[10]!, m[14]!);\n writePlane(out, 20, m[3]! - m[2]!, m[7]! - m[6]!, m[11]! - m[10]!, m[15]! - m[14]!);\n}\n\nfunction writePlane(out: Float32Array, offset: number, x: number, y: number, z: number, w: number): void {\n const invLen = 1 / Math.hypot(x, y, z);\n out[offset] = x * invLen;\n out[offset + 1] = y * invLen;\n out[offset + 2] = z * invLen;\n out[offset + 3] = w * invLen;\n}\n\nfunction computeLocalSphere(mesh: Mesh, out: Float32Array): boolean {\n const positions = mesh._cpuPositions;\n if (!positions || positions.length < 3) {\n return false;\n }\n let minX = Infinity,\n minY = Infinity,\n minZ = Infinity;\n let maxX = -Infinity,\n maxY = -Infinity,\n maxZ = -Infinity;\n for (let i = 0; i < positions.length; i += 3) {\n const x = positions[i]!;\n const y = positions[i + 1]!;\n const z = positions[i + 2]!;\n if (x < minX) {\n minX = x;\n }\n if (x > maxX) {\n maxX = x;\n }\n if (y < minY) {\n minY = y;\n }\n if (y > maxY) {\n maxY = y;\n }\n if (z < minZ) {\n minZ = z;\n }\n if (z > maxZ) {\n maxZ = z;\n }\n }\n if (!isFinite(minX)) {\n return false;\n }\n const cx = (minX + maxX) * 0.5;\n const cy = (minY + maxY) * 0.5;\n const cz = (minZ + maxZ) * 0.5;\n const dx = maxX - cx;\n const dy = maxY - cy;\n const dz = maxZ - cz;\n out[0] = cx;\n out[1] = cy;\n out[2] = cz;\n out[3] = Math.hypot(dx, dy, dz);\n return true;\n}\n","/** Shared per-binding GPU frustum-culling lifecycle for thin-instanced renderables.\n *\n * Dynamically imported only when a scene enables thin-instance GPU culling, and\n * it statically pulls in the compute-cull module — so non-culling scenes fetch\n * neither this helper nor `thin-instance-gpu-culling.ts`.\n *\n * Factored here so Standard, PBR, and ShaderMaterial renderables share one\n * implementation of the cull lifecycle instead of copy-pasting it three times.\n * `tryBind` is the single seam a renderable's `bind()` calls: it does the\n * opaque-only gate + per-mesh `_gpuCullingEnabled` check, marks the renderable\n * `_direct` (read by the render task's buildBindings right after `bind()`\n * returns), and creates the per-binding state. The renderable then reads\n * `cullDrawBufs` for the compacted instance source and calls `binding.draw(...)`\n * for the indirect-vs-fallback draw call. Keeping these few seams tiny is what\n * lets non-culling scenes — which still fetch the per-material renderable\n * chunks — stay within their bundle-size ceilings. */\n\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { SceneContext } from \"../scene/scene.js\";\nimport type { DrawUpdateContext, Renderable } from \"../render/renderable.js\";\nimport type { Mesh } from \"./mesh.js\";\nimport type { ThinInstanceDrawBuffers } from \"./thin-instance-gpu.js\";\nimport { createTiCullState, destroyTiCullState, prepareTiCull } from \"./thin-instance-gpu-culling.js\";\n\n/** Per-binding cull lifecycle. The renderable's `bind()` obtains one from\n * `tryBind`, uses `update` as the binding's update, reads `cullDrawBufs` (the\n * compacted instance source) and calls `draw()` for the final draw call. */\nexport interface TiCullBinding {\n /** Run the binding's base update, then dispatch the compute cull pass and stash the result. */\n update(context: DrawUpdateContext): void;\n /** Compacted visible-instance buffers, or null to fall back to a full instanced draw. */\n cullDrawBufs: ThinInstanceDrawBuffers | null;\n /** @internal Indirect draw-args buffer (null until/unless culling ran this frame). */\n _args: GPUBuffer | null;\n /** Issue the indirect (culled) draw when visible instances were compacted, else a full instanced draw. */\n draw(pass: GPURenderPassEncoder | GPURenderBundleEncoder, indexCount: number, instanceCount: number): void;\n}\n\n/** Create a per-binding cull lifecycle for one thin-instanced renderable binding,\n * iff the mesh opts in and is not excluded (transparent / transmissive — v1 is\n * opaque-only). Marks the renderable `_direct` so it leaves the cached opaque\n * bundle; this is safe to do during `bind()` because buildBindings reads\n * `_direct` only after `bind()` returns. Returns undefined when culling does not\n * apply, so the caller falls back to a normal instanced draw. */\nexport function tryBind(\n renderable: Renderable,\n scene: SceneContext,\n mesh: Mesh,\n engine: EngineContext,\n hasColor: boolean,\n excluded: boolean,\n baseUpdate: ((context: DrawUpdateContext) => void) | undefined\n): TiCullBinding | undefined {\n const ti = mesh.thinInstances;\n if (excluded || !ti?._gpuCullingEnabled) {\n return undefined;\n }\n (renderable as { _direct?: boolean })._direct = true;\n const state = createTiCullState();\n scene._meshDisposables.get(mesh)?.push(() => {\n destroyTiCullState(state);\n });\n const binding: TiCullBinding = {\n cullDrawBufs: null,\n _args: null,\n update(context: DrawUpdateContext): void {\n baseUpdate?.(context);\n const res = prepareTiCull(engine, state, mesh, mesh._gpu, ti, hasColor, context);\n binding.cullDrawBufs = res?.drawBuffers ?? null;\n binding._args = res?.argsBuffer ?? null;\n },\n draw(pass: GPURenderPassEncoder | GPURenderBundleEncoder, indexCount: number, instanceCount: number): void {\n if (binding._args) {\n pass.drawIndexedIndirect(binding._args, 0);\n } else {\n pass.drawIndexed(indexCount, instanceCount);\n }\n },\n };\n return binding;\n}\n"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { p as packMat4IntoF32 } from "./index-B7Qhw0xL.js";
1
2
  function syncThinInstanceGpuData(engine, ti, hasColor) {
2
3
  var _a, _b;
3
4
  const device = engine._device;
@@ -9,7 +10,11 @@ function syncThinInstanceGpuData(engine, ti, hasColor) {
9
10
  (_a = ti._gpuBuffer) == null ? void 0 : _a.destroy();
10
11
  ti._gpuBuffer = device.createBuffer({
11
12
  size: Math.max(ti._capacity * 64, 4),
12
- usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST | (needsStorage ? GPUBufferUsage.STORAGE : 0)
13
+ // STORAGE is always included: the GPU picker binds this matrix
14
+ // buffer as a read-only storage buffer for thin-instance picking,
15
+ // so it must be storage-capable even when compute culling is off
16
+ // (otherwise the whole pick pass is invalidated → nothing is pickable).
17
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE
13
18
  });
14
19
  ti._gpuBufferStorage = needsStorage;
15
20
  bufferRecreated = true;
@@ -19,7 +24,19 @@ function syncThinInstanceGpuData(engine, ti, hasColor) {
19
24
  if (dirtyMax > dirtyMin) {
20
25
  const minByte = dirtyMin * 64;
21
26
  const maxByte = dirtyMax * 64;
22
- device.queue.writeBuffer(ti._gpuBuffer, minByte, ti.matrices.buffer, ti.matrices.byteOffset + minByte, maxByte - minByte);
27
+ if (ti.matrices instanceof Float32Array) {
28
+ device.queue.writeBuffer(ti._gpuBuffer, minByte, ti.matrices.buffer, ti.matrices.byteOffset + minByte, maxByte - minByte);
29
+ } else {
30
+ const neededFloats = ti._capacity * 16;
31
+ if (!ti._uploadF32 || ti._uploadF32.length < neededFloats) {
32
+ ti._uploadF32 = new Float32Array(neededFloats);
33
+ }
34
+ const upload = ti._uploadF32;
35
+ for (let i = dirtyMin; i < dirtyMax; i++) {
36
+ packMat4IntoF32(upload, ti.matrices, i * 16, i * 16);
37
+ }
38
+ device.queue.writeBuffer(ti._gpuBuffer, minByte, upload.buffer, upload.byteOffset + minByte, maxByte - minByte);
39
+ }
23
40
  }
24
41
  ti._dirtyMin = ti.count;
25
42
  ti._dirtyMax = 0;
@@ -59,4 +76,4 @@ export {
59
76
  syncThinInstanceBuffers,
60
77
  syncThinInstanceGpuData
61
78
  };
62
- //# sourceMappingURL=thin-instance-gpu-C9Gv_Z1w.js.map
79
+ //# sourceMappingURL=thin-instance-gpu-E8DBd8XL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thin-instance-gpu-E8DBd8XL.js","sources":["../src/mesh/thin-instance-gpu.ts"],"sourcesContent":["/** Thin instance GPU buffer sync — dynamically loaded only by scenes with thin instances.\n * Keeps the standard renderable chunk unchanged for scenes without thin instances. */\n\nimport type { ThinInstanceData } from \"./thin-instance.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport { packMat4IntoF32 } from \"../math/pack-mat4-into-f32.js\";\n\n/** @internal Optional replacement buffers used by GPU culling after it compacts visible instances. */\nexport interface ThinInstanceDrawBuffers {\n readonly matrixBuffer: GPUBuffer;\n readonly colorBuffer: GPUBuffer | null;\n}\n\n/** @internal Sync CPU thin-instance data to GPU buffers, optionally with STORAGE usage for compute culling. */\nexport function syncThinInstanceGpuData(engine: EngineContext, ti: ThinInstanceData, hasColor: boolean): void {\n const device = engine._device;\n const needsStorage = ti._gpuCullingEnabled;\n if (ti._version !== ti._gpuVersion || ti._gpuBufferStorage !== needsStorage) {\n const byteSize = ti.count * 64;\n let bufferRecreated = false;\n if (!ti._gpuBuffer || ti._gpuBuffer.size < byteSize || ti._gpuBufferStorage !== needsStorage) {\n ti._gpuBuffer?.destroy();\n ti._gpuBuffer = device.createBuffer({\n size: Math.max(ti._capacity * 64, 4),\n // STORAGE is always included: the GPU picker binds this matrix\n // buffer as a read-only storage buffer for thin-instance picking,\n // so it must be storage-capable even when compute culling is off\n // (otherwise the whole pick pass is invalidated → nothing is pickable).\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,\n });\n ti._gpuBufferStorage = needsStorage;\n bufferRecreated = true;\n }\n // Upload only the dirty range (or full range if buffer was just created)\n const dirtyMin = bufferRecreated ? 0 : ti._dirtyMin;\n const dirtyMax = bufferRecreated ? ti.count : Math.min(ti._dirtyMax, ti.count);\n if (dirtyMax > dirtyMin) {\n const minByte = dirtyMin * 64;\n const maxByte = dirtyMax * 64;\n if (ti.matrices instanceof Float32Array) {\n // Fast path: F32 source — direct byte copy, no per-instance pack.\n device.queue.writeBuffer(ti._gpuBuffer, minByte, ti.matrices.buffer, ti.matrices.byteOffset + minByte, maxByte - minByte);\n } else {\n // F64 source (HPM-on path) — pack each dirty instance into a\n // per-mesh reused F32 upload scratch, then writeBuffer the\n // dirty subrange. Scratch is sized to capacity in F32 floats\n // and grown when capacity grows; never per-frame allocated.\n const neededFloats = ti._capacity * 16;\n if (!ti._uploadF32 || ti._uploadF32.length < neededFloats) {\n ti._uploadF32 = new Float32Array(neededFloats);\n }\n const upload = ti._uploadF32;\n for (let i = dirtyMin; i < dirtyMax; i++) {\n packMat4IntoF32(upload, ti.matrices, i * 16, i * 16);\n }\n device.queue.writeBuffer(ti._gpuBuffer, minByte, upload.buffer, upload.byteOffset + minByte, maxByte - minByte);\n }\n }\n ti._dirtyMin = ti.count;\n ti._dirtyMax = 0;\n ti._gpuVersion = ti._version;\n }\n\n if (hasColor && ti.colors) {\n if (ti._colorVersion !== ti._colorGpuVersion || ti._colorGpuBufferStorage !== needsStorage) {\n const colorByteSize = ti.count * 16;\n if (!ti._colorGpuBuffer || ti._colorGpuBuffer.size < colorByteSize || ti._colorGpuBufferStorage !== needsStorage) {\n ti._colorGpuBuffer?.destroy();\n ti._colorGpuBuffer = device.createBuffer({\n size: Math.max(ti._capacity * 16, 4),\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST | (needsStorage ? GPUBufferUsage.STORAGE : 0),\n });\n ti._colorGpuBufferStorage = needsStorage;\n }\n device.queue.writeBuffer(ti._colorGpuBuffer, 0, ti.colors.buffer, ti.colors.byteOffset, colorByteSize);\n ti._colorGpuVersion = ti._colorVersion;\n }\n }\n}\n\n/** Sync thin instance matrix + optional color GPU buffers and bind to vertex slots. */\nexport function syncThinInstanceBuffers(\n engine: EngineContext,\n ti: ThinInstanceData,\n pass: GPURenderPassEncoder | GPURenderBundleEncoder,\n slot: number,\n hasColor: boolean,\n drawBuffers?: ThinInstanceDrawBuffers | null\n): number {\n syncThinInstanceGpuData(engine, ti, hasColor);\n const matrixBuffer = drawBuffers?.matrixBuffer ?? ti._gpuBuffer;\n if (matrixBuffer) {\n pass.setVertexBuffer(slot++, matrixBuffer);\n }\n\n if (hasColor) {\n const colorBuffer = drawBuffers?.colorBuffer ?? ti._colorGpuBuffer;\n if (colorBuffer) {\n pass.setVertexBuffer(slot++, colorBuffer);\n }\n }\n\n return slot;\n}\n"],"names":[],"mappings":";AAcO,SAAS,wBAAwB,QAAuB,IAAsB,UAAyB;;AAC1G,QAAM,SAAS,OAAO;AACtB,QAAM,eAAe,GAAG;AACxB,MAAI,GAAG,aAAa,GAAG,eAAe,GAAG,sBAAsB,cAAc;AACzE,UAAM,WAAW,GAAG,QAAQ;AAC5B,QAAI,kBAAkB;AACtB,QAAI,CAAC,GAAG,cAAc,GAAG,WAAW,OAAO,YAAY,GAAG,sBAAsB,cAAc;AAC1F,eAAG,eAAH,mBAAe;AACf,SAAG,aAAa,OAAO,aAAa;AAAA,QAChC,MAAM,KAAK,IAAI,GAAG,YAAY,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,QAKnC,OAAO,eAAe,SAAS,eAAe,WAAW,eAAe;AAAA,MAAA,CAC3E;AACD,SAAG,oBAAoB;AACvB,wBAAkB;AAAA,IACtB;AAEA,UAAM,WAAW,kBAAkB,IAAI,GAAG;AAC1C,UAAM,WAAW,kBAAkB,GAAG,QAAQ,KAAK,IAAI,GAAG,WAAW,GAAG,KAAK;AAC7E,QAAI,WAAW,UAAU;AACrB,YAAM,UAAU,WAAW;AAC3B,YAAM,UAAU,WAAW;AAC3B,UAAI,GAAG,oBAAoB,cAAc;AAErC,eAAO,MAAM,YAAY,GAAG,YAAY,SAAS,GAAG,SAAS,QAAQ,GAAG,SAAS,aAAa,SAAS,UAAU,OAAO;AAAA,MAC5H,OAAO;AAKH,cAAM,eAAe,GAAG,YAAY;AACpC,YAAI,CAAC,GAAG,cAAc,GAAG,WAAW,SAAS,cAAc;AACvD,aAAG,aAAa,IAAI,aAAa,YAAY;AAAA,QACjD;AACA,cAAM,SAAS,GAAG;AAClB,iBAAS,IAAI,UAAU,IAAI,UAAU,KAAK;AACtC,0BAAgB,QAAQ,GAAG,UAAU,IAAI,IAAI,IAAI,EAAE;AAAA,QACvD;AACA,eAAO,MAAM,YAAY,GAAG,YAAY,SAAS,OAAO,QAAQ,OAAO,aAAa,SAAS,UAAU,OAAO;AAAA,MAClH;AAAA,IACJ;AACA,OAAG,YAAY,GAAG;AAClB,OAAG,YAAY;AACf,OAAG,cAAc,GAAG;AAAA,EACxB;AAEA,MAAI,YAAY,GAAG,QAAQ;AACvB,QAAI,GAAG,kBAAkB,GAAG,oBAAoB,GAAG,2BAA2B,cAAc;AACxF,YAAM,gBAAgB,GAAG,QAAQ;AACjC,UAAI,CAAC,GAAG,mBAAmB,GAAG,gBAAgB,OAAO,iBAAiB,GAAG,2BAA2B,cAAc;AAC9G,iBAAG,oBAAH,mBAAoB;AACpB,WAAG,kBAAkB,OAAO,aAAa;AAAA,UACrC,MAAM,KAAK,IAAI,GAAG,YAAY,IAAI,CAAC;AAAA,UACnC,OAAO,eAAe,SAAS,eAAe,YAAY,eAAe,eAAe,UAAU;AAAA,QAAA,CACrG;AACD,WAAG,yBAAyB;AAAA,MAChC;AACA,aAAO,MAAM,YAAY,GAAG,iBAAiB,GAAG,GAAG,OAAO,QAAQ,GAAG,OAAO,YAAY,aAAa;AACrG,SAAG,mBAAmB,GAAG;AAAA,IAC7B;AAAA,EACJ;AACJ;AAGO,SAAS,wBACZ,QACA,IACA,MACA,MACA,UACA,aACM;AACN,0BAAwB,QAAQ,IAAI,QAAQ;AAC5C,QAAM,gBAAe,2CAAa,iBAAgB,GAAG;AACrD,MAAI,cAAc;AACd,SAAK,gBAAgB,QAAQ,YAAY;AAAA,EAC7C;AAEA,MAAI,UAAU;AACV,UAAM,eAAc,2CAAa,gBAAe,GAAG;AACnD,QAAI,aAAa;AACb,WAAK,gBAAgB,QAAQ,WAAW;AAAA,IAC5C;AAAA,EACJ;AAEA,SAAO;AACX;"}
@@ -1,4 +1,4 @@
1
- import { m as markMaterialUboDirty } from "./index-C8HOR2sB.js";
1
+ import { m as markMaterialUboDirty } from "./index-B7Qhw0xL.js";
2
2
  function observableColor3(r, g, b, owner) {
3
3
  const arr = [r, g, b];
4
4
  for (let i = 0; i < 3; i++) {
@@ -79,4 +79,4 @@ export {
79
79
  observableColor3 as o,
80
80
  trackScalar as t
81
81
  };
82
- //# sourceMappingURL=tracking-primitives-wgdBY85t.js.map
82
+ //# sourceMappingURL=tracking-primitives-w4BVV9p9.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tracking-primitives-wgdBY85t.js","sources":["../src/material/tracking/tracking-primitives.ts"],"sourcesContent":["/** Shared tracking primitives for observable material properties. */\n\nimport type { Material } from \"../material.js\";\nimport { markMaterialUboDirty } from \"../material-dirty.js\";\n\nexport function observableColor3(r: number, g: number, b: number, owner: Material): [number, number, number] {\n const arr = [r, g, b] as [number, number, number];\n for (let i = 0; i < 3; i++) {\n let val = arr[i]!;\n Object.defineProperty(arr, i, {\n get() {\n return val;\n },\n set(v: number) {\n if (val !== v) {\n val = v;\n markMaterialUboDirty(owner);\n }\n },\n configurable: true,\n enumerable: true,\n });\n }\n return arr;\n}\n\nexport function observableVec2(x: number, y: number, owner: Material): [number, number] {\n const arr = [x, y] as [number, number];\n for (let i = 0; i < 2; i++) {\n let val = arr[i]!;\n Object.defineProperty(arr, i, {\n get() {\n return val;\n },\n set(v: number) {\n if (val !== v) {\n val = v;\n markMaterialUboDirty(owner);\n }\n },\n configurable: true,\n enumerable: true,\n });\n }\n return arr;\n}\n\nexport function trackScalar(obj: any, key: string): void {\n let val = obj[key];\n Object.defineProperty(obj, key, {\n get() {\n return val;\n },\n set(v: any) {\n if (val !== v) {\n val = v;\n markMaterialUboDirty(obj as Material);\n }\n },\n configurable: true,\n enumerable: true,\n });\n}\n\nexport function trackSubProps(parent: Material, sub: any, keys: string[]): void {\n for (const key of keys) {\n let val = sub[key];\n Object.defineProperty(sub, key, {\n get() {\n return val;\n },\n set(v: any) {\n if (val !== v) {\n val = v;\n markMaterialUboDirty(parent);\n }\n },\n configurable: true,\n enumerable: true,\n });\n }\n}\n"],"names":[],"mappings":";AAKO,SAAS,iBAAiB,GAAW,GAAW,GAAW,OAA2C;AACzG,QAAM,MAAM,CAAC,GAAG,GAAG,CAAC;AACpB,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AACxB,QAAI,MAAM,IAAI,CAAC;AACf,WAAO,eAAe,KAAK,GAAG;AAAA,MAC1B,MAAM;AACF,eAAO;AAAA,MACX;AAAA,MACA,IAAI,GAAW;AACX,YAAI,QAAQ,GAAG;AACX,gBAAM;AACN,+BAAqB,KAAK;AAAA,QAC9B;AAAA,MACJ;AAAA,MACA,cAAc;AAAA,MACd,YAAY;AAAA,IAAA,CACf;AAAA,EACL;AACA,SAAO;AACX;AAEO,SAAS,eAAe,GAAW,GAAW,OAAmC;AACpF,QAAM,MAAM,CAAC,GAAG,CAAC;AACjB,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AACxB,QAAI,MAAM,IAAI,CAAC;AACf,WAAO,eAAe,KAAK,GAAG;AAAA,MAC1B,MAAM;AACF,eAAO;AAAA,MACX;AAAA,MACA,IAAI,GAAW;AACX,YAAI,QAAQ,GAAG;AACX,gBAAM;AACN,+BAAqB,KAAK;AAAA,QAC9B;AAAA,MACJ;AAAA,MACA,cAAc;AAAA,MACd,YAAY;AAAA,IAAA,CACf;AAAA,EACL;AACA,SAAO;AACX;AAEO,SAAS,YAAY,KAAU,KAAmB;AACrD,MAAI,MAAM,IAAI,GAAG;AACjB,SAAO,eAAe,KAAK,KAAK;AAAA,IAC5B,MAAM;AACF,aAAO;AAAA,IACX;AAAA,IACA,IAAI,GAAQ;AACR,UAAI,QAAQ,GAAG;AACX,cAAM;AACN,6BAAqB,GAAe;AAAA,MACxC;AAAA,IACJ;AAAA,IACA,cAAc;AAAA,IACd,YAAY;AAAA,EAAA,CACf;AACL;AAEO,SAAS,cAAc,QAAkB,KAAU,MAAsB;AAC5E,aAAW,OAAO,MAAM;AACpB,QAAI,MAAM,IAAI,GAAG;AACjB,WAAO,eAAe,KAAK,KAAK;AAAA,MAC5B,MAAM;AACF,eAAO;AAAA,MACX;AAAA,MACA,IAAI,GAAQ;AACR,YAAI,QAAQ,GAAG;AACX,gBAAM;AACN,+BAAqB,MAAM;AAAA,QAC/B;AAAA,MACJ;AAAA,MACA,cAAc;AAAA,MACd,YAAY;AAAA,IAAA,CACf;AAAA,EACL;AACJ;"}
1
+ {"version":3,"file":"tracking-primitives-w4BVV9p9.js","sources":["../src/material/tracking/tracking-primitives.ts"],"sourcesContent":["/** Shared tracking primitives for observable material properties. */\n\nimport type { Material } from \"../material.js\";\nimport { markMaterialUboDirty } from \"../material-dirty.js\";\n\nexport function observableColor3(r: number, g: number, b: number, owner: Material): [number, number, number] {\n const arr = [r, g, b] as [number, number, number];\n for (let i = 0; i < 3; i++) {\n let val = arr[i]!;\n Object.defineProperty(arr, i, {\n get() {\n return val;\n },\n set(v: number) {\n if (val !== v) {\n val = v;\n markMaterialUboDirty(owner);\n }\n },\n configurable: true,\n enumerable: true,\n });\n }\n return arr;\n}\n\nexport function observableVec2(x: number, y: number, owner: Material): [number, number] {\n const arr = [x, y] as [number, number];\n for (let i = 0; i < 2; i++) {\n let val = arr[i]!;\n Object.defineProperty(arr, i, {\n get() {\n return val;\n },\n set(v: number) {\n if (val !== v) {\n val = v;\n markMaterialUboDirty(owner);\n }\n },\n configurable: true,\n enumerable: true,\n });\n }\n return arr;\n}\n\nexport function trackScalar(obj: any, key: string): void {\n let val = obj[key];\n Object.defineProperty(obj, key, {\n get() {\n return val;\n },\n set(v: any) {\n if (val !== v) {\n val = v;\n markMaterialUboDirty(obj as Material);\n }\n },\n configurable: true,\n enumerable: true,\n });\n}\n\nexport function trackSubProps(parent: Material, sub: any, keys: string[]): void {\n for (const key of keys) {\n let val = sub[key];\n Object.defineProperty(sub, key, {\n get() {\n return val;\n },\n set(v: any) {\n if (val !== v) {\n val = v;\n markMaterialUboDirty(parent);\n }\n },\n configurable: true,\n enumerable: true,\n });\n }\n}\n"],"names":[],"mappings":";AAKO,SAAS,iBAAiB,GAAW,GAAW,GAAW,OAA2C;AACzG,QAAM,MAAM,CAAC,GAAG,GAAG,CAAC;AACpB,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AACxB,QAAI,MAAM,IAAI,CAAC;AACf,WAAO,eAAe,KAAK,GAAG;AAAA,MAC1B,MAAM;AACF,eAAO;AAAA,MACX;AAAA,MACA,IAAI,GAAW;AACX,YAAI,QAAQ,GAAG;AACX,gBAAM;AACN,+BAAqB,KAAK;AAAA,QAC9B;AAAA,MACJ;AAAA,MACA,cAAc;AAAA,MACd,YAAY;AAAA,IAAA,CACf;AAAA,EACL;AACA,SAAO;AACX;AAEO,SAAS,eAAe,GAAW,GAAW,OAAmC;AACpF,QAAM,MAAM,CAAC,GAAG,CAAC;AACjB,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AACxB,QAAI,MAAM,IAAI,CAAC;AACf,WAAO,eAAe,KAAK,GAAG;AAAA,MAC1B,MAAM;AACF,eAAO;AAAA,MACX;AAAA,MACA,IAAI,GAAW;AACX,YAAI,QAAQ,GAAG;AACX,gBAAM;AACN,+BAAqB,KAAK;AAAA,QAC9B;AAAA,MACJ;AAAA,MACA,cAAc;AAAA,MACd,YAAY;AAAA,IAAA,CACf;AAAA,EACL;AACA,SAAO;AACX;AAEO,SAAS,YAAY,KAAU,KAAmB;AACrD,MAAI,MAAM,IAAI,GAAG;AACjB,SAAO,eAAe,KAAK,KAAK;AAAA,IAC5B,MAAM;AACF,aAAO;AAAA,IACX;AAAA,IACA,IAAI,GAAQ;AACR,UAAI,QAAQ,GAAG;AACX,cAAM;AACN,6BAAqB,GAAe;AAAA,MACxC;AAAA,IACJ;AAAA,IACA,cAAc;AAAA,IACd,YAAY;AAAA,EAAA,CACf;AACL;AAEO,SAAS,cAAc,QAAkB,KAAU,MAAsB;AAC5E,aAAW,OAAO,MAAM;AACpB,QAAI,MAAM,IAAI,GAAG;AACjB,WAAO,eAAe,KAAK,KAAK;AAAA,MAC5B,MAAM;AACF,eAAO;AAAA,MACX;AAAA,MACA,IAAI,GAAQ;AACR,YAAI,QAAQ,GAAG;AACX,gBAAM;AACN,+BAAqB,MAAM;AAAA,QAC/B;AAAA,MACJ;AAAA,MACA,cAAc;AAAA,MACd,YAAY;AAAA,IAAA,CACf;AAAA,EACL;AACJ;"}
@@ -1,4 +1,4 @@
1
- import { aM as PBR2_HAS_UNLIT } from "./index-C8HOR2sB.js";
1
+ import { aA as PBR2_HAS_UNLIT } from "./index-B7Qhw0xL.js";
2
2
  function createUnlitFragment(hasIbl) {
3
3
  const assign = `color = baseColor * material.unlitColor;`;
4
4
  return {
@@ -40,4 +40,4 @@ export {
40
40
  pbrExt,
41
41
  writeUnlitUBO
42
42
  };
43
- //# sourceMappingURL=unlit-fragment-BIlhJpz6.js.map
43
+ //# sourceMappingURL=unlit-fragment-DU9_mhzZ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"unlit-fragment-BIlhJpz6.js","sources":["../src/material/pbr/fragments/unlit-fragment.ts"],"sourcesContent":["/**\n * Unlit Fragment (KHR_materials_unlit).\n *\n * Replaces the lit-color computation with `baseColor * unlitColor` right\n * before the tonemap/gamma/contrast chain runs. Depends on the IBL fragment\n * when present so our AI injection runs *after* IBL's, overwriting the IBL\n * color contribution. The subsequent tonemap/gamma/contrast stages still\n * apply, matching BJS's unlit output under `createDefaultEnvironment`.\n *\n * Zero bytes in bundles for scenes that don't use unlit materials.\n */\n\nimport type { ShaderFragment } from \"../../../shader/fragment-types.js\";\nimport type { PbrMaterialProps } from \"../pbr-material.js\";\nimport type { PbrExt } from \"../pbr-flags.js\";\nimport { PBR2_HAS_UNLIT } from \"../pbr-flag-bits.js\";\n\nexport function createUnlitFragment(hasIbl: boolean): ShaderFragment {\n const assign = `color = baseColor * material.unlitColor;`;\n return {\n _id: \"unlit\",\n _dependencies: hasIbl ? [\"ibl\"] : undefined,\n _uboFields: [\n { _name: \"unlitColor\", _type: \"vec3<f32>\" },\n { _name: \"_unlitColorPad\", _type: \"f32\" },\n ],\n _fragmentSlots: hasIbl ? { AI: assign } : { NI: assign },\n };\n}\n\n/** Write the unlit material-UBO slice. */\nexport function writeUnlitUBO(data: Float32Array, material: PbrMaterialProps, offsets: ReadonlyMap<string, number>): void {\n if (!material.unlit || !offsets.has(\"unlitColor\")) {\n return;\n }\n const off = offsets.get(\"unlitColor\")! / 4;\n const tint = material.unlitColor ?? [1, 1, 1];\n data[off] = tint[0]!;\n data[off + 1] = tint[1]!;\n data[off + 2] = tint[2]!;\n}\n\nexport const pbrExt: PbrExt = {\n id: \"unlit\",\n phase: \"fragment\",\n detect(mat) {\n return (mat as PbrMaterialProps).unlit ? { f: 0, f2: PBR2_HAS_UNLIT } : { f: 0, f2: 0 };\n },\n frag(ctx) {\n if (!(ctx._features2 & PBR2_HAS_UNLIT)) {\n return null;\n }\n return createUnlitFragment(ctx._hasIbl);\n },\n writeUbo: writeUnlitUBO as PbrExt[\"writeUbo\"],\n};\n"],"names":[],"mappings":";AAiBO,SAAS,oBAAoB,QAAiC;AACjE,QAAM,SAAS;AACf,SAAO;AAAA,IACH,KAAK;AAAA,IACL,eAAe,SAAS,CAAC,KAAK,IAAI;AAAA,IAClC,YAAY;AAAA,MACR,EAAE,OAAO,cAAc,OAAO,YAAA;AAAA,MAC9B,EAAE,OAAO,kBAAkB,OAAO,MAAA;AAAA,IAAM;AAAA,IAE5C,gBAAgB,SAAS,EAAE,IAAI,WAAW,EAAE,IAAI,OAAA;AAAA,EAAO;AAE/D;AAGO,SAAS,cAAc,MAAoB,UAA4B,SAA4C;AACtH,MAAI,CAAC,SAAS,SAAS,CAAC,QAAQ,IAAI,YAAY,GAAG;AAC/C;AAAA,EACJ;AACA,QAAM,MAAM,QAAQ,IAAI,YAAY,IAAK;AACzC,QAAM,OAAO,SAAS,cAAc,CAAC,GAAG,GAAG,CAAC;AAC5C,OAAK,GAAG,IAAI,KAAK,CAAC;AAClB,OAAK,MAAM,CAAC,IAAI,KAAK,CAAC;AACtB,OAAK,MAAM,CAAC,IAAI,KAAK,CAAC;AAC1B;AAEO,MAAM,SAAiB;AAAA,EAC1B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,OAAO,KAAK;AACR,WAAQ,IAAyB,QAAQ,EAAE,GAAG,GAAG,IAAI,eAAA,IAAmB,EAAE,GAAG,GAAG,IAAI,EAAA;AAAA,EACxF;AAAA,EACA,KAAK,KAAK;AACN,QAAI,EAAE,IAAI,aAAa,iBAAiB;AACpC,aAAO;AAAA,IACX;AACA,WAAO,oBAAoB,IAAI,OAAO;AAAA,EAC1C;AAAA,EACA,UAAU;AACd;"}
1
+ {"version":3,"file":"unlit-fragment-DU9_mhzZ.js","sources":["../src/material/pbr/fragments/unlit-fragment.ts"],"sourcesContent":["/**\n * Unlit Fragment (KHR_materials_unlit).\n *\n * Replaces the lit-color computation with `baseColor * unlitColor` right\n * before the tonemap/gamma/contrast chain runs. Depends on the IBL fragment\n * when present so our AI injection runs *after* IBL's, overwriting the IBL\n * color contribution. The subsequent tonemap/gamma/contrast stages still\n * apply, matching BJS's unlit output under `createDefaultEnvironment`.\n *\n * Zero bytes in bundles for scenes that don't use unlit materials.\n */\n\nimport type { ShaderFragment } from \"../../../shader/fragment-types.js\";\nimport type { PbrMaterialProps } from \"../pbr-material.js\";\nimport type { PbrExt } from \"../pbr-flags.js\";\nimport { PBR2_HAS_UNLIT } from \"../pbr-flag-bits.js\";\n\nexport function createUnlitFragment(hasIbl: boolean): ShaderFragment {\n const assign = `color = baseColor * material.unlitColor;`;\n return {\n _id: \"unlit\",\n _dependencies: hasIbl ? [\"ibl\"] : undefined,\n _uboFields: [\n { _name: \"unlitColor\", _type: \"vec3<f32>\" },\n { _name: \"_unlitColorPad\", _type: \"f32\" },\n ],\n _fragmentSlots: hasIbl ? { AI: assign } : { NI: assign },\n };\n}\n\n/** Write the unlit material-UBO slice. */\nexport function writeUnlitUBO(data: Float32Array, material: PbrMaterialProps, offsets: ReadonlyMap<string, number>): void {\n if (!material.unlit || !offsets.has(\"unlitColor\")) {\n return;\n }\n const off = offsets.get(\"unlitColor\")! / 4;\n const tint = material.unlitColor ?? [1, 1, 1];\n data[off] = tint[0]!;\n data[off + 1] = tint[1]!;\n data[off + 2] = tint[2]!;\n}\n\nexport const pbrExt: PbrExt = {\n id: \"unlit\",\n phase: \"fragment\",\n detect(mat) {\n return (mat as PbrMaterialProps).unlit ? { f: 0, f2: PBR2_HAS_UNLIT } : { f: 0, f2: 0 };\n },\n frag(ctx) {\n if (!(ctx._features2 & PBR2_HAS_UNLIT)) {\n return null;\n }\n return createUnlitFragment(ctx._hasIbl);\n },\n writeUbo: writeUnlitUBO as PbrExt[\"writeUbo\"],\n};\n"],"names":[],"mappings":";AAiBO,SAAS,oBAAoB,QAAiC;AACjE,QAAM,SAAS;AACf,SAAO;AAAA,IACH,KAAK;AAAA,IACL,eAAe,SAAS,CAAC,KAAK,IAAI;AAAA,IAClC,YAAY;AAAA,MACR,EAAE,OAAO,cAAc,OAAO,YAAA;AAAA,MAC9B,EAAE,OAAO,kBAAkB,OAAO,MAAA;AAAA,IAAM;AAAA,IAE5C,gBAAgB,SAAS,EAAE,IAAI,WAAW,EAAE,IAAI,OAAA;AAAA,EAAO;AAE/D;AAGO,SAAS,cAAc,MAAoB,UAA4B,SAA4C;AACtH,MAAI,CAAC,SAAS,SAAS,CAAC,QAAQ,IAAI,YAAY,GAAG;AAC/C;AAAA,EACJ;AACA,QAAM,MAAM,QAAQ,IAAI,YAAY,IAAK;AACzC,QAAM,OAAO,SAAS,cAAc,CAAC,GAAG,GAAG,CAAC;AAC5C,OAAK,GAAG,IAAI,KAAK,CAAC;AAClB,OAAK,MAAM,CAAC,IAAI,KAAK,CAAC;AACtB,OAAK,MAAM,CAAC,IAAI,KAAK,CAAC;AAC1B;AAEO,MAAM,SAAiB;AAAA,EAC1B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,OAAO,KAAK;AACR,WAAQ,IAAyB,QAAQ,EAAE,GAAG,GAAG,IAAI,eAAA,IAAmB,EAAE,GAAG,GAAG,IAAI,EAAA;AAAA,EACxF;AAAA,EACA,KAAK,KAAK;AACN,QAAI,EAAE,IAAI,aAAa,iBAAiB;AACpC,aAAO;AAAA,IACX;AACA,WAAO,oBAAoB,IAAI,OAAO;AAAA,EAC1C;AAAA,EACA,UAAU;AACd;"}
@@ -41,8 +41,8 @@ return mix(-normVariance, normVariance, rand);
41
41
  const WGSL_NO_DITHER = "fn dither(a:vec2<f32>,b:f32)->f32{return 0.0;}";
42
42
  export {
43
43
  WGSL_PERTURB_NORMAL as W,
44
- WGSL_DITHER as a,
45
- WGSL_NO_DITHER as b,
46
- WGSL_FOG as c
44
+ WGSL_FOG as a,
45
+ WGSL_DITHER as b,
46
+ WGSL_NO_DITHER as c
47
47
  };
48
- //# sourceMappingURL=wgsl-helpers-DyzNzCeE.js.map
48
+ //# sourceMappingURL=wgsl-helpers-D8sl1VVA.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"wgsl-helpers-DyzNzCeE.js","sources":["../src/shader/wgsl-helpers.ts"],"sourcesContent":["/** Shared WGSL helper snippets used by both PBR and Standard material systems.\n *\n * These are pure WGSL function strings — no bindings, no UBO declarations.\n * Each material system wraps them with its own binding declarations. */\n\n/** Cotangent-frame bump mapping.\n * Requires: `bT` (texture_2d) and `bS` (sampler) in scope. */\nexport const WGSL_PERTURB_NORMAL = `\nfn perturbNormal(vNormalW: vec3<f32>, positionW: vec3<f32>, uv: vec2<f32>, bumpScale: f32) -> vec3<f32> {\nlet normalSample = textureSample(bT, bS, uv).rgb * 2.0 - 1.0;\nlet N = normalize(vNormalW) * bumpScale;\nlet dp1 = dpdx(positionW);\nlet dp2 = -dpdy(positionW);\nlet duv1 = dpdx(uv);\nlet duv2 = -dpdy(uv);\nlet dp2perp = cross(dp2, N);\nlet dp1perp = cross(N, dp1);\nvar tangent = dp2perp * duv1.x + dp1perp * duv2.x;\nvar bitangent = dp2perp * duv1.y + dp1perp * duv2.y;\nlet det = max(dot(tangent, tangent), dot(bitangent, bitangent));\nlet invmax = select(inverseSqrt(det), 0.0, det == 0.0);\nlet cotangentFrame = mat3x3<f32>(tangent * invmax, bitangent * invmax, N);\nreturn normalize(cotangentFrame * normalSample);\n}\n`;\n\n/** ESM shadow helper functions.\n * Requires: `shadowTex` (texture_2d), `shadowSampler` (sampler) in scope. */\nexport const WGSL_SHADOW_ESM = `\nfn computeFallOff(value: f32, clipSpace: vec2<f32>, frustumEdgeFalloff: f32) -> f32 {\nlet mask = smoothstep(1.0 - frustumEdgeFalloff, 1.00000012, clamp(dot(clipSpace, clipSpace), 0.0, 1.0));\nreturn mix(value, 1.0, mask);\n}\nfn computeShadowWithESM(posFromLight: vec4<f32>, depthMetric: f32, darkness: f32, depthScale: f32, frustumEdgeFalloff: f32) -> f32 {\nlet clipSpace = posFromLight.xyz / posFromLight.w;\nlet uv = vec2<f32>(0.5 * clipSpace.x + 0.5, 0.5 - 0.5 * clipSpace.y);\nif (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) { return 1.0; }\nlet shadowPixelDepth = clamp(depthMetric, 0.0, 1.0);\nlet shadowMapSample = textureSampleLevel(shadowTex, shadowSampler, uv, 0.0).x;\nlet esm = 1.0 - clamp(exp(min(87.0, depthScale * shadowPixelDepth)) * shadowMapSample, 0.0, 1.0 - darkness);\nreturn computeFallOff(esm, clipSpace.xy, frustumEdgeFalloff);\n}\n`;\n\n/** Fog calculation helper.\n * Requires: `scene.vFogInfos` (vec4) in scope. */\nexport const WGSL_FOG = `\nconst E_FOG: f32 = 2.71828;\nfn calcFogFactor(fogDistance: vec3<f32>) -> f32 {\nvar fogCoeff: f32 = 1.0;\nlet fogMode = scene.vFogInfos.x;\nlet fogStart = scene.vFogInfos.y;\nlet fogEnd = scene.vFogInfos.z;\nlet fogDensity = scene.vFogInfos.w;\nlet dist = length(fogDistance);\nif (fogMode == 3.0) { fogCoeff = (fogEnd - dist) / (fogEnd - fogStart); }\nelse if (fogMode == 1.0) { fogCoeff = 1.0 / pow(E_FOG, dist * fogDensity); }\nelse if (fogMode == 2.0) { fogCoeff = 1.0 / pow(E_FOG, dist * dist * fogDensity * fogDensity); }\nreturn clamp(fogCoeff, 0.0, 1.0);\n}\n`;\n\n/** Dither noise function.\n * Pure math — no UBO dependency. */\nexport const WGSL_DITHER = `\nfn dither(seed: vec2<f32>, varianceAmount: f32) -> f32 {\nlet rand = fract(sin(dot(seed, vec2<f32>(12.9898, 78.233))) * 43758.5453);\nlet normVariance = varianceAmount / 255.0;\nreturn mix(-normVariance, normVariance, rand);\n}\n`;\n\n/** Noise-disabled replacement for shaders that still call dither(). */\nexport const WGSL_NO_DITHER = \"fn dither(a:vec2<f32>,b:f32)->f32{return 0.0;}\";\n"],"names":[],"mappings":"AAOO,MAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuC5B,MAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBjB,MAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASpB,MAAM,iBAAiB;"}
1
+ {"version":3,"file":"wgsl-helpers-D8sl1VVA.js","sources":["../src/shader/wgsl-helpers.ts"],"sourcesContent":["/** Shared WGSL helper snippets used by both PBR and Standard material systems.\n *\n * These are pure WGSL function strings — no bindings, no UBO declarations.\n * Each material system wraps them with its own binding declarations. */\n\n/** Cotangent-frame bump mapping.\n * Requires: `bT` (texture_2d) and `bS` (sampler) in scope. */\nexport const WGSL_PERTURB_NORMAL = `\nfn perturbNormal(vNormalW: vec3<f32>, positionW: vec3<f32>, uv: vec2<f32>, bumpScale: f32) -> vec3<f32> {\nlet normalSample = textureSample(bT, bS, uv).rgb * 2.0 - 1.0;\nlet N = normalize(vNormalW) * bumpScale;\nlet dp1 = dpdx(positionW);\nlet dp2 = -dpdy(positionW);\nlet duv1 = dpdx(uv);\nlet duv2 = -dpdy(uv);\nlet dp2perp = cross(dp2, N);\nlet dp1perp = cross(N, dp1);\nvar tangent = dp2perp * duv1.x + dp1perp * duv2.x;\nvar bitangent = dp2perp * duv1.y + dp1perp * duv2.y;\nlet det = max(dot(tangent, tangent), dot(bitangent, bitangent));\nlet invmax = select(inverseSqrt(det), 0.0, det == 0.0);\nlet cotangentFrame = mat3x3<f32>(tangent * invmax, bitangent * invmax, N);\nreturn normalize(cotangentFrame * normalSample);\n}\n`;\n\n/** ESM shadow helper functions.\n * Requires: `shadowTex` (texture_2d), `shadowSampler` (sampler) in scope. */\nexport const WGSL_SHADOW_ESM = `\nfn computeFallOff(value: f32, clipSpace: vec2<f32>, frustumEdgeFalloff: f32) -> f32 {\nlet mask = smoothstep(1.0 - frustumEdgeFalloff, 1.00000012, clamp(dot(clipSpace, clipSpace), 0.0, 1.0));\nreturn mix(value, 1.0, mask);\n}\nfn computeShadowWithESM(posFromLight: vec4<f32>, depthMetric: f32, darkness: f32, depthScale: f32, frustumEdgeFalloff: f32) -> f32 {\nlet clipSpace = posFromLight.xyz / posFromLight.w;\nlet uv = vec2<f32>(0.5 * clipSpace.x + 0.5, 0.5 - 0.5 * clipSpace.y);\nif (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) { return 1.0; }\nlet shadowPixelDepth = clamp(depthMetric, 0.0, 1.0);\nlet shadowMapSample = textureSampleLevel(shadowTex, shadowSampler, uv, 0.0).x;\nlet esm = 1.0 - clamp(exp(min(87.0, depthScale * shadowPixelDepth)) * shadowMapSample, 0.0, 1.0 - darkness);\nreturn computeFallOff(esm, clipSpace.xy, frustumEdgeFalloff);\n}\n`;\n\n/** Fog calculation helper.\n * Requires: `scene.vFogInfos` (vec4) in scope. */\nexport const WGSL_FOG = `\nconst E_FOG: f32 = 2.71828;\nfn calcFogFactor(fogDistance: vec3<f32>) -> f32 {\nvar fogCoeff: f32 = 1.0;\nlet fogMode = scene.vFogInfos.x;\nlet fogStart = scene.vFogInfos.y;\nlet fogEnd = scene.vFogInfos.z;\nlet fogDensity = scene.vFogInfos.w;\nlet dist = length(fogDistance);\nif (fogMode == 3.0) { fogCoeff = (fogEnd - dist) / (fogEnd - fogStart); }\nelse if (fogMode == 1.0) { fogCoeff = 1.0 / pow(E_FOG, dist * fogDensity); }\nelse if (fogMode == 2.0) { fogCoeff = 1.0 / pow(E_FOG, dist * dist * fogDensity * fogDensity); }\nreturn clamp(fogCoeff, 0.0, 1.0);\n}\n`;\n\n/** Dither noise function.\n * Pure math — no UBO dependency. */\nexport const WGSL_DITHER = `\nfn dither(seed: vec2<f32>, varianceAmount: f32) -> f32 {\nlet rand = fract(sin(dot(seed, vec2<f32>(12.9898, 78.233))) * 43758.5453);\nlet normVariance = varianceAmount / 255.0;\nreturn mix(-normVariance, normVariance, rand);\n}\n`;\n\n/** Noise-disabled replacement for shaders that still call dither(). */\nexport const WGSL_NO_DITHER = \"fn dither(a:vec2<f32>,b:f32)->f32{return 0.0;}\";\n"],"names":[],"mappings":"AAOO,MAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuC5B,MAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBjB,MAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASpB,MAAM,iBAAiB;"}