@babylonjs/lite 1.0.0 → 1.1.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 (219) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +51 -0
  3. package/THIRD_PARTY_NOTICES.txt +318 -0
  4. package/{_mat4-storage-f64-CjDoht2w.js → _mat4-storage-f64-WeexU-hd.js} +2 -2
  5. package/{_mat4-storage-f64-CjDoht2w.js.map → _mat4-storage-f64-WeexU-hd.js.map} +1 -1
  6. package/{alpha-test-fragment-B7DjSnF7.js → alpha-test-fragment-x2mnjLgC.js} +2 -2
  7. package/{alpha-test-fragment-B7DjSnF7.js.map → alpha-test-fragment-x2mnjLgC.js.map} +1 -1
  8. package/{background-dds-skybox-BEX309u3.js → background-dds-skybox-BpcDr-9c.js} +3 -3
  9. package/{background-dds-skybox-BEX309u3.js.map → background-dds-skybox-BpcDr-9c.js.map} +1 -1
  10. package/{background-ground-BU0HOcM4.js → background-ground-Bm6gjWqx.js} +2 -2
  11. package/{background-ground-BU0HOcM4.js.map → background-ground-Bm6gjWqx.js.map} +1 -1
  12. package/{background-hdr-skybox--RRRic_K.js → background-hdr-skybox-CSFo8RX6.js} +3 -3
  13. package/{background-hdr-skybox--RRRic_K.js.map → background-hdr-skybox-CSFo8RX6.js.map} +1 -1
  14. package/{background-solid-skybox-BrH2fXSu.js → background-solid-skybox-DOOBeDIz.js} +2 -2
  15. package/{background-solid-skybox-BrH2fXSu.js.map → background-solid-skybox-DOOBeDIz.js.map} +1 -1
  16. package/{billboard-renderable-BHWryAeC.js → billboard-renderable-IJfCpeDS.js} +2 -2
  17. package/{billboard-renderable-BHWryAeC.js.map → billboard-renderable-IJfCpeDS.js.map} +1 -1
  18. package/{clamp-block-DqbwnQGW.js → clamp-block-BD_t8I89.js} +2 -2
  19. package/{clamp-block-DqbwnQGW.js.map → clamp-block-BD_t8I89.js.map} +1 -1
  20. package/{clearcoat-fragment-D6FSCie1.js → clearcoat-fragment-Dj7vGX2u.js} +2 -2
  21. package/{clearcoat-fragment-D6FSCie1.js.map → clearcoat-fragment-Dj7vGX2u.js.map} +1 -1
  22. package/{create-skeleton-D_uplboC.js → create-skeleton-s0hjrC3A.js} +2 -2
  23. package/{create-skeleton-D_uplboC.js.map → create-skeleton-s0hjrC3A.js.map} +1 -1
  24. package/{cubemap-skybox-material-DQcMMdf-.js → cubemap-skybox-material-8lzbgi7K.js} +2 -2
  25. package/{cubemap-skybox-material-DQcMMdf-.js.map → cubemap-skybox-material-8lzbgi7K.js.map} +1 -1
  26. package/{curve-block-21rT0JjG.js → curve-block-Ditr4R7V.js} +2 -2
  27. package/{curve-block-21rT0JjG.js.map → curve-block-Ditr4R7V.js.map} +1 -1
  28. package/{emissive-fragment-C5FtBs3y.js → emissive-fragment-BOAezkfk.js} +2 -2
  29. package/{emissive-fragment-C5FtBs3y.js.map → emissive-fragment-BOAezkfk.js.map} +1 -1
  30. package/{esm-shadow-view-c5YV4Eg9.js → esm-shadow-view-DRpyRAfa.js} +2 -2
  31. package/{esm-shadow-view-c5YV4Eg9.js.map → esm-shadow-view-DRpyRAfa.js.map} +1 -1
  32. package/{esm-shadow-view-Gtd1LWRP.js → esm-shadow-view-DmIORQGZ.js} +2 -2
  33. package/{esm-shadow-view-Gtd1LWRP.js.map → esm-shadow-view-DmIORQGZ.js.map} +1 -1
  34. package/{esm-shadow-view-Cl3rPGof.js → esm-shadow-view-JCPaOOi7.js} +2 -2
  35. package/{esm-shadow-view-Cl3rPGof.js.map → esm-shadow-view-JCPaOOi7.js.map} +1 -1
  36. package/{gaussian-splatting-pipeline-sh-7J31V23x.js → gaussian-splatting-pipeline-sh-B30Mu56i.js} +2 -2
  37. package/{gaussian-splatting-pipeline-sh-7J31V23x.js.map → gaussian-splatting-pipeline-sh-B30Mu56i.js.map} +1 -1
  38. package/{geometry-texture-output-dXk4E9uu.js → geometry-texture-output-DURiaJ_n.js} +2 -2
  39. package/{geometry-texture-output-dXk4E9uu.js.map → geometry-texture-output-DURiaJ_n.js.map} +1 -1
  40. package/{geometry-view-BsFJpBJa.js → geometry-view-DRrscyWU.js} +4 -4
  41. package/{geometry-view-BsFJpBJa.js.map → geometry-view-DRrscyWU.js.map} +1 -1
  42. package/{gltf-animation-K_zZxj_d.js → gltf-animation-BjnXkop6.js} +2 -2
  43. package/{gltf-animation-K_zZxj_d.js.map → gltf-animation-BjnXkop6.js.map} +1 -1
  44. package/{gltf-ext-basisu-CDbPclzZ.js → gltf-ext-basisu-DtzVV1Xx.js} +2 -202
  45. package/gltf-ext-basisu-DtzVV1Xx.js.map +1 -0
  46. package/{gltf-ext-node-visibility-DXCJEYr6.js → gltf-ext-node-visibility-BhX0DmiP.js} +2 -2
  47. package/{gltf-ext-node-visibility-DXCJEYr6.js.map → gltf-ext-node-visibility-BhX0DmiP.js.map} +1 -1
  48. package/{gltf-ext-quantization-CvHI_0Vg.js → gltf-ext-quantization-DaymajCR.js} +2 -2
  49. package/{gltf-ext-quantization-CvHI_0Vg.js.map → gltf-ext-quantization-DaymajCR.js.map} +1 -1
  50. package/{gltf-ext-uv-transform-DgYazJBs.js → gltf-ext-uv-transform-DFmNJ8kA.js} +2 -2
  51. package/{gltf-ext-uv-transform-DgYazJBs.js.map → gltf-ext-uv-transform-DFmNJ8kA.js.map} +1 -1
  52. package/{gltf-feature-animation-pointer-D1RJRFBw.js → gltf-feature-animation-pointer-C40tqOhL.js} +3 -3
  53. package/{gltf-feature-animation-pointer-D1RJRFBw.js.map → gltf-feature-animation-pointer-C40tqOhL.js.map} +1 -1
  54. package/{gltf-feature-animations-Cmc1uoIu.js → gltf-feature-animations-v0S_yb4T.js} +2 -2
  55. package/{gltf-feature-animations-Cmc1uoIu.js.map → gltf-feature-animations-v0S_yb4T.js.map} +1 -1
  56. package/{gltf-feature-draco-CKKzT5E3.js → gltf-feature-draco-CljWrsna.js} +2 -2
  57. package/{gltf-feature-draco-CKKzT5E3.js.map → gltf-feature-draco-CljWrsna.js.map} +1 -1
  58. package/{gltf-feature-gpu-instancing-n87SO6Vh.js → gltf-feature-gpu-instancing-BoeSm6Tn.js} +2 -2
  59. package/{gltf-feature-gpu-instancing-n87SO6Vh.js.map → gltf-feature-gpu-instancing-BoeSm6Tn.js.map} +1 -1
  60. package/{gltf-feature-lights-punctual-Ckm3ciL8.js → gltf-feature-lights-punctual-BCTwgyi_.js} +5 -5
  61. package/{gltf-feature-lights-punctual-Ckm3ciL8.js.map → gltf-feature-lights-punctual-BCTwgyi_.js.map} +1 -1
  62. package/{gltf-feature-meshopt-DLC4SF1E.js → gltf-feature-meshopt-DItMkOMt.js} +2 -2
  63. package/{gltf-feature-meshopt-DLC4SF1E.js.map → gltf-feature-meshopt-DItMkOMt.js.map} +1 -1
  64. package/{gltf-feature-morph-Cjtu7hYa.js → gltf-feature-morph-Cv0mEYIq.js} +3 -3
  65. package/{gltf-feature-morph-Cjtu7hYa.js.map → gltf-feature-morph-Cv0mEYIq.js.map} +1 -1
  66. package/{gltf-feature-registry-C63Hjp9w.js → gltf-feature-registry-wNbt6UC-.js} +15 -15
  67. package/{gltf-feature-registry-C63Hjp9w.js.map → gltf-feature-registry-wNbt6UC-.js.map} +1 -1
  68. package/{gltf-feature-skeleton-DKbOGidp.js → gltf-feature-skeleton-Deh2UBAn.js} +3 -3
  69. package/{gltf-feature-skeleton-DKbOGidp.js.map → gltf-feature-skeleton-Deh2UBAn.js.map} +1 -1
  70. package/{gltf-feature-variants-Cmzu0O0e.js → gltf-feature-variants-DGSdFNJq.js} +2 -2
  71. package/{gltf-feature-variants-Cmzu0O0e.js.map → gltf-feature-variants-DGSdFNJq.js.map} +1 -1
  72. package/{gltf-glb-parser-Cj5MHS-v.js → gltf-glb-parser-DSQWsT4r.js} +2 -2
  73. package/{gltf-glb-parser-Cj5MHS-v.js.map → gltf-glb-parser-DSQWsT4r.js.map} +1 -1
  74. package/{gltf-interleave-gHf9_t0i.js → gltf-interleave-OBqmlu-h.js} +11 -5
  75. package/gltf-interleave-OBqmlu-h.js.map +1 -0
  76. package/{gltf-normals-b2h74380.js → gltf-normals-D_P0KA4b.js} +10 -2
  77. package/gltf-normals-D_P0KA4b.js.map +1 -0
  78. package/{gltf-pbr-builder-ext-edNcjwPf.js → gltf-pbr-builder-ext-3imk8Tev.js} +2 -2
  79. package/{gltf-pbr-builder-ext-edNcjwPf.js.map → gltf-pbr-builder-ext-3imk8Tev.js.map} +1 -1
  80. package/{gltf-variants-CPxNdtP4.js → gltf-variants-Dyr54wwg.js} +4 -4
  81. package/{gltf-variants-CPxNdtP4.js.map → gltf-variants-Dyr54wwg.js.map} +1 -1
  82. package/gpu-task-timer-DVBNZfq5.js +236 -0
  83. package/gpu-task-timer-DVBNZfq5.js.map +1 -0
  84. package/gpu-timer-CUpqT_hK.js +55 -0
  85. package/gpu-timer-CUpqT_hK.js.map +1 -0
  86. package/{gs-picking-pipeline-DYaW_Lg3.js → gs-picking-pipeline-CERN-Trj.js} +2 -2
  87. package/{gs-picking-pipeline-DYaW_Lg3.js.map → gs-picking-pipeline-CERN-Trj.js.map} +1 -1
  88. package/{havok-floating-origin-Dr-18Nds.js → havok-floating-origin-VVdJRUYc.js} +2 -2
  89. package/{havok-floating-origin-Dr-18Nds.js.map → havok-floating-origin-VVdJRUYc.js.map} +1 -1
  90. package/{index-CYZDclhF.js → index-7Bk-uLSM.js} +2 -2
  91. package/{index-CYZDclhF.js.map → index-7Bk-uLSM.js.map} +1 -1
  92. package/{index-CLElg2Bo.js → index-BgY3QEzL.js} +4774 -1276
  93. package/index-BgY3QEzL.js.map +1 -0
  94. package/{index-SMJ67XwT.js → index-Dr5LK2tg.js} +2 -2
  95. package/{index-SMJ67XwT.js.map → index-Dr5LK2tg.js.map} +1 -1
  96. package/index.d.ts +1047 -13
  97. package/index.js +508 -444
  98. package/{input-block-DqEedWF2.js → input-block-DjdlndCL.js} +2 -2
  99. package/{input-block-DqEedWF2.js.map → input-block-DjdlndCL.js.map} +1 -1
  100. package/{iridescence-fragment-BHU59-gQ.js → iridescence-fragment-kfsCs8lN.js} +2 -2
  101. package/{iridescence-fragment-BHU59-gQ.js.map → iridescence-fragment-kfsCs8lN.js.map} +1 -1
  102. package/{light-block-Bv37V8vl.js → light-block-qjCrz3de.js} +2 -2
  103. package/{light-block-Bv37V8vl.js.map → light-block-qjCrz3de.js.map} +1 -1
  104. package/{loop-block-qTg8vb99.js → loop-block-C8vkQ2bz.js} +2 -2
  105. package/{loop-block-qTg8vb99.js.map → loop-block-C8vkQ2bz.js.map} +1 -1
  106. package/{manifold-AS8POaOr.js → manifold-DeXMNgxT.js} +3 -3
  107. package/{manifold-AS8POaOr.js.map → manifold-DeXMNgxT.js.map} +1 -1
  108. package/{morph-fragment-BRCUr2wQ.js → morph-fragment-NpZYyIIU.js} +2 -2
  109. package/{morph-fragment-BRCUr2wQ.js.map → morph-fragment-NpZYyIIU.js.map} +1 -1
  110. package/{multilight-wgsl-DMeppAdZ.js → multilight-wgsl-I5SncF0q.js} +2 -2
  111. package/{multilight-wgsl-DMeppAdZ.js.map → multilight-wgsl-I5SncF0q.js.map} +1 -1
  112. package/{node-env-Bc559GmY.js → node-env-D7Aee08u.js} +2 -2
  113. package/{node-env-Bc559GmY.js.map → node-env-D7Aee08u.js.map} +1 -1
  114. package/{node-geometry-view-COmWsRXK.js → node-geometry-view-DfKXWNfV.js} +3 -3
  115. package/{node-geometry-view-COmWsRXK.js.map → node-geometry-view-DfKXWNfV.js.map} +1 -1
  116. package/{node-registry-extra-compat-dWrv7gpS.js → node-registry-extra-compat-CDLeBR1P.js} +2 -2
  117. package/{node-registry-extra-compat-dWrv7gpS.js.map → node-registry-extra-compat-CDLeBR1P.js.map} +1 -1
  118. package/{node-registry-extra-math-Bn854sX9.js → node-registry-extra-math-BA8_l4lB.js} +2 -2
  119. package/{node-registry-extra-math-Bn854sX9.js.map → node-registry-extra-math-BA8_l4lB.js.map} +1 -1
  120. package/{node-renderable-B5G8WcdH.js → node-renderable-EwLLnaL1.js} +2 -2
  121. package/{node-renderable-B5G8WcdH.js.map → node-renderable-EwLLnaL1.js.map} +1 -1
  122. package/{node-shadow-CVIUlNf0.js → node-shadow-CeTmT6g4.js} +2 -2
  123. package/{node-shadow-CVIUlNf0.js.map → node-shadow-CeTmT6g4.js.map} +1 -1
  124. package/{normal-map-fragment-CQSxhjCy.js → normal-map-fragment-BHImLyM-.js} +2 -2
  125. package/{normal-map-fragment-CQSxhjCy.js.map → normal-map-fragment-BHImLyM-.js.map} +1 -1
  126. package/package.json +10 -3
  127. package/{parse-camera-pBRT_6i5.js → parse-camera-5IGdctAS.js} +2 -2
  128. package/{parse-camera-pBRT_6i5.js.map → parse-camera-5IGdctAS.js.map} +1 -1
  129. package/{pbr-geometry-view-NiZY_juX.js → pbr-geometry-view-Dthf9Aut.js} +3 -3
  130. package/{pbr-geometry-view-NiZY_juX.js.map → pbr-geometry-view-Dthf9Aut.js.map} +1 -1
  131. package/{pbr-metallic-roughness-block-full-Ta9lR2cz.js → pbr-metallic-roughness-block-full-DD6zI_Lx.js} +2 -2
  132. package/{pbr-metallic-roughness-block-full-Ta9lR2cz.js.map → pbr-metallic-roughness-block-full-DD6zI_Lx.js.map} +1 -1
  133. package/{pbr-metallic-roughness-block-JBSi-tQN.js → pbr-metallic-roughness-block-g7wjzwN_.js} +2 -2
  134. package/{pbr-metallic-roughness-block-JBSi-tQN.js.map → pbr-metallic-roughness-block-g7wjzwN_.js.map} +1 -1
  135. package/{pbr-mr-helper-core-BVWNR08D.js → pbr-mr-helper-core-CWROQ7OA.js} +2 -2
  136. package/{pbr-mr-helper-core-BVWNR08D.js.map → pbr-mr-helper-core-CWROQ7OA.js.map} +1 -1
  137. package/{pbr-refraction-C9FvFmAp.js → pbr-refraction-Dxsm_gii.js} +2 -2
  138. package/{pbr-refraction-C9FvFmAp.js.map → pbr-refraction-Dxsm_gii.js.map} +1 -1
  139. package/{pbr-renderable-DzUF2QIk.js → pbr-renderable-CuKWalEM.js} +22 -22
  140. package/{pbr-renderable-DzUF2QIk.js.map → pbr-renderable-CuKWalEM.js.map} +1 -1
  141. package/{pbr-shadow-fragment-CnqnbGYS.js → pbr-shadow-fragment-waeIBQUq.js} +2 -2
  142. package/{pbr-shadow-fragment-CnqnbGYS.js.map → pbr-shadow-fragment-waeIBQUq.js.map} +1 -1
  143. package/{pbr-tracking-3tU1kqea.js → pbr-tracking-CdeqbBrh.js} +2 -2
  144. package/{pbr-tracking-3tU1kqea.js.map → pbr-tracking-CdeqbBrh.js.map} +1 -1
  145. package/{pbr-transmission-ext-BcLjRxfB.js → pbr-transmission-ext-BNiXngZc.js} +2 -2
  146. package/{pbr-transmission-ext-BcLjRxfB.js.map → pbr-transmission-ext-BNiXngZc.js.map} +1 -1
  147. package/{recast-navigation.wasm-DG_0AFuk.js → recast-navigation.wasm-VC4lGlEe.js} +3 -3
  148. package/{recast-navigation.wasm-DG_0AFuk.js.map → recast-navigation.wasm-VC4lGlEe.js.map} +1 -1
  149. package/{recast-navigation.wasm-compat-C-Bf2ylB.js → recast-navigation.wasm-compat-CTwYOzRz.js} +3 -3
  150. package/{recast-navigation.wasm-compat-C-Bf2ylB.js.map → recast-navigation.wasm-compat-CTwYOzRz.js.map} +1 -1
  151. package/{reflectance-fragment-Dbpgw3Jt.js → reflectance-fragment-BQFZ_pgy.js} +2 -2
  152. package/{reflectance-fragment-Dbpgw3Jt.js.map → reflectance-fragment-BQFZ_pgy.js.map} +1 -1
  153. package/{rgbd-decode-DoyUquy3.js → rgbd-decode-duTlXMWd.js} +2 -2
  154. package/{rgbd-decode-DoyUquy3.js.map → rgbd-decode-duTlXMWd.js.map} +1 -1
  155. package/{scene-material-swap-nNUH4nGn.js → scene-material-swap-4qM0tpBK.js} +1 -2
  156. package/scene-material-swap-4qM0tpBK.js.map +1 -0
  157. package/{screenshot-readback-D0Sj9qq3.js → screenshot-readback-DnxR4rhp.js} +2 -2
  158. package/{screenshot-readback-D0Sj9qq3.js.map → screenshot-readback-DnxR4rhp.js.map} +1 -1
  159. package/{shader-composer-BUD_pSX4.js → shader-composer-CBy2i8nU.js} +2 -2
  160. package/{shader-composer-BUD_pSX4.js.map → shader-composer-CBy2i8nU.js.map} +1 -1
  161. package/{shader-renderable-D7-RyVxa.js → shader-renderable-DVMVD6zP.js} +41 -9
  162. package/shader-renderable-DVMVD6zP.js.map +1 -0
  163. package/{shader-thin-instance-DuBotxDO.js → shader-thin-instance-CsDo3ULk.js} +2 -2
  164. package/{shader-thin-instance-DuBotxDO.js.map → shader-thin-instance-CsDo3ULk.js.map} +1 -1
  165. package/{sheen-fragment-1MkEMcbc.js → sheen-fragment-B_Jd7wrr.js} +2 -2
  166. package/{sheen-fragment-1MkEMcbc.js.map → sheen-fragment-B_Jd7wrr.js.map} +1 -1
  167. package/{singlelight-directional-wgsl-BsV8G456.js → singlelight-directional-wgsl-Bw84txva.js} +2 -2
  168. package/{singlelight-directional-wgsl-BsV8G456.js.map → singlelight-directional-wgsl-Bw84txva.js.map} +1 -1
  169. package/{singlelight-hemispheric-wgsl-Bo0jKlW5.js → singlelight-hemispheric-wgsl-DjxhgI8r.js} +2 -2
  170. package/{singlelight-hemispheric-wgsl-Bo0jKlW5.js.map → singlelight-hemispheric-wgsl-DjxhgI8r.js.map} +1 -1
  171. package/{singlelight-point-wgsl-DV39UP5Y.js → singlelight-point-wgsl-iA1aRkXA.js} +2 -2
  172. package/{singlelight-point-wgsl-DV39UP5Y.js.map → singlelight-point-wgsl-iA1aRkXA.js.map} +1 -1
  173. package/{singlelight-spot-wgsl-yg3od6vL.js → singlelight-spot-wgsl-MDdTdstF.js} +2 -2
  174. package/{singlelight-spot-wgsl-yg3od6vL.js.map → singlelight-spot-wgsl-MDdTdstF.js.map} +1 -1
  175. package/{skeleton-fragment-DdxYG6kv.js → skeleton-fragment-COdHWFcK.js} +2 -2
  176. package/{skeleton-fragment-DdxYG6kv.js.map → skeleton-fragment-COdHWFcK.js.map} +1 -1
  177. package/{skybox-renderable-CJD4XmX5.js → skybox-renderable-DJYkfw32.js} +2 -2
  178. package/{skybox-renderable-CJD4XmX5.js.map → skybox-renderable-DJYkfw32.js.map} +1 -1
  179. package/{splat-ply-compressed-DHjyiVmI.js → splat-ply-compressed-SxMlsKNK.js} +2 -2
  180. package/{splat-ply-compressed-DHjyiVmI.js.map → splat-ply-compressed-SxMlsKNK.js.map} +1 -1
  181. package/{standard-pipeline-XTbHL7MY.js → standard-pipeline-DXFOUqU_.js} +3 -3
  182. package/{standard-pipeline-XTbHL7MY.js.map → standard-pipeline-DXFOUqU_.js.map} +1 -1
  183. package/{standard-renderable-CREWLNHI.js → standard-renderable-BAc-i-ig.js} +3 -3
  184. package/{standard-renderable-CREWLNHI.js.map → standard-renderable-BAc-i-ig.js.map} +1 -1
  185. package/{std-ambient-fragment-Bjx3VFrr.js → std-ambient-fragment-P8dHZ4An.js} +2 -2
  186. package/{std-ambient-fragment-Bjx3VFrr.js.map → std-ambient-fragment-P8dHZ4An.js.map} +1 -1
  187. package/{std-cube-reflection-fragment-y9WWdXUt.js → std-cube-reflection-fragment-CF03MuQt.js} +2 -2
  188. package/{std-cube-reflection-fragment-y9WWdXUt.js.map → std-cube-reflection-fragment-CF03MuQt.js.map} +1 -1
  189. package/{std-emissive-fragment-C8Lnmojh.js → std-emissive-fragment-P8yJGclx.js} +2 -2
  190. package/{std-emissive-fragment-C8Lnmojh.js.map → std-emissive-fragment-P8yJGclx.js.map} +1 -1
  191. package/{std-lightmap-fragment-DFxGcoA5.js → std-lightmap-fragment-CymEG79z.js} +9 -6
  192. package/std-lightmap-fragment-CymEG79z.js.map +1 -0
  193. package/{std-opacity-fragment-EXzFWiSp.js → std-opacity-fragment-DLa1zV06.js} +2 -2
  194. package/{std-opacity-fragment-EXzFWiSp.js.map → std-opacity-fragment-DLa1zV06.js.map} +1 -1
  195. package/{std-reflection-fragment-BoJORqpG.js → std-reflection-fragment-BLySsYos.js} +2 -2
  196. package/{std-reflection-fragment-BoJORqpG.js.map → std-reflection-fragment-BLySsYos.js.map} +1 -1
  197. package/{std-shadow-fragment-Bq-Wc8UJ.js → std-shadow-fragment-C_q27Mdi.js} +2 -2
  198. package/{std-shadow-fragment-Bq-Wc8UJ.js.map → std-shadow-fragment-C_q27Mdi.js.map} +1 -1
  199. package/{std-specular-fragment-CM5R5j2g.js → std-specular-fragment-CaBXyAWY.js} +2 -2
  200. package/{std-specular-fragment-CM5R5j2g.js.map → std-specular-fragment-CaBXyAWY.js.map} +1 -1
  201. package/{std-tracking-Cif_wXeT.js → std-tracking-Bw61Dv98.js} +2 -2
  202. package/{std-tracking-Cif_wXeT.js.map → std-tracking-Bw61Dv98.js.map} +1 -1
  203. package/{subsurface-fragment-BEaAXYXz.js → subsurface-fragment-BNQoG9gr.js} +2 -2
  204. package/{subsurface-fragment-BEaAXYXz.js.map → subsurface-fragment-BNQoG9gr.js.map} +1 -1
  205. package/{thin-instance-cull-binding-DWKUt5ZN.js → thin-instance-cull-binding-BNC5JiGw.js} +3 -3
  206. package/{thin-instance-cull-binding-DWKUt5ZN.js.map → thin-instance-cull-binding-BNC5JiGw.js.map} +1 -1
  207. package/{thin-instance-gpu-BDdRcNAh.js → thin-instance-gpu-C1DGstap.js} +2 -2
  208. package/{thin-instance-gpu-BDdRcNAh.js.map → thin-instance-gpu-C1DGstap.js.map} +1 -1
  209. package/{tracking-primitives-CglRNTlX.js → tracking-primitives-CMBWLxGr.js} +2 -2
  210. package/{tracking-primitives-CglRNTlX.js.map → tracking-primitives-CMBWLxGr.js.map} +1 -1
  211. package/{unlit-fragment-kxfZWlnp.js → unlit-fragment-BsHrS9XX.js} +2 -2
  212. package/{unlit-fragment-kxfZWlnp.js.map → unlit-fragment-BsHrS9XX.js.map} +1 -1
  213. package/gltf-ext-basisu-CDbPclzZ.js.map +0 -1
  214. package/gltf-interleave-gHf9_t0i.js.map +0 -1
  215. package/gltf-normals-b2h74380.js.map +0 -1
  216. package/index-CLElg2Bo.js.map +0 -1
  217. package/scene-material-swap-nNUH4nGn.js.map +0 -1
  218. package/shader-renderable-D7-RyVxa.js.map +0 -1
  219. package/std-lightmap-fragment-DFxGcoA5.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"background-dds-skybox-BEX309u3.js","sources":["../shaders/skybox-dds.vertex.wgsl?raw","../shaders/skybox-dds.fragment.wgsl?raw","../src/material/pbr/background-dds-skybox.ts"],"sourcesContent":["export default \"// DDS Skybox Vertex Shader — standard world transform.\\n// positionUVW uses local position for cube direction lookup.\\n\\nstruct MeshUniforms {\\n world: mat4x4<f32>,\\n};\\n\\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\\n\\nstruct VertexOutput {\\n @builtin(position) clipPos: vec4<f32>,\\n @location(0) positionUVW: vec3<f32>,\\n @location(1) positionW: vec3<f32>,\\n};\\n\\n@vertex\\nfn main(@location(0) position: vec3<f32>) -> VertexOutput {\\n var output: VertexOutput;\\n output.positionUVW = position;\\n let worldPos = (mesh.world * vec4<f32>(position, 1.0)).xyz;\\n output.positionW = worldPos;\\n output.clipPos = scene.viewProjection * vec4<f32>(worldPos, 1.0);\\n return output;\\n}\\n\"","export default \"// DDS Cube Skybox Fragment Shader — samples DDS cube texture with BJS image processing.\\n// Used by scenes that load backgroundSkybox.dds (createDefaultEnvironment).\\n// Pipeline: exposure → Reinhard tonemap → gamma → contrast → dither.\\n\\nstruct MeshUniforms {\\n world: mat4x4<f32>,\\n primaryColor: vec3<f32>,\\n exposureLinear: f32,\\n contrast: f32,\\n _pad1: f32,\\n _pad2: f32,\\n _pad3: f32,\\n};\\n\\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\\n@group(1) @binding(1) var envCubemap: texture_cube<f32>;\\n@group(1) @binding(2) var envSampler: sampler;\\n\\nstruct FragmentInput {\\n @location(0) positionUVW: vec3<f32>,\\n @location(1) positionW: vec3<f32>,\\n};\\n\\n@fragment\\nfn main(input: FragmentInput) -> @location(0) vec4<f32> {\\n let dir = normalize(input.positionUVW);\\n var color = textureSampleLevel(envCubemap, envSampler, dir, 0.0).rgb;\\n\\n // BJS BackgroundMaterial: colorBase = reflectionColor.rgb * primaryColor.rgb\\n color *= mesh.primaryColor;\\n\\n if (scene.vImageInfos.w >= 0.0) {\\n // Exposure\\n color *= mesh.exposureLinear;\\n // Reinhard tonemap (matches BJS toneMappingType 0)\\n color = 1.0 - exp2(-1.590579 * color);\\n // Gamma\\n color = pow(color, vec3<f32>(1.0 / 2.2));\\n color = saturate(color);\\n\\n // Contrast\\n let highContrast = color * color * (3.0 - 2.0 * color);\\n color = mix(color, highContrast, mesh.contrast - 1.0);\\n\\n // Dithering (enableNoise=true, variance=0.5)\\n color = color + vec3<f32>(dither(input.positionW.xy, 0.5));\\n color = max(color, vec3<f32>(0.0));\\n }\\n\\n return vec4<f32>(color, 1.0);\\n}\\n\"","/** DDS cube skybox — lazy-loaded only when skyboxUrl ends with .dds.\n * Loads backgroundSkybox.dds and renders it with BJS image processing. */\n\nimport { F32, I32, U16, U8 } from \"../../engine/typed-arrays.js\";\nimport { TU, BU } from \"../../engine/gpu-flags.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { Renderable } from \"../../render/renderable.js\";\nimport { getOrCreateSampler } from \"../../resource/gpu-pool.js\";\nimport { createMappedBuffer, createUniformBuffer } from \"../../resource/gpu-buffers.js\";\nimport { WGSL_DITHER, WGSL_NO_DITHER } from \"../../shader/wgsl-helpers.js\";\nimport { SCENE_UBO_WGSL } from \"../../shader/scene-uniforms.js\";\nimport { createCubemapSkyboxMaterial } from \"./cubemap-skybox-material.js\";\nimport ddsSkyboxVertSrc from \"../../../shaders/skybox-dds.vertex.wgsl?raw\";\nimport ddsSkyboxFragSrc from \"../../../shaders/skybox-dds.fragment.wgsl?raw\";\n\nconst SKY_DDS_UNIFORM_SIZE = 96;\nconst DEFAULT_SKY_URL = \"https://assets.babylonjs.com/core/environments/backgroundSkybox.dds\";\n\nfunction createSkyboxBuffers(engine: EngineContext, S: number): { posBuffer: GPUBuffer; idxBuffer: GPUBuffer; idxCount: number } {\n // prettier-ignore\n const positions = new F32([\n S,-S, S, -S,-S, S, -S, S, S, S, S, S,\n S, S,-S, -S, S,-S, -S,-S,-S, S,-S,-S,\n S, S,-S, S,-S,-S, S,-S, S, S, S, S,\n -S, S, S, -S,-S, S, -S,-S,-S, -S, S,-S,\n -S, S, S, -S, S,-S, S, S,-S, S, S, S,\n S,-S, S, S,-S,-S, -S,-S,-S, -S,-S, S,\n ]);\n // prettier-ignore\n const indices = new U16([\n 2, 1, 0, 3, 2, 0, 6, 5, 4, 7, 6, 4,\n 10, 9, 8, 11,10, 8, 14,13,12, 15,14,12,\n 18,17,16, 19,18,16, 22,21,20, 23,22,20,\n ]);\n return {\n posBuffer: createMappedBuffer(engine, positions, BU.VERTEX),\n idxBuffer: createMappedBuffer(engine, indices, BU.INDEX),\n idxCount: 36,\n };\n}\n\nfunction buildSkyboxWorldMatrix(rootPosition: [number, number, number]): Float32Array {\n const world = new F32(16);\n world[0] = 1;\n world[5] = 1;\n world[10] = 1;\n world[15] = 1;\n world[12] = rootPosition[0];\n world[13] = rootPosition[1];\n world[14] = rootPosition[2];\n return world;\n}\n\n/** Build a DDS cube skybox as a complete Renderable (order 0). */\nexport async function buildDdsSkyboxRenderable(\n scene: SceneContext,\n skyHalfSize: number,\n rootPosition: [number, number, number],\n primaryColor: [number, number, number],\n skyboxTextureUrl?: string,\n enableNoise = true\n): Promise<Renderable> {\n const engine = scene.surface.engine;\n\n const skyboxWorld = buildSkyboxWorldMatrix(rootPosition);\n\n const skyBufs = createSkyboxBuffers(engine, skyHalfSize);\n const { cubeView, sampler } = await loadDdsCube(engine, skyboxTextureUrl ?? DEFAULT_SKY_URL);\n\n const fragCode = SCENE_UBO_WGSL + (enableNoise ? WGSL_DITHER : WGSL_NO_DITHER) + ddsSkyboxFragSrc;\n const mat = createCubemapSkyboxMaterial(enableNoise ? \"skybox-dds\" : \"skybox-dds0\", SCENE_UBO_WGSL + ddsSkyboxVertSrc, fragCode);\n const ubo = createDdsMeshUBO(engine, skyboxWorld, primaryColor, scene.imageProcessing.exposure, scene.imageProcessing.contrast);\n const bindGroup = mat.createBindGroup(engine, ubo, cubeView, sampler);\n\n const r: Renderable = {\n order: 0,\n isTransparent: false,\n bind(eng, sig) {\n return {\n renderable: r,\n pipeline: mat.getPipeline(eng as EngineContext, sig),\n draw(pass) {\n pass.setBindGroup(1, bindGroup);\n pass.setVertexBuffer(0, skyBufs.posBuffer);\n pass.setIndexBuffer(skyBufs.idxBuffer, \"uint16\");\n pass.drawIndexed(skyBufs.idxCount);\n return 1;\n },\n };\n },\n };\n return r;\n}\n\n// ─── DDS Skybox UBO ──────────────────────────────────────────────────────────\n\nfunction createDdsMeshUBO(engine: EngineContext, world: Float32Array, primaryColor: [number, number, number], exposureLinear: number, contrast: number): GPUBuffer {\n const data = new F32(SKY_DDS_UNIFORM_SIZE / 4);\n data.set(world, 0);\n data[16] = primaryColor[0];\n data[17] = primaryColor[1];\n data[18] = primaryColor[2];\n data[19] = exposureLinear;\n data[20] = contrast;\n return createUniformBuffer(engine, data);\n}\n\n// ─── DDS Cube Texture Loader ─────────────────────────────────────────────────\n\n/** Load a DDS cube texture (rgba16float) and return a cube texture view + sampler.\n * Uploads only mip 0 from the DDS file and generates remaining mipmaps on the\n * GPU so that cube face edges blend seamlessly — matching BJS's behaviour. */\nasync function loadDdsCube(engine: EngineContext, url: string): Promise<{ cubeView: GPUTextureView; sampler: GPUSampler }> {\n const device = engine._device;\n const buf = await (await fetch(url)).arrayBuffer();\n const header = new I32(buf, 0, 32);\n const width = header[3]!;\n const height = header[4]!;\n const mipCount = Math.max(header[7]!, 1);\n\n // DDS pixel format offset 76..107 — for rgba16float, FourCC = 'DX10'\n // DDS_HEADER_DX10 at byte 128: dxgiFormat, resourceDimension, miscFlag, arraySize, etc.\n // For cube: miscFlag has RESOURCE_MISC_TEXTURECUBE (0x4), arraySize = 1 (6 faces in data)\n const dataOffset = header[21] === 0x30315844 /* 'DX10' */ ? 128 + 20 : 128;\n const raw = new U8(buf, dataOffset);\n\n const fmt: GPUTextureFormat = \"rgba16float\";\n const tex = device.createTexture({\n size: [width, height, 6],\n format: fmt,\n mipLevelCount: mipCount,\n usage: TU.TEXTURE_BINDING | TU.COPY_DST | TU.RENDER_ATTACHMENT,\n dimension: \"2d\",\n });\n\n // Upload all mip levels for each face from the DDS (face-major layout).\n // Even though the skybox shader samples mip 0 explicitly, uploading all\n // mips avoids the need for GPU-side mipmap generation.\n let offset = 0;\n for (let face = 0; face < 6; face++) {\n for (let m = 0; m < mipCount; m++) {\n const s = Math.max(width >> m, 1);\n device.queue.writeTexture(\n { texture: tex, origin: { x: 0, y: 0, z: face }, mipLevel: m },\n raw.buffer,\n { offset: raw.byteOffset + offset, bytesPerRow: s * 8 },\n { width: s, height: s }\n );\n offset += s * s * 8;\n }\n }\n\n const cubeView = tex.createView({ dimension: \"cube\" });\n const sampler = getOrCreateSampler(engine, {\n magFilter: \"linear\",\n minFilter: \"linear\",\n mipmapFilter: \"linear\",\n addressModeU: \"clamp-to-edge\",\n addressModeV: \"clamp-to-edge\",\n addressModeW: \"clamp-to-edge\",\n maxAnisotropy: 4,\n });\n\n return { cubeView, sampler };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"background-dds-skybox-BpcDr-9c.js","sources":["../shaders/skybox-dds.vertex.wgsl?raw","../shaders/skybox-dds.fragment.wgsl?raw","../src/material/pbr/background-dds-skybox.ts"],"sourcesContent":["export default \"// DDS Skybox Vertex Shader — standard world transform.\\n// positionUVW uses local position for cube direction lookup.\\n\\nstruct MeshUniforms {\\n world: mat4x4<f32>,\\n};\\n\\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\\n\\nstruct VertexOutput {\\n @builtin(position) clipPos: vec4<f32>,\\n @location(0) positionUVW: vec3<f32>,\\n @location(1) positionW: vec3<f32>,\\n};\\n\\n@vertex\\nfn main(@location(0) position: vec3<f32>) -> VertexOutput {\\n var output: VertexOutput;\\n output.positionUVW = position;\\n let worldPos = (mesh.world * vec4<f32>(position, 1.0)).xyz;\\n output.positionW = worldPos;\\n output.clipPos = scene.viewProjection * vec4<f32>(worldPos, 1.0);\\n return output;\\n}\\n\"","export default \"// DDS Cube Skybox Fragment Shader — samples DDS cube texture with BJS image processing.\\n// Used by scenes that load backgroundSkybox.dds (createDefaultEnvironment).\\n// Pipeline: exposure → Reinhard tonemap → gamma → contrast → dither.\\n\\nstruct MeshUniforms {\\n world: mat4x4<f32>,\\n primaryColor: vec3<f32>,\\n exposureLinear: f32,\\n contrast: f32,\\n _pad1: f32,\\n _pad2: f32,\\n _pad3: f32,\\n};\\n\\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\\n@group(1) @binding(1) var envCubemap: texture_cube<f32>;\\n@group(1) @binding(2) var envSampler: sampler;\\n\\nstruct FragmentInput {\\n @location(0) positionUVW: vec3<f32>,\\n @location(1) positionW: vec3<f32>,\\n};\\n\\n@fragment\\nfn main(input: FragmentInput) -> @location(0) vec4<f32> {\\n let dir = normalize(input.positionUVW);\\n var color = textureSampleLevel(envCubemap, envSampler, dir, 0.0).rgb;\\n\\n // BJS BackgroundMaterial: colorBase = reflectionColor.rgb * primaryColor.rgb\\n color *= mesh.primaryColor;\\n\\n if (scene.vImageInfos.w >= 0.0) {\\n // Exposure\\n color *= mesh.exposureLinear;\\n // Reinhard tonemap (matches BJS toneMappingType 0)\\n color = 1.0 - exp2(-1.590579 * color);\\n // Gamma\\n color = pow(color, vec3<f32>(1.0 / 2.2));\\n color = saturate(color);\\n\\n // Contrast\\n let highContrast = color * color * (3.0 - 2.0 * color);\\n color = mix(color, highContrast, mesh.contrast - 1.0);\\n\\n // Dithering (enableNoise=true, variance=0.5)\\n color = color + vec3<f32>(dither(input.positionW.xy, 0.5));\\n color = max(color, vec3<f32>(0.0));\\n }\\n\\n return vec4<f32>(color, 1.0);\\n}\\n\"","/** DDS cube skybox — lazy-loaded only when skyboxUrl ends with .dds.\n * Loads backgroundSkybox.dds and renders it with BJS image processing. */\n\nimport { F32, I32, U16, U8 } from \"../../engine/typed-arrays.js\";\nimport { TU, BU } from \"../../engine/gpu-flags.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { Renderable } from \"../../render/renderable.js\";\nimport { getOrCreateSampler } from \"../../resource/gpu-pool.js\";\nimport { createMappedBuffer, createUniformBuffer } from \"../../resource/gpu-buffers.js\";\nimport { WGSL_DITHER, WGSL_NO_DITHER } from \"../../shader/wgsl-helpers.js\";\nimport { SCENE_UBO_WGSL } from \"../../shader/scene-uniforms.js\";\nimport { createCubemapSkyboxMaterial } from \"./cubemap-skybox-material.js\";\nimport ddsSkyboxVertSrc from \"../../../shaders/skybox-dds.vertex.wgsl?raw\";\nimport ddsSkyboxFragSrc from \"../../../shaders/skybox-dds.fragment.wgsl?raw\";\n\nconst SKY_DDS_UNIFORM_SIZE = 96;\nconst DEFAULT_SKY_URL = \"https://assets.babylonjs.com/core/environments/backgroundSkybox.dds\";\n\nfunction createSkyboxBuffers(engine: EngineContext, S: number): { posBuffer: GPUBuffer; idxBuffer: GPUBuffer; idxCount: number } {\n // prettier-ignore\n const positions = new F32([\n S,-S, S, -S,-S, S, -S, S, S, S, S, S,\n S, S,-S, -S, S,-S, -S,-S,-S, S,-S,-S,\n S, S,-S, S,-S,-S, S,-S, S, S, S, S,\n -S, S, S, -S,-S, S, -S,-S,-S, -S, S,-S,\n -S, S, S, -S, S,-S, S, S,-S, S, S, S,\n S,-S, S, S,-S,-S, -S,-S,-S, -S,-S, S,\n ]);\n // prettier-ignore\n const indices = new U16([\n 2, 1, 0, 3, 2, 0, 6, 5, 4, 7, 6, 4,\n 10, 9, 8, 11,10, 8, 14,13,12, 15,14,12,\n 18,17,16, 19,18,16, 22,21,20, 23,22,20,\n ]);\n return {\n posBuffer: createMappedBuffer(engine, positions, BU.VERTEX),\n idxBuffer: createMappedBuffer(engine, indices, BU.INDEX),\n idxCount: 36,\n };\n}\n\nfunction buildSkyboxWorldMatrix(rootPosition: [number, number, number]): Float32Array {\n const world = new F32(16);\n world[0] = 1;\n world[5] = 1;\n world[10] = 1;\n world[15] = 1;\n world[12] = rootPosition[0];\n world[13] = rootPosition[1];\n world[14] = rootPosition[2];\n return world;\n}\n\n/** Build a DDS cube skybox as a complete Renderable (order 0). */\nexport async function buildDdsSkyboxRenderable(\n scene: SceneContext,\n skyHalfSize: number,\n rootPosition: [number, number, number],\n primaryColor: [number, number, number],\n skyboxTextureUrl?: string,\n enableNoise = true\n): Promise<Renderable> {\n const engine = scene.surface.engine;\n\n const skyboxWorld = buildSkyboxWorldMatrix(rootPosition);\n\n const skyBufs = createSkyboxBuffers(engine, skyHalfSize);\n const { cubeView, sampler } = await loadDdsCube(engine, skyboxTextureUrl ?? DEFAULT_SKY_URL);\n\n const fragCode = SCENE_UBO_WGSL + (enableNoise ? WGSL_DITHER : WGSL_NO_DITHER) + ddsSkyboxFragSrc;\n const mat = createCubemapSkyboxMaterial(enableNoise ? \"skybox-dds\" : \"skybox-dds0\", SCENE_UBO_WGSL + ddsSkyboxVertSrc, fragCode);\n const ubo = createDdsMeshUBO(engine, skyboxWorld, primaryColor, scene.imageProcessing.exposure, scene.imageProcessing.contrast);\n const bindGroup = mat.createBindGroup(engine, ubo, cubeView, sampler);\n\n const r: Renderable = {\n order: 0,\n isTransparent: false,\n bind(eng, sig) {\n return {\n renderable: r,\n pipeline: mat.getPipeline(eng as EngineContext, sig),\n draw(pass) {\n pass.setBindGroup(1, bindGroup);\n pass.setVertexBuffer(0, skyBufs.posBuffer);\n pass.setIndexBuffer(skyBufs.idxBuffer, \"uint16\");\n pass.drawIndexed(skyBufs.idxCount);\n return 1;\n },\n };\n },\n };\n return r;\n}\n\n// ─── DDS Skybox UBO ──────────────────────────────────────────────────────────\n\nfunction createDdsMeshUBO(engine: EngineContext, world: Float32Array, primaryColor: [number, number, number], exposureLinear: number, contrast: number): GPUBuffer {\n const data = new F32(SKY_DDS_UNIFORM_SIZE / 4);\n data.set(world, 0);\n data[16] = primaryColor[0];\n data[17] = primaryColor[1];\n data[18] = primaryColor[2];\n data[19] = exposureLinear;\n data[20] = contrast;\n return createUniformBuffer(engine, data);\n}\n\n// ─── DDS Cube Texture Loader ─────────────────────────────────────────────────\n\n/** Load a DDS cube texture (rgba16float) and return a cube texture view + sampler.\n * Uploads only mip 0 from the DDS file and generates remaining mipmaps on the\n * GPU so that cube face edges blend seamlessly — matching BJS's behaviour. */\nasync function loadDdsCube(engine: EngineContext, url: string): Promise<{ cubeView: GPUTextureView; sampler: GPUSampler }> {\n const device = engine._device;\n const buf = await (await fetch(url)).arrayBuffer();\n const header = new I32(buf, 0, 32);\n const width = header[3]!;\n const height = header[4]!;\n const mipCount = Math.max(header[7]!, 1);\n\n // DDS pixel format offset 76..107 — for rgba16float, FourCC = 'DX10'\n // DDS_HEADER_DX10 at byte 128: dxgiFormat, resourceDimension, miscFlag, arraySize, etc.\n // For cube: miscFlag has RESOURCE_MISC_TEXTURECUBE (0x4), arraySize = 1 (6 faces in data)\n const dataOffset = header[21] === 0x30315844 /* 'DX10' */ ? 128 + 20 : 128;\n const raw = new U8(buf, dataOffset);\n\n const fmt: GPUTextureFormat = \"rgba16float\";\n const tex = device.createTexture({\n size: [width, height, 6],\n format: fmt,\n mipLevelCount: mipCount,\n usage: TU.TEXTURE_BINDING | TU.COPY_DST | TU.RENDER_ATTACHMENT,\n dimension: \"2d\",\n });\n\n // Upload all mip levels for each face from the DDS (face-major layout).\n // Even though the skybox shader samples mip 0 explicitly, uploading all\n // mips avoids the need for GPU-side mipmap generation.\n let offset = 0;\n for (let face = 0; face < 6; face++) {\n for (let m = 0; m < mipCount; m++) {\n const s = Math.max(width >> m, 1);\n device.queue.writeTexture(\n { texture: tex, origin: { x: 0, y: 0, z: face }, mipLevel: m },\n raw.buffer,\n { offset: raw.byteOffset + offset, bytesPerRow: s * 8 },\n { width: s, height: s }\n );\n offset += s * s * 8;\n }\n }\n\n const cubeView = tex.createView({ dimension: \"cube\" });\n const sampler = getOrCreateSampler(engine, {\n magFilter: \"linear\",\n minFilter: \"linear\",\n mipmapFilter: \"linear\",\n addressModeU: \"clamp-to-edge\",\n addressModeV: \"clamp-to-edge\",\n addressModeW: \"clamp-to-edge\",\n maxAnisotropy: 4,\n });\n\n return { cubeView, sampler };\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { a as F32, cb as getBilinearSampler, j as createMappedBuffer, B as BU, h as U16, av as createUniformBuffer, T as TU, e as U8, x as targetSignatureKey, q as SCENE_UBO_WGSL, z as getSceneBindGroupLayout, S as SS } from "./index-CLElg2Bo.js";
1
+ import { a as F32, cf as getBilinearSampler, k as createMappedBuffer, B as BU, j as U16, ay as createUniformBuffer, T as TU, e as U8, y as targetSignatureKey, q as SCENE_UBO_WGSL, A as getSceneBindGroupLayout, S as SS } from "./index-BgY3QEzL.js";
2
2
  import { b as WGSL_DITHER, c as WGSL_NO_DITHER } from "./wgsl-helpers-D8sl1VVA.js";
3
3
  const groundVertSrc = "// Background Ground Vertex Shader\n// Matches BJS shd_15: DIFFUSE, OPACITYFRESNEL, PREMULTIPLYALPHA (no REFLECTION)\n\nstruct MeshUniforms {\n world: mat4x4<f32>,\n};\n\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\n\nstruct VertexInput {\n @location(0) position: vec3<f32>,\n @location(1) normal: vec3<f32>,\n @location(2) uv: vec2<f32>,\n};\n\nstruct VertexOutput {\n @builtin(position) clipPos: vec4<f32>,\n @location(0) vPositionW: vec3<f32>,\n @location(1) vNormalW: vec3<f32>,\n @location(2) vUV: vec2<f32>,\n};\n\n@vertex\nfn main(input: VertexInput) -> VertexOutput {\n var output: VertexOutput;\n let finalWorld = mesh.world;\n let worldPos4 = finalWorld * vec4<f32>(input.position, 1.0);\n output.vPositionW = worldPos4.xyz;\n output.clipPos = scene.viewProjection * worldPos4;\n let normalWorld = mat3x3<f32>(finalWorld[0].xyz, finalWorld[1].xyz, finalWorld[2].xyz);\n output.vNormalW = normalize(normalWorld * input.normal);\n output.vUV = input.uv;\n return output;\n}\n";
4
4
  const groundFragSrc = "// Background Ground Fragment Shader\n// Matches BJS shd_16: DIFFUSE, OPACITYFRESNEL, PREMULTIPLYALPHA (no REFLECTION)\n// Verified via Spector.GPU capture of BJS scene 1\n\nstruct MeshUniforms {\n world: mat4x4<f32>,\n primaryColor: vec3<f32>,\n alpha: f32,\n backgroundCenter: vec3<f32>,\n _pad: f32,\n};\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\n\n@group(1) @binding(1) var groundTexture: texture_2d<f32>;\n@group(1) @binding(2) var groundSampler: sampler;\n\nstruct FragmentInput {\n @location(0) vPositionW: vec3<f32>,\n @location(1) vNormalW: vec3<f32>,\n @location(2) vUV: vec2<f32>,\n};\n\n@fragment\nfn main(input: FragmentInput) -> @location(0) vec4<f32> {\n let normalW = normalize(input.vNormalW);\n\n // Sample diffuse texture (BJS backgroundGround.png: white RGB, radial alpha gradient)\n let diffuseMap = textureSample(groundTexture, groundSampler, input.vUV);\n\n // BJS: reflectionColor = vec4(1) (no REFLECTION define)\n let diffuseColor = diffuseMap.rgb;\n let colorBase = max(diffuseColor, vec3<f32>(0.0));\n let mainColor = mesh.primaryColor;\n let finalColor = colorBase * mainColor;\n\n // Alpha starts from material alpha, multiplied by texture alpha\n var finalAlpha = mesh.alpha * diffuseMap.a;\n\n // OPACITYFRESNEL — BJS shd_16 lines 367-370\n let viewAngleToFloor = dot(normalW, normalize(scene.vEyePosition.xyz - mesh.backgroundCenter));\n const startAngle: f32 = 0.1;\n let fadeFactor = clamp(viewAngleToFloor / startAngle, 0.0, 1.0);\n finalAlpha *= fadeFactor * fadeFactor;\n\n // Image processing (preserves alpha)\n var color = vec4<f32>(finalColor, finalAlpha);\n if (scene.vImageInfos.w >= 0.0) {\n color = applyImageProcessing(color);\n }\n\n // PREMULTIPLYALPHA — BJS shd_16 line 373\n color = vec4<f32>(color.rgb * color.a, color.a);\n\n // Dithering\n color = vec4<f32>(color.rgb + vec3<f32>(dither(input.vPositionW.xy, 0.5)), color.a);\n color = max(color, vec4<f32>(0.0));\n\n return color;\n}\n";
@@ -232,4 +232,4 @@ async function loadGroundTexture(engine, url, preloadedImage) {
232
232
  export {
233
233
  buildGroundRenderable
234
234
  };
235
- //# sourceMappingURL=background-ground-BU0HOcM4.js.map
235
+ //# sourceMappingURL=background-ground-Bm6gjWqx.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"background-ground-BU0HOcM4.js","sources":["../shaders/background.vertex.wgsl?raw","../shaders/background.ground.fragment.wgsl?raw","../src/material/pbr/background-ground.ts"],"sourcesContent":["export default \"// Background Ground Vertex Shader\\n// Matches BJS shd_15: DIFFUSE, OPACITYFRESNEL, PREMULTIPLYALPHA (no REFLECTION)\\n\\nstruct MeshUniforms {\\n world: mat4x4<f32>,\\n};\\n\\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\\n\\nstruct VertexInput {\\n @location(0) position: vec3<f32>,\\n @location(1) normal: vec3<f32>,\\n @location(2) uv: vec2<f32>,\\n};\\n\\nstruct VertexOutput {\\n @builtin(position) clipPos: vec4<f32>,\\n @location(0) vPositionW: vec3<f32>,\\n @location(1) vNormalW: vec3<f32>,\\n @location(2) vUV: vec2<f32>,\\n};\\n\\n@vertex\\nfn main(input: VertexInput) -> VertexOutput {\\n var output: VertexOutput;\\n let finalWorld = mesh.world;\\n let worldPos4 = finalWorld * vec4<f32>(input.position, 1.0);\\n output.vPositionW = worldPos4.xyz;\\n output.clipPos = scene.viewProjection * worldPos4;\\n let normalWorld = mat3x3<f32>(finalWorld[0].xyz, finalWorld[1].xyz, finalWorld[2].xyz);\\n output.vNormalW = normalize(normalWorld * input.normal);\\n output.vUV = input.uv;\\n return output;\\n}\\n\"","export default \"// Background Ground Fragment Shader\\n// Matches BJS shd_16: DIFFUSE, OPACITYFRESNEL, PREMULTIPLYALPHA (no REFLECTION)\\n// Verified via Spector.GPU capture of BJS scene 1\\n\\nstruct MeshUniforms {\\n world: mat4x4<f32>,\\n primaryColor: vec3<f32>,\\n alpha: f32,\\n backgroundCenter: vec3<f32>,\\n _pad: f32,\\n};\\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\\n\\n@group(1) @binding(1) var groundTexture: texture_2d<f32>;\\n@group(1) @binding(2) var groundSampler: sampler;\\n\\nstruct FragmentInput {\\n @location(0) vPositionW: vec3<f32>,\\n @location(1) vNormalW: vec3<f32>,\\n @location(2) vUV: vec2<f32>,\\n};\\n\\n@fragment\\nfn main(input: FragmentInput) -> @location(0) vec4<f32> {\\n let normalW = normalize(input.vNormalW);\\n\\n // Sample diffuse texture (BJS backgroundGround.png: white RGB, radial alpha gradient)\\n let diffuseMap = textureSample(groundTexture, groundSampler, input.vUV);\\n\\n // BJS: reflectionColor = vec4(1) (no REFLECTION define)\\n let diffuseColor = diffuseMap.rgb;\\n let colorBase = max(diffuseColor, vec3<f32>(0.0));\\n let mainColor = mesh.primaryColor;\\n let finalColor = colorBase * mainColor;\\n\\n // Alpha starts from material alpha, multiplied by texture alpha\\n var finalAlpha = mesh.alpha * diffuseMap.a;\\n\\n // OPACITYFRESNEL — BJS shd_16 lines 367-370\\n let viewAngleToFloor = dot(normalW, normalize(scene.vEyePosition.xyz - mesh.backgroundCenter));\\n const startAngle: f32 = 0.1;\\n let fadeFactor = clamp(viewAngleToFloor / startAngle, 0.0, 1.0);\\n finalAlpha *= fadeFactor * fadeFactor;\\n\\n // Image processing (preserves alpha)\\n var color = vec4<f32>(finalColor, finalAlpha);\\n if (scene.vImageInfos.w >= 0.0) {\\n color = applyImageProcessing(color);\\n }\\n\\n // PREMULTIPLYALPHA — BJS shd_16 line 373\\n color = vec4<f32>(color.rgb * color.a, color.a);\\n\\n // Dithering\\n color = vec4<f32>(color.rgb + vec3<f32>(dither(input.vPositionW.xy, 0.5)), color.a);\\n color = max(color, vec4<f32>(0.0));\\n\\n return color;\\n}\\n\"","/** Ground plane renderable — lazy-loaded only when a scene includes a ground.\n * Contains the ground material, mesh buffers, texture loading, and UBO creation.\n * Tree-shaken away from scenes that use `skipGround: true`. */\n\nimport { F32, U16, U8 } from \"../../engine/typed-arrays.js\";\nimport { TU, BU, SS } from \"../../engine/gpu-flags.js\";\nimport type { Mat4 } from \"../../math/types.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { Renderable } from \"../../render/renderable.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\nimport { getBilinearSampler } from \"../../resource/samplers.js\";\nimport { createUniformBuffer } from \"../../resource/gpu-buffers.js\";\nimport { getSceneBindGroupLayout } from \"../../render/scene-helpers.js\";\nimport { targetSignatureKey } from \"../../engine/render-target.js\";\nimport groundVertSrc from \"../../../shaders/background.vertex.wgsl?raw\";\nimport groundFragSrc from \"../../../shaders/background.ground.fragment.wgsl?raw\";\nimport { createMappedBuffer } from \"../../resource/gpu-buffers.js\";\nimport { SCENE_UBO_WGSL } from \"../../shader/scene-uniforms.js\";\nimport { WGSL_DITHER, WGSL_NO_DITHER } from \"../../shader/wgsl-helpers.js\";\n\n// ── Ground-frag-only WGSL helpers (kept here so scenes that don't load the ground\n// don't pay for the image-processing helper in the shared wgsl-helpers chunk). ──\n\n/** Image processing: exposure → Reinhard tonemap → gamma → contrast. */\nconst WGSL_IMAGE_PROCESSING = `\nfn applyImageProcessing(result: vec4<f32>) -> vec4<f32> {\nvar rgb = result.rgb;\nrgb *= scene.vImageInfos.x;\nconst tonemappingCalibration: f32 = 1.590579;\nrgb = 1.0 - exp2(-tonemappingCalibration * rgb);\nrgb = pow(rgb, vec3<f32>(1.0 / 2.2));\nrgb = clamp(rgb, vec3<f32>(0.0), vec3<f32>(1.0));\nlet highContrast = rgb * rgb * (3.0 - 2.0 * rgb);\nif (scene.vImageInfos.y < 1.0) {\nrgb = mix(vec3<f32>(0.5), rgb, scene.vImageInfos.y);\n} else {\nrgb = mix(rgb, highContrast, scene.vImageInfos.y - 1.0);\n}\nrgb = max(rgb, vec3<f32>(0.0));\nreturn vec4<f32>(rgb, result.a);\n}\n`;\n\nconst BG_MESH_UNIFORM_SIZE = 96; // mat4x4 + primaryColor vec3 + alpha + backgroundCenter vec3 + pad\n\n/** Build the ground renderable for a PBR environment scene. */\nexport async function buildGroundRenderable(\n engine: EngineContext,\n groundSize: number,\n rootPosition: [number, number, number],\n primaryColor: [number, number, number],\n groundTextureUrl?: string,\n groundImagePromise?: Promise<ImageBitmap>,\n enableNoise = true\n): Promise<Renderable> {\n const fragCode = SCENE_UBO_WGSL + WGSL_IMAGE_PROCESSING + (enableNoise ? WGSL_DITHER : WGSL_NO_DITHER) + groundFragSrc;\n const gndMat = createGroundMaterial(enableNoise, fragCode);\n\n // Ground world: rotated 90° X (XY→XZ), translated to rootPosition\n // Column-major for WGSL: ground quad in XY plane, normal +Z → world +Y\n // Offset Y by -0.01 to prevent z-fighting with scene floor geometry.\n const eps = 2.220446049250313e-16;\n const groundWorld = new F32(16);\n groundWorld[0] = 1;\n groundWorld[5] = eps;\n groundWorld[6] = -1;\n groundWorld[9] = 1;\n groundWorld[10] = eps;\n groundWorld[12] = rootPosition[0];\n groundWorld[13] = rootPosition[1];\n groundWorld[14] = rootPosition[2];\n groundWorld[15] = 1;\n\n const gndBufs = createGroundBuffers(engine, groundSize);\n const gndUBO = createBgMeshUBO(engine, groundWorld as unknown as Mat4, primaryColor);\n\n const groundTex = await loadGroundTexture(engine, groundTextureUrl, groundImagePromise);\n const groundTexView = groundTex.createView();\n const groundSamp = getBilinearSampler(engine);\n const gndBG = gndMat.createBindGroup(engine, gndUBO, groundTexView, groundSamp);\n\n const r: Renderable = {\n order: 200, // ground renders last (transparent)\n isTransparent: true,\n bind(eng, sig) {\n return {\n renderable: r,\n pipeline: gndMat.getPipeline(eng as EngineContext, sig),\n draw(pass) {\n pass.setBindGroup(1, gndBG);\n pass.setVertexBuffer(0, gndBufs.posBuffer);\n pass.setVertexBuffer(1, gndBufs.normBuffer);\n pass.setVertexBuffer(2, gndBufs.uvBuffer);\n pass.setIndexBuffer(gndBufs.idxBuffer, \"uint16\");\n pass.drawIndexed(gndBufs.idxCount);\n return 1;\n },\n };\n },\n };\n return r;\n}\n\n// ─── Ground Material ────────────────────────────────────────────────────────\n\ninterface GroundMaterial {\n getPipeline(engine: EngineContext, sig: RenderTargetSignature): GPURenderPipeline;\n createBindGroup(engine: EngineContext, meshUBO: GPUBuffer, groundTextureView: GPUTextureView, groundSampler: GPUSampler): GPUBindGroup;\n}\n\n/** Module-global pipeline cache — keyed by noise mode + full target signature (color/depth/samples/flipY).\n * All ground renderables share this cache. */\nconst _gndPipelines = new Map<string, GPURenderPipeline>();\nlet _gndLayout: GPUBindGroupLayout | null = null;\nlet _gndCachedDevice: GPUDevice | null = null;\n\nfunction createGroundMaterial(enableNoise: boolean, fragCode: string): GroundMaterial {\n function getLayout(engine: EngineContext): GPUBindGroupLayout {\n const device = engine._device;\n if (_gndLayout && _gndCachedDevice === device) {\n return _gndLayout;\n }\n _gndLayout = device.createBindGroupLayout({\n label: \"ground-material\",\n entries: [\n { binding: 0, visibility: SS.VERTEX | SS.FRAGMENT, buffer: { type: \"uniform\" } },\n { binding: 1, visibility: SS.FRAGMENT, texture: { sampleType: \"float\", viewDimension: \"2d\" } },\n { binding: 2, visibility: SS.FRAGMENT, sampler: { type: \"filtering\" } },\n ],\n });\n _gndCachedDevice = device;\n return _gndLayout;\n }\n\n return {\n getPipeline(engine, sig) {\n const device = engine._device;\n if (_gndCachedDevice !== device) {\n _gndPipelines.clear();\n _gndLayout = null;\n _gndCachedDevice = device;\n }\n const key = `${+enableNoise}|${targetSignatureKey(sig)}`;\n const cached = _gndPipelines.get(key);\n if (cached) {\n return cached;\n }\n const vertModule = device.createShaderModule({ code: SCENE_UBO_WGSL + groundVertSrc, label: \"ground-vert\" });\n const fragModule = device.createShaderModule({ code: fragCode, label: \"ground-frag\" });\n\n // Matches BJS rp_8: premultiplied alpha blend, depthWrite=false\n const pipeline = device.createRenderPipeline({\n label: \"ground-pipeline\",\n layout: device.createPipelineLayout({ bindGroupLayouts: [getSceneBindGroupLayout(engine), getLayout(engine)] }),\n vertex: {\n module: vertModule,\n entryPoint: \"main\",\n buffers: [\n { arrayStride: 12, attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x3\" as GPUVertexFormat }] },\n { arrayStride: 12, attributes: [{ shaderLocation: 1, offset: 0, format: \"float32x3\" as GPUVertexFormat }] },\n { arrayStride: 8, attributes: [{ shaderLocation: 2, offset: 0, format: \"float32x2\" as GPUVertexFormat }] },\n ],\n },\n fragment: {\n module: fragModule,\n entryPoint: \"main\",\n targets: [\n {\n format: sig._colorFormat!,\n blend: {\n color: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n },\n },\n ],\n },\n depthStencil: {\n format: sig._depthStencilFormat ?? \"depth24plus-stencil8\",\n depthCompare: sig._depthCompare ?? \"greater-equal\",\n depthWriteEnabled: false,\n },\n multisample: { count: sig._sampleCount },\n primitive: { topology: \"triangle-list\", cullMode: \"back\", frontFace: \"ccw\" },\n });\n _gndPipelines.set(key, pipeline);\n return pipeline;\n },\n\n createBindGroup(engine, meshUBO, groundTextureView, groundSampler) {\n const device = engine._device;\n return device.createBindGroup({\n layout: getLayout(engine),\n entries: [\n { binding: 0, resource: { buffer: meshUBO } },\n { binding: 1, resource: groundTextureView },\n { binding: 2, resource: groundSampler },\n ],\n });\n },\n };\n}\n\n// ─── Ground Mesh Data ───────────────────────────────────────────────────────\n\n/** Ground quad (4 verts, 6 indices — matches BJS CreatePlane with BACKSIDE).\n * XY plane, normals +Z (become +Y after world rotation). */\nfunction createGroundBuffers(\n engine: EngineContext,\n groundSize: number\n): {\n posBuffer: GPUBuffer;\n normBuffer: GPUBuffer;\n uvBuffer: GPUBuffer;\n idxBuffer: GPUBuffer;\n idxCount: number;\n} {\n const h = groundSize / 2;\n // prettier-ignore\n const positions = new F32([\n -h, -h, 0,\n h, -h, 0,\n h, h, 0,\n -h, h, 0,\n ]);\n // prettier-ignore\n const normals = new F32([\n 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,\n ]);\n // prettier-ignore\n const uvs = new F32([\n 0, 0, 1, 0, 1, 1, 0, 1,\n ]);\n // BACKSIDE winding\n // prettier-ignore\n const indices = new U16([0, 2, 1, 0, 3, 2]);\n\n return {\n posBuffer: createMappedBuffer(engine, positions, BU.VERTEX),\n normBuffer: createMappedBuffer(engine, normals, BU.VERTEX),\n uvBuffer: createMappedBuffer(engine, uvs, BU.VERTEX),\n idxBuffer: createMappedBuffer(engine, indices, BU.INDEX),\n idxCount: 6,\n };\n}\n\n// ─── Ground UBO ─────────────────────────────────────────────────────────────\n\nfunction createBgMeshUBO(engine: EngineContext, world: Mat4, primaryColor: [number, number, number]): GPUBuffer {\n const data = new F32(BG_MESH_UNIFORM_SIZE / 4);\n data.set(world, 0); // offset 0: world mat4x4\n data[16] = primaryColor[0]; // offset 64: primaryColor.r\n data[17] = primaryColor[1]; // offset 68: primaryColor.g\n data[18] = primaryColor[2]; // offset 72: primaryColor.b\n data[19] = 0.9; // offset 76: alpha (BJS default groundOpacity)\n data[20] = 0;\n data[21] = 0;\n data[22] = 0; // offset 80: backgroundCenter\n return createUniformBuffer(engine, data);\n}\n\n// ─── Ground Texture ─────────────────────────────────────────────────────────\n\n/** Load a ground diffuse texture from URL and upload to GPU.\n * Falls back to a 1×1 white pixel if no URL provided. */\nasync function loadGroundTexture(engine: EngineContext, url?: string, preloadedImage?: Promise<ImageBitmap>): Promise<GPUTexture> {\n const device = engine._device;\n if (!url) {\n const tex = device.createTexture({\n size: [1, 1],\n format: \"rgba8unorm\",\n usage: TU.TEXTURE_BINDING | TU.COPY_DST,\n });\n device.queue.writeTexture({ texture: tex }, new U8([255, 255, 255, 255]), { bytesPerRow: 4 }, [1, 1]);\n return tex;\n }\n // Use pre-fetched image if available (started early in loadEnvironment)\n const bmp = preloadedImage\n ? await preloadedImage\n : await fetch(url)\n .then((r) => r.blob())\n .then((b) => createImageBitmap(b, { premultiplyAlpha: \"none\" }));\n const tex = device.createTexture({\n size: [bmp.width, bmp.height],\n format: \"rgba8unorm\",\n usage: TU.TEXTURE_BINDING | TU.COPY_DST | TU.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture({ source: bmp }, { texture: tex }, [bmp.width, bmp.height]);\n bmp.close();\n return tex;\n}\n"],"names":["tex"],"mappings":"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"}
1
+ {"version":3,"file":"background-ground-Bm6gjWqx.js","sources":["../shaders/background.vertex.wgsl?raw","../shaders/background.ground.fragment.wgsl?raw","../src/material/pbr/background-ground.ts"],"sourcesContent":["export default \"// Background Ground Vertex Shader\\n// Matches BJS shd_15: DIFFUSE, OPACITYFRESNEL, PREMULTIPLYALPHA (no REFLECTION)\\n\\nstruct MeshUniforms {\\n world: mat4x4<f32>,\\n};\\n\\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\\n\\nstruct VertexInput {\\n @location(0) position: vec3<f32>,\\n @location(1) normal: vec3<f32>,\\n @location(2) uv: vec2<f32>,\\n};\\n\\nstruct VertexOutput {\\n @builtin(position) clipPos: vec4<f32>,\\n @location(0) vPositionW: vec3<f32>,\\n @location(1) vNormalW: vec3<f32>,\\n @location(2) vUV: vec2<f32>,\\n};\\n\\n@vertex\\nfn main(input: VertexInput) -> VertexOutput {\\n var output: VertexOutput;\\n let finalWorld = mesh.world;\\n let worldPos4 = finalWorld * vec4<f32>(input.position, 1.0);\\n output.vPositionW = worldPos4.xyz;\\n output.clipPos = scene.viewProjection * worldPos4;\\n let normalWorld = mat3x3<f32>(finalWorld[0].xyz, finalWorld[1].xyz, finalWorld[2].xyz);\\n output.vNormalW = normalize(normalWorld * input.normal);\\n output.vUV = input.uv;\\n return output;\\n}\\n\"","export default \"// Background Ground Fragment Shader\\n// Matches BJS shd_16: DIFFUSE, OPACITYFRESNEL, PREMULTIPLYALPHA (no REFLECTION)\\n// Verified via Spector.GPU capture of BJS scene 1\\n\\nstruct MeshUniforms {\\n world: mat4x4<f32>,\\n primaryColor: vec3<f32>,\\n alpha: f32,\\n backgroundCenter: vec3<f32>,\\n _pad: f32,\\n};\\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\\n\\n@group(1) @binding(1) var groundTexture: texture_2d<f32>;\\n@group(1) @binding(2) var groundSampler: sampler;\\n\\nstruct FragmentInput {\\n @location(0) vPositionW: vec3<f32>,\\n @location(1) vNormalW: vec3<f32>,\\n @location(2) vUV: vec2<f32>,\\n};\\n\\n@fragment\\nfn main(input: FragmentInput) -> @location(0) vec4<f32> {\\n let normalW = normalize(input.vNormalW);\\n\\n // Sample diffuse texture (BJS backgroundGround.png: white RGB, radial alpha gradient)\\n let diffuseMap = textureSample(groundTexture, groundSampler, input.vUV);\\n\\n // BJS: reflectionColor = vec4(1) (no REFLECTION define)\\n let diffuseColor = diffuseMap.rgb;\\n let colorBase = max(diffuseColor, vec3<f32>(0.0));\\n let mainColor = mesh.primaryColor;\\n let finalColor = colorBase * mainColor;\\n\\n // Alpha starts from material alpha, multiplied by texture alpha\\n var finalAlpha = mesh.alpha * diffuseMap.a;\\n\\n // OPACITYFRESNEL — BJS shd_16 lines 367-370\\n let viewAngleToFloor = dot(normalW, normalize(scene.vEyePosition.xyz - mesh.backgroundCenter));\\n const startAngle: f32 = 0.1;\\n let fadeFactor = clamp(viewAngleToFloor / startAngle, 0.0, 1.0);\\n finalAlpha *= fadeFactor * fadeFactor;\\n\\n // Image processing (preserves alpha)\\n var color = vec4<f32>(finalColor, finalAlpha);\\n if (scene.vImageInfos.w >= 0.0) {\\n color = applyImageProcessing(color);\\n }\\n\\n // PREMULTIPLYALPHA — BJS shd_16 line 373\\n color = vec4<f32>(color.rgb * color.a, color.a);\\n\\n // Dithering\\n color = vec4<f32>(color.rgb + vec3<f32>(dither(input.vPositionW.xy, 0.5)), color.a);\\n color = max(color, vec4<f32>(0.0));\\n\\n return color;\\n}\\n\"","/** Ground plane renderable — lazy-loaded only when a scene includes a ground.\n * Contains the ground material, mesh buffers, texture loading, and UBO creation.\n * Tree-shaken away from scenes that use `skipGround: true`. */\n\nimport { F32, U16, U8 } from \"../../engine/typed-arrays.js\";\nimport { TU, BU, SS } from \"../../engine/gpu-flags.js\";\nimport type { Mat4 } from \"../../math/types.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { Renderable } from \"../../render/renderable.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\nimport { getBilinearSampler } from \"../../resource/samplers.js\";\nimport { createUniformBuffer } from \"../../resource/gpu-buffers.js\";\nimport { getSceneBindGroupLayout } from \"../../render/scene-helpers.js\";\nimport { targetSignatureKey } from \"../../engine/render-target.js\";\nimport groundVertSrc from \"../../../shaders/background.vertex.wgsl?raw\";\nimport groundFragSrc from \"../../../shaders/background.ground.fragment.wgsl?raw\";\nimport { createMappedBuffer } from \"../../resource/gpu-buffers.js\";\nimport { SCENE_UBO_WGSL } from \"../../shader/scene-uniforms.js\";\nimport { WGSL_DITHER, WGSL_NO_DITHER } from \"../../shader/wgsl-helpers.js\";\n\n// ── Ground-frag-only WGSL helpers (kept here so scenes that don't load the ground\n// don't pay for the image-processing helper in the shared wgsl-helpers chunk). ──\n\n/** Image processing: exposure → Reinhard tonemap → gamma → contrast. */\nconst WGSL_IMAGE_PROCESSING = `\nfn applyImageProcessing(result: vec4<f32>) -> vec4<f32> {\nvar rgb = result.rgb;\nrgb *= scene.vImageInfos.x;\nconst tonemappingCalibration: f32 = 1.590579;\nrgb = 1.0 - exp2(-tonemappingCalibration * rgb);\nrgb = pow(rgb, vec3<f32>(1.0 / 2.2));\nrgb = clamp(rgb, vec3<f32>(0.0), vec3<f32>(1.0));\nlet highContrast = rgb * rgb * (3.0 - 2.0 * rgb);\nif (scene.vImageInfos.y < 1.0) {\nrgb = mix(vec3<f32>(0.5), rgb, scene.vImageInfos.y);\n} else {\nrgb = mix(rgb, highContrast, scene.vImageInfos.y - 1.0);\n}\nrgb = max(rgb, vec3<f32>(0.0));\nreturn vec4<f32>(rgb, result.a);\n}\n`;\n\nconst BG_MESH_UNIFORM_SIZE = 96; // mat4x4 + primaryColor vec3 + alpha + backgroundCenter vec3 + pad\n\n/** Build the ground renderable for a PBR environment scene. */\nexport async function buildGroundRenderable(\n engine: EngineContext,\n groundSize: number,\n rootPosition: [number, number, number],\n primaryColor: [number, number, number],\n groundTextureUrl?: string,\n groundImagePromise?: Promise<ImageBitmap>,\n enableNoise = true\n): Promise<Renderable> {\n const fragCode = SCENE_UBO_WGSL + WGSL_IMAGE_PROCESSING + (enableNoise ? WGSL_DITHER : WGSL_NO_DITHER) + groundFragSrc;\n const gndMat = createGroundMaterial(enableNoise, fragCode);\n\n // Ground world: rotated 90° X (XY→XZ), translated to rootPosition\n // Column-major for WGSL: ground quad in XY plane, normal +Z → world +Y\n // Offset Y by -0.01 to prevent z-fighting with scene floor geometry.\n const eps = 2.220446049250313e-16;\n const groundWorld = new F32(16);\n groundWorld[0] = 1;\n groundWorld[5] = eps;\n groundWorld[6] = -1;\n groundWorld[9] = 1;\n groundWorld[10] = eps;\n groundWorld[12] = rootPosition[0];\n groundWorld[13] = rootPosition[1];\n groundWorld[14] = rootPosition[2];\n groundWorld[15] = 1;\n\n const gndBufs = createGroundBuffers(engine, groundSize);\n const gndUBO = createBgMeshUBO(engine, groundWorld as unknown as Mat4, primaryColor);\n\n const groundTex = await loadGroundTexture(engine, groundTextureUrl, groundImagePromise);\n const groundTexView = groundTex.createView();\n const groundSamp = getBilinearSampler(engine);\n const gndBG = gndMat.createBindGroup(engine, gndUBO, groundTexView, groundSamp);\n\n const r: Renderable = {\n order: 200, // ground renders last (transparent)\n isTransparent: true,\n bind(eng, sig) {\n return {\n renderable: r,\n pipeline: gndMat.getPipeline(eng as EngineContext, sig),\n draw(pass) {\n pass.setBindGroup(1, gndBG);\n pass.setVertexBuffer(0, gndBufs.posBuffer);\n pass.setVertexBuffer(1, gndBufs.normBuffer);\n pass.setVertexBuffer(2, gndBufs.uvBuffer);\n pass.setIndexBuffer(gndBufs.idxBuffer, \"uint16\");\n pass.drawIndexed(gndBufs.idxCount);\n return 1;\n },\n };\n },\n };\n return r;\n}\n\n// ─── Ground Material ────────────────────────────────────────────────────────\n\ninterface GroundMaterial {\n getPipeline(engine: EngineContext, sig: RenderTargetSignature): GPURenderPipeline;\n createBindGroup(engine: EngineContext, meshUBO: GPUBuffer, groundTextureView: GPUTextureView, groundSampler: GPUSampler): GPUBindGroup;\n}\n\n/** Module-global pipeline cache — keyed by noise mode + full target signature (color/depth/samples/flipY).\n * All ground renderables share this cache. */\nconst _gndPipelines = new Map<string, GPURenderPipeline>();\nlet _gndLayout: GPUBindGroupLayout | null = null;\nlet _gndCachedDevice: GPUDevice | null = null;\n\nfunction createGroundMaterial(enableNoise: boolean, fragCode: string): GroundMaterial {\n function getLayout(engine: EngineContext): GPUBindGroupLayout {\n const device = engine._device;\n if (_gndLayout && _gndCachedDevice === device) {\n return _gndLayout;\n }\n _gndLayout = device.createBindGroupLayout({\n label: \"ground-material\",\n entries: [\n { binding: 0, visibility: SS.VERTEX | SS.FRAGMENT, buffer: { type: \"uniform\" } },\n { binding: 1, visibility: SS.FRAGMENT, texture: { sampleType: \"float\", viewDimension: \"2d\" } },\n { binding: 2, visibility: SS.FRAGMENT, sampler: { type: \"filtering\" } },\n ],\n });\n _gndCachedDevice = device;\n return _gndLayout;\n }\n\n return {\n getPipeline(engine, sig) {\n const device = engine._device;\n if (_gndCachedDevice !== device) {\n _gndPipelines.clear();\n _gndLayout = null;\n _gndCachedDevice = device;\n }\n const key = `${+enableNoise}|${targetSignatureKey(sig)}`;\n const cached = _gndPipelines.get(key);\n if (cached) {\n return cached;\n }\n const vertModule = device.createShaderModule({ code: SCENE_UBO_WGSL + groundVertSrc, label: \"ground-vert\" });\n const fragModule = device.createShaderModule({ code: fragCode, label: \"ground-frag\" });\n\n // Matches BJS rp_8: premultiplied alpha blend, depthWrite=false\n const pipeline = device.createRenderPipeline({\n label: \"ground-pipeline\",\n layout: device.createPipelineLayout({ bindGroupLayouts: [getSceneBindGroupLayout(engine), getLayout(engine)] }),\n vertex: {\n module: vertModule,\n entryPoint: \"main\",\n buffers: [\n { arrayStride: 12, attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x3\" as GPUVertexFormat }] },\n { arrayStride: 12, attributes: [{ shaderLocation: 1, offset: 0, format: \"float32x3\" as GPUVertexFormat }] },\n { arrayStride: 8, attributes: [{ shaderLocation: 2, offset: 0, format: \"float32x2\" as GPUVertexFormat }] },\n ],\n },\n fragment: {\n module: fragModule,\n entryPoint: \"main\",\n targets: [\n {\n format: sig._colorFormat!,\n blend: {\n color: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n },\n },\n ],\n },\n depthStencil: {\n format: sig._depthStencilFormat ?? \"depth24plus-stencil8\",\n depthCompare: sig._depthCompare ?? \"greater-equal\",\n depthWriteEnabled: false,\n },\n multisample: { count: sig._sampleCount },\n primitive: { topology: \"triangle-list\", cullMode: \"back\", frontFace: \"ccw\" },\n });\n _gndPipelines.set(key, pipeline);\n return pipeline;\n },\n\n createBindGroup(engine, meshUBO, groundTextureView, groundSampler) {\n const device = engine._device;\n return device.createBindGroup({\n layout: getLayout(engine),\n entries: [\n { binding: 0, resource: { buffer: meshUBO } },\n { binding: 1, resource: groundTextureView },\n { binding: 2, resource: groundSampler },\n ],\n });\n },\n };\n}\n\n// ─── Ground Mesh Data ───────────────────────────────────────────────────────\n\n/** Ground quad (4 verts, 6 indices — matches BJS CreatePlane with BACKSIDE).\n * XY plane, normals +Z (become +Y after world rotation). */\nfunction createGroundBuffers(\n engine: EngineContext,\n groundSize: number\n): {\n posBuffer: GPUBuffer;\n normBuffer: GPUBuffer;\n uvBuffer: GPUBuffer;\n idxBuffer: GPUBuffer;\n idxCount: number;\n} {\n const h = groundSize / 2;\n // prettier-ignore\n const positions = new F32([\n -h, -h, 0,\n h, -h, 0,\n h, h, 0,\n -h, h, 0,\n ]);\n // prettier-ignore\n const normals = new F32([\n 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,\n ]);\n // prettier-ignore\n const uvs = new F32([\n 0, 0, 1, 0, 1, 1, 0, 1,\n ]);\n // BACKSIDE winding\n // prettier-ignore\n const indices = new U16([0, 2, 1, 0, 3, 2]);\n\n return {\n posBuffer: createMappedBuffer(engine, positions, BU.VERTEX),\n normBuffer: createMappedBuffer(engine, normals, BU.VERTEX),\n uvBuffer: createMappedBuffer(engine, uvs, BU.VERTEX),\n idxBuffer: createMappedBuffer(engine, indices, BU.INDEX),\n idxCount: 6,\n };\n}\n\n// ─── Ground UBO ─────────────────────────────────────────────────────────────\n\nfunction createBgMeshUBO(engine: EngineContext, world: Mat4, primaryColor: [number, number, number]): GPUBuffer {\n const data = new F32(BG_MESH_UNIFORM_SIZE / 4);\n data.set(world, 0); // offset 0: world mat4x4\n data[16] = primaryColor[0]; // offset 64: primaryColor.r\n data[17] = primaryColor[1]; // offset 68: primaryColor.g\n data[18] = primaryColor[2]; // offset 72: primaryColor.b\n data[19] = 0.9; // offset 76: alpha (BJS default groundOpacity)\n data[20] = 0;\n data[21] = 0;\n data[22] = 0; // offset 80: backgroundCenter\n return createUniformBuffer(engine, data);\n}\n\n// ─── Ground Texture ─────────────────────────────────────────────────────────\n\n/** Load a ground diffuse texture from URL and upload to GPU.\n * Falls back to a 1×1 white pixel if no URL provided. */\nasync function loadGroundTexture(engine: EngineContext, url?: string, preloadedImage?: Promise<ImageBitmap>): Promise<GPUTexture> {\n const device = engine._device;\n if (!url) {\n const tex = device.createTexture({\n size: [1, 1],\n format: \"rgba8unorm\",\n usage: TU.TEXTURE_BINDING | TU.COPY_DST,\n });\n device.queue.writeTexture({ texture: tex }, new U8([255, 255, 255, 255]), { bytesPerRow: 4 }, [1, 1]);\n return tex;\n }\n // Use pre-fetched image if available (started early in loadEnvironment)\n const bmp = preloadedImage\n ? await preloadedImage\n : await fetch(url)\n .then((r) => r.blob())\n .then((b) => createImageBitmap(b, { premultiplyAlpha: \"none\" }));\n const tex = device.createTexture({\n size: [bmp.width, bmp.height],\n format: \"rgba8unorm\",\n usage: TU.TEXTURE_BINDING | TU.COPY_DST | TU.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture({ source: bmp }, { texture: tex }, [bmp.width, bmp.height]);\n bmp.close();\n return tex;\n}\n"],"names":["tex"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { a as F32, j as createMappedBuffer, B as BU, h as U16, av as createUniformBuffer, q as SCENE_UBO_WGSL } from "./index-CLElg2Bo.js";
2
- import { c as createCubemapSkyboxMaterial } from "./cubemap-skybox-material-DQcMMdf-.js";
1
+ import { a as F32, k as createMappedBuffer, B as BU, j as U16, ay as createUniformBuffer, q as SCENE_UBO_WGSL } from "./index-BgY3QEzL.js";
2
+ import { c as createCubemapSkyboxMaterial } from "./cubemap-skybox-material-8lzbgi7K.js";
3
3
  import { s as skyboxVertSrc } from "./skybox.vertex-DJgi072W.js";
4
4
  const skyboxHdrFragSrc = "// HDR Skybox Fragment Shader — samples HDR environment cubemap with image processing.\n// Used when scene has an HDR environment rendered as the background.\n// Matches BJS BackgroundMaterial: cubemap at LOD 0 + exposure + gamma + contrast.\n\nstruct MeshUniforms {\n world: mat4x4<f32>,\n primaryColor: vec3<f32>,\n _pad: f32,\n skyOutputColor: vec3<f32>,\n _pad2: f32,\n exposureLinear: f32,\n contrast: f32,\n _pad3: f32,\n _pad4: f32,\n};\n\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\n@group(1) @binding(1) var envCubemap: texture_cube<f32>;\n@group(1) @binding(2) var envSampler: sampler;\n\nstruct FragmentInput {\n @location(0) positionUVW: vec3<f32>,\n @location(1) positionW: vec3<f32>,\n};\n\n@fragment\nfn main(input: FragmentInput) -> @location(0) vec4<f32> {\n let dir = normalize(input.positionUVW);\n var color = textureSampleLevel(envCubemap, envSampler, dir, 0.0).rgb;\n\n // Image processing: exposure → gamma → contrast (matches BJS applyImageProcessing)\n color *= mesh.exposureLinear;\n color = pow(color, vec3<f32>(1.0 / 2.2));\n color = clamp(color, vec3<f32>(0.0), vec3<f32>(1.0));\n\n let highContrast = color * color * (3.0 - 2.0 * color);\n if (mesh.contrast < 1.0) { color = mix(vec3<f32>(0.5), color, mesh.contrast); }\n else { color = mix(color, highContrast, mesh.contrast - 1.0); }\n color = max(color, vec3<f32>(0.0));\n\n return vec4<f32>(color, 1.0);\n}\n";
5
5
  const SKY_HDR_UNIFORM_SIZE = 112;
@@ -176,4 +176,4 @@ function createSkyHdrMeshUBO(engine, world, primaryColor, skyOutputColor, exposu
176
176
  export {
177
177
  buildHdrSkyboxRenderable
178
178
  };
179
- //# sourceMappingURL=background-hdr-skybox--RRRic_K.js.map
179
+ //# sourceMappingURL=background-hdr-skybox-CSFo8RX6.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"background-hdr-skybox--RRRic_K.js","sources":["../shaders/skybox-hdr.fragment.wgsl?raw","../src/material/pbr/background-hdr-skybox.ts"],"sourcesContent":["export default \"// HDR Skybox Fragment Shader — samples HDR environment cubemap with image processing.\\n// Used when scene has an HDR environment rendered as the background.\\n// Matches BJS BackgroundMaterial: cubemap at LOD 0 + exposure + gamma + contrast.\\n\\nstruct MeshUniforms {\\n world: mat4x4<f32>,\\n primaryColor: vec3<f32>,\\n _pad: f32,\\n skyOutputColor: vec3<f32>,\\n _pad2: f32,\\n exposureLinear: f32,\\n contrast: f32,\\n _pad3: f32,\\n _pad4: f32,\\n};\\n\\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\\n@group(1) @binding(1) var envCubemap: texture_cube<f32>;\\n@group(1) @binding(2) var envSampler: sampler;\\n\\nstruct FragmentInput {\\n @location(0) positionUVW: vec3<f32>,\\n @location(1) positionW: vec3<f32>,\\n};\\n\\n@fragment\\nfn main(input: FragmentInput) -> @location(0) vec4<f32> {\\n let dir = normalize(input.positionUVW);\\n var color = textureSampleLevel(envCubemap, envSampler, dir, 0.0).rgb;\\n\\n // Image processing: exposure → gamma → contrast (matches BJS applyImageProcessing)\\n color *= mesh.exposureLinear;\\n color = pow(color, vec3<f32>(1.0 / 2.2));\\n color = clamp(color, vec3<f32>(0.0), vec3<f32>(1.0));\\n\\n let highContrast = color * color * (3.0 - 2.0 * color);\\n if (mesh.contrast < 1.0) { color = mix(vec3<f32>(0.5), color, mesh.contrast); }\\n else { color = mix(color, highContrast, mesh.contrast - 1.0); }\\n color = max(color, vec3<f32>(0.0));\\n\\n return vec4<f32>(color, 1.0);\\n}\\n\"","/** HDR cubemap skybox — lazy-loaded only when useCubemapSkybox is true.\n * Contains the HDR skybox material, shader, UBO, and skybox geometry.\n * Self-contained: computes scene bounds and builds a full Renderable.\n * Tree-shaken away from scenes that use the default solid-color skybox. */\n\nimport { F32, U16 } from \"../../engine/typed-arrays.js\";\nimport { BU } from \"../../engine/gpu-flags.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { EnvironmentTextures } from \"../../loader-env/load-env.js\";\n// Mat4 import removed: local world matrices stored as Float32Array.\nimport type { Renderable } from \"../../render/renderable.js\";\nimport { createCubemapSkyboxMaterial } from \"./cubemap-skybox-material.js\";\nimport skyboxVertSrc from \"../../../shaders/skybox.vertex.wgsl?raw\";\nimport skyboxHdrFragSrc from \"../../../shaders/skybox-hdr.fragment.wgsl?raw\";\nimport { SCENE_UBO_WGSL } from \"../../shader/scene-uniforms.js\";\nimport { createMappedBuffer, createUniformBuffer } from \"../../resource/gpu-buffers.js\";\n\nconst SKY_HDR_UNIFORM_SIZE = 112; // mat4x4 + primaryColor vec3 + pad + skyOutputColor vec3 + pad + exposure + contrast + pad2\n\nfunction createSkyboxBuffers(engine: EngineContext, S: number): { posBuffer: GPUBuffer; idxBuffer: GPUBuffer; idxCount: number } {\n // prettier-ignore\n const positions = new F32([\n S,-S, S, -S,-S, S, -S, S, S, S, S, S,\n S, S,-S, -S, S,-S, -S,-S,-S, S,-S,-S,\n S, S,-S, S,-S,-S, S,-S, S, S, S, S,\n -S, S, S, -S,-S, S, -S,-S,-S, -S, S,-S,\n -S, S, S, -S, S,-S, S, S,-S, S, S, S,\n S,-S, S, S,-S,-S, -S,-S,-S, -S,-S, S,\n ]);\n // prettier-ignore\n const indices = new U16([\n 2, 1, 0, 3, 2, 0, 6, 5, 4, 7, 6, 4,\n 10, 9, 8, 11,10, 8, 14,13,12, 15,14,12,\n 18,17,16, 19,18,16, 22,21,20, 23,22,20,\n ]);\n return {\n posBuffer: createMappedBuffer(engine, positions, BU.VERTEX),\n idxBuffer: createMappedBuffer(engine, indices, BU.INDEX),\n idxCount: 36,\n };\n}\n\nfunction buildSkyboxWorldMatrix(rootPosition: [number, number, number]): Float32Array {\n const world = new F32(16);\n world[0] = 1;\n world[5] = 1;\n world[10] = 1;\n world[15] = 1;\n world[12] = rootPosition[0];\n world[13] = rootPosition[1];\n world[14] = rootPosition[2];\n return world;\n}\n\n/** Build an HDR cubemap skybox as a complete Renderable (order 0). */\nexport function buildHdrSkyboxRenderable(\n scene: SceneContext,\n envTextures: EnvironmentTextures,\n skyHalfSize: number,\n rootPosition: [number, number, number],\n primaryColor: [number, number, number]\n): Renderable {\n const engine = scene.surface.engine;\n\n const skyboxWorld = buildSkyboxWorldMatrix(rootPosition);\n\n const cc = scene.clearColor;\n\n const skyBufs = createSkyboxBuffers(engine, skyHalfSize);\n const mat = createCubemapSkyboxMaterial(\"skybox-hdr\", SCENE_UBO_WGSL + skyboxVertSrc, skyboxHdrFragSrc);\n const ubo = createSkyHdrMeshUBO(engine, skyboxWorld, primaryColor, [cc.r, cc.g, cc.b], scene.imageProcessing.exposure, scene.imageProcessing.contrast);\n\n const bindGroup = mat.createBindGroup(engine, ubo, envTextures.specularCubeView!, envTextures.cubeSampler);\n\n const r: Renderable = {\n order: 0,\n isTransparent: false,\n bind(eng, sig) {\n return {\n renderable: r,\n pipeline: mat.getPipeline(eng as EngineContext, sig),\n draw(pass) {\n pass.setBindGroup(1, bindGroup);\n pass.setVertexBuffer(0, skyBufs.posBuffer);\n pass.setIndexBuffer(skyBufs.idxBuffer, \"uint16\");\n pass.drawIndexed(skyBufs.idxCount);\n return 1;\n },\n };\n },\n };\n return r;\n}\n\n// ─── HDR Skybox UBO ─────────────────────────────────────────────────────────────\n\nfunction createSkyHdrMeshUBO(\n engine: EngineContext,\n world: Float32Array,\n primaryColor: [number, number, number],\n skyOutputColor: [number, number, number],\n exposure: number,\n contrast: number\n): GPUBuffer {\n const data = new F32(SKY_HDR_UNIFORM_SIZE / 4);\n data.set(world, 0);\n data[16] = primaryColor[0];\n data[17] = primaryColor[1];\n data[18] = primaryColor[2];\n data[20] = skyOutputColor[0];\n data[21] = skyOutputColor[1];\n data[22] = skyOutputColor[2];\n data[24] = exposure; // exposureLinear\n data[25] = contrast; // contrast\n return createUniformBuffer(engine, data);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"background-hdr-skybox-CSFo8RX6.js","sources":["../shaders/skybox-hdr.fragment.wgsl?raw","../src/material/pbr/background-hdr-skybox.ts"],"sourcesContent":["export default \"// HDR Skybox Fragment Shader — samples HDR environment cubemap with image processing.\\n// Used when scene has an HDR environment rendered as the background.\\n// Matches BJS BackgroundMaterial: cubemap at LOD 0 + exposure + gamma + contrast.\\n\\nstruct MeshUniforms {\\n world: mat4x4<f32>,\\n primaryColor: vec3<f32>,\\n _pad: f32,\\n skyOutputColor: vec3<f32>,\\n _pad2: f32,\\n exposureLinear: f32,\\n contrast: f32,\\n _pad3: f32,\\n _pad4: f32,\\n};\\n\\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\\n@group(1) @binding(1) var envCubemap: texture_cube<f32>;\\n@group(1) @binding(2) var envSampler: sampler;\\n\\nstruct FragmentInput {\\n @location(0) positionUVW: vec3<f32>,\\n @location(1) positionW: vec3<f32>,\\n};\\n\\n@fragment\\nfn main(input: FragmentInput) -> @location(0) vec4<f32> {\\n let dir = normalize(input.positionUVW);\\n var color = textureSampleLevel(envCubemap, envSampler, dir, 0.0).rgb;\\n\\n // Image processing: exposure → gamma → contrast (matches BJS applyImageProcessing)\\n color *= mesh.exposureLinear;\\n color = pow(color, vec3<f32>(1.0 / 2.2));\\n color = clamp(color, vec3<f32>(0.0), vec3<f32>(1.0));\\n\\n let highContrast = color * color * (3.0 - 2.0 * color);\\n if (mesh.contrast < 1.0) { color = mix(vec3<f32>(0.5), color, mesh.contrast); }\\n else { color = mix(color, highContrast, mesh.contrast - 1.0); }\\n color = max(color, vec3<f32>(0.0));\\n\\n return vec4<f32>(color, 1.0);\\n}\\n\"","/** HDR cubemap skybox — lazy-loaded only when useCubemapSkybox is true.\n * Contains the HDR skybox material, shader, UBO, and skybox geometry.\n * Self-contained: computes scene bounds and builds a full Renderable.\n * Tree-shaken away from scenes that use the default solid-color skybox. */\n\nimport { F32, U16 } from \"../../engine/typed-arrays.js\";\nimport { BU } from \"../../engine/gpu-flags.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { EnvironmentTextures } from \"../../loader-env/load-env.js\";\n// Mat4 import removed: local world matrices stored as Float32Array.\nimport type { Renderable } from \"../../render/renderable.js\";\nimport { createCubemapSkyboxMaterial } from \"./cubemap-skybox-material.js\";\nimport skyboxVertSrc from \"../../../shaders/skybox.vertex.wgsl?raw\";\nimport skyboxHdrFragSrc from \"../../../shaders/skybox-hdr.fragment.wgsl?raw\";\nimport { SCENE_UBO_WGSL } from \"../../shader/scene-uniforms.js\";\nimport { createMappedBuffer, createUniformBuffer } from \"../../resource/gpu-buffers.js\";\n\nconst SKY_HDR_UNIFORM_SIZE = 112; // mat4x4 + primaryColor vec3 + pad + skyOutputColor vec3 + pad + exposure + contrast + pad2\n\nfunction createSkyboxBuffers(engine: EngineContext, S: number): { posBuffer: GPUBuffer; idxBuffer: GPUBuffer; idxCount: number } {\n // prettier-ignore\n const positions = new F32([\n S,-S, S, -S,-S, S, -S, S, S, S, S, S,\n S, S,-S, -S, S,-S, -S,-S,-S, S,-S,-S,\n S, S,-S, S,-S,-S, S,-S, S, S, S, S,\n -S, S, S, -S,-S, S, -S,-S,-S, -S, S,-S,\n -S, S, S, -S, S,-S, S, S,-S, S, S, S,\n S,-S, S, S,-S,-S, -S,-S,-S, -S,-S, S,\n ]);\n // prettier-ignore\n const indices = new U16([\n 2, 1, 0, 3, 2, 0, 6, 5, 4, 7, 6, 4,\n 10, 9, 8, 11,10, 8, 14,13,12, 15,14,12,\n 18,17,16, 19,18,16, 22,21,20, 23,22,20,\n ]);\n return {\n posBuffer: createMappedBuffer(engine, positions, BU.VERTEX),\n idxBuffer: createMappedBuffer(engine, indices, BU.INDEX),\n idxCount: 36,\n };\n}\n\nfunction buildSkyboxWorldMatrix(rootPosition: [number, number, number]): Float32Array {\n const world = new F32(16);\n world[0] = 1;\n world[5] = 1;\n world[10] = 1;\n world[15] = 1;\n world[12] = rootPosition[0];\n world[13] = rootPosition[1];\n world[14] = rootPosition[2];\n return world;\n}\n\n/** Build an HDR cubemap skybox as a complete Renderable (order 0). */\nexport function buildHdrSkyboxRenderable(\n scene: SceneContext,\n envTextures: EnvironmentTextures,\n skyHalfSize: number,\n rootPosition: [number, number, number],\n primaryColor: [number, number, number]\n): Renderable {\n const engine = scene.surface.engine;\n\n const skyboxWorld = buildSkyboxWorldMatrix(rootPosition);\n\n const cc = scene.clearColor;\n\n const skyBufs = createSkyboxBuffers(engine, skyHalfSize);\n const mat = createCubemapSkyboxMaterial(\"skybox-hdr\", SCENE_UBO_WGSL + skyboxVertSrc, skyboxHdrFragSrc);\n const ubo = createSkyHdrMeshUBO(engine, skyboxWorld, primaryColor, [cc.r, cc.g, cc.b], scene.imageProcessing.exposure, scene.imageProcessing.contrast);\n\n const bindGroup = mat.createBindGroup(engine, ubo, envTextures.specularCubeView!, envTextures.cubeSampler);\n\n const r: Renderable = {\n order: 0,\n isTransparent: false,\n bind(eng, sig) {\n return {\n renderable: r,\n pipeline: mat.getPipeline(eng as EngineContext, sig),\n draw(pass) {\n pass.setBindGroup(1, bindGroup);\n pass.setVertexBuffer(0, skyBufs.posBuffer);\n pass.setIndexBuffer(skyBufs.idxBuffer, \"uint16\");\n pass.drawIndexed(skyBufs.idxCount);\n return 1;\n },\n };\n },\n };\n return r;\n}\n\n// ─── HDR Skybox UBO ─────────────────────────────────────────────────────────────\n\nfunction createSkyHdrMeshUBO(\n engine: EngineContext,\n world: Float32Array,\n primaryColor: [number, number, number],\n skyOutputColor: [number, number, number],\n exposure: number,\n contrast: number\n): GPUBuffer {\n const data = new F32(SKY_HDR_UNIFORM_SIZE / 4);\n data.set(world, 0);\n data[16] = primaryColor[0];\n data[17] = primaryColor[1];\n data[18] = primaryColor[2];\n data[20] = skyOutputColor[0];\n data[21] = skyOutputColor[1];\n data[22] = skyOutputColor[2];\n data[24] = exposure; // exposureLinear\n data[25] = contrast; // contrast\n return createUniformBuffer(engine, data);\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { a as F32, j as createMappedBuffer, B as BU, h as U16, av as createUniformBuffer, x as targetSignatureKey, q as SCENE_UBO_WGSL, y as createDefaultPipelineDescriptor, z as getSceneBindGroupLayout, bM as createSingleUniformBGL, S as SS } from "./index-CLElg2Bo.js";
1
+ import { a as F32, k as createMappedBuffer, B as BU, j as U16, ay as createUniformBuffer, y as targetSignatureKey, q as SCENE_UBO_WGSL, z as createDefaultPipelineDescriptor, A as getSceneBindGroupLayout, bR as createSingleUniformBGL, S as SS } from "./index-BgY3QEzL.js";
2
2
  import { s as skyboxVertSrc } from "./skybox.vertex-DJgi072W.js";
3
3
  import { b as WGSL_DITHER } from "./wgsl-helpers-D8sl1VVA.js";
4
4
  const skyboxFragSrc = "// Skybox Fragment Shader — matches Babylon BackgroundMaterial\n// BJS loads a separate CDN skybox texture (backgroundSkybox.dds) that produces\n// exactly scene.clearColor when rendered through the BackgroundMaterial pipeline.\n// We replicate this by outputting the pre-computed clearColor directly from a UBO.\n\nstruct MeshUniforms {\n world: mat4x4<f32>,\n primaryColor: vec3<f32>,\n _pad: f32,\n // Pre-computed sRGB output color for the sky background (= scene.clearColor).\n skyOutputColor: vec3<f32>,\n _pad2: f32,\n};\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\n\nstruct FragmentInput {\n @location(0) positionUVW: vec3<f32>,\n @location(1) positionW: vec3<f32>,\n};\n\n@fragment\nfn main(input: FragmentInput) -> @location(0) vec4<f32> {\n var result = vec4<f32>(mesh.skyOutputColor, 1.0);\n\n // Dithering (enableNoise=true, variance=0.5)\n result = vec4<f32>(result.rgb + vec3<f32>(dither(input.positionW.xy, 0.5)), result.a);\n result = max(result, vec4<f32>(0.0));\n\n return result;\n}\n";
@@ -231,4 +231,4 @@ function createSkyMeshUBO(engine, world, primaryColor, skyOutputColor) {
231
231
  export {
232
232
  buildSolidSkyboxRenderable
233
233
  };
234
- //# sourceMappingURL=background-solid-skybox-BrH2fXSu.js.map
234
+ //# sourceMappingURL=background-solid-skybox-DOOBeDIz.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"background-solid-skybox-BrH2fXSu.js","sources":["../shaders/skybox.fragment.wgsl?raw","../src/material/pbr/background-solid-skybox.ts"],"sourcesContent":["export default \"// Skybox Fragment Shader — matches Babylon BackgroundMaterial\\n// BJS loads a separate CDN skybox texture (backgroundSkybox.dds) that produces\\n// exactly scene.clearColor when rendered through the BackgroundMaterial pipeline.\\n// We replicate this by outputting the pre-computed clearColor directly from a UBO.\\n\\nstruct MeshUniforms {\\n world: mat4x4<f32>,\\n primaryColor: vec3<f32>,\\n _pad: f32,\\n // Pre-computed sRGB output color for the sky background (= scene.clearColor).\\n skyOutputColor: vec3<f32>,\\n _pad2: f32,\\n};\\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\\n\\nstruct FragmentInput {\\n @location(0) positionUVW: vec3<f32>,\\n @location(1) positionW: vec3<f32>,\\n};\\n\\n@fragment\\nfn main(input: FragmentInput) -> @location(0) vec4<f32> {\\n var result = vec4<f32>(mesh.skyOutputColor, 1.0);\\n\\n // Dithering (enableNoise=true, variance=0.5)\\n result = vec4<f32>(result.rgb + vec3<f32>(dither(input.positionW.xy, 0.5)), result.a);\\n result = max(result, vec4<f32>(0.0));\\n\\n return result;\\n}\\n\"","/** Solid-color skybox renderable — the clear-color background used by PBR\n * environment scenes when no HDR/DDS skybox is provided.\n *\n * Dynamically imported from `background-renderable.ts` so scenes that pass\n * `skipSkybox: true` (or use a dyn-imported HDR/DDS skybox instead) don't\n * pay for the shader module or cube geometry. */\n\nimport { F32, U16 } from \"../../engine/typed-arrays.js\";\nimport { BU, SS } from \"../../engine/gpu-flags.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { EnvironmentTextures } from \"../../loader-env/load-env.js\";\nimport type { Mat4 } from \"../../math/types.js\";\nimport type { Renderable } from \"../../render/renderable.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\n\nimport skyboxVertSrc from \"../../../shaders/skybox.vertex.wgsl?raw\";\nimport skyboxFragSrc from \"../../../shaders/skybox.fragment.wgsl?raw\";\nimport { createDefaultPipelineDescriptor, getSceneBindGroupLayout } from \"../../render/scene-helpers.js\";\nimport { targetSignatureKey } from \"../../engine/render-target.js\";\nimport { WGSL_DITHER } from \"../../shader/wgsl-helpers.js\";\nimport { SCENE_UBO_WGSL } from \"../../shader/scene-uniforms.js\";\nimport { createMappedBuffer, createUniformBuffer } from \"../../resource/gpu-buffers.js\";\nimport { createSingleUniformBGL } from \"../../shader/bgl-helpers.js\";\n\nconst SKY_MESH_UNIFORM_SIZE = 96; // mat4x4 + primaryColor vec3 + pad + skyOutputColor vec3 + pad\n\nfunction createSkyboxBuffers(engine: EngineContext, S: number): { posBuffer: GPUBuffer; idxBuffer: GPUBuffer; idxCount: number } {\n // prettier-ignore\n const positions = new F32([\n S,-S, S, -S,-S, S, -S, S, S, S, S, S,\n S, S,-S, -S, S,-S, -S,-S,-S, S,-S,-S,\n S, S,-S, S,-S,-S, S,-S, S, S, S, S,\n -S, S, S, -S,-S, S, -S,-S,-S, -S, S,-S,\n -S, S, S, -S, S,-S, S, S,-S, S, S, S,\n S,-S, S, S,-S,-S, -S,-S,-S, -S,-S, S,\n ]);\n // prettier-ignore\n const indices = new U16([\n 2, 1, 0, 3, 2, 0, 6, 5, 4, 7, 6, 4,\n 10, 9, 8, 11,10, 8, 14,13,12, 15,14,12,\n 18,17,16, 19,18,16, 22,21,20, 23,22,20,\n ]);\n return {\n posBuffer: createMappedBuffer(engine, positions, BU.VERTEX),\n idxBuffer: createMappedBuffer(engine, indices, BU.INDEX),\n idxCount: 36,\n };\n}\n\nfunction buildSkyboxWorldMatrix(rootPosition: [number, number, number]): Float32Array {\n const world = new F32(16);\n world[0] = 1;\n world[5] = 1;\n world[10] = 1;\n world[15] = 1;\n world[12] = rootPosition[0];\n world[13] = rootPosition[1];\n world[14] = rootPosition[2];\n return world;\n}\n\ninterface SkyboxMaterial {\n getPipeline(engine: EngineContext, sig: RenderTargetSignature): GPURenderPipeline;\n createBindGroup(engine: EngineContext, meshUBO: GPUBuffer, env: EnvironmentTextures): GPUBindGroup;\n}\n\nconst SKYBOX_POS_BUFFER: GPUVertexBufferLayout[] = [{ arrayStride: 12, attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x3\" as GPUVertexFormat }] }];\n\n/** Module-global pipeline cache shared by all solid-skybox renderables. */\nconst _skyPipelines = new Map<string, GPURenderPipeline>();\nlet _skyLayout: GPUBindGroupLayout | null = null;\nlet _skyCachedDevice: GPUDevice | null = null;\n\nfunction createSkyboxMaterial(): SkyboxMaterial {\n function getLayout(engine: EngineContext): GPUBindGroupLayout {\n const device = engine._device;\n if (_skyLayout && _skyCachedDevice === device) {\n return _skyLayout;\n }\n _skyLayout = createSingleUniformBGL(engine, \"skybox-material\", SS.VERTEX | SS.FRAGMENT);\n return _skyLayout;\n }\n\n return {\n getPipeline(_engine, sig) {\n const device = _engine._device;\n if (_skyCachedDevice !== device) {\n _skyPipelines.clear();\n _skyLayout = null;\n _skyCachedDevice = device;\n }\n const key = targetSignatureKey(sig);\n const cached = _skyPipelines.get(key);\n if (cached) {\n return cached;\n }\n const _vertModule = device.createShaderModule({ code: SCENE_UBO_WGSL + skyboxVertSrc, label: \"skybox-vert\" });\n const _fragModule = device.createShaderModule({ code: WGSL_DITHER + skyboxFragSrc, label: \"skybox-frag\" });\n\n const pipeline = device.createRenderPipeline(\n createDefaultPipelineDescriptor({\n _label: \"skybox-pipeline\",\n _engine,\n _bgls: [getSceneBindGroupLayout(_engine), getLayout(_engine)],\n _vertModule,\n _fragModule,\n _vertexBuffers: SKYBOX_POS_BUFFER,\n _format: sig._colorFormat!,\n _depthStencilFormat: sig._depthStencilFormat,\n _depthCompare: sig._depthCompare,\n _msaaSamples: sig._sampleCount,\n _depthWriteEnabled: false,\n })\n );\n _skyPipelines.set(key, pipeline);\n return pipeline;\n },\n\n createBindGroup(engine, meshUBO, _env) {\n const device = engine._device;\n return device.createBindGroup({\n layout: getLayout(engine),\n entries: [{ binding: 0, resource: { buffer: meshUBO } }],\n });\n },\n };\n}\n\nexport function buildSolidSkyboxRenderable(\n scene: SceneContext,\n envTextures: EnvironmentTextures,\n skyHalfSize: number,\n rootPosition: [number, number, number],\n primaryColor: [number, number, number]\n): Renderable {\n const engine = scene.surface.engine;\n const skyboxWorld = buildSkyboxWorldMatrix(rootPosition);\n const cc = scene.clearColor;\n const skyBufs = createSkyboxBuffers(engine, skyHalfSize);\n\n const skyMat = createSkyboxMaterial();\n const skyOutputColor: [number, number, number] = [cc.r, cc.g, cc.b];\n const skyUBO = createSkyMeshUBO(engine, skyboxWorld as unknown as Mat4, primaryColor, skyOutputColor);\n const skyBG = skyMat.createBindGroup(engine, skyUBO, envTextures);\n\n const r: Renderable = {\n order: 0, // skybox renders first (behind everything)\n isTransparent: false,\n bind(eng, sig) {\n return {\n renderable: r,\n pipeline: skyMat.getPipeline(eng as EngineContext, sig),\n draw(pass) {\n pass.setBindGroup(1, skyBG);\n pass.setVertexBuffer(0, skyBufs.posBuffer);\n pass.setIndexBuffer(skyBufs.idxBuffer, \"uint16\");\n pass.drawIndexed(skyBufs.idxCount);\n return 1;\n },\n };\n },\n };\n return r;\n}\n\nfunction createSkyMeshUBO(engine: EngineContext, world: Mat4, primaryColor: [number, number, number], skyOutputColor: [number, number, number]): GPUBuffer {\n const data = new F32(SKY_MESH_UNIFORM_SIZE / 4);\n data.set(world, 0);\n data[16] = primaryColor[0];\n data[17] = primaryColor[1];\n data[18] = primaryColor[2];\n data[20] = skyOutputColor[0];\n data[21] = skyOutputColor[1];\n data[22] = skyOutputColor[2];\n return createUniformBuffer(engine, data);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"background-solid-skybox-DOOBeDIz.js","sources":["../shaders/skybox.fragment.wgsl?raw","../src/material/pbr/background-solid-skybox.ts"],"sourcesContent":["export default \"// Skybox Fragment Shader — matches Babylon BackgroundMaterial\\n// BJS loads a separate CDN skybox texture (backgroundSkybox.dds) that produces\\n// exactly scene.clearColor when rendered through the BackgroundMaterial pipeline.\\n// We replicate this by outputting the pre-computed clearColor directly from a UBO.\\n\\nstruct MeshUniforms {\\n world: mat4x4<f32>,\\n primaryColor: vec3<f32>,\\n _pad: f32,\\n // Pre-computed sRGB output color for the sky background (= scene.clearColor).\\n skyOutputColor: vec3<f32>,\\n _pad2: f32,\\n};\\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\\n\\nstruct FragmentInput {\\n @location(0) positionUVW: vec3<f32>,\\n @location(1) positionW: vec3<f32>,\\n};\\n\\n@fragment\\nfn main(input: FragmentInput) -> @location(0) vec4<f32> {\\n var result = vec4<f32>(mesh.skyOutputColor, 1.0);\\n\\n // Dithering (enableNoise=true, variance=0.5)\\n result = vec4<f32>(result.rgb + vec3<f32>(dither(input.positionW.xy, 0.5)), result.a);\\n result = max(result, vec4<f32>(0.0));\\n\\n return result;\\n}\\n\"","/** Solid-color skybox renderable — the clear-color background used by PBR\n * environment scenes when no HDR/DDS skybox is provided.\n *\n * Dynamically imported from `background-renderable.ts` so scenes that pass\n * `skipSkybox: true` (or use a dyn-imported HDR/DDS skybox instead) don't\n * pay for the shader module or cube geometry. */\n\nimport { F32, U16 } from \"../../engine/typed-arrays.js\";\nimport { BU, SS } from \"../../engine/gpu-flags.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { EnvironmentTextures } from \"../../loader-env/load-env.js\";\nimport type { Mat4 } from \"../../math/types.js\";\nimport type { Renderable } from \"../../render/renderable.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\n\nimport skyboxVertSrc from \"../../../shaders/skybox.vertex.wgsl?raw\";\nimport skyboxFragSrc from \"../../../shaders/skybox.fragment.wgsl?raw\";\nimport { createDefaultPipelineDescriptor, getSceneBindGroupLayout } from \"../../render/scene-helpers.js\";\nimport { targetSignatureKey } from \"../../engine/render-target.js\";\nimport { WGSL_DITHER } from \"../../shader/wgsl-helpers.js\";\nimport { SCENE_UBO_WGSL } from \"../../shader/scene-uniforms.js\";\nimport { createMappedBuffer, createUniformBuffer } from \"../../resource/gpu-buffers.js\";\nimport { createSingleUniformBGL } from \"../../shader/bgl-helpers.js\";\n\nconst SKY_MESH_UNIFORM_SIZE = 96; // mat4x4 + primaryColor vec3 + pad + skyOutputColor vec3 + pad\n\nfunction createSkyboxBuffers(engine: EngineContext, S: number): { posBuffer: GPUBuffer; idxBuffer: GPUBuffer; idxCount: number } {\n // prettier-ignore\n const positions = new F32([\n S,-S, S, -S,-S, S, -S, S, S, S, S, S,\n S, S,-S, -S, S,-S, -S,-S,-S, S,-S,-S,\n S, S,-S, S,-S,-S, S,-S, S, S, S, S,\n -S, S, S, -S,-S, S, -S,-S,-S, -S, S,-S,\n -S, S, S, -S, S,-S, S, S,-S, S, S, S,\n S,-S, S, S,-S,-S, -S,-S,-S, -S,-S, S,\n ]);\n // prettier-ignore\n const indices = new U16([\n 2, 1, 0, 3, 2, 0, 6, 5, 4, 7, 6, 4,\n 10, 9, 8, 11,10, 8, 14,13,12, 15,14,12,\n 18,17,16, 19,18,16, 22,21,20, 23,22,20,\n ]);\n return {\n posBuffer: createMappedBuffer(engine, positions, BU.VERTEX),\n idxBuffer: createMappedBuffer(engine, indices, BU.INDEX),\n idxCount: 36,\n };\n}\n\nfunction buildSkyboxWorldMatrix(rootPosition: [number, number, number]): Float32Array {\n const world = new F32(16);\n world[0] = 1;\n world[5] = 1;\n world[10] = 1;\n world[15] = 1;\n world[12] = rootPosition[0];\n world[13] = rootPosition[1];\n world[14] = rootPosition[2];\n return world;\n}\n\ninterface SkyboxMaterial {\n getPipeline(engine: EngineContext, sig: RenderTargetSignature): GPURenderPipeline;\n createBindGroup(engine: EngineContext, meshUBO: GPUBuffer, env: EnvironmentTextures): GPUBindGroup;\n}\n\nconst SKYBOX_POS_BUFFER: GPUVertexBufferLayout[] = [{ arrayStride: 12, attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x3\" as GPUVertexFormat }] }];\n\n/** Module-global pipeline cache shared by all solid-skybox renderables. */\nconst _skyPipelines = new Map<string, GPURenderPipeline>();\nlet _skyLayout: GPUBindGroupLayout | null = null;\nlet _skyCachedDevice: GPUDevice | null = null;\n\nfunction createSkyboxMaterial(): SkyboxMaterial {\n function getLayout(engine: EngineContext): GPUBindGroupLayout {\n const device = engine._device;\n if (_skyLayout && _skyCachedDevice === device) {\n return _skyLayout;\n }\n _skyLayout = createSingleUniformBGL(engine, \"skybox-material\", SS.VERTEX | SS.FRAGMENT);\n return _skyLayout;\n }\n\n return {\n getPipeline(_engine, sig) {\n const device = _engine._device;\n if (_skyCachedDevice !== device) {\n _skyPipelines.clear();\n _skyLayout = null;\n _skyCachedDevice = device;\n }\n const key = targetSignatureKey(sig);\n const cached = _skyPipelines.get(key);\n if (cached) {\n return cached;\n }\n const _vertModule = device.createShaderModule({ code: SCENE_UBO_WGSL + skyboxVertSrc, label: \"skybox-vert\" });\n const _fragModule = device.createShaderModule({ code: WGSL_DITHER + skyboxFragSrc, label: \"skybox-frag\" });\n\n const pipeline = device.createRenderPipeline(\n createDefaultPipelineDescriptor({\n _label: \"skybox-pipeline\",\n _engine,\n _bgls: [getSceneBindGroupLayout(_engine), getLayout(_engine)],\n _vertModule,\n _fragModule,\n _vertexBuffers: SKYBOX_POS_BUFFER,\n _format: sig._colorFormat!,\n _depthStencilFormat: sig._depthStencilFormat,\n _depthCompare: sig._depthCompare,\n _msaaSamples: sig._sampleCount,\n _depthWriteEnabled: false,\n })\n );\n _skyPipelines.set(key, pipeline);\n return pipeline;\n },\n\n createBindGroup(engine, meshUBO, _env) {\n const device = engine._device;\n return device.createBindGroup({\n layout: getLayout(engine),\n entries: [{ binding: 0, resource: { buffer: meshUBO } }],\n });\n },\n };\n}\n\nexport function buildSolidSkyboxRenderable(\n scene: SceneContext,\n envTextures: EnvironmentTextures,\n skyHalfSize: number,\n rootPosition: [number, number, number],\n primaryColor: [number, number, number]\n): Renderable {\n const engine = scene.surface.engine;\n const skyboxWorld = buildSkyboxWorldMatrix(rootPosition);\n const cc = scene.clearColor;\n const skyBufs = createSkyboxBuffers(engine, skyHalfSize);\n\n const skyMat = createSkyboxMaterial();\n const skyOutputColor: [number, number, number] = [cc.r, cc.g, cc.b];\n const skyUBO = createSkyMeshUBO(engine, skyboxWorld as unknown as Mat4, primaryColor, skyOutputColor);\n const skyBG = skyMat.createBindGroup(engine, skyUBO, envTextures);\n\n const r: Renderable = {\n order: 0, // skybox renders first (behind everything)\n isTransparent: false,\n bind(eng, sig) {\n return {\n renderable: r,\n pipeline: skyMat.getPipeline(eng as EngineContext, sig),\n draw(pass) {\n pass.setBindGroup(1, skyBG);\n pass.setVertexBuffer(0, skyBufs.posBuffer);\n pass.setIndexBuffer(skyBufs.idxBuffer, \"uint16\");\n pass.drawIndexed(skyBufs.idxCount);\n return 1;\n },\n };\n },\n };\n return r;\n}\n\nfunction createSkyMeshUBO(engine: EngineContext, world: Mat4, primaryColor: [number, number, number], skyOutputColor: [number, number, number]): GPUBuffer {\n const data = new F32(SKY_MESH_UNIFORM_SIZE / 4);\n data.set(world, 0);\n data[16] = primaryColor[0];\n data[17] = primaryColor[1];\n data[18] = primaryColor[2];\n data[20] = skyOutputColor[0];\n data[21] = skyOutputColor[1];\n data[22] = skyOutputColor[2];\n return createUniformBuffer(engine, data);\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { j as createMappedBuffer, B as BU, Z as BILLBOARD_INDEX_DATA, _ as createEmptyUniformBuffer, $ as BILLBOARD_SYSTEM_UBO_BYTES, a0 as createBillboardInstanceBuffer, a1 as _getBillboardFxHook, a as F32, a2 as createBillboardInstanceSortScratch, a3 as getOrCreateBillboardPipeline, z as getSceneBindGroupLayout, a4 as createBillboardSystemBindGroup, a5 as resetBillboardPipelineCache, a6 as ensureBillboardInstanceBuffer, I as getViewMatrix, a7 as uploadSortedBillboardInstances, a8 as uploadBillboardInstances, a9 as buildBillboardSystemUbo, aa as writeBillboardSystemUboIfDirty, ab as createBillboardPipelineCache } from "./index-CLElg2Bo.js";
1
+ import { k as createMappedBuffer, B as BU, _ as BILLBOARD_INDEX_DATA, $ as createEmptyUniformBuffer, a0 as BILLBOARD_SYSTEM_UBO_BYTES, a1 as createBillboardInstanceBuffer, a2 as _getBillboardFxHook, a as F32, a3 as createBillboardInstanceSortScratch, a4 as getOrCreateBillboardPipeline, A as getSceneBindGroupLayout, a5 as createBillboardSystemBindGroup, a6 as resetBillboardPipelineCache, a7 as ensureBillboardInstanceBuffer, J as getViewMatrix, a8 as uploadSortedBillboardInstances, a9 as uploadBillboardInstances, aa as buildBillboardSystemUbo, ab as writeBillboardSystemUboIfDirty, ac as createBillboardPipelineCache } from "./index-BgY3QEzL.js";
2
2
  let _sharedPipelineCache = null;
3
3
  let _sharedPipelineCacheRefs = 0;
4
4
  function acquireSharedPipelineCache() {
@@ -275,4 +275,4 @@ function disposeRenderable(renderable) {
275
275
  export {
276
276
  buildBillboardRenderable
277
277
  };
278
- //# sourceMappingURL=billboard-renderable-BHWryAeC.js.map
278
+ //# sourceMappingURL=billboard-renderable-IJfCpeDS.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"billboard-renderable-BHWryAeC.js","sources":["../src/sprite/billboard-renderable.ts"],"sourcesContent":["import { F32 } from \"../engine/typed-arrays.js\";\nimport { BU } from \"../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { RenderTargetSignature } from \"../engine/render-target.js\";\nimport type { DrawBinding, DrawUpdateContext, Renderable } from \"../render/renderable.js\";\nimport type { Camera } from \"../camera/camera.js\";\nimport { getViewMatrix } from \"../camera/camera.js\";\nimport { getSceneBindGroupLayout } from \"../render/scene-helpers.js\";\nimport { createEmptyUniformBuffer, createMappedBuffer } from \"../resource/gpu-buffers.js\";\nimport type { SpriteLayerFx } from \"./custom-shader-core.js\";\nimport { _getBillboardFxHook } from \"./sprite-fx-hook.js\";\nimport type { BillboardSpriteSystem } from \"./billboard-sprite.js\";\nimport {\n BILLBOARD_INDEX_DATA,\n BILLBOARD_SYSTEM_UBO_BYTES,\n buildBillboardSystemUbo,\n createBillboardInstanceBuffer,\n createBillboardInstanceSortScratch,\n createBillboardPipelineCache,\n createBillboardSystemBindGroup,\n ensureBillboardInstanceBuffer,\n getOrCreateBillboardPipeline,\n resetBillboardPipelineCache,\n uploadBillboardInstances,\n uploadSortedBillboardInstances,\n writeBillboardSystemUboIfDirty,\n} from \"./billboard-pipeline.js\";\nimport type { BillboardInstanceSortScratch, BillboardPipelineCache } from \"./billboard-pipeline.js\";\n\nlet _sharedPipelineCache: BillboardPipelineCache | null = null;\nlet _sharedPipelineCacheRefs = 0;\n\nfunction acquireSharedPipelineCache(): BillboardPipelineCache {\n _sharedPipelineCache ??= createBillboardPipelineCache();\n _sharedPipelineCacheRefs++;\n return _sharedPipelineCache;\n}\n\nfunction releaseSharedPipelineCache(): void {\n if (_sharedPipelineCacheRefs === 0) {\n return;\n }\n _sharedPipelineCacheRefs--;\n if (_sharedPipelineCacheRefs === 0 && _sharedPipelineCache) {\n resetBillboardPipelineCache(_sharedPipelineCache);\n _sharedPipelineCache = null;\n }\n}\n\ninterface BillboardRenderableInternal extends Renderable {\n _engine: EngineContext;\n _system: BillboardSpriteSystem;\n _indexBuffer: GPUBuffer;\n _uniformBuffer: GPUBuffer;\n _instanceBuffer: GPUBuffer;\n _instanceBufferCapacity: number;\n _instanceSortScratch: BillboardInstanceSortScratch;\n _pipelineCache: BillboardPipelineCache;\n _bindGroups: Map<GPURenderPipeline, GPUBindGroup>;\n _uploadedVersion: number;\n _uploadedCamera: Camera | null;\n _uploadedCameraViewVersion: number;\n _uploadedSorted: boolean;\n _centerVersion: number;\n _drawableCount: number;\n _uboUploaded: boolean;\n _lastUbo: Float32Array;\n _scratchUbo: Float32Array;\n _fx: SpriteLayerFx | null;\n _disposed: boolean;\n}\n\nexport function buildBillboardRenderable(engine: EngineContext, system: BillboardSpriteSystem): { renderable: Renderable; dispose: () => void } {\n const indexBuffer = createMappedBuffer(engine, BILLBOARD_INDEX_DATA, BU.INDEX);\n const uniformBuffer = createEmptyUniformBuffer(engine, BILLBOARD_SYSTEM_UBO_BYTES, `${system._orientation}-billboard-system-ubo`);\n const instanceBuffer = createBillboardInstanceBuffer(engine._device, system, `${system._orientation}-billboard-instances`);\n const fx = _getBillboardFxHook()?.createLayerFx(engine, `${system._orientation}-billboard-fx-ubo`, system) ?? null;\n const isTransparent = system._depthMode === \"transparent\";\n const renderable: BillboardRenderableInternal = {\n order: system.order,\n isTransparent,\n _direct: !isTransparent,\n _engine: engine,\n _system: system,\n _indexBuffer: indexBuffer,\n _uniformBuffer: uniformBuffer,\n _instanceBuffer: instanceBuffer,\n _instanceBufferCapacity: system._capacity,\n _instanceSortScratch: createBillboardInstanceSortScratch(),\n _pipelineCache: acquireSharedPipelineCache(),\n _bindGroups: new Map(),\n _uploadedVersion: -1,\n _uploadedCamera: null,\n _uploadedCameraViewVersion: -1,\n _uploadedSorted: false,\n _centerVersion: -1,\n _drawableCount: 0,\n _uboUploaded: false,\n _lastUbo: new F32(BILLBOARD_SYSTEM_UBO_BYTES / 4),\n _scratchUbo: new F32(BILLBOARD_SYSTEM_UBO_BYTES / 4),\n _fx: fx,\n _disposed: false,\n _worldCenter: [0, 0, 0],\n bind(engine, target) {\n return bindSystem(renderable, engine, target);\n },\n };\n refreshBillboardWorldCenter(renderable);\n return {\n renderable,\n dispose() {\n disposeRenderable(renderable);\n },\n };\n}\n\nfunction bindSystem(renderable: BillboardRenderableInternal, engine: EngineContext, target: RenderTargetSignature): DrawBinding {\n if (!target._depthStencilFormat) {\n throw new Error(\"BillboardSpriteSystem requires a depth-stencil render target.\");\n }\n const sampleCount = target._sampleCount === 1 ? 1 : 4;\n const pipeline = getOrCreateBillboardPipeline(\n engine,\n renderable._pipelineCache,\n target._colorFormat!,\n sampleCount,\n renderable._system,\n target._depthStencilFormat,\n getSceneBindGroupLayout(engine)\n );\n let bindGroup = renderable._bindGroups.get(pipeline);\n if (!bindGroup) {\n bindGroup = createBillboardSystemBindGroup(engine, pipeline, renderable._system, renderable._uniformBuffer, renderable._fx);\n renderable._bindGroups.set(pipeline, bindGroup);\n }\n return {\n renderable,\n pipeline,\n update(context) {\n uploadSystem(renderable, context);\n },\n draw(pass) {\n return drawSystem(renderable, bindGroup, pass);\n },\n };\n}\n\nfunction uploadSystem(renderable: BillboardRenderableInternal, context: DrawUpdateContext): void {\n if (renderable._disposed) {\n return;\n }\n refreshBillboardWorldCenter(renderable);\n if (!renderable._system.visible || renderable._system.count === 0) {\n if (renderable._system.count === 0) {\n renderable._system._dirtyMin = 0;\n renderable._system._dirtyMax = 0;\n renderable._uploadedVersion = renderable._system._version;\n renderable._uploadedSorted = false;\n }\n return;\n }\n // Match the pure-2D `SpriteRenderer` path: advance `fx.time` (and write the FX UBO) only for\n // visible, non-empty systems so time semantics stay consistent and we avoid wasted `writeBuffer` traffic.\n if (renderable._fx) {\n _getBillboardFxHook()!.updateFx(renderable._fx, renderable._system, renderable._engine._currentDelta);\n }\n const grown = ensureBillboardInstanceBuffer(\n renderable._engine._device,\n renderable._system,\n renderable._instanceBuffer,\n renderable._instanceBufferCapacity,\n `${renderable._system._orientation}-billboard-instances`\n );\n if (grown.reallocated) {\n renderable._instanceBuffer = grown.buffer;\n renderable._instanceBufferCapacity = grown.capacity;\n renderable._uploadedVersion = -1;\n renderable._uploadedCamera = null;\n renderable._uploadedCameraViewVersion = -1;\n renderable._uploadedSorted = false;\n }\n const camera = context._camera;\n const useFloatingOrigin = renderable._engine.useFloatingOrigin && camera != null;\n let foX = 0;\n let foY = 0;\n let foZ = 0;\n if (useFloatingOrigin) {\n const wm = camera!.worldMatrix;\n foX = wm[12]!;\n foY = wm[13]!;\n foZ = wm[14]!;\n }\n if (renderable._system._depthMode === \"transparent\" && camera) {\n const cameraViewMatrix = getViewMatrix(camera);\n if (\n !renderable._uploadedSorted ||\n renderable._uploadedVersion !== renderable._system._version ||\n renderable._uploadedCamera !== camera ||\n renderable._uploadedCameraViewVersion !== camera.worldMatrixVersion\n ) {\n uploadSortedBillboardInstances(\n renderable._engine._device,\n renderable._system,\n renderable._instanceBuffer,\n renderable._instanceSortScratch,\n cameraViewMatrix,\n foX,\n foY,\n foZ\n );\n renderable._uploadedVersion = renderable._system._version;\n renderable._uploadedCamera = camera;\n renderable._uploadedCameraViewVersion = camera.worldMatrixVersion;\n renderable._uploadedSorted = true;\n }\n } else {\n let uploadedVersion = renderable._uploadedSorted ? -1 : renderable._uploadedVersion;\n // Under floating origin the eye-relative anchors depend on the live camera\n // offset, so force a full re-upload whenever the camera (offset) has moved.\n if (useFloatingOrigin && (renderable._uploadedCamera !== camera || renderable._uploadedCameraViewVersion !== camera!.worldMatrixVersion)) {\n uploadedVersion = -1;\n }\n renderable._uploadedVersion = uploadBillboardInstances(\n renderable._engine._device,\n renderable._system,\n renderable._instanceBuffer,\n uploadedVersion,\n foX,\n foY,\n foZ,\n renderable._instanceSortScratch\n );\n if (useFloatingOrigin) {\n renderable._uploadedCamera = camera!;\n renderable._uploadedCameraViewVersion = camera!.worldMatrixVersion;\n } else {\n renderable._uploadedCamera = null;\n renderable._uploadedCameraViewVersion = -1;\n }\n renderable._uploadedSorted = false;\n }\n buildBillboardSystemUbo(renderable._system, renderable._scratchUbo);\n writeBillboardSystemUboIfDirty(renderable._engine._device, renderable._uniformBuffer, renderable._scratchUbo, renderable._lastUbo, !renderable._uboUploaded);\n renderable._uboUploaded = true;\n}\n\nfunction refreshBillboardWorldCenter(renderable: BillboardRenderableInternal): void {\n const system = renderable._system;\n if (renderable._centerVersion === system._version) {\n return;\n }\n const center = renderable._worldCenter!;\n if (system.count === 0) {\n center[0] = 0;\n center[1] = 0;\n center[2] = 0;\n renderable._drawableCount = 0;\n renderable._centerVersion = system._version;\n return;\n }\n const data = system._instanceData;\n const stride = system._instanceFloatsPerSprite;\n let minX = Infinity;\n let minY = Infinity;\n let minZ = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let maxZ = -Infinity;\n let drawableCount = 0;\n for (let index = 0; index < system.count; index++) {\n const base = index * stride;\n const width = data[base + 3]!;\n const height = data[base + 4]!;\n if (width === 0 || height === 0) {\n continue;\n }\n const x = data[base]!;\n const y = data[base + 1]!;\n const z = data[base + 2]!;\n if (x < minX) {\n minX = x;\n }\n if (y < minY) {\n minY = y;\n }\n if (z < minZ) {\n minZ = z;\n }\n if (x > maxX) {\n maxX = x;\n }\n if (y > maxY) {\n maxY = y;\n }\n if (z > maxZ) {\n maxZ = z;\n }\n drawableCount++;\n }\n if (drawableCount === 0) {\n center[0] = 0;\n center[1] = 0;\n center[2] = 0;\n } else {\n center[0] = (minX + maxX) * 0.5;\n center[1] = (minY + maxY) * 0.5;\n center[2] = (minZ + maxZ) * 0.5;\n }\n renderable._drawableCount = drawableCount;\n renderable._centerVersion = system._version;\n}\n\nfunction drawSystem(renderable: BillboardRenderableInternal, bindGroup: GPUBindGroup, pass: GPURenderPassEncoder | GPURenderBundleEncoder): number {\n if (renderable._disposed) {\n return 0;\n }\n refreshBillboardWorldCenter(renderable);\n if (!renderable._system.visible || renderable._system.count === 0 || renderable._drawableCount === 0) {\n return 0;\n }\n pass.setBindGroup(1, bindGroup);\n pass.setIndexBuffer(renderable._indexBuffer, \"uint16\");\n pass.setVertexBuffer(0, renderable._instanceBuffer);\n pass.drawIndexed(6, renderable._system.count, 0, 0, 0);\n return 1;\n}\n\nfunction disposeRenderable(renderable: BillboardRenderableInternal): void {\n if (renderable._disposed) {\n return;\n }\n renderable._disposed = true;\n renderable._instanceBuffer.destroy();\n renderable._uniformBuffer.destroy();\n renderable._indexBuffer.destroy();\n if (renderable._fx) {\n _getBillboardFxHook()!.disposeFx(renderable._fx);\n }\n renderable._bindGroups.clear();\n releaseSharedPipelineCache();\n}\n"],"names":["engine"],"mappings":"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"}
1
+ {"version":3,"file":"billboard-renderable-IJfCpeDS.js","sources":["../src/sprite/billboard-renderable.ts"],"sourcesContent":["import { F32 } from \"../engine/typed-arrays.js\";\nimport { BU } from \"../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { RenderTargetSignature } from \"../engine/render-target.js\";\nimport type { DrawBinding, DrawUpdateContext, Renderable } from \"../render/renderable.js\";\nimport type { Camera } from \"../camera/camera.js\";\nimport { getViewMatrix } from \"../camera/camera.js\";\nimport { getSceneBindGroupLayout } from \"../render/scene-helpers.js\";\nimport { createEmptyUniformBuffer, createMappedBuffer } from \"../resource/gpu-buffers.js\";\nimport type { SpriteLayerFx } from \"./custom-shader-core.js\";\nimport { _getBillboardFxHook } from \"./sprite-fx-hook.js\";\nimport type { BillboardSpriteSystem } from \"./billboard-sprite.js\";\nimport {\n BILLBOARD_INDEX_DATA,\n BILLBOARD_SYSTEM_UBO_BYTES,\n buildBillboardSystemUbo,\n createBillboardInstanceBuffer,\n createBillboardInstanceSortScratch,\n createBillboardPipelineCache,\n createBillboardSystemBindGroup,\n ensureBillboardInstanceBuffer,\n getOrCreateBillboardPipeline,\n resetBillboardPipelineCache,\n uploadBillboardInstances,\n uploadSortedBillboardInstances,\n writeBillboardSystemUboIfDirty,\n} from \"./billboard-pipeline.js\";\nimport type { BillboardInstanceSortScratch, BillboardPipelineCache } from \"./billboard-pipeline.js\";\n\nlet _sharedPipelineCache: BillboardPipelineCache | null = null;\nlet _sharedPipelineCacheRefs = 0;\n\nfunction acquireSharedPipelineCache(): BillboardPipelineCache {\n _sharedPipelineCache ??= createBillboardPipelineCache();\n _sharedPipelineCacheRefs++;\n return _sharedPipelineCache;\n}\n\nfunction releaseSharedPipelineCache(): void {\n if (_sharedPipelineCacheRefs === 0) {\n return;\n }\n _sharedPipelineCacheRefs--;\n if (_sharedPipelineCacheRefs === 0 && _sharedPipelineCache) {\n resetBillboardPipelineCache(_sharedPipelineCache);\n _sharedPipelineCache = null;\n }\n}\n\ninterface BillboardRenderableInternal extends Renderable {\n _engine: EngineContext;\n _system: BillboardSpriteSystem;\n _indexBuffer: GPUBuffer;\n _uniformBuffer: GPUBuffer;\n _instanceBuffer: GPUBuffer;\n _instanceBufferCapacity: number;\n _instanceSortScratch: BillboardInstanceSortScratch;\n _pipelineCache: BillboardPipelineCache;\n _bindGroups: Map<GPURenderPipeline, GPUBindGroup>;\n _uploadedVersion: number;\n _uploadedCamera: Camera | null;\n _uploadedCameraViewVersion: number;\n _uploadedSorted: boolean;\n _centerVersion: number;\n _drawableCount: number;\n _uboUploaded: boolean;\n _lastUbo: Float32Array;\n _scratchUbo: Float32Array;\n _fx: SpriteLayerFx | null;\n _disposed: boolean;\n}\n\nexport function buildBillboardRenderable(engine: EngineContext, system: BillboardSpriteSystem): { renderable: Renderable; dispose: () => void } {\n const indexBuffer = createMappedBuffer(engine, BILLBOARD_INDEX_DATA, BU.INDEX);\n const uniformBuffer = createEmptyUniformBuffer(engine, BILLBOARD_SYSTEM_UBO_BYTES, `${system._orientation}-billboard-system-ubo`);\n const instanceBuffer = createBillboardInstanceBuffer(engine._device, system, `${system._orientation}-billboard-instances`);\n const fx = _getBillboardFxHook()?.createLayerFx(engine, `${system._orientation}-billboard-fx-ubo`, system) ?? null;\n const isTransparent = system._depthMode === \"transparent\";\n const renderable: BillboardRenderableInternal = {\n order: system.order,\n isTransparent,\n _direct: !isTransparent,\n _engine: engine,\n _system: system,\n _indexBuffer: indexBuffer,\n _uniformBuffer: uniformBuffer,\n _instanceBuffer: instanceBuffer,\n _instanceBufferCapacity: system._capacity,\n _instanceSortScratch: createBillboardInstanceSortScratch(),\n _pipelineCache: acquireSharedPipelineCache(),\n _bindGroups: new Map(),\n _uploadedVersion: -1,\n _uploadedCamera: null,\n _uploadedCameraViewVersion: -1,\n _uploadedSorted: false,\n _centerVersion: -1,\n _drawableCount: 0,\n _uboUploaded: false,\n _lastUbo: new F32(BILLBOARD_SYSTEM_UBO_BYTES / 4),\n _scratchUbo: new F32(BILLBOARD_SYSTEM_UBO_BYTES / 4),\n _fx: fx,\n _disposed: false,\n _worldCenter: [0, 0, 0],\n bind(engine, target) {\n return bindSystem(renderable, engine, target);\n },\n };\n refreshBillboardWorldCenter(renderable);\n return {\n renderable,\n dispose() {\n disposeRenderable(renderable);\n },\n };\n}\n\nfunction bindSystem(renderable: BillboardRenderableInternal, engine: EngineContext, target: RenderTargetSignature): DrawBinding {\n if (!target._depthStencilFormat) {\n throw new Error(\"BillboardSpriteSystem requires a depth-stencil render target.\");\n }\n const sampleCount = target._sampleCount === 1 ? 1 : 4;\n const pipeline = getOrCreateBillboardPipeline(\n engine,\n renderable._pipelineCache,\n target._colorFormat!,\n sampleCount,\n renderable._system,\n target._depthStencilFormat,\n getSceneBindGroupLayout(engine)\n );\n let bindGroup = renderable._bindGroups.get(pipeline);\n if (!bindGroup) {\n bindGroup = createBillboardSystemBindGroup(engine, pipeline, renderable._system, renderable._uniformBuffer, renderable._fx);\n renderable._bindGroups.set(pipeline, bindGroup);\n }\n return {\n renderable,\n pipeline,\n update(context) {\n uploadSystem(renderable, context);\n },\n draw(pass) {\n return drawSystem(renderable, bindGroup, pass);\n },\n };\n}\n\nfunction uploadSystem(renderable: BillboardRenderableInternal, context: DrawUpdateContext): void {\n if (renderable._disposed) {\n return;\n }\n refreshBillboardWorldCenter(renderable);\n if (!renderable._system.visible || renderable._system.count === 0) {\n if (renderable._system.count === 0) {\n renderable._system._dirtyMin = 0;\n renderable._system._dirtyMax = 0;\n renderable._uploadedVersion = renderable._system._version;\n renderable._uploadedSorted = false;\n }\n return;\n }\n // Match the pure-2D `SpriteRenderer` path: advance `fx.time` (and write the FX UBO) only for\n // visible, non-empty systems so time semantics stay consistent and we avoid wasted `writeBuffer` traffic.\n if (renderable._fx) {\n _getBillboardFxHook()!.updateFx(renderable._fx, renderable._system, renderable._engine._currentDelta);\n }\n const grown = ensureBillboardInstanceBuffer(\n renderable._engine._device,\n renderable._system,\n renderable._instanceBuffer,\n renderable._instanceBufferCapacity,\n `${renderable._system._orientation}-billboard-instances`\n );\n if (grown.reallocated) {\n renderable._instanceBuffer = grown.buffer;\n renderable._instanceBufferCapacity = grown.capacity;\n renderable._uploadedVersion = -1;\n renderable._uploadedCamera = null;\n renderable._uploadedCameraViewVersion = -1;\n renderable._uploadedSorted = false;\n }\n const camera = context._camera;\n const useFloatingOrigin = renderable._engine.useFloatingOrigin && camera != null;\n let foX = 0;\n let foY = 0;\n let foZ = 0;\n if (useFloatingOrigin) {\n const wm = camera!.worldMatrix;\n foX = wm[12]!;\n foY = wm[13]!;\n foZ = wm[14]!;\n }\n if (renderable._system._depthMode === \"transparent\" && camera) {\n const cameraViewMatrix = getViewMatrix(camera);\n if (\n !renderable._uploadedSorted ||\n renderable._uploadedVersion !== renderable._system._version ||\n renderable._uploadedCamera !== camera ||\n renderable._uploadedCameraViewVersion !== camera.worldMatrixVersion\n ) {\n uploadSortedBillboardInstances(\n renderable._engine._device,\n renderable._system,\n renderable._instanceBuffer,\n renderable._instanceSortScratch,\n cameraViewMatrix,\n foX,\n foY,\n foZ\n );\n renderable._uploadedVersion = renderable._system._version;\n renderable._uploadedCamera = camera;\n renderable._uploadedCameraViewVersion = camera.worldMatrixVersion;\n renderable._uploadedSorted = true;\n }\n } else {\n let uploadedVersion = renderable._uploadedSorted ? -1 : renderable._uploadedVersion;\n // Under floating origin the eye-relative anchors depend on the live camera\n // offset, so force a full re-upload whenever the camera (offset) has moved.\n if (useFloatingOrigin && (renderable._uploadedCamera !== camera || renderable._uploadedCameraViewVersion !== camera!.worldMatrixVersion)) {\n uploadedVersion = -1;\n }\n renderable._uploadedVersion = uploadBillboardInstances(\n renderable._engine._device,\n renderable._system,\n renderable._instanceBuffer,\n uploadedVersion,\n foX,\n foY,\n foZ,\n renderable._instanceSortScratch\n );\n if (useFloatingOrigin) {\n renderable._uploadedCamera = camera!;\n renderable._uploadedCameraViewVersion = camera!.worldMatrixVersion;\n } else {\n renderable._uploadedCamera = null;\n renderable._uploadedCameraViewVersion = -1;\n }\n renderable._uploadedSorted = false;\n }\n buildBillboardSystemUbo(renderable._system, renderable._scratchUbo);\n writeBillboardSystemUboIfDirty(renderable._engine._device, renderable._uniformBuffer, renderable._scratchUbo, renderable._lastUbo, !renderable._uboUploaded);\n renderable._uboUploaded = true;\n}\n\nfunction refreshBillboardWorldCenter(renderable: BillboardRenderableInternal): void {\n const system = renderable._system;\n if (renderable._centerVersion === system._version) {\n return;\n }\n const center = renderable._worldCenter!;\n if (system.count === 0) {\n center[0] = 0;\n center[1] = 0;\n center[2] = 0;\n renderable._drawableCount = 0;\n renderable._centerVersion = system._version;\n return;\n }\n const data = system._instanceData;\n const stride = system._instanceFloatsPerSprite;\n let minX = Infinity;\n let minY = Infinity;\n let minZ = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let maxZ = -Infinity;\n let drawableCount = 0;\n for (let index = 0; index < system.count; index++) {\n const base = index * stride;\n const width = data[base + 3]!;\n const height = data[base + 4]!;\n if (width === 0 || height === 0) {\n continue;\n }\n const x = data[base]!;\n const y = data[base + 1]!;\n const z = data[base + 2]!;\n if (x < minX) {\n minX = x;\n }\n if (y < minY) {\n minY = y;\n }\n if (z < minZ) {\n minZ = z;\n }\n if (x > maxX) {\n maxX = x;\n }\n if (y > maxY) {\n maxY = y;\n }\n if (z > maxZ) {\n maxZ = z;\n }\n drawableCount++;\n }\n if (drawableCount === 0) {\n center[0] = 0;\n center[1] = 0;\n center[2] = 0;\n } else {\n center[0] = (minX + maxX) * 0.5;\n center[1] = (minY + maxY) * 0.5;\n center[2] = (minZ + maxZ) * 0.5;\n }\n renderable._drawableCount = drawableCount;\n renderable._centerVersion = system._version;\n}\n\nfunction drawSystem(renderable: BillboardRenderableInternal, bindGroup: GPUBindGroup, pass: GPURenderPassEncoder | GPURenderBundleEncoder): number {\n if (renderable._disposed) {\n return 0;\n }\n refreshBillboardWorldCenter(renderable);\n if (!renderable._system.visible || renderable._system.count === 0 || renderable._drawableCount === 0) {\n return 0;\n }\n pass.setBindGroup(1, bindGroup);\n pass.setIndexBuffer(renderable._indexBuffer, \"uint16\");\n pass.setVertexBuffer(0, renderable._instanceBuffer);\n pass.drawIndexed(6, renderable._system.count, 0, 0, 0);\n return 1;\n}\n\nfunction disposeRenderable(renderable: BillboardRenderableInternal): void {\n if (renderable._disposed) {\n return;\n }\n renderable._disposed = true;\n renderable._instanceBuffer.destroy();\n renderable._uniformBuffer.destroy();\n renderable._indexBuffer.destroy();\n if (renderable._fx) {\n _getBillboardFxHook()!.disposeFx(renderable._fx);\n }\n renderable._bindGroups.clear();\n releaseSharedPipelineCache();\n}\n"],"names":["engine"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { f as formatFloat } from "./_math-factory-C-QqW-Wi.js";
2
- import { aG as WGSL } from "./index-CLElg2Bo.js";
2
+ import { aJ as WGSL } from "./index-BgY3QEzL.js";
3
3
  const emitter = {
4
4
  className: "ClampBlock",
5
5
  emit(block, _outputName, stage, state, ctx) {
@@ -18,4 +18,4 @@ const emitter = {
18
18
  export {
19
19
  emitter
20
20
  };
21
- //# sourceMappingURL=clamp-block-DqbwnQGW.js.map
21
+ //# sourceMappingURL=clamp-block-BD_t8I89.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"clamp-block-DqbwnQGW.js","sources":["../src/material/node/blocks/clamp-block.ts"],"sourcesContent":["import type { BlockEmitter } from \"../node-types.js\";\nimport { formatFloat } from \"./_math-factory.js\";\nimport { WGSL } from \"../node-types.js\";\n\nexport const emitter: BlockEmitter = {\n className: \"ClampBlock\",\n emit(block, _outputName, stage, state, ctx) {\n const value = ctx.resolve(block, \"value\", stage, state);\n const minRaw = block.serialized.minimum;\n const maxRaw = block.serialized.maximum;\n const minScalar = typeof minRaw === \"number\" ? formatFloat(minRaw) : \"0.0\";\n const maxScalar = typeof maxRaw === \"number\" ? formatFloat(maxRaw) : \"1.0\";\n // WGSL clamp requires all three args to have matching types. Promote\n // scalar bounds to the value's vector type when needed.\n if (value.type === \"f32\") {\n return { expr: `clamp(${value.expr}, ${minScalar}, ${maxScalar})`, type: value.type };\n }\n const t = WGSL[value.type];\n return { expr: `clamp(${value.expr}, ${t}(${minScalar}), ${t}(${maxScalar}))`, type: value.type };\n },\n};\n"],"names":[],"mappings":";;AAIO,MAAM,UAAwB;AAAA,EACjC,WAAW;AAAA,EACX,KAAK,OAAO,aAAa,OAAO,OAAO,KAAK;AACxC,UAAM,QAAQ,IAAI,QAAQ,OAAO,SAAS,OAAO,KAAK;AACtD,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,YAAY,OAAO,WAAW,WAAW,YAAY,MAAM,IAAI;AACrE,UAAM,YAAY,OAAO,WAAW,WAAW,YAAY,MAAM,IAAI;AAGrE,QAAI,MAAM,SAAS,OAAO;AACtB,aAAO,EAAE,MAAM,SAAS,MAAM,IAAI,KAAK,SAAS,KAAK,SAAS,KAAK,MAAM,MAAM,KAAA;AAAA,IACnF;AACA,UAAM,IAAI,KAAK,MAAM,IAAI;AACzB,WAAO,EAAE,MAAM,SAAS,MAAM,IAAI,KAAK,CAAC,IAAI,SAAS,MAAM,CAAC,IAAI,SAAS,MAAM,MAAM,MAAM,KAAA;AAAA,EAC/F;AACJ;"}
1
+ {"version":3,"file":"clamp-block-BD_t8I89.js","sources":["../src/material/node/blocks/clamp-block.ts"],"sourcesContent":["import type { BlockEmitter } from \"../node-types.js\";\nimport { formatFloat } from \"./_math-factory.js\";\nimport { WGSL } from \"../node-types.js\";\n\nexport const emitter: BlockEmitter = {\n className: \"ClampBlock\",\n emit(block, _outputName, stage, state, ctx) {\n const value = ctx.resolve(block, \"value\", stage, state);\n const minRaw = block.serialized.minimum;\n const maxRaw = block.serialized.maximum;\n const minScalar = typeof minRaw === \"number\" ? formatFloat(minRaw) : \"0.0\";\n const maxScalar = typeof maxRaw === \"number\" ? formatFloat(maxRaw) : \"1.0\";\n // WGSL clamp requires all three args to have matching types. Promote\n // scalar bounds to the value's vector type when needed.\n if (value.type === \"f32\") {\n return { expr: `clamp(${value.expr}, ${minScalar}, ${maxScalar})`, type: value.type };\n }\n const t = WGSL[value.type];\n return { expr: `clamp(${value.expr}, ${t}(${minScalar}), ${t}(${maxScalar}))`, type: value.type };\n },\n};\n"],"names":[],"mappings":";;AAIO,MAAM,UAAwB;AAAA,EACjC,WAAW;AAAA,EACX,KAAK,OAAO,aAAa,OAAO,OAAO,KAAK;AACxC,UAAM,QAAQ,IAAI,QAAQ,OAAO,SAAS,OAAO,KAAK;AACtD,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,YAAY,OAAO,WAAW,WAAW,YAAY,MAAM,IAAI;AACrE,UAAM,YAAY,OAAO,WAAW,WAAW,YAAY,MAAM,IAAI;AAGrE,QAAI,MAAM,SAAS,OAAO;AACtB,aAAO,EAAE,MAAM,SAAS,MAAM,IAAI,KAAK,SAAS,KAAK,SAAS,KAAK,MAAM,MAAM,KAAA;AAAA,IACnF;AACA,UAAM,IAAI,KAAK,MAAM,IAAI;AACzB,WAAO,EAAE,MAAM,SAAS,MAAM,IAAI,KAAK,CAAC,IAAI,SAAS,MAAM,CAAC,IAAI,SAAS,MAAM,MAAM,MAAM,KAAA;AAAA,EAC/F;AACJ;"}
@@ -1,4 +1,4 @@
1
- import { aO as PBR_HAS_CLEARCOAT, aP as PBR2_CC_INT_MAP, aQ as PBR2_CC_ROUGH_MAP, aR as PBR2_CC_NORMAL_MAP, aJ as PBR_HAS_METALLIC_REFLECTANCE_MAP, aK as PBR_HAS_REFLECTANCE_MAP, aS as PBR2_CC_F0_REMAP_OFF } from "./index-CLElg2Bo.js";
1
+ import { aR as PBR_HAS_CLEARCOAT, aS as PBR2_CC_INT_MAP, aT as PBR2_CC_ROUGH_MAP, aU as PBR2_CC_NORMAL_MAP, aM as PBR_HAS_METALLIC_REFLECTANCE_MAP, aN as PBR_HAS_REFLECTANCE_MAP, aV as PBR2_CC_F0_REMAP_OFF } from "./index-BgY3QEzL.js";
2
2
  const STAGE_FRAGMENT = 2;
3
3
  const CC_HELPERS = `
4
4
  fn visibility_Kelemen(VdotH_kl: f32) -> f32 {
@@ -253,4 +253,4 @@ export {
253
253
  pbrExt,
254
254
  writeClearcoatUBO
255
255
  };
256
- //# sourceMappingURL=clearcoat-fragment-D6FSCie1.js.map
256
+ //# sourceMappingURL=clearcoat-fragment-Dj7vGX2u.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"clearcoat-fragment-D6FSCie1.js","sources":["../src/material/pbr/fragments/clearcoat-fragment.ts"],"sourcesContent":["/**\n * Clearcoat Fragment\n *\n * Adds a glossy transparent top layer (like car paint or lacquered surfaces).\n * Only bundled when a scene uses PbrMaterialProps.clearCoat.\n *\n * Math follows BJS PBRClearCoatConfiguration:\n * - F0 from IOR: ((1-ior)/(1+ior))^2\n * - F0 remap: base F0 adjusted for coat/base interface\n * - Direct: GGX + Kelemen visibility + Schlick fresnel\n * - IBL: Jones analytical BRDF (not BRDF LUT)\n * - Conservation: base layer attenuated by (1 - fresnel * intensity)\n *\n * Supports glTF KHR_materials_clearcoat textures:\n * - clearcoatTexture (R channel multiplies intensity)\n * - clearcoatRoughnessTexture (G channel multiplies roughness)\n * - clearcoatNormalTexture (tangent-space normal, perturbs coat normal)\n */\n\nimport type { ShaderFragment, BindingDecl } from \"../../../shader/fragment-types.js\";\nimport type { PbrMaterialProps, ClearCoatProps } from \"../pbr-material.js\";\nimport type { PbrExt } from \"../pbr-flags.js\";\nimport {\n PBR_HAS_CLEARCOAT,\n PBR_HAS_METALLIC_REFLECTANCE_MAP,\n PBR_HAS_REFLECTANCE_MAP,\n PBR2_CC_INT_MAP,\n PBR2_CC_ROUGH_MAP,\n PBR2_CC_NORMAL_MAP,\n PBR2_CC_F0_REMAP_OFF,\n} from \"../pbr-flag-bits.js\";\n\nconst STAGE_FRAGMENT = 0x2;\n\nconst CC_HELPERS = `\nfn visibility_Kelemen(VdotH_kl: f32) -> f32 {\nreturn 0.25 / (VdotH_kl * VdotH_kl + 0.0000001);\n}\nfn getR0RemappedForClearCoat(f0_rc: vec3<f32>, ccA: f32, ccB: f32) -> vec3<f32> {\nlet sf0 = sqrt(f0_rc);\nlet num = ccA + ccB * sf0;\nlet den = ccB + ccA * sf0;\nreturn saturate((num / den) * (num / den));\n}\nfn ccSchlick(f0: f32, cosTheta: f32) -> f32 {\nlet t = 1.0 - cosTheta;\nlet t2 = t * t;\nreturn f0 + (1.0 - f0) * (t2 * t2 * t);\n}\n`;\n\nconst CC_INT_TEX = `material.ccParams.x * textureSample(ccIntensityTexture, ccIntensitySampler_, input.uv).r`;\nconst CC_INT_PLAIN = `material.ccParams.x`;\nconst CC_ROUGH_TEX = `clamp(material.ccParams.y * textureSample(ccRoughnessTexture, ccRoughnessSampler_, input.uv).g, 0.0, 1.0)`;\nconst CC_ROUGH_PLAIN = `material.ccParams.y`;\n\n// WGSL fragment: coat-layer normal. Computes ccN (coat world-space normal)\n// using a locally-derived cotangent frame from world-position and UV derivatives.\n// Emitted in /*AC*/ so ccN is in scope for direct + IBL blocks.\nconst CC_NORMAL_COMPUTE = `\nlet cc_dp1 = dpdx(input.worldPos);\nlet cc_dp2 = dpdy(input.worldPos);\nlet cc_duv1 = dpdx(input.uv);\nlet cc_duv2 = dpdy(input.uv);\nlet cc_dp2perp = cross(cc_dp2, N_geom);\nlet cc_dp1perp = cross(N_geom, cc_dp1);\nlet cc_tFrame = cc_dp2perp * cc_duv1.x + cc_dp1perp * cc_duv2.x;\nlet cc_bFrame = -(cc_dp2perp * cc_duv1.y + cc_dp1perp * cc_duv2.y);\nlet cc_det = max(dot(cc_tFrame, cc_tFrame), dot(cc_bFrame, cc_bFrame));\nlet cc_invmax = select(inverseSqrt(cc_det), 0.0, cc_det == 0.0);\nlet cc_frame = mat3x3<f32>(cc_tFrame * cc_invmax, cc_bFrame * cc_invmax, N_geom);\nlet ccNormSampleRaw = textureSample(ccNormalTexture, ccNormalSampler_, input.uv).rgb * 2.0 - 1.0;\nlet ccNormScale = material.ccParams.z;\nvar ccN = normalize(cc_frame * normalize(ccNormSampleRaw * vec3<f32>(ccNormScale, ccNormScale, 1.0)));\n`;\n\nfunction makeF0Remap(intensityExpr: string): string {\n return `\n{\nlet ccInt_r = ${intensityExpr};\nlet remappedF0 = getR0RemappedForClearCoat(colorF0, material.ccRefractionParams.z, material.ccRefractionParams.w);\ncolorF0 = mix(colorF0, remappedF0, ccInt_r);\n}\n`;\n}\n\nfunction makeDirectMod(intensityExpr: string, roughnessExpr: string, hasNormalMap: boolean): string {\n const N = hasNormalMap ? \"ccN\" : \"N_geom\";\n return `\nvar ccDirectAttenuation = 1.0;\nvar ccDirectSpecularTerm = vec3<f32>(0.0);\n{\nlet ccInt_dl = ${intensityExpr};\nlet ccRough_dl = ${roughnessExpr};\nlet ccF0_dl = material.ccRefractionParams.x;\nlet ccAlphaG_dl = ccRough_dl * ccRough_dl + 0.0005;\nlet ccNdotL_dl = saturate(dot(${N}, L));\nlet ccH_dl = normalize(V + L);\nlet ccNdotH_dl = clamp(dot(${N}, ccH_dl), 0.0000001, 1.0);\nlet ccVdotH_dl = saturate(dot(V, ccH_dl));\nlet ccD_dl = distributionGGX(ccNdotH_dl, ccAlphaG_dl);\nlet ccVis_dl = visibility_Kelemen(ccVdotH_dl);\nlet ccFresnel_dl = ccSchlick(ccF0_dl, ccVdotH_dl);\nlet ccTerm = ccFresnel_dl * ccD_dl * ccVis_dl * ccNdotL_dl;\nccDirectSpecularTerm = vec3<f32>(ccTerm) * lightColor * lightAtten * material.directIntensity * ccInt_dl;\nccDirectAttenuation = 1.0 - ccFresnel_dl * ccInt_dl;\n}\n`;\n}\n\nfunction makeIblMod(intensityExpr: string, roughnessExpr: string, hasNormalMap: boolean, hasSpecularAA: boolean, hasBaseNormalMap: boolean): string {\n const N = hasNormalMap ? \"ccN\" : \"N_geom\";\n const alphaG = hasSpecularAA\n ? `let ccAlphaG_ibl_base = ccRough_ibl * ccRough_ibl + 0.0005;\nlet cc_nDfdx_AA = dpdx(${N});\nlet cc_nDfdy_AA = dpdy(${N});\nlet cc_slopeSquare_AA = max(dot(cc_nDfdx_AA, cc_nDfdx_AA), dot(cc_nDfdy_AA, cc_nDfdy_AA));\nlet ccAlphaG_ibl = ccAlphaG_ibl_base + sqrt(cc_slopeSquare_AA) * 0.75;`\n : `let ccAlphaG_ibl = ccRough_ibl * ccRough_ibl + 0.0005;`;\n const ehoLine = hasBaseNormalMap ? `let ccEho_ibl = environmentHorizonOcclusion(-V, ${N}, N_geom);` : `let ccEho_ibl = 1.0;`;\n return `\n{\nlet ccInt_ibl = ${intensityExpr};\nlet ccRough_ibl = ${roughnessExpr};\nlet ccF0_ibl = material.ccRefractionParams.x;\nlet ccR_raw = reflect(-V, ${N});\nlet ccR_ibl = rotateY(ccR_raw, scene.envRotationY);\nlet ccNdotV_ibl = abs(dot(${N}, V)) + 0.0000001;\n${alphaG}\nvar ccSpecLod_ibl = log2(cubemapDim * ccAlphaG_ibl) * scene.vImageInfos.z;\nlet ccEnvRadiance_ibl = textureSampleLevel(iblTexture, iblSampler, ccR_ibl, clamp(ccSpecLod_ibl, 0.0, maxLod)).rgb * material.environmentIntensity;\nlet ccBrdf_ibl = textureSample(brdfLUT, brdfSampler_, vec2<f32>(ccNdotV_ibl, ccRough_ibl)).rgb;\n${ehoLine}\nlet ccSpecEnvRefl = (vec3<f32>(ccF0_ibl) * ccBrdf_ibl.y + (vec3<f32>(1.0) - vec3<f32>(ccF0_ibl)) * ccBrdf_ibl.x) * ccInt_ibl * ccEho_ibl;\nlet ccFresnelIBL = ccSchlick(ccF0_ibl, ccNdotV_ibl);\nlet ccConservation_ibl = 1.0 - ccFresnelIBL * ccInt_ibl;\nlet ccFinalRadiance_ibl = ccEnvRadiance_ibl * ccSpecEnvRefl;\ncolor = finalIrradiance * ccConservation_ibl\n + finalRadianceScaled * ccConservation_ibl\n + finalSpecularScaled * ccDirectAttenuation\n + directDiffuse * ccDirectAttenuation\n + ccDirectSpecularTerm\n + ccFinalRadiance_ibl\n + emissive;\n}\n`;\n}\n\nfunction makeNonIblMod(intensityExpr: string): string {\n return `\n{\nlet ccF0_noIbl = material.ccRefractionParams.x;\nlet ccInt_noIbl = ${intensityExpr};\nlet ccFresnelNoIbl = ccSchlick(ccF0_noIbl, NdotV);\nlet ccCons_noIbl = 1.0 - ccFresnelNoIbl * ccInt_noIbl;\ncolor = (color - emissive) * ccCons_noIbl + emissive + ccDirectSpecularTerm;\n}\n`;\n}\n\nexport function createClearcoatFragment(features: number, features2: number, hasIbl: boolean, hasBaseNormalMap: boolean, hasSpecularAA: boolean): ShaderFragment | null {\n if ((features & PBR_HAS_CLEARCOAT) === 0) {\n return null;\n }\n const hasReflectance = (features & (PBR_HAS_METALLIC_REFLECTANCE_MAP | PBR_HAS_REFLECTANCE_MAP)) !== 0;\n const hasIntensityMap = (features2 & PBR2_CC_INT_MAP) !== 0;\n const hasRoughnessMap = (features2 & PBR2_CC_ROUGH_MAP) !== 0;\n const hasNormalMap = (features2 & PBR2_CC_NORMAL_MAP) !== 0;\n const disableF0Remap = (features2 & PBR2_CC_F0_REMAP_OFF) !== 0;\n const intensityExpr = hasIntensityMap ? CC_INT_TEX : CC_INT_PLAIN;\n const roughnessExpr = hasRoughnessMap ? CC_ROUGH_TEX : CC_ROUGH_PLAIN;\n const slots: Partial<Record<string, string>> = {\n MF: disableF0Remap ? \"\" : makeF0Remap(intensityExpr),\n AD: makeDirectMod(intensityExpr, roughnessExpr, hasNormalMap),\n BL: `var ccDirectAttenuation = 1.0;\\nvar ccDirectSpecularTerm = vec3<f32>(0.0);`,\n };\n if (hasNormalMap) {\n slots.AC = CC_NORMAL_COMPUTE;\n }\n // AI and NI are mutually exclusive — only one path runs\n if (hasIbl) {\n slots.AI = makeIblMod(intensityExpr, roughnessExpr, hasNormalMap, hasSpecularAA, hasBaseNormalMap);\n } else {\n slots.NI = makeNonIblMod(intensityExpr);\n }\n const deps: string[] = [];\n if (hasIbl) {\n deps.push(\"ibl\");\n }\n if (hasReflectance) {\n deps.push(\"reflectance\");\n }\n // Fragment id varies with texture config so shader-composer's fragmentKey\n // (and downstream pipeline cache) distinguishes variants.\n const suffix =\n (hasIntensityMap ? \"I\" : \"\") +\n (hasRoughnessMap ? \"R\" : \"\") +\n (hasNormalMap ? \"N\" : \"\") +\n (disableF0Remap ? \"X\" : \"\") +\n (hasSpecularAA ? \"A\" : \"\") +\n (hasBaseNormalMap ? \"B\" : \"\");\n const bindings: BindingDecl[] = [];\n if (hasIntensityMap) {\n bindings.push(\n { _name: \"ccIntensityTexture\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" }, _visibility: STAGE_FRAGMENT },\n { _name: \"ccIntensitySampler_\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" }, _visibility: STAGE_FRAGMENT }\n );\n }\n if (hasRoughnessMap) {\n bindings.push(\n { _name: \"ccRoughnessTexture\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" }, _visibility: STAGE_FRAGMENT },\n { _name: \"ccRoughnessSampler_\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" }, _visibility: STAGE_FRAGMENT }\n );\n }\n if (hasNormalMap) {\n bindings.push(\n { _name: \"ccNormalTexture\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" }, _visibility: STAGE_FRAGMENT },\n { _name: \"ccNormalSampler_\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" }, _visibility: STAGE_FRAGMENT }\n );\n }\n\n return {\n _id: suffix ? `clearcoat-${suffix}` : \"clearcoat\",\n _dependencies: deps.length > 0 ? deps : undefined,\n\n _uboFields: [\n { _name: \"ccParams\", _type: \"vec4<f32>\" },\n { _name: \"ccRefractionParams\", _type: \"vec4<f32>\" },\n ],\n\n _bindings: bindings,\n\n _helperFunctions: CC_HELPERS,\n\n _fragmentSlots: slots,\n };\n}\n\n/** Write the clearcoat material-UBO slice (ccParams + ccParams2). */\nexport function writeClearcoatUBO(data: Float32Array, material: PbrMaterialProps, offsets: ReadonlyMap<string, number>): void {\n const cc = material.clearCoat as ClearCoatProps | undefined;\n if (!cc?.isEnabled || !offsets.has(\"ccParams\")) {\n return;\n }\n const off = offsets.get(\"ccParams\")! / 4;\n const ior = cc.indexOfRefraction ?? 1.5;\n const a = 1 - ior;\n const b = 1 + ior;\n data[off] = cc.intensity ?? 1.0;\n data[off + 1] = cc.roughness ?? 0.0;\n data[off + 2] = cc.bumpTextureScale ?? 1.0;\n data[off + 4] = Math.pow(-a / b, 2);\n data[off + 5] = 1 / ior;\n data[off + 6] = a;\n data[off + 7] = b;\n}\n\nconst CC_TEX: ReadonlyArray<readonly [number, \"texture\" | \"roughnessTexture\" | \"bumpTexture\"]> = [\n [PBR2_CC_INT_MAP, \"texture\"],\n [PBR2_CC_ROUGH_MAP, \"roughnessTexture\"],\n [PBR2_CC_NORMAL_MAP, \"bumpTexture\"],\n];\n\n/** Clearcoat PBR extension (group 1, base-tex phase). */\nexport const pbrExt: PbrExt = {\n id: \"clearcoat\",\n phase: \"base-tex\",\n detect(mat) {\n const cc = (mat as PbrMaterialProps).clearCoat as ClearCoatProps | undefined;\n if (!cc?.isEnabled) {\n return { f: 0, f2: 0 };\n }\n let f2 = 0;\n for (const [flag, key] of CC_TEX) {\n if (cc[key]) {\n f2 |= flag;\n }\n }\n if (cc.useF0Remap === false) {\n f2 |= PBR2_CC_F0_REMAP_OFF;\n }\n return { f: PBR_HAS_CLEARCOAT, f2 };\n },\n frag: (ctx) => createClearcoatFragment(ctx._features, ctx._features2, ctx._hasIbl, ctx._hasAnyNormal, ctx._hasSpecularAA),\n writeUbo: writeClearcoatUBO as PbrExt[\"writeUbo\"],\n bind(ctx, entries, b) {\n const cc = (ctx._material as PbrMaterialProps).clearCoat as ClearCoatProps | undefined;\n if (!cc) {\n return b;\n }\n for (const [flag, key] of CC_TEX) {\n const tex = cc[key];\n if ((ctx._features2 & flag) !== 0 && 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, t) {\n const cc = (mat as PbrMaterialProps).clearCoat;\n if (!cc) {\n return;\n }\n for (const [, key] of CC_TEX) {\n const tex = cc[key];\n if (tex) {\n t.push(tex);\n }\n }\n },\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"clearcoat-fragment-Dj7vGX2u.js","sources":["../src/material/pbr/fragments/clearcoat-fragment.ts"],"sourcesContent":["/**\n * Clearcoat Fragment\n *\n * Adds a glossy transparent top layer (like car paint or lacquered surfaces).\n * Only bundled when a scene uses PbrMaterialProps.clearCoat.\n *\n * Math follows BJS PBRClearCoatConfiguration:\n * - F0 from IOR: ((1-ior)/(1+ior))^2\n * - F0 remap: base F0 adjusted for coat/base interface\n * - Direct: GGX + Kelemen visibility + Schlick fresnel\n * - IBL: Jones analytical BRDF (not BRDF LUT)\n * - Conservation: base layer attenuated by (1 - fresnel * intensity)\n *\n * Supports glTF KHR_materials_clearcoat textures:\n * - clearcoatTexture (R channel multiplies intensity)\n * - clearcoatRoughnessTexture (G channel multiplies roughness)\n * - clearcoatNormalTexture (tangent-space normal, perturbs coat normal)\n */\n\nimport type { ShaderFragment, BindingDecl } from \"../../../shader/fragment-types.js\";\nimport type { PbrMaterialProps, ClearCoatProps } from \"../pbr-material.js\";\nimport type { PbrExt } from \"../pbr-flags.js\";\nimport {\n PBR_HAS_CLEARCOAT,\n PBR_HAS_METALLIC_REFLECTANCE_MAP,\n PBR_HAS_REFLECTANCE_MAP,\n PBR2_CC_INT_MAP,\n PBR2_CC_ROUGH_MAP,\n PBR2_CC_NORMAL_MAP,\n PBR2_CC_F0_REMAP_OFF,\n} from \"../pbr-flag-bits.js\";\n\nconst STAGE_FRAGMENT = 0x2;\n\nconst CC_HELPERS = `\nfn visibility_Kelemen(VdotH_kl: f32) -> f32 {\nreturn 0.25 / (VdotH_kl * VdotH_kl + 0.0000001);\n}\nfn getR0RemappedForClearCoat(f0_rc: vec3<f32>, ccA: f32, ccB: f32) -> vec3<f32> {\nlet sf0 = sqrt(f0_rc);\nlet num = ccA + ccB * sf0;\nlet den = ccB + ccA * sf0;\nreturn saturate((num / den) * (num / den));\n}\nfn ccSchlick(f0: f32, cosTheta: f32) -> f32 {\nlet t = 1.0 - cosTheta;\nlet t2 = t * t;\nreturn f0 + (1.0 - f0) * (t2 * t2 * t);\n}\n`;\n\nconst CC_INT_TEX = `material.ccParams.x * textureSample(ccIntensityTexture, ccIntensitySampler_, input.uv).r`;\nconst CC_INT_PLAIN = `material.ccParams.x`;\nconst CC_ROUGH_TEX = `clamp(material.ccParams.y * textureSample(ccRoughnessTexture, ccRoughnessSampler_, input.uv).g, 0.0, 1.0)`;\nconst CC_ROUGH_PLAIN = `material.ccParams.y`;\n\n// WGSL fragment: coat-layer normal. Computes ccN (coat world-space normal)\n// using a locally-derived cotangent frame from world-position and UV derivatives.\n// Emitted in /*AC*/ so ccN is in scope for direct + IBL blocks.\nconst CC_NORMAL_COMPUTE = `\nlet cc_dp1 = dpdx(input.worldPos);\nlet cc_dp2 = dpdy(input.worldPos);\nlet cc_duv1 = dpdx(input.uv);\nlet cc_duv2 = dpdy(input.uv);\nlet cc_dp2perp = cross(cc_dp2, N_geom);\nlet cc_dp1perp = cross(N_geom, cc_dp1);\nlet cc_tFrame = cc_dp2perp * cc_duv1.x + cc_dp1perp * cc_duv2.x;\nlet cc_bFrame = -(cc_dp2perp * cc_duv1.y + cc_dp1perp * cc_duv2.y);\nlet cc_det = max(dot(cc_tFrame, cc_tFrame), dot(cc_bFrame, cc_bFrame));\nlet cc_invmax = select(inverseSqrt(cc_det), 0.0, cc_det == 0.0);\nlet cc_frame = mat3x3<f32>(cc_tFrame * cc_invmax, cc_bFrame * cc_invmax, N_geom);\nlet ccNormSampleRaw = textureSample(ccNormalTexture, ccNormalSampler_, input.uv).rgb * 2.0 - 1.0;\nlet ccNormScale = material.ccParams.z;\nvar ccN = normalize(cc_frame * normalize(ccNormSampleRaw * vec3<f32>(ccNormScale, ccNormScale, 1.0)));\n`;\n\nfunction makeF0Remap(intensityExpr: string): string {\n return `\n{\nlet ccInt_r = ${intensityExpr};\nlet remappedF0 = getR0RemappedForClearCoat(colorF0, material.ccRefractionParams.z, material.ccRefractionParams.w);\ncolorF0 = mix(colorF0, remappedF0, ccInt_r);\n}\n`;\n}\n\nfunction makeDirectMod(intensityExpr: string, roughnessExpr: string, hasNormalMap: boolean): string {\n const N = hasNormalMap ? \"ccN\" : \"N_geom\";\n return `\nvar ccDirectAttenuation = 1.0;\nvar ccDirectSpecularTerm = vec3<f32>(0.0);\n{\nlet ccInt_dl = ${intensityExpr};\nlet ccRough_dl = ${roughnessExpr};\nlet ccF0_dl = material.ccRefractionParams.x;\nlet ccAlphaG_dl = ccRough_dl * ccRough_dl + 0.0005;\nlet ccNdotL_dl = saturate(dot(${N}, L));\nlet ccH_dl = normalize(V + L);\nlet ccNdotH_dl = clamp(dot(${N}, ccH_dl), 0.0000001, 1.0);\nlet ccVdotH_dl = saturate(dot(V, ccH_dl));\nlet ccD_dl = distributionGGX(ccNdotH_dl, ccAlphaG_dl);\nlet ccVis_dl = visibility_Kelemen(ccVdotH_dl);\nlet ccFresnel_dl = ccSchlick(ccF0_dl, ccVdotH_dl);\nlet ccTerm = ccFresnel_dl * ccD_dl * ccVis_dl * ccNdotL_dl;\nccDirectSpecularTerm = vec3<f32>(ccTerm) * lightColor * lightAtten * material.directIntensity * ccInt_dl;\nccDirectAttenuation = 1.0 - ccFresnel_dl * ccInt_dl;\n}\n`;\n}\n\nfunction makeIblMod(intensityExpr: string, roughnessExpr: string, hasNormalMap: boolean, hasSpecularAA: boolean, hasBaseNormalMap: boolean): string {\n const N = hasNormalMap ? \"ccN\" : \"N_geom\";\n const alphaG = hasSpecularAA\n ? `let ccAlphaG_ibl_base = ccRough_ibl * ccRough_ibl + 0.0005;\nlet cc_nDfdx_AA = dpdx(${N});\nlet cc_nDfdy_AA = dpdy(${N});\nlet cc_slopeSquare_AA = max(dot(cc_nDfdx_AA, cc_nDfdx_AA), dot(cc_nDfdy_AA, cc_nDfdy_AA));\nlet ccAlphaG_ibl = ccAlphaG_ibl_base + sqrt(cc_slopeSquare_AA) * 0.75;`\n : `let ccAlphaG_ibl = ccRough_ibl * ccRough_ibl + 0.0005;`;\n const ehoLine = hasBaseNormalMap ? `let ccEho_ibl = environmentHorizonOcclusion(-V, ${N}, N_geom);` : `let ccEho_ibl = 1.0;`;\n return `\n{\nlet ccInt_ibl = ${intensityExpr};\nlet ccRough_ibl = ${roughnessExpr};\nlet ccF0_ibl = material.ccRefractionParams.x;\nlet ccR_raw = reflect(-V, ${N});\nlet ccR_ibl = rotateY(ccR_raw, scene.envRotationY);\nlet ccNdotV_ibl = abs(dot(${N}, V)) + 0.0000001;\n${alphaG}\nvar ccSpecLod_ibl = log2(cubemapDim * ccAlphaG_ibl) * scene.vImageInfos.z;\nlet ccEnvRadiance_ibl = textureSampleLevel(iblTexture, iblSampler, ccR_ibl, clamp(ccSpecLod_ibl, 0.0, maxLod)).rgb * material.environmentIntensity;\nlet ccBrdf_ibl = textureSample(brdfLUT, brdfSampler_, vec2<f32>(ccNdotV_ibl, ccRough_ibl)).rgb;\n${ehoLine}\nlet ccSpecEnvRefl = (vec3<f32>(ccF0_ibl) * ccBrdf_ibl.y + (vec3<f32>(1.0) - vec3<f32>(ccF0_ibl)) * ccBrdf_ibl.x) * ccInt_ibl * ccEho_ibl;\nlet ccFresnelIBL = ccSchlick(ccF0_ibl, ccNdotV_ibl);\nlet ccConservation_ibl = 1.0 - ccFresnelIBL * ccInt_ibl;\nlet ccFinalRadiance_ibl = ccEnvRadiance_ibl * ccSpecEnvRefl;\ncolor = finalIrradiance * ccConservation_ibl\n + finalRadianceScaled * ccConservation_ibl\n + finalSpecularScaled * ccDirectAttenuation\n + directDiffuse * ccDirectAttenuation\n + ccDirectSpecularTerm\n + ccFinalRadiance_ibl\n + emissive;\n}\n`;\n}\n\nfunction makeNonIblMod(intensityExpr: string): string {\n return `\n{\nlet ccF0_noIbl = material.ccRefractionParams.x;\nlet ccInt_noIbl = ${intensityExpr};\nlet ccFresnelNoIbl = ccSchlick(ccF0_noIbl, NdotV);\nlet ccCons_noIbl = 1.0 - ccFresnelNoIbl * ccInt_noIbl;\ncolor = (color - emissive) * ccCons_noIbl + emissive + ccDirectSpecularTerm;\n}\n`;\n}\n\nexport function createClearcoatFragment(features: number, features2: number, hasIbl: boolean, hasBaseNormalMap: boolean, hasSpecularAA: boolean): ShaderFragment | null {\n if ((features & PBR_HAS_CLEARCOAT) === 0) {\n return null;\n }\n const hasReflectance = (features & (PBR_HAS_METALLIC_REFLECTANCE_MAP | PBR_HAS_REFLECTANCE_MAP)) !== 0;\n const hasIntensityMap = (features2 & PBR2_CC_INT_MAP) !== 0;\n const hasRoughnessMap = (features2 & PBR2_CC_ROUGH_MAP) !== 0;\n const hasNormalMap = (features2 & PBR2_CC_NORMAL_MAP) !== 0;\n const disableF0Remap = (features2 & PBR2_CC_F0_REMAP_OFF) !== 0;\n const intensityExpr = hasIntensityMap ? CC_INT_TEX : CC_INT_PLAIN;\n const roughnessExpr = hasRoughnessMap ? CC_ROUGH_TEX : CC_ROUGH_PLAIN;\n const slots: Partial<Record<string, string>> = {\n MF: disableF0Remap ? \"\" : makeF0Remap(intensityExpr),\n AD: makeDirectMod(intensityExpr, roughnessExpr, hasNormalMap),\n BL: `var ccDirectAttenuation = 1.0;\\nvar ccDirectSpecularTerm = vec3<f32>(0.0);`,\n };\n if (hasNormalMap) {\n slots.AC = CC_NORMAL_COMPUTE;\n }\n // AI and NI are mutually exclusive — only one path runs\n if (hasIbl) {\n slots.AI = makeIblMod(intensityExpr, roughnessExpr, hasNormalMap, hasSpecularAA, hasBaseNormalMap);\n } else {\n slots.NI = makeNonIblMod(intensityExpr);\n }\n const deps: string[] = [];\n if (hasIbl) {\n deps.push(\"ibl\");\n }\n if (hasReflectance) {\n deps.push(\"reflectance\");\n }\n // Fragment id varies with texture config so shader-composer's fragmentKey\n // (and downstream pipeline cache) distinguishes variants.\n const suffix =\n (hasIntensityMap ? \"I\" : \"\") +\n (hasRoughnessMap ? \"R\" : \"\") +\n (hasNormalMap ? \"N\" : \"\") +\n (disableF0Remap ? \"X\" : \"\") +\n (hasSpecularAA ? \"A\" : \"\") +\n (hasBaseNormalMap ? \"B\" : \"\");\n const bindings: BindingDecl[] = [];\n if (hasIntensityMap) {\n bindings.push(\n { _name: \"ccIntensityTexture\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" }, _visibility: STAGE_FRAGMENT },\n { _name: \"ccIntensitySampler_\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" }, _visibility: STAGE_FRAGMENT }\n );\n }\n if (hasRoughnessMap) {\n bindings.push(\n { _name: \"ccRoughnessTexture\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" }, _visibility: STAGE_FRAGMENT },\n { _name: \"ccRoughnessSampler_\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" }, _visibility: STAGE_FRAGMENT }\n );\n }\n if (hasNormalMap) {\n bindings.push(\n { _name: \"ccNormalTexture\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" }, _visibility: STAGE_FRAGMENT },\n { _name: \"ccNormalSampler_\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" }, _visibility: STAGE_FRAGMENT }\n );\n }\n\n return {\n _id: suffix ? `clearcoat-${suffix}` : \"clearcoat\",\n _dependencies: deps.length > 0 ? deps : undefined,\n\n _uboFields: [\n { _name: \"ccParams\", _type: \"vec4<f32>\" },\n { _name: \"ccRefractionParams\", _type: \"vec4<f32>\" },\n ],\n\n _bindings: bindings,\n\n _helperFunctions: CC_HELPERS,\n\n _fragmentSlots: slots,\n };\n}\n\n/** Write the clearcoat material-UBO slice (ccParams + ccParams2). */\nexport function writeClearcoatUBO(data: Float32Array, material: PbrMaterialProps, offsets: ReadonlyMap<string, number>): void {\n const cc = material.clearCoat as ClearCoatProps | undefined;\n if (!cc?.isEnabled || !offsets.has(\"ccParams\")) {\n return;\n }\n const off = offsets.get(\"ccParams\")! / 4;\n const ior = cc.indexOfRefraction ?? 1.5;\n const a = 1 - ior;\n const b = 1 + ior;\n data[off] = cc.intensity ?? 1.0;\n data[off + 1] = cc.roughness ?? 0.0;\n data[off + 2] = cc.bumpTextureScale ?? 1.0;\n data[off + 4] = Math.pow(-a / b, 2);\n data[off + 5] = 1 / ior;\n data[off + 6] = a;\n data[off + 7] = b;\n}\n\nconst CC_TEX: ReadonlyArray<readonly [number, \"texture\" | \"roughnessTexture\" | \"bumpTexture\"]> = [\n [PBR2_CC_INT_MAP, \"texture\"],\n [PBR2_CC_ROUGH_MAP, \"roughnessTexture\"],\n [PBR2_CC_NORMAL_MAP, \"bumpTexture\"],\n];\n\n/** Clearcoat PBR extension (group 1, base-tex phase). */\nexport const pbrExt: PbrExt = {\n id: \"clearcoat\",\n phase: \"base-tex\",\n detect(mat) {\n const cc = (mat as PbrMaterialProps).clearCoat as ClearCoatProps | undefined;\n if (!cc?.isEnabled) {\n return { f: 0, f2: 0 };\n }\n let f2 = 0;\n for (const [flag, key] of CC_TEX) {\n if (cc[key]) {\n f2 |= flag;\n }\n }\n if (cc.useF0Remap === false) {\n f2 |= PBR2_CC_F0_REMAP_OFF;\n }\n return { f: PBR_HAS_CLEARCOAT, f2 };\n },\n frag: (ctx) => createClearcoatFragment(ctx._features, ctx._features2, ctx._hasIbl, ctx._hasAnyNormal, ctx._hasSpecularAA),\n writeUbo: writeClearcoatUBO as PbrExt[\"writeUbo\"],\n bind(ctx, entries, b) {\n const cc = (ctx._material as PbrMaterialProps).clearCoat as ClearCoatProps | undefined;\n if (!cc) {\n return b;\n }\n for (const [flag, key] of CC_TEX) {\n const tex = cc[key];\n if ((ctx._features2 & flag) !== 0 && 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, t) {\n const cc = (mat as PbrMaterialProps).clearCoat;\n if (!cc) {\n return;\n }\n for (const [, key] of CC_TEX) {\n const tex = cc[key];\n if (tex) {\n t.push(tex);\n }\n }\n },\n};\n"],"names":[],"mappings":"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"}