@zephyr3d/scene 0.9.27 → 0.10.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 (502) hide show
  1. package/README.md +60 -27
  2. package/dist/animation/animation_bank.js +634 -0
  3. package/dist/animation/animation_bank.js.map +1 -0
  4. package/dist/animation/animation_bank_gpu.js +256 -0
  5. package/dist/animation/animation_bank_gpu.js.map +1 -0
  6. package/dist/animation/animationset.js +54 -0
  7. package/dist/animation/animationset.js.map +1 -1
  8. package/dist/animation/cloth/gpu_cloth_component.js +406 -0
  9. package/dist/animation/cloth/gpu_cloth_component.js.map +1 -0
  10. package/dist/animation/cloth/gpu_cloth_system.js +332 -202
  11. package/dist/animation/cloth/gpu_cloth_system.js.map +1 -1
  12. package/dist/animation/gpu_animation_driver.js +289 -0
  13. package/dist/animation/gpu_animation_driver.js.map +1 -0
  14. package/dist/animation/joint_dynamics/collision.js +112 -1
  15. package/dist/animation/joint_dynamics/collision.js.map +1 -1
  16. package/dist/animation/joint_dynamics/controller.js +6 -0
  17. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  18. package/dist/animation/joint_dynamics/joint_dynamics_system.js +11 -0
  19. package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
  20. package/dist/animation/joint_dynamics/solver.js +50 -12
  21. package/dist/animation/joint_dynamics/solver.js.map +1 -1
  22. package/dist/animation/joint_dynamics/types.js.map +1 -1
  23. package/dist/animation/skeleton.js +279 -55
  24. package/dist/animation/skeleton.js.map +1 -1
  25. package/dist/animation/skin_palette_atlas.js +252 -0
  26. package/dist/animation/skin_palette_atlas.js.map +1 -0
  27. package/dist/animation/spring/multi_chain_spring_system.js +298 -38
  28. package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
  29. package/dist/animation/spring/spring_chain.js +2 -0
  30. package/dist/animation/spring/spring_chain.js.map +1 -1
  31. package/dist/animation/spring/spring_collider.js +159 -21
  32. package/dist/animation/spring/spring_collider.js.map +1 -1
  33. package/dist/animation/spring/spring_particle.js +1 -0
  34. package/dist/animation/spring/spring_particle.js.map +1 -1
  35. package/dist/animation/spring/spring_solver.js +173 -0
  36. package/dist/animation/spring/spring_solver.js.map +1 -0
  37. package/dist/animation/spring/spring_system.js +249 -24
  38. package/dist/animation/spring/spring_system.js.map +1 -1
  39. package/dist/animation/spring_modifier.js +32 -1
  40. package/dist/animation/spring_modifier.js.map +1 -1
  41. package/dist/app/app.js +26 -0
  42. package/dist/app/app.js.map +1 -1
  43. package/dist/app/engine.js +86 -15
  44. package/dist/app/engine.js.map +1 -1
  45. package/dist/app/gamepad.js +191 -0
  46. package/dist/app/gamepad.js.map +1 -0
  47. package/dist/app/inputactions.js +271 -0
  48. package/dist/app/inputactions.js.map +1 -0
  49. package/dist/app/inputmgr.js +331 -22
  50. package/dist/app/inputmgr.js.map +1 -1
  51. package/dist/app/loading.js +138 -0
  52. package/dist/app/loading.js.map +1 -0
  53. package/dist/app/pipelinecache.js +209 -0
  54. package/dist/app/pipelinecache.js.map +1 -0
  55. package/dist/app/runtimescript.js +25 -0
  56. package/dist/app/runtimescript.js.map +1 -1
  57. package/dist/app/scriptingsystem.js +54 -0
  58. package/dist/app/scriptingsystem.js.map +1 -1
  59. package/dist/app/scriptregistry.js +7 -2
  60. package/dist/app/scriptregistry.js.map +1 -1
  61. package/dist/asset/asset_manifest.js +59 -0
  62. package/dist/asset/asset_manifest.js.map +1 -0
  63. package/dist/asset/asset_preload.js +258 -0
  64. package/dist/asset/asset_preload.js.map +1 -0
  65. package/dist/asset/assetmanager.js +117 -65
  66. package/dist/asset/assetmanager.js.map +1 -1
  67. package/dist/asset/loaders/ktx2/basis/LICENSE +201 -0
  68. package/dist/asset/loaders/ktx2/basis/basis_transcoder.js +2 -0
  69. package/dist/asset/loaders/ktx2/basis/basis_transcoder.wasm +0 -0
  70. package/dist/asset/loaders/ktx2/basis_location.js +17 -0
  71. package/dist/asset/loaders/ktx2/basis_location.js.map +1 -0
  72. package/dist/asset/loaders/ktx2/ktx2_loader.js +88 -0
  73. package/dist/asset/loaders/ktx2/ktx2_loader.js.map +1 -0
  74. package/dist/asset/loaders/ktx2/ktx2_targets.js +118 -0
  75. package/dist/asset/loaders/ktx2/ktx2_targets.js.map +1 -0
  76. package/dist/asset/loaders/ktx2/transcoder_pool.js +259 -0
  77. package/dist/asset/loaders/ktx2/transcoder_pool.js.map +1 -0
  78. package/dist/asset/mesh_lod_builder.js +104 -0
  79. package/dist/asset/mesh_lod_builder.js.map +1 -0
  80. package/dist/asset/mesh_settings.js +111 -0
  81. package/dist/asset/mesh_settings.js.map +1 -0
  82. package/dist/asset/meshopt_decoder.js +18 -0
  83. package/dist/asset/meshopt_decoder.js.map +1 -0
  84. package/dist/asset/meshopt_simplifier.js +26 -0
  85. package/dist/asset/meshopt_simplifier.js.map +1 -0
  86. package/dist/asset/model.js +171 -1
  87. package/dist/asset/model.js.map +1 -1
  88. package/dist/asset/texture_settings.js +231 -0
  89. package/dist/asset/texture_settings.js.map +1 -0
  90. package/dist/asset/zmsh_binary.js +131 -0
  91. package/dist/asset/zmsh_binary.js.map +1 -0
  92. package/dist/asset/zsdf_binary.js +111 -0
  93. package/dist/asset/zsdf_binary.js.map +1 -0
  94. package/dist/blitter/bilateralblur.js +1 -2
  95. package/dist/blitter/bilateralblur.js.map +1 -1
  96. package/dist/blitter/gaussianblur.js +1 -6
  97. package/dist/blitter/gaussianblur.js.map +1 -1
  98. package/dist/camera/base.js +31 -10
  99. package/dist/camera/base.js.map +1 -1
  100. package/dist/camera/camera.js +104 -178
  101. package/dist/camera/camera.js.map +1 -1
  102. package/dist/camera/follow.js +342 -0
  103. package/dist/camera/follow.js.map +1 -0
  104. package/dist/camera/fps.js +9 -7
  105. package/dist/camera/fps.js.map +1 -1
  106. package/dist/camera/orbit.js +46 -19
  107. package/dist/camera/orbit.js.map +1 -1
  108. package/dist/index.d.ts +25436 -15990
  109. package/dist/index.js +65 -11
  110. package/dist/index.js.map +1 -1
  111. package/dist/material/blinn.js +3 -0
  112. package/dist/material/blinn.js.map +1 -1
  113. package/dist/material/eye.js +1 -1
  114. package/dist/material/eye.js.map +1 -1
  115. package/dist/material/hair.js +2 -3
  116. package/dist/material/hair.js.map +1 -1
  117. package/dist/material/lambert.js +4 -1
  118. package/dist/material/lambert.js.map +1 -1
  119. package/dist/material/material.js +66 -4
  120. package/dist/material/material.js.map +1 -1
  121. package/dist/material/meshmaterial.js +118 -45
  122. package/dist/material/meshmaterial.js.map +1 -1
  123. package/dist/material/mixins/lightmodel/blinnphong.js +1 -1
  124. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  125. package/dist/material/mixins/lightmodel/lambert.js +1 -1
  126. package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
  127. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +34 -61
  128. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
  129. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +16 -2
  130. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  131. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +2 -1
  132. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  133. package/dist/material/mixins/lit.js +191 -83
  134. package/dist/material/mixins/lit.js.map +1 -1
  135. package/dist/material/mixins/pbr/common.js +31 -206
  136. package/dist/material/mixins/pbr/common.js.map +1 -1
  137. package/dist/material/mtoon.js +1 -1
  138. package/dist/material/mtoon.js.map +1 -1
  139. package/dist/material/pbrmr.js +3 -0
  140. package/dist/material/pbrmr.js.map +1 -1
  141. package/dist/material/pbrsg.js +3 -0
  142. package/dist/material/pbrsg.js.map +1 -1
  143. package/dist/material/sdf_debug.js +78 -0
  144. package/dist/material/sdf_debug.js.map +1 -0
  145. package/dist/material/shader/helper.js +333 -191
  146. package/dist/material/shader/helper.js.map +1 -1
  147. package/dist/material/shader/terrain_blend.js +204 -43
  148. package/dist/material/shader/terrain_blend.js.map +1 -1
  149. package/dist/material/skin.js +331 -297
  150. package/dist/material/skin.js.map +1 -1
  151. package/dist/material/skinprofile.js +1058 -0
  152. package/dist/material/skinprofile.js.map +1 -0
  153. package/dist/material/sss.js +353 -0
  154. package/dist/material/sss.js.map +1 -0
  155. package/dist/material/sss_kernel.js +265 -0
  156. package/dist/material/sss_kernel.js.map +1 -0
  157. package/dist/material/sssprofile.js +879 -0
  158. package/dist/material/sssprofile.js.map +1 -0
  159. package/dist/material/subsurfaceprofile.js +4 -8
  160. package/dist/material/subsurfaceprofile.js.map +1 -1
  161. package/dist/material/terrain-cm.js +464 -188
  162. package/dist/material/terrain-cm.js.map +1 -1
  163. package/dist/material/unlit.js +3 -0
  164. package/dist/material/unlit.js.map +1 -1
  165. package/dist/material/water.js +1261 -1438
  166. package/dist/material/water.js.map +1 -1
  167. package/dist/node_modules/meshoptimizer/LICENSE +21 -0
  168. package/dist/node_modules/meshoptimizer/meshopt_decoder.js +197 -0
  169. package/dist/node_modules/meshoptimizer/meshopt_decoder.js.map +1 -0
  170. package/dist/node_modules/meshoptimizer/meshopt_simplifier.js +677 -0
  171. package/dist/node_modules/meshoptimizer/meshopt_simplifier.js.map +1 -0
  172. package/dist/physics/character.js +226 -0
  173. package/dist/physics/character.js.map +1 -0
  174. package/dist/physics/collider.js +209 -0
  175. package/dist/physics/collider.js.map +1 -0
  176. package/dist/physics/events.js +79 -0
  177. package/dist/physics/events.js.map +1 -0
  178. package/dist/physics/joint.js +272 -0
  179. package/dist/physics/joint.js.map +1 -0
  180. package/dist/physics/node_physics.js +234 -0
  181. package/dist/physics/node_physics.js.map +1 -0
  182. package/dist/physics/part.js +91 -0
  183. package/dist/physics/part.js.map +1 -0
  184. package/dist/physics/rigid_body.js +379 -0
  185. package/dist/physics/rigid_body.js.map +1 -0
  186. package/dist/physics/vehicle.js +335 -0
  187. package/dist/physics/vehicle.js.map +1 -0
  188. package/dist/physics/world.js +25 -0
  189. package/dist/physics/world.js.map +1 -0
  190. package/dist/posteffect/bloom.js +49 -14
  191. package/dist/posteffect/bloom.js.map +1 -1
  192. package/dist/posteffect/motionblur.js +106 -106
  193. package/dist/posteffect/motionblur.js.map +1 -1
  194. package/dist/posteffect/postsss.js +572 -0
  195. package/dist/posteffect/postsss.js.map +1 -0
  196. package/dist/posteffect/sao.js +2 -6
  197. package/dist/posteffect/sao.js.map +1 -1
  198. package/dist/posteffect/skinsss.js +605 -355
  199. package/dist/posteffect/skinsss.js.map +1 -1
  200. package/dist/posteffect/ssgi.js +91 -162
  201. package/dist/posteffect/ssgi.js.map +1 -1
  202. package/dist/posteffect/ssr.js +3 -11
  203. package/dist/posteffect/ssr.js.map +1 -1
  204. package/dist/posteffect/sss.js +4 -13
  205. package/dist/posteffect/sss.js.map +1 -1
  206. package/dist/posteffect/taa.js +1 -0
  207. package/dist/posteffect/taa.js.map +1 -1
  208. package/dist/render/abuffer_oit.js +3 -2
  209. package/dist/render/abuffer_oit.js.map +1 -1
  210. package/dist/render/clipmap.js +179 -64
  211. package/dist/render/clipmap.js.map +1 -1
  212. package/dist/render/cluster_light.js +958 -224
  213. package/dist/render/cluster_light.js.map +1 -1
  214. package/dist/render/cull_visitor.js +25 -5
  215. package/dist/render/cull_visitor.js.map +1 -1
  216. package/dist/render/debug_views.js +37 -0
  217. package/dist/render/debug_views.js.map +1 -0
  218. package/dist/render/depthpass.js +5 -1
  219. package/dist/render/depthpass.js.map +1 -1
  220. package/dist/render/drawable_mixin.js +53 -6
  221. package/dist/render/drawable_mixin.js.map +1 -1
  222. package/dist/render/dualdepthpeeling_oit.js +5 -5
  223. package/dist/render/dualdepthpeeling_oit.js.map +1 -1
  224. package/dist/render/envlight.js +196 -113
  225. package/dist/render/envlight.js.map +1 -1
  226. package/dist/render/fbm_wavegenerator.js +5 -10
  227. package/dist/render/fbm_wavegenerator.js.map +1 -1
  228. package/dist/render/fft_wavegenerator.js +247 -157
  229. package/dist/render/fft_wavegenerator.js.map +1 -1
  230. package/dist/render/gerstner_wavegenerator.js +16 -38
  231. package/dist/render/gerstner_wavegenerator.js.map +1 -1
  232. package/dist/render/gi/probe_volume.js +1334 -0
  233. package/dist/render/gi/probe_volume.js.map +1 -0
  234. package/dist/render/gi/scene_gi.js +282 -0
  235. package/dist/render/gi/scene_gi.js.map +1 -0
  236. package/dist/render/gi/voxel_atlas.js +198 -0
  237. package/dist/render/gi/voxel_atlas.js.map +1 -0
  238. package/dist/render/gi/voxel_lighting.js +652 -0
  239. package/dist/render/gi/voxel_lighting.js.map +1 -0
  240. package/dist/render/gi/voxel_scene.js +642 -0
  241. package/dist/render/gi/voxel_scene.js.map +1 -0
  242. package/dist/render/gi/voxelize_pass.js +223 -0
  243. package/dist/render/gi/voxelize_pass.js.map +1 -0
  244. package/dist/render/globalbindgroup_allocator.js +3 -2
  245. package/dist/render/globalbindgroup_allocator.js.map +1 -1
  246. package/dist/render/gpu_picking.js +9 -36
  247. package/dist/render/gpu_picking.js.map +1 -1
  248. package/dist/render/instance_culling.js +499 -0
  249. package/dist/render/instance_culling.js.map +1 -0
  250. package/dist/render/lightpass.js +19 -8
  251. package/dist/render/lightpass.js.map +1 -1
  252. package/dist/render/lod.js +46 -0
  253. package/dist/render/lod.js.map +1 -0
  254. package/dist/render/primitive.js +301 -9
  255. package/dist/render/primitive.js.map +1 -1
  256. package/dist/render/primitive_readback.js +209 -0
  257. package/dist/render/primitive_readback.js.map +1 -0
  258. package/dist/render/render_queue.js +162 -11
  259. package/dist/render/render_queue.js.map +1 -1
  260. package/dist/render/renderer.js +10 -7
  261. package/dist/render/renderer.js.map +1 -1
  262. package/dist/render/rendergraph/blackboard.js +14 -1
  263. package/dist/render/rendergraph/blackboard.js.map +1 -1
  264. package/dist/render/rendergraph/executor.js +136 -0
  265. package/dist/render/rendergraph/executor.js.map +1 -1
  266. package/dist/render/rendergraph/forward_plus_builder.js +272 -55
  267. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  268. package/dist/render/rendergraph/frame_graph_context.js +41 -0
  269. package/dist/render/rendergraph/frame_graph_context.js.map +1 -0
  270. package/dist/render/rendergraph/scene_render_context.js +31 -2
  271. package/dist/render/rendergraph/scene_render_context.js.map +1 -1
  272. package/dist/render/rendergraph/types.js.map +1 -1
  273. package/dist/render/renderpass.js +28 -5
  274. package/dist/render/renderpass.js.map +1 -1
  275. package/dist/render/sdf/box_allocator.js +98 -0
  276. package/dist/render/sdf/box_allocator.js.map +1 -0
  277. package/dist/render/sdf/global_sdf.js +865 -0
  278. package/dist/render/sdf/global_sdf.js.map +1 -0
  279. package/dist/render/sdf/scene_sdf.js +562 -0
  280. package/dist/render/sdf/scene_sdf.js.map +1 -0
  281. package/dist/render/sdf/sdf_atlas.js +227 -0
  282. package/dist/render/sdf/sdf_atlas.js.map +1 -0
  283. package/dist/render/sdf/sdf_programs.js +42 -0
  284. package/dist/render/sdf/sdf_programs.js.map +1 -0
  285. package/dist/render/sdf/sdf_view.js +199 -0
  286. package/dist/render/sdf/sdf_view.js.map +1 -0
  287. package/dist/render/sdf/waterline.js +610 -0
  288. package/dist/render/sdf/waterline.js.map +1 -0
  289. package/dist/render/shadow_mask_pass.js +142 -25
  290. package/dist/render/shadow_mask_pass.js.map +1 -1
  291. package/dist/render/shore_wave_generator.js +1193 -0
  292. package/dist/render/shore_wave_generator.js.map +1 -0
  293. package/dist/render/sky.js +516 -86
  294. package/dist/render/sky.js.map +1 -1
  295. package/dist/render/transmission_thickness_pass.js +477 -0
  296. package/dist/render/transmission_thickness_pass.js.map +1 -0
  297. package/dist/render/underwater.js +58 -158
  298. package/dist/render/underwater.js.map +1 -1
  299. package/dist/render/virtualtexture/virtual_texture.js +1214 -0
  300. package/dist/render/virtualtexture/virtual_texture.js.map +1 -0
  301. package/dist/render/volumetric_cloud/cloud_common.js +472 -0
  302. package/dist/render/volumetric_cloud/cloud_common.js.map +1 -0
  303. package/dist/render/volumetric_cloud/cloud_noise.js +189 -0
  304. package/dist/render/volumetric_cloud/cloud_noise.js.map +1 -0
  305. package/dist/render/volumetric_cloud/debug_view.js +131 -0
  306. package/dist/render/volumetric_cloud/debug_view.js.map +1 -0
  307. package/dist/render/volumetric_cloud/resources.js +380 -0
  308. package/dist/render/volumetric_cloud/resources.js.map +1 -0
  309. package/dist/render/volumetric_cloud/sky_cache.js +380 -0
  310. package/dist/render/volumetric_cloud/sky_cache.js.map +1 -0
  311. package/dist/render/volumetric_cloud/volumetric_cloud.js +318 -0
  312. package/dist/render/volumetric_cloud/volumetric_cloud.js.map +1 -0
  313. package/dist/render/water_caustics.js +134 -319
  314. package/dist/render/water_caustics.js.map +1 -1
  315. package/dist/render/water_foam.js +627 -0
  316. package/dist/render/water_foam.js.map +1 -0
  317. package/dist/render/water_interaction.js +1795 -0
  318. package/dist/render/water_interaction.js.map +1 -0
  319. package/dist/render/weightedblended_oit.js +3 -3
  320. package/dist/render/weightedblended_oit.js.map +1 -1
  321. package/dist/scene/basesprite.js +9 -4
  322. package/dist/scene/basesprite.js.map +1 -1
  323. package/dist/scene/batchgroup.js +108 -12
  324. package/dist/scene/batchgroup.js.map +1 -1
  325. package/dist/scene/environment.js +28 -7
  326. package/dist/scene/environment.js.map +1 -1
  327. package/dist/scene/foliage.js +1020 -0
  328. package/dist/scene/foliage.js.map +1 -0
  329. package/dist/scene/foliage_buckets.js +147 -0
  330. package/dist/scene/foliage_buckets.js.map +1 -0
  331. package/dist/scene/foliage_mask.js +358 -0
  332. package/dist/scene/foliage_mask.js.map +1 -0
  333. package/dist/scene/hair.js +15 -4
  334. package/dist/scene/hair.js.map +1 -1
  335. package/dist/scene/light.js +179 -13
  336. package/dist/scene/light.js.map +1 -1
  337. package/dist/scene/mesh.js +327 -45
  338. package/dist/scene/mesh.js.map +1 -1
  339. package/dist/scene/meshdrawable.js +6 -0
  340. package/dist/scene/meshdrawable.js.map +1 -1
  341. package/dist/scene/msdftext.js +9 -3
  342. package/dist/scene/msdftext.js.map +1 -1
  343. package/dist/scene/msdftextsprite.js +9 -3
  344. package/dist/scene/msdftextsprite.js.map +1 -1
  345. package/dist/scene/particlesys.js +8 -2
  346. package/dist/scene/particlesys.js.map +1 -1
  347. package/dist/scene/physics_settings.js +157 -0
  348. package/dist/scene/physics_settings.js.map +1 -0
  349. package/dist/scene/scene.js +190 -44
  350. package/dist/scene/scene.js.map +1 -1
  351. package/dist/scene/scene_node.js +147 -6
  352. package/dist/scene/scene_node.js.map +1 -1
  353. package/dist/scene/terrain-cm/bladegrassmaterial.js +735 -0
  354. package/dist/scene/terrain-cm/bladegrassmaterial.js.map +1 -0
  355. package/dist/scene/terrain-cm/grass.js +881 -42
  356. package/dist/scene/terrain-cm/grass.js.map +1 -1
  357. package/dist/scene/terrain-cm/grass_gpu.js +929 -0
  358. package/dist/scene/terrain-cm/grass_gpu.js.map +1 -0
  359. package/dist/scene/terrain-cm/grassmaterial.js +180 -9
  360. package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
  361. package/dist/scene/terrain-cm/terrain-cm.js +465 -36
  362. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  363. package/dist/scene/terrain-cm/terrain_gi_albedo.js +257 -0
  364. package/dist/scene/terrain-cm/terrain_gi_albedo.js.map +1 -0
  365. package/dist/scene/terrain-cm/terrain_rvt.js +395 -0
  366. package/dist/scene/terrain-cm/terrain_rvt.js.map +1 -0
  367. package/dist/scene/update_queue.js +54 -0
  368. package/dist/scene/update_queue.js.map +1 -0
  369. package/dist/scene/water.js +633 -268
  370. package/dist/scene/water.js.map +1 -1
  371. package/dist/scene/water_surface_sampler.js +324 -0
  372. package/dist/scene/water_surface_sampler.js.map +1 -0
  373. package/dist/scene/wind.js +317 -0
  374. package/dist/scene/wind.js.map +1 -0
  375. package/dist/shaders/atmosphere.js +388 -166
  376. package/dist/shaders/atmosphere.js.map +1 -1
  377. package/dist/shaders/fog.js +100 -32
  378. package/dist/shaders/fog.js.map +1 -1
  379. package/dist/shaders/gi.js +365 -0
  380. package/dist/shaders/gi.js.map +1 -0
  381. package/dist/shaders/ltc_rect.js +202 -0
  382. package/dist/shaders/ltc_rect.js.map +1 -0
  383. package/dist/shaders/misc.js +1 -10
  384. package/dist/shaders/misc.js.map +1 -1
  385. package/dist/shaders/noise.js +5 -1
  386. package/dist/shaders/noise.js.map +1 -1
  387. package/dist/shaders/probes.js +309 -0
  388. package/dist/shaders/probes.js.map +1 -0
  389. package/dist/shaders/sdf.js +537 -0
  390. package/dist/shaders/sdf.js.map +1 -0
  391. package/dist/shaders/shadow.js +104 -70
  392. package/dist/shaders/shadow.js.map +1 -1
  393. package/dist/shaders/skin_brdf.js +243 -0
  394. package/dist/shaders/skin_brdf.js.map +1 -0
  395. package/dist/shaders/ssgi.js +63 -0
  396. package/dist/shaders/ssgi.js.map +1 -0
  397. package/dist/shaders/ssgi_reprojection.js +118 -0
  398. package/dist/shaders/ssgi_reprojection.js.map +1 -0
  399. package/dist/shaders/ssr.js +6 -159
  400. package/dist/shaders/ssr.js.map +1 -1
  401. package/dist/shaders/temporal.js +38 -27
  402. package/dist/shaders/temporal.js.map +1 -1
  403. package/dist/shaders/water.js +32 -82
  404. package/dist/shaders/water.js.map +1 -1
  405. package/dist/shaders/water_medium.js +7 -21
  406. package/dist/shaders/water_medium.js.map +1 -1
  407. package/dist/shadow/dom.js +110 -19
  408. package/dist/shadow/dom.js.map +1 -1
  409. package/dist/shadow/esm.js +3 -3
  410. package/dist/shadow/esm.js.map +1 -1
  411. package/dist/shadow/pcf_opt.js +15 -48
  412. package/dist/shadow/pcf_opt.js.map +1 -1
  413. package/dist/shadow/pcf_pd.js +15 -53
  414. package/dist/shadow/pcf_pd.js.map +1 -1
  415. package/dist/shadow/pcss.js +34 -9
  416. package/dist/shadow/pcss.js.map +1 -1
  417. package/dist/shadow/shadow_impl.js +3 -8
  418. package/dist/shadow/shadow_impl.js.map +1 -1
  419. package/dist/shadow/shadow_region.js +40 -2
  420. package/dist/shadow/shadow_region.js.map +1 -1
  421. package/dist/shadow/shadowmapper.js +93 -53
  422. package/dist/shadow/shadowmapper.js.map +1 -1
  423. package/dist/shadow/ssm.js +18 -72
  424. package/dist/shadow/ssm.js.map +1 -1
  425. package/dist/shadow/vsm.js +3 -3
  426. package/dist/shadow/vsm.js.map +1 -1
  427. package/dist/shapes/shape.js +44 -1
  428. package/dist/shapes/shape.js.map +1 -1
  429. package/dist/utility/buoyancy.js +287 -0
  430. package/dist/utility/buoyancy.js.map +1 -0
  431. package/dist/utility/physical.js +10 -1
  432. package/dist/utility/physical.js.map +1 -1
  433. package/dist/utility/pmrem.js +17 -43
  434. package/dist/utility/pmrem.js.map +1 -1
  435. package/dist/utility/sdf/bake.js +435 -0
  436. package/dist/utility/sdf/bake.js.map +1 -0
  437. package/dist/utility/sdf/bvh.js +576 -0
  438. package/dist/utility/sdf/bvh.js.map +1 -0
  439. package/dist/utility/serialization/manager.js +34 -6
  440. package/dist/utility/serialization/manager.js.map +1 -1
  441. package/dist/utility/serialization/scene/animation.js +46 -5
  442. package/dist/utility/serialization/scene/animation.js.map +1 -1
  443. package/dist/utility/serialization/scene/batch.js +11 -4
  444. package/dist/utility/serialization/scene/batch.js.map +1 -1
  445. package/dist/utility/serialization/scene/camera.js +87 -254
  446. package/dist/utility/serialization/scene/camera.js.map +1 -1
  447. package/dist/utility/serialization/scene/cloth.js +25 -0
  448. package/dist/utility/serialization/scene/cloth.js.map +1 -0
  449. package/dist/utility/serialization/scene/common.js +14 -6
  450. package/dist/utility/serialization/scene/common.js.map +1 -1
  451. package/dist/utility/serialization/scene/foliage.js +821 -0
  452. package/dist/utility/serialization/scene/foliage.js.map +1 -0
  453. package/dist/utility/serialization/scene/hair.js +11 -4
  454. package/dist/utility/serialization/scene/hair.js.map +1 -1
  455. package/dist/utility/serialization/scene/light.js +115 -7
  456. package/dist/utility/serialization/scene/light.js.map +1 -1
  457. package/dist/utility/serialization/scene/material.js +388 -220
  458. package/dist/utility/serialization/scene/material.js.map +1 -1
  459. package/dist/utility/serialization/scene/mesh.js +69 -4
  460. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  461. package/dist/utility/serialization/scene/node.js +140 -5
  462. package/dist/utility/serialization/scene/node.js.map +1 -1
  463. package/dist/utility/serialization/scene/node_physics.js +1318 -0
  464. package/dist/utility/serialization/scene/node_physics.js.map +1 -0
  465. package/dist/utility/serialization/scene/particle.js +11 -4
  466. package/dist/utility/serialization/scene/particle.js.map +1 -1
  467. package/dist/utility/serialization/scene/physics.js +120 -0
  468. package/dist/utility/serialization/scene/physics.js.map +1 -0
  469. package/dist/utility/serialization/scene/primitive.js +124 -10
  470. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  471. package/dist/utility/serialization/scene/scene.js +1687 -51
  472. package/dist/utility/serialization/scene/scene.js.map +1 -1
  473. package/dist/utility/serialization/scene/sprite.js +11 -4
  474. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  475. package/dist/utility/serialization/scene/terrain.js +163 -33
  476. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  477. package/dist/utility/serialization/scene/text.js +11 -4
  478. package/dist/utility/serialization/scene/text.js.map +1 -1
  479. package/dist/utility/serialization/scene/water.js +1543 -264
  480. package/dist/utility/serialization/scene/water.js.map +1 -1
  481. package/dist/utility/serialization/types.js.map +1 -1
  482. package/dist/utility/shprojector.js +10 -22
  483. package/dist/utility/shprojector.js.map +1 -1
  484. package/dist/utility/textures/foam.js +170 -0
  485. package/dist/utility/textures/foam.js.map +1 -0
  486. package/dist/utility/textures/ggxlut.js +17 -43
  487. package/dist/utility/textures/ggxlut.js.map +1 -1
  488. package/dist/utility/textures/ltcdata.js +4 -4
  489. package/dist/utility/textures/ltcdata.js.map +1 -1
  490. package/dist/utility/textures/ltclut.js +16 -6
  491. package/dist/utility/textures/ltclut.js.map +1 -1
  492. package/dist/utility/unsupported.js +24 -0
  493. package/dist/utility/unsupported.js.map +1 -0
  494. package/dist/values.js +13 -1
  495. package/dist/values.js.map +1 -1
  496. package/package.json +25 -12
  497. package/src/asset/loaders/ktx2/basis/LICENSE +201 -0
  498. package/src/asset/loaders/ktx2/basis/basis_transcoder.js +2 -0
  499. package/src/asset/loaders/ktx2/basis/basis_transcoder.wasm +0 -0
  500. package/src/asset/meshoptimizer/LICENSE +21 -0
  501. package/dist/animation/joint_dynamics/convex_collider.js +0 -320
  502. package/dist/animation/joint_dynamics/convex_collider.js.map +0 -1
@@ -11,14 +11,11 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
11
11
  * Which waters each camera is currently inside, and the rest plane of each.
12
12
  *
13
13
  * Written by {@link Water.updatePerCamera}, which runs for every water every
14
- * frame whether or not the surface survived culling. Reading the render queue
15
- * instead would lose the state the moment the surface left the frustum - which
16
- * is exactly what happens to a camera deep underwater looking down.
14
+ * frame whether or not the surface survived culling, so the state survives the
15
+ * surface leaving the frustum.
17
16
  *
18
- * Keyed on the camera so multiple views stay independent. The inner map holds a
19
- * strong reference to the water, which a disposed node would keep alive; entries
20
- * are pruned on read rather than on dispose, since a disposed water simply stops
21
- * updating its own entry.
17
+ * Keyed on the camera so multiple views stay independent. Entries of disposed
18
+ * waters are pruned on read.
22
19
  *
23
20
  * @internal
24
21
  */ const _submergence = new WeakMap();
@@ -45,9 +42,8 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
45
42
  /**
46
43
  * The water the camera is currently inside, or null when it is above all of them.
47
44
  *
48
- * Several can qualify - a pool inside a lake, water on terraces - and the one
49
- * that matters is the highest of them: that is the last surface the eye crossed
50
- * on its way down, so it owns the column the eye is looking through.
45
+ * When several qualify, the highest wins: it is the last surface the eye crossed
46
+ * on its way down.
51
47
  *
52
48
  * @param ctx - Frame draw context.
53
49
  * @returns The submerged state, or null.
@@ -84,18 +80,15 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
84
80
  /**
85
81
  * Optical depth at which a channel is taken to have died completely.
86
82
  *
87
- * exp(-30) is about 1e-13, which is zero in any format the scene color uses. The
88
- * path length fed to the medium is capped at whatever distance reaches this on
89
- * the least attenuated channel, so a huge far plane cannot push the exponent
90
- * anywhere unpleasant.
83
+ * exp(-30) is about 1e-13, zero in any scene color format. The path length is
84
+ * capped at the distance reaching this on the least attenuated channel.
91
85
  * @internal
92
86
  */ const OPTICAL_DEPTH_CAP = 30;
93
87
  /**
94
88
  * Global name of the shadow map the receiver helpers sample.
95
89
  *
96
- * Fixed by `ShaderHelper`, which declares it under this name for materials and
97
- * reads it from the implementation's `computeShadow`; a standalone pass sampling
98
- * shadows has to use the same one.
90
+ * Must match the name `ShaderHelper` declares and the shadow implementation's
91
+ * `computeShadow` reads.
99
92
  * @internal
100
93
  */ const SHADOW_MAP_UNIFORM = 'Z_UniformShadowMap';
101
94
  /**
@@ -106,16 +99,12 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
106
99
  * 1. multiply by the medium's transmittance, then
107
100
  * 2. add what the medium scatters back towards the eye.
108
101
  *
109
- * Two rather than one because the transmittance is per channel - red dies within
110
- * a metre or two of clear water while blue carries tens of metres, which is the
111
- * entire reason water reads as water - and a single blend equation only has a
112
- * scalar `src-alpha` to attenuate the destination with. Splitting them lets the
113
- * first draw use `src-color` as the destination factor and keep the colour.
102
+ * Two draws because the transmittance is per channel and a single blend equation
103
+ * only has a scalar `src-alpha`; the first draw uses `src-color` as the
104
+ * destination factor.
114
105
  *
115
- * The pass runs after the sky, and treats a sky pixel as a ray that never left
116
- * the water: its path length is the cap above, so its transmittance is zero and
117
- * the horizon is pure medium. That is what replaces the sky underwater, rather
118
- * than any separate handling of it.
106
+ * The pass runs after the sky and treats a sky pixel as a ray that never left
107
+ * the water: its path length is the cap, so the horizon is pure medium.
119
108
  *
120
109
  * @internal
121
110
  */ class UnderwaterRenderer {
@@ -138,11 +127,7 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
138
127
  _cameraParams;
139
128
  _implParams;
140
129
  _cameraForward;
141
- /**
142
- * Scratch for the cascade matrices. Copied rather than passed through, because
143
- * the uniform setter wants an array it owns the buffer type of; reused so the
144
- * copy does not allocate every frame.
145
- */ _shadowMatrices;
130
+ /** Reused scratch copy of the cascade matrices for the uniform setter. */ _shadowMatrices;
146
131
  constructor(){
147
132
  this._extinctionProgram = null;
148
133
  this._extinctionBindGroup = null;
@@ -173,15 +158,11 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
173
158
  */ render(ctx, state, colorFramebuffer, depthTexture) {
174
159
  const device = ctx.device;
175
160
  const material = state.material;
176
- // Shafts need the caustic map as the surface's transmittance, and the sun
177
- // that map was built for. Without one the march has nothing to modulate and
178
- // would paint a uniform cone, so it degrades to the ambient term alone.
161
+ // Shafts need the caustic map and its sun; without them only the ambient term
162
+ // is drawn.
179
163
  const sun = ctx.waterCausticLight;
180
164
  const godRays = material.underwaterGodRays && !!ctx.waterCaustics && !!sun && material.underwaterGodRayIntensity > 0;
181
165
  const steps = godRays ? material.underwaterGodRaySteps : 0;
182
- // The caustic light is required to cast shadows for the map to exist at all,
183
- // so its params are normally there; the lookup stays defensive because this
184
- // runs a module later and nothing re-checks in between.
185
166
  const shadowMapParams = godRays && material.underwaterGodRayShadow ? ctx.shadowMapInfo?.get(sun) ?? null : null;
186
167
  const shadow = shadowMapParams?.shadowMap ? shadowMapParams : null;
187
168
  const { extinctionPass, inscatterPass } = this._prepare(device, steps, shadow);
@@ -257,11 +238,8 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
257
238
  /**
258
239
  * Upload the shadow receiver uniforms the march samples.
259
240
  *
260
- * The names and the struct layouts are dictated by the helpers that read them
261
- * (`ShaderHelper.calculateShadowSpaceVertex`, the shadow implementation's
262
- * `computeShadow`), which expect the material light pass's globals. This is
263
- * the same arrangement the shadow mask pass makes for the same reason - see
264
- * `ShadowMaskRenderer.setUniforms`.
241
+ * Names and struct layouts match the material light pass's globals, which the
242
+ * shadow helpers read; see `ShadowMaskRenderer.setUniforms`.
265
243
  * @internal
266
244
  */ _setShadowUniforms(bindGroup, ctx, light, shadowMapParams) {
267
245
  const camera = ctx.camera;
@@ -299,10 +277,8 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
299
277
  envLightStrength: ShaderHelper.getEnvLightLuminance(ctx),
300
278
  envLightSpecularStrength: ctx.env?.light.specularStrength ?? 1
301
279
  });
302
- // Which way the camera looks, for the cascade split test. The march knows
303
- // how far along its ray a sample is, and the splits are measured in view
304
- // depth; using the radial distance instead would pick a coarser cascade
305
- // towards the edges of a wide frustum and bend the cascade seam.
280
+ // Camera forward, for the cascade split test, which is measured in view
281
+ // depth rather than radial distance.
306
282
  camera.worldMatrix.getRow(2, this._cameraForward);
307
283
  this._cameraForward.scaleBy(-1);
308
284
  bindGroup.setValue('cameraForward', this._cameraForward.xyz());
@@ -323,24 +299,19 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
323
299
  this._extinctionStates = device.createRenderStateSet();
324
300
  this._extinctionStates.useRasterizerState().setCullMode('none');
325
301
  this._extinctionStates.useDepthState().enableTest(false).enableWrite(false);
326
- // dst.rgb *= src.rgb. The whole reason this is its own draw: the
327
- // destination factor has to be the per-channel transmittance.
302
+ // dst.rgb *= src.rgb (per-channel transmittance).
328
303
  this._extinctionStates.useBlendingState().enable(true).setBlendFuncRGB('zero', 'src-color').setBlendFuncAlpha('zero', 'one');
329
304
  }
330
305
  if (!this._inscatterStates) {
331
306
  this._inscatterStates = device.createRenderStateSet();
332
307
  this._inscatterStates.useRasterizerState().setCullMode('none');
333
308
  this._inscatterStates.useDepthState().enableTest(false).enableWrite(false);
334
- // dst.rgb += src.rgb. Alpha is left alone, as in the fog pass: folding a
335
- // transmittance into the framebuffer coverage makes a dense medium show
336
- // the page through the canvas.
309
+ // dst.rgb += src.rgb. Alpha is left alone, as in the fog pass, so a dense
310
+ // medium does not make the canvas transparent.
337
311
  this._inscatterStates.useBlendingState().enable(true).setBlendFuncRGB('one', 'one').setBlendFuncAlpha('zero', 'one');
338
312
  }
339
- // The march is unrolled, so the step count is part of the program identity.
340
- // Authoring it as a uniform loop bound instead would cost a dynamic loop in
341
- // every variant including the one with no shafts at all. The shadow hash
342
- // joins it because the receiver code is generated from the implementation,
343
- // the cascade count and the shadow map's own type.
313
+ // The march is unrolled, so the step count is part of the program identity,
314
+ // as is the shadow hash the receiver code is generated from.
344
315
  const key = `${steps}|${shadow ? shadow.shaderHash : ''}`;
345
316
  let inscatter = this._inscatterPrograms.get(key);
346
317
  if (!inscatter) {
@@ -406,9 +377,8 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
406
377
  ShaderHelper.declareWaterCausticUniforms(pb);
407
378
  }
408
379
  if (shadow) {
409
- // The shadow receiver helpers read the material light pass's globals by
410
- // name, so a standalone pass has to reproduce them field for field.
411
- // Same arrangement, and same reason, as ShadowMaskRenderer.
380
+ // Reproduces the material light pass's globals the shadow helpers read
381
+ // by name, as ShadowMaskRenderer does.
412
382
  const cameraStruct = pb.defineStruct([
413
383
  pb.vec4('position'),
414
384
  pb.vec4('params'),
@@ -442,13 +412,8 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
442
412
  shadowTex.sampleType('unfilterable-float');
443
413
  }
444
414
  this[SHADOW_MAP_UNIFORM] = shadowTex.uniform(0);
445
- // How much sun reaches a point inside the water column.
446
- //
447
- // No normal offset bias: that exists to stop a surface shadowing
448
- // itself at grazing incidence, and a point floating in the medium has
449
- // no surface to do it with. NoL is passed as 1 for the same reason -
450
- // there is no receiver orientation, and 1 is the value that asks the
451
- // depth bias for its smallest correction.
415
+ // How much sun reaches a point inside the water column. A point in the
416
+ // medium has no surface orientation, so no normal offset and NoL = 1.
452
417
  pb.func('zUnderwaterShadow', [
453
418
  pb.vec3('worldPos'),
454
419
  pb.float('viewDepth')
@@ -457,27 +422,13 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
457
422
  this.$l.comparison = pb.vec4(pb.greaterThan(pb.vec4(this.viewDepth), this.light.cascadeDistances));
458
423
  this.$l.cascadeFlags = pb.vec4(pb.float(pb.greaterThan(this.light.shadowCascades, 0)), pb.float(pb.greaterThan(this.light.shadowCascades, 1)), pb.float(pb.greaterThan(this.light.shadowCascades, 2)), pb.float(pb.greaterThan(this.light.shadowCascades, 3)));
459
424
  this.$l.split = pb.int(pb.dot(this.comparison, this.cascadeFlags));
460
- if (device.type === 'webgl') {
461
- // WebGL1 cannot index the matrix array dynamically.
462
- this.$l.shadowVertex = pb.vec4();
463
- this.$for(pb.int('cascade'), 0, 4, function() {
464
- this.$if(pb.equal(this.cascade, this.split), function() {
465
- this.shadowVertex = ShaderHelper.calculateShadowSpaceVertex(this, pb.vec4(this.worldPos, 1), this.cascade);
466
- this.$break();
467
- });
468
- });
469
- } else {
470
- this.$l.shadowVertex = ShaderHelper.calculateShadowSpaceVertex(this, pb.vec4(this.worldPos, 1), this.split);
471
- }
425
+ this.$l.shadowVertex = ShaderHelper.calculateShadowSpaceVertex(this, pb.vec4(this.worldPos, 1), this.split);
472
426
  this.$l.shadow = shadow.impl.computeShadowCSM(shadow, this, this.shadowVertex, pb.float(1), this.split);
473
427
  } else {
474
428
  this.$l.shadowVertex = ShaderHelper.calculateShadowSpaceVertex(this, pb.vec4(this.worldPos, 1));
475
429
  this.$l.shadow = shadow.impl.computeShadow(shadow, this, this.shadowVertex, pb.float(1));
476
430
  }
477
- // Past the shadow distance there is no map left to read, so the
478
- // shafts have to come back to unshadowed rather than to whatever the
479
- // last cascade's border holds. Same fade the surfaces use, so a shaft
480
- // and the sea bed under it stop being shadowed together.
431
+ // Fade to unshadowed towards the shadow distance, as the surfaces do.
481
432
  this.$l.shadowDistance = this.light.shadowCameraParams.w;
482
433
  this.shadow = pb.mix(this.shadow, 1, pb.smoothStep(pb.mul(this.shadowDistance, 0.8), this.shadowDistance, pb.distance(this.camera.position.xyz, this.worldPos)));
483
434
  this.shadow = pb.mix(1, this.shadow, this.light.shadowStrength);
@@ -491,84 +442,42 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
491
442
  this.$l.hPos = pb.mul(this.invProjViewMatrix, this.clipSpacePos);
492
443
  this.$l.worldPos = pb.div(this.hPos, this.hPos.w).xyz;
493
444
  this.$l.isSky = ShaderHelper.isFarthestDepth(this, this.depthValue);
494
- // Direction the eye is looking, as a unit vector. Normalised from the
495
- // raw difference rather than divided by the capped path length below:
496
- // the cap is a limit on how far the medium is integrated, not on where
497
- // the geometry is, so dividing by it scaled this to |worldPos - eye| /
498
- // cap - up to 2.4 in the turbid ocean preset. That put cosTheta outside
499
- // [-1, 1], drove the Henyey-Greenstein denominator negative, and the
500
- // clamp guarding pow() then returned a phase of some 40000 in a flat
501
- // band across the distance.
445
+ // Normalised from the raw difference, not divided by the capped path
446
+ // length, so it stays a unit vector and cosTheta stays in [-1, 1].
502
447
  this.$l.viewDir = pb.normalize(pb.sub(this.worldPos, this.cameraPosition));
503
448
  // A ray that reached the sky never left the water, so it takes the
504
- // whole cap rather than the far plane's world position. That is the
505
- // one thing that makes the horizon converge to the medium instead of
506
- // showing the sky through it.
449
+ // whole cap.
507
450
  this.$l.pathLength = this.$choice(this.isSky, this.params.z, pb.min(pb.distance(this.worldPos, this.cameraPosition), this.params.z));
508
451
  this.$l.transmittance = pb.exp(pb.neg(pb.mul(this.mediumExtinction, this.pathLength)));
509
452
  if (!inscatter) {
510
453
  this.$outputs.outColor = pb.vec4(this.transmittance, 1);
511
454
  } else {
512
- // Downwelling sky light reaching the column, attenuated over the
513
- // vertical depth rather than along the view ray: what lights the
514
- // water is the sun and sky above it, and how far down this stretch
515
- // of column sits is what decides how much of that is left. Averaged
516
- // over the two ends of the path, which is exact for a column at
517
- // constant depth and a fair stand-in when it is not.
455
+ // Downwelling sky light, attenuated over the vertical depth averaged
456
+ // between the two ends of the path.
518
457
  this.$l.endY = this.$choice(this.isSky, this.cameraPosition.y, this.worldPos.y);
519
458
  this.$l.columnDepth = pb.mul(0.5, pb.add(pb.max(pb.sub(this.params.y, this.cameraPosition.y), 0), pb.max(pb.sub(this.params.y, this.endY), 0)));
520
459
  this.$l.ambient = pb.mul(pb.textureSampleLevel(this.skyLut, pb.vec2(0.5), 0).rgb, this.params.x, pb.exp(pb.neg(pb.mul(this.mediumExtinction, this.columnDepth))));
521
- // Single scattering: the albedo is the share of the extinguished
522
- // energy that comes back rather than being absorbed, the same form
523
- // getScattering() uses on the surface.
460
+ // Single scattering, the same form getScattering() uses on the surface.
524
461
  this.$l.inscatter = pb.mul(this.mediumAlbedo, pb.sub(pb.vec3(1), this.transmittance), this.ambient);
525
462
  if (godRays) {
526
- // Shafts of sunlight through the column. The ambient term above is
527
- // directionless and cannot produce them; this is the same single
528
- // scattering integral evaluated against the sun instead, and the
529
- // only way to get it is to walk the ray, because how much sun
530
- // reaches a point depends on the surface overhead at that point.
463
+ // Sun shafts: the single scattering integral against the sun,
464
+ // marched along the view ray since the sun reaching each point
465
+ // depends on the surface overhead.
531
466
  //
532
- // Angle between the sun's travel and the direction the scattered
533
- // light has to leave in to reach the eye, which is back along the
534
- // view ray. Constant along a ray from a directional light, so it
535
- // is hoisted out of the march. Clamped because both inputs are
536
- // unit vectors only up to rounding, and the phase function below
537
- // is not defined outside the range.
467
+ // Scattering angle, constant along the ray; clamped against rounding.
538
468
  this.$l.cosTheta = pb.clamp(pb.neg(pb.dot(this.sunDirection, this.viewDir)), -1, 1);
539
469
  this.$l.phase = waterScatterPhase(this, this.cosTheta, this.phaseParams.x);
540
- // Dithered sample offset. A fixed one puts every ray's samples on
541
- // the same set of distances, and the shafts then show as concentric
542
- // bands rather than as beams; the noise turns that structure into
543
- // grain the eye reads as the water itself.
470
+ // Dithered sample offset, trading banding for grain.
544
471
  this.$l.jitter = interleavedGradientNoise(this, this.$builtins.fragCoord.xy);
545
472
  // The integral is sigma_s * integral(sunAtP(t) * exp(-sigma_t * t) dt),
546
473
  // and only `sunAtP` needs sampling - the exponential is analytic.
547
474
  // So the march estimates the transmittance-weighted *mean* of
548
475
  // sunAtP and the closed form below supplies the rest.
549
476
  //
550
- // Samples are placed by inverting that exponential rather than
551
- // spread evenly along the ray. Evenly spaced ones broke the turbid
552
- // ocean preset: at sigma_t = 0.46/m over a 125m cap, 24 steps sit
553
- // 5.2m apart against a 2.2m mean free path, so the first sample
554
- // outweighed the second tenfold and the red channel was decided by
555
- // a single jittered position - noise per pixel. Importance
556
- // sampling packs them into the few metres that carry the weight,
557
- // where consecutive samples land close enough that the jitter
558
- // barely moves them.
559
- //
560
- // Placement goes by the *least* attenuated channel, not by the
561
- // luminance-weighted mean. The per-channel correction is
562
- // exp(-sigma_c * t) / pdf, which grows like
563
- // exp((sigma_place - sigma_c) * t): any channel thinner than the
564
- // placement rate gets an exponentially growing weight, and its
565
- // mean ends up decided by the single furthest sample. The
566
- // luminance mean did exactly that here - sigma_lum = 0.30 against
567
- // a blue 0.24 put a factor of 2000 on the last sample at 125m,
568
- // which is both far outside the caustic map (so no pattern, hence
569
- // no visible shafts) and violently jittered (hence the grain).
570
- // Taking the minimum makes every exponent non-positive, so no
571
- // weight can ever run away.
477
+ // Samples are importance-sampled by inverting the exponential of
478
+ // the *least* attenuated channel: the per-channel correction grows
479
+ // like exp((sigma_place - sigma_c) * t), so this keeps every
480
+ // exponent non-positive and no weight can run away.
572
481
  this.$l.sigmaPlace = pb.max(pb.min(pb.min(this.mediumExtinction.x, this.mediumExtinction.y), this.mediumExtinction.z), 1e-3);
573
482
  // Renormalises the exponential to the finite path, so the samples
574
483
  // span exactly the visible stretch however short it is.
@@ -579,34 +488,25 @@ import { drawFullscreenQuad } from './fullscreenquad.js';
579
488
  this.$l.u = pb.div(pb.add(pb.float(this.i), this.jitter), steps);
580
489
  this.$l.t = pb.min(pb.div(pb.neg(pb.log(pb.max(pb.sub(1, pb.mul(this.u, this.cdfMax)), 1e-6))), this.sigmaPlace), this.pathLength);
581
490
  this.$l.samplePos = pb.add(this.cameraPosition, pb.mul(this.viewDir, this.t));
582
- // How much sun survives to this point: the caustic map's own
583
- // answer, which already carries both the Beer-Lambert
584
- // transmittance down the sun ray and the focusing pattern the
585
- // waves impose on it. Sharing it is what makes a shaft line up
586
- // with the caustic cell it lands in.
491
+ // Sun reaching this point: the caustic map already carries the
492
+ // Beer-Lambert transmittance down the sun ray and the focusing
493
+ // pattern, so shafts line up with the caustics.
587
494
  this.$l.sunAtP = ShaderHelper.sampleWaterCaustic(this, this.samplePos, pb.int(LIGHT_TYPE_DIRECTIONAL), this.sunDirection, false);
588
495
  if (shadow) {
589
- // What the caustic map cannot know: it describes what the
590
- // *surface* did to the sunlight and nothing about what stands
591
- // under it, so without this a shaft runs straight through a
592
- // piling. The sea bed's own shadow is unaffected either way -
593
- // that comes from the ordinary lighting path.
496
+ // Occlusion by geometry under the surface, which the caustic
497
+ // map does not know about.
594
498
  this.$l.viewDepth = pb.dot(pb.sub(this.samplePos, this.cameraPosition), this.cameraForward);
595
499
  this.sunAtP = pb.mul(this.sunAtP, this.zUnderwaterShadow(this.samplePos, this.viewDepth));
596
500
  }
597
- // Transmittance back to the eye over the density the sample was
598
- // drawn from. The constant factors of the pdf - sigmaPlace and
599
- // cdfMax - are the same for every sample, so they cancel in the
600
- // ratio below and only the exponentials are kept.
501
+ // Transmittance back to the eye over the sampling pdf; the pdf's
502
+ // constant factors cancel in the ratio below.
601
503
  this.$l.weight = pb.exp(pb.mul(pb.sub(pb.vec3(this.sigmaPlace), this.mediumExtinction), this.t));
602
504
  this.shafts = pb.add(this.shafts, pb.mul(this.sunAtP, this.weight));
603
505
  this.weightSum = pb.add(this.weightSum, this.weight);
604
506
  });
605
- // The closed form of the same integral with sunAtP held at its
606
- // sampled mean: sigma_s/sigma_t * (1 - exp(-sigma_t * path)) is
607
- // exactly the (1 - transmittance) factor the ambient term uses, so
608
- // the two halves of the in-scattering share one normalisation and
609
- // a shaft can never exceed the light available to it.
507
+ // Closed form with sunAtP at its sampled mean:
508
+ // sigma_s/sigma_t * (1 - exp(-sigma_t * path)), the same
509
+ // normalisation as the ambient term.
610
510
  this.$l.meanSun = pb.div(this.shafts, pb.max(this.weightSum, pb.vec3(1e-6)));
611
511
  this.inscatter = pb.add(this.inscatter, pb.mul(this.meanSun, this.mediumAlbedo, pb.sub(pb.vec3(1), this.transmittance), this.sunColor, pb.mul(this.phase, this.params.w)));
612
512
  }