@woosh/meep-engine 3.42.0 → 3.44.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 (345) hide show
  1. package/editor/prototypeEditorShell.d.ts.map +1 -1
  2. package/editor/prototypeEditorShell.js +4 -2
  3. package/package.json +91 -96
  4. package/src/engine/Clock.d.ts +15 -0
  5. package/src/engine/Clock.d.ts.map +1 -1
  6. package/src/engine/Clock.js +29 -5
  7. package/src/engine/Engine.d.ts.map +1 -1
  8. package/src/engine/Engine.js +11 -19
  9. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts +57 -0
  10. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts.map +1 -0
  11. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.js +84 -0
  12. package/src/engine/graphics3/AnimationGraphSystem.d.ts +23 -13
  13. package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
  14. package/src/engine/graphics3/AnimationGraphSystem.js +61 -64
  15. package/src/engine/graphics3/AnimationSystem.d.ts +24 -15
  16. package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
  17. package/src/engine/graphics3/AnimationSystem.js +67 -61
  18. package/src/engine/graphics3/MeshSkinSystem.d.ts +56 -0
  19. package/src/engine/graphics3/MeshSkinSystem.d.ts.map +1 -0
  20. package/src/engine/graphics3/MeshSkinSystem.js +317 -0
  21. package/src/engine/graphics3/MeshSystem.d.ts +15 -35
  22. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  23. package/src/engine/graphics3/MeshSystem.js +21 -298
  24. package/src/engine/graphics3/RowChains.d.ts +76 -0
  25. package/src/engine/graphics3/RowChains.d.ts.map +1 -0
  26. package/src/engine/graphics3/RowChains.js +347 -0
  27. package/src/engine/graphics3/ShadedGeometrySystem.d.ts +6 -0
  28. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  29. package/src/engine/graphics3/ShadedGeometrySystem.js +329 -309
  30. package/src/engine/graphics3/animation/AnimationClips.d.ts +56 -0
  31. package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -0
  32. package/src/engine/graphics3/animation/AnimationClips.js +79 -0
  33. package/src/engine/graphics3/animation/ClipListPlayer.d.ts +13 -14
  34. package/src/engine/graphics3/animation/ClipListPlayer.d.ts.map +1 -1
  35. package/src/engine/graphics3/animation/ClipListPlayer.js +262 -263
  36. package/src/engine/graphics3/animation/write_clip_playback.d.ts +3 -3
  37. package/src/engine/graphics3/animation/write_clip_playback.js +4 -4
  38. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts +5 -0
  39. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  40. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +80 -75
  41. package/src/engine/graphics3/prefab/PrefabInstance.d.ts +4 -24
  42. package/src/engine/graphics3/prefab/PrefabInstance.d.ts.map +1 -1
  43. package/src/engine/graphics3/prefab/PrefabInstance.js +60 -80
  44. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts +16 -3
  45. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts.map +1 -1
  46. package/src/engine/graphics3/prefab/prefab_instantiate.js +49 -12
  47. package/src/engine/graphics3/prefab/prefab_place.d.ts +31 -17
  48. package/src/engine/graphics3/prefab/prefab_place.d.ts.map +1 -1
  49. package/src/engine/graphics3/prefab/prefab_place.js +175 -130
  50. package/src/engine/graphics3/register_clips.d.ts +64 -0
  51. package/src/engine/graphics3/register_clips.d.ts.map +1 -0
  52. package/src/engine/graphics3/register_clips.js +114 -0
  53. package/src/engine/physics/cloth/MEASUREMENTS.md +795 -0
  54. package/src/engine/physics/cloth/PLAN.md +339 -9
  55. package/src/engine/physics/cloth/build/ClothProxy.d.ts +113 -61
  56. package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -1
  57. package/src/engine/physics/cloth/build/ClothProxy.js +142 -77
  58. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts +22 -0
  59. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts.map +1 -0
  60. package/src/engine/physics/cloth/build/cloth_bind_in_frame.js +75 -0
  61. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +43 -30
  62. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  63. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +357 -284
  64. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts +62 -0
  65. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts.map +1 -0
  66. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.js +280 -0
  67. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +1 -1
  68. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +1 -1
  69. package/src/engine/physics/cloth/ecs/Cloth.d.ts +17 -9
  70. package/src/engine/physics/cloth/ecs/Cloth.d.ts.map +1 -1
  71. package/src/engine/physics/cloth/ecs/Cloth.js +220 -212
  72. package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +6 -0
  73. package/src/engine/physics/cloth/ecs/ClothHold.d.ts +91 -0
  74. package/src/engine/physics/cloth/ecs/ClothHold.d.ts.map +1 -0
  75. package/src/engine/physics/cloth/ecs/ClothHold.js +103 -0
  76. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +254 -48
  77. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  78. package/src/engine/physics/cloth/ecs/ClothInstance.js +277 -47
  79. package/src/engine/physics/cloth/ecs/ClothPin.d.ts +73 -0
  80. package/src/engine/physics/cloth/ecs/ClothPin.d.ts.map +1 -0
  81. package/src/engine/physics/cloth/ecs/ClothPin.js +92 -0
  82. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts +36 -0
  83. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts.map +1 -0
  84. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.js +61 -0
  85. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +23 -17
  86. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -1
  87. package/src/engine/physics/cloth/ecs/ClothRig.js +29 -27
  88. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +12 -14
  89. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  90. package/src/engine/physics/cloth/ecs/ClothSystem.js +20 -15
  91. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +57 -36
  92. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  93. package/src/engine/physics/cloth/ecs/ClothWorld.js +816 -179
  94. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +12 -13
  95. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
  96. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +20 -14
  97. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +63 -11
  98. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  99. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +321 -84
  100. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +9 -7
  101. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  102. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +9 -7
  103. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +3 -3
  104. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +30 -30
  105. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts +37 -0
  106. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts.map +1 -0
  107. package/src/engine/physics/cloth/ecs/cloth_geodesic.js +142 -0
  108. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts +97 -0
  109. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts.map +1 -0
  110. package/src/engine/physics/cloth/ecs/cloth_holds.js +608 -0
  111. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +2 -2
  112. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -1
  113. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +160 -9
  114. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +17 -22
  115. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  116. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +55 -117
  117. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -6
  118. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  119. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +44 -15
  120. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +5 -0
  121. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  122. package/src/engine/physics/cloth/ecs/cloth_write_back.js +60 -16
  123. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -1
  124. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +65 -58
  125. package/src/engine/physics/cloth/playground/collide_main.js +1 -1
  126. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -1
  127. package/src/engine/physics/cloth/playground/garment_build.js +17 -5
  128. package/src/engine/physics/cloth/playground/garment_main.js +1 -1
  129. package/src/engine/physics/cloth/playground/rig_build.d.ts.map +1 -1
  130. package/src/engine/physics/cloth/playground/rig_build.js +302 -296
  131. package/src/engine/physics/cloth/solver/ClothState.d.ts +45 -7
  132. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  133. package/src/engine/physics/cloth/solver/ClothState.js +63 -7
  134. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +6 -1
  135. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  136. package/src/engine/physics/cloth/solver/cloth_contact_find.js +7 -2
  137. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts +114 -0
  138. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts.map +1 -0
  139. package/src/engine/physics/cloth/solver/cloth_hold_line.js +362 -0
  140. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +6 -2
  141. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -1
  142. package/src/engine/physics/cloth/solver/cloth_self_find.js +13 -13
  143. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +24 -12
  144. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  145. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +24 -12
  146. package/src/engine/physics/cloth/solver/cloth_step.d.ts +16 -0
  147. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  148. package/src/engine/physics/cloth/solver/cloth_step.js +183 -20
  149. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +1 -0
  150. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -1
  151. package/src/engine/physics/cloth/solver/cloth_step_instance.js +10 -3
  152. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts +1 -1
  153. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts.map +1 -1
  154. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.js +353 -346
  155. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +7 -5
  156. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -1
  157. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +7 -5
  158. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +9 -9
  159. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
  160. package/src/engine/physics/cloth/wind/cloth_sample_air.js +26 -26
  161. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  162. package/src/engine/simulation/Ticker.d.ts +13 -0
  163. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  164. package/src/engine/simulation/Ticker.js +43 -8
  165. package/src/shade/RENDERER_CONTRACT.md +8 -2
  166. package/src/shade/playground/mesh_row_ceiling/main.js +2 -1
  167. package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -1
  168. package/src/shade/playground/skinned_blas_refit/main.js +11 -19
  169. package/src/shade/playground/skinned_blas_refit/place_character.d.ts +6 -3
  170. package/src/shade/playground/skinned_blas_refit/place_character.d.ts.map +1 -1
  171. package/src/shade/playground/skinned_blas_refit/place_character.js +90 -90
  172. package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -1
  173. package/src/shade/playground/skinned_mesh_soup/main.js +502 -509
  174. package/src/shade/playground/texture_encode/README.md +129 -109
  175. package/src/shade/playground/texture_encode/main.js +1430 -1430
  176. package/src/shade/playground/vgeo_runtime/README.md +5 -4
  177. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  178. package/src/shade/renderer/Renderer.js +6 -5
  179. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +45 -14
  180. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  181. package/src/shade/renderer/animation/GPUAnimationManager.js +316 -64
  182. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +5 -0
  183. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  184. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +11 -1
  185. package/src/shade/renderer/atmosphere/GPUSky.d.ts +12 -0
  186. package/src/shade/renderer/atmosphere/GPUSky.d.ts.map +1 -1
  187. package/src/shade/renderer/atmosphere/GPUSky.js +162 -147
  188. package/src/shade/renderer/geometry/BoxGeometry.d.ts +1 -11
  189. package/src/shade/renderer/geometry/BoxGeometry.d.ts.map +1 -1
  190. package/src/shade/renderer/geometry/BoxGeometry.js +6 -13
  191. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts +19 -0
  192. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts.map +1 -0
  193. package/src/shade/renderer/geometry/CapsuleGeometry.js +24 -0
  194. package/src/shade/renderer/geometry/ConeGeometry.d.ts +20 -0
  195. package/src/shade/renderer/geometry/ConeGeometry.d.ts.map +1 -0
  196. package/src/shade/renderer/geometry/ConeGeometry.js +33 -0
  197. package/src/shade/renderer/geometry/CylinderGeometry.d.ts +21 -0
  198. package/src/shade/renderer/geometry/CylinderGeometry.d.ts.map +1 -0
  199. package/src/shade/renderer/geometry/CylinderGeometry.js +35 -0
  200. package/src/shade/renderer/geometry/PlaneGeometry.d.ts +17 -0
  201. package/src/shade/renderer/geometry/PlaneGeometry.d.ts.map +1 -0
  202. package/src/shade/renderer/geometry/PlaneGeometry.js +22 -0
  203. package/src/shade/renderer/geometry/TorusGeometry.d.ts +18 -0
  204. package/src/shade/renderer/geometry/TorusGeometry.d.ts.map +1 -0
  205. package/src/shade/renderer/geometry/TorusGeometry.js +23 -0
  206. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts +21 -0
  207. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts.map +1 -0
  208. package/src/shade/renderer/geometry/UVSphereGeometry.js +34 -0
  209. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts +19 -0
  210. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts.map +1 -0
  211. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.js +205 -0
  212. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts +21 -0
  213. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts.map +1 -0
  214. package/src/shade/renderer/geometry/primitives/make_cone_geometry.js +36 -0
  215. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts +1 -1
  216. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts.map +1 -1
  217. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.js +44 -9
  218. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts +20 -0
  219. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts.map +1 -0
  220. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.js +190 -0
  221. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  222. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +7 -2
  223. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts +26 -8
  224. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts.map +1 -1
  225. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js +56 -39
  226. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts +7 -0
  227. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts.map +1 -1
  228. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.js +46 -4
  229. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.d.ts.map +1 -1
  230. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.js +4 -2
  231. package/src/shade/renderer/gpu_primitive/sort/defs.d.ts +2 -2
  232. package/src/shade/renderer/gpu_primitive/sort/defs.js +79 -79
  233. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts +1 -1
  234. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -1
  235. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +7 -3
  236. package/src/shade/renderer/lightmap/bake/shader_lightmap_denoise_sh.d.ts.map +1 -1
  237. package/src/shade/renderer/lightmap/bake/shader_lightmap_denoise_sh.js +10 -3
  238. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  239. package/src/shade/renderer/particles/DESIGN.md +13 -9
  240. package/src/shade/renderer/particles/GPUParticleSystem.js +1 -1
  241. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts +4 -3
  242. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts.map +1 -1
  243. package/src/shade/renderer/particles/coherence/graph_particle_bucket.js +200 -194
  244. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  245. package/src/shade/renderer/particles/graph_particles.js +6 -2
  246. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +1 -1
  247. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +1 -1
  248. package/src/shade/renderer/particles/warmup/graph_particle_warmup.d.ts.map +1 -1
  249. package/src/shade/renderer/particles/warmup/graph_particle_warmup.js +334 -329
  250. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  251. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  252. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +7 -2
  253. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
  254. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +16 -4
  255. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +3 -2
  256. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  257. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +3 -2
  258. package/src/shade/renderer/scene/GPUSceneContext.d.ts +9 -1
  259. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  260. package/src/shade/renderer/scene/GPUSceneContext.js +23 -1
  261. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +2444 -2345
  262. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.d.ts.map +1 -1
  263. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.js +312 -310
  264. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts +3 -3
  265. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts.map +1 -1
  266. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.js +383 -375
  267. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.d.ts.map +1 -1
  268. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.js +349 -346
  269. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts +58 -0
  270. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts.map +1 -0
  271. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.js +536 -0
  272. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts +21 -7
  273. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts.map +1 -1
  274. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.js +291 -327
  275. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts +25 -0
  276. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts.map +1 -0
  277. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.js +99 -0
  278. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts +5 -3
  279. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts.map +1 -1
  280. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.js +47 -71
  281. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts +10 -0
  282. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts.map +1 -0
  283. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.js +50 -0
  284. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts +4 -5
  285. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts.map +1 -1
  286. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.js +7 -8
  287. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +4 -1
  288. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  289. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +74 -3
  290. package/src/shade/renderer/volumetrics/NOTES.md +1023 -957
  291. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.d.ts +5 -4
  292. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.d.ts.map +1 -1
  293. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.js +5 -4
  294. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.d.ts +1 -1
  295. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.js +1 -1
  296. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.d.ts +1 -1
  297. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.js +1 -1
  298. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts +41 -0
  299. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts.map +1 -0
  300. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.js +112 -0
  301. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +9 -23
  302. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
  303. package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +18 -126
  304. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.d.ts +22 -0
  305. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.d.ts.map +1 -0
  306. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.js +228 -0
  307. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  308. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +0 -53
  309. package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -1
  310. package/src/shade/renderer/water/chunk_water_transport.js +7 -5
  311. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
  312. package/src/shade/renderer/water/medium/GPUWaterBodies.js +8 -2
  313. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts +3 -2
  314. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts.map +1 -1
  315. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.js +3 -2
  316. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  317. package/src/shade/renderer/water/shader_water.js +3 -1
  318. package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts.map +1 -1
  319. package/src/shade/renderer/water/surface/GPUWaterSurface.js +3 -1
  320. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts +4 -3
  321. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts.map +1 -1
  322. package/src/shade/renderer/water/surface/chunk_water_surface_sample.js +17 -7
  323. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -1
  324. package/src/shade/renderer/water/surface/graph_water_tessellation.js +11 -4
  325. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
  326. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +93 -30
  327. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts.map +1 -1
  328. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js +13 -5
  329. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts +29 -8
  330. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts.map +1 -1
  331. package/src/shade/renderer/water/surface/particles/chunk_water_particle.js +155 -30
  332. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts +6 -1
  333. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -1
  334. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +157 -39
  335. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts +91 -21
  336. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts.map +1 -1
  337. package/src/shade/renderer/water/surface/particles/shader_water_particles.js +442 -70
  338. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +11 -3
  339. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  340. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +3 -0
  341. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  342. package/src/shade/wgsl/validate_wgsl_source.js +74 -3
  343. package/src/engine/graphics3/register_instance_animation.d.ts +0 -114
  344. package/src/engine/graphics3/register_instance_animation.d.ts.map +0 -1
  345. package/src/engine/graphics3/register_instance_animation.js +0 -201
@@ -1,5 +1,8 @@
1
1
  import { assert } from "../../../../../core/assert.js";
2
- import { graph_prefix_scan_csdldf } from "../../../gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js";
2
+ import {
3
+ graph_prefix_scan_csdldf,
4
+ prefix_scan_csdldf_output_descriptor
5
+ } from "../../../gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js";
3
6
  import {
4
7
  build_indirect_compute_dispatch_command,
5
8
  INDIRECT_COMPUTE_COMMAND_DESCRIPTOR
@@ -10,15 +13,23 @@ import { WATER_PARTICLE_ENTRY_STRUCT, WATER_PARTICLE_STRUCT } from "./WATER_PART
10
13
  import {
11
14
  shader_water_particles_bin,
12
15
  shader_water_particles_bounds,
16
+ shader_water_particles_clear,
13
17
  shader_water_particles_emit,
14
18
  shader_water_particles_finalize,
19
+ shader_water_particles_fronts,
20
+ shader_water_particles_groups,
21
+ shader_water_particles_nest,
15
22
  shader_water_particles_rank,
23
+ shader_water_particles_runs,
16
24
  shader_water_particles_scatter,
25
+ shader_water_particles_share,
17
26
  shader_water_particles_split,
18
27
  shader_water_particles_total,
19
28
  shader_water_particles_update,
20
29
  shader_water_particles_weigh,
21
- WATER_PARTICLE_CORNERS
30
+ WATER_PARTICLE_CORNERS,
31
+ WATER_PARTICLE_CROWD_WORDS,
32
+ WATER_PARTICLE_NEST_WORDS
22
33
  } from "./shader_water_particles.js";
23
34
 
24
35
  /** The longest step a particle takes in one frame, seconds: a stalled tab does not fling fronts across a lake. */
@@ -45,10 +56,18 @@ export class GPUWaterParticles {
45
56
  #parity = 0;
46
57
  #particles = [];
47
58
  #children = null;
59
+ #child_sums = null;
60
+ #images = null;
61
+ #fronts = null;
62
+ #front_sums = null;
63
+ #runs = null;
64
+ #draw = null;
48
65
  #buckets = null;
66
+ #offsets = null;
49
67
  #slots = null;
50
68
  #bucket_amplitude = null;
51
69
  #bucket_weight = null;
70
+ #bucket_nest = null;
52
71
  #visible = null;
53
72
  #staging = null;
54
73
  #entries = null;
@@ -56,7 +75,7 @@ export class GPUWaterParticles {
56
75
  #commands = null;
57
76
 
58
77
  /** @returns {GPUBuffer} the frame's hash: table size, then inclusive bucket offsets */
59
- get offsets() { return this.#buckets; }
78
+ get offsets() { return this.#offsets; }
60
79
  /** @returns {GPUBuffer} the frame's entries, bucket by bucket, each bucket ordered by particle */
61
80
  get entries() { return this.#entries; }
62
81
  /** @returns {GPUBuffer} per wave row: occupied-level mask, then a height bound per level (f32 bits) */
@@ -89,16 +108,33 @@ export class GPUWaterParticles {
89
108
  size: Math.max(16, size), usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | usage });
90
109
  const array_size = 16 + capacity * WATER_PARTICLE_STRUCT.size;
91
110
  this.#particles = [buffer('a', array_size), buffer('b', array_size)];
111
+ // a scan reads one buffer and writes another: per particle how many it leaves, then where they end
112
+ const sums = elements => prefix_scan_csdldf_output_descriptor(elements).size;
92
113
  this.#children = buffer('children', 16 + capacity * 4);
114
+ this.#child_sums = buffer('child sums', sums(capacity));
115
+ // per particle the mirror image the step left beside it at the outline
116
+ this.#images = buffer('images', capacity * WATER_PARTICLE_STRUCT.size);
117
+ // per particle whether it starts a run, then the scanned run it is in; per run its first particle and its
118
+ // share; per particle its run and how it is drawn
119
+ this.#fronts = buffer('fronts', 16 + capacity * 4);
120
+ this.#front_sums = buffer('front sums', sums(capacity));
121
+ this.#runs = buffer('runs', capacity * 8);
122
+ this.#draw = buffer('draw', capacity * 8);
123
+ // per bucket its entries, then the hash: table size and inclusive offsets
93
124
  this.#buckets = buffer('buckets', 16 + this.#table_limit * 4);
125
+ this.#offsets = buffer('offsets', sums(this.#table_limit));
94
126
  this.#slots = buffer('slots', capacity * WATER_PARTICLE_CORNERS * 4);
95
127
  this.#bucket_amplitude = buffer('bucket amplitude', this.#table_limit * 4);
96
- this.#bucket_weight = buffer('bucket weight', this.#table_limit * 4);
128
+ // the summed steepness, the largest front and front complement entered, and the entries; then the most a point
129
+ // under it reads, and its entries by key
130
+ this.#bucket_weight = buffer('bucket weight', this.#table_limit * WATER_PARTICLE_CROWD_WORDS * 4);
131
+ this.#bucket_nest = buffer('bucket nest', this.#table_limit * WATER_PARTICLE_NEST_WORDS * 4);
97
132
  this.#visible = buffer('visible', capacity * 4);
98
133
  const entries = capacity * WATER_PARTICLE_CORNERS * WATER_PARTICLE_ENTRY_STRUCT.size;
99
134
  this.#staging = buffer('staging', entries);
100
135
  this.#entries = buffer('entries', entries);
101
- this.#commands = [0, 1].map(i => device.createBuffer({ label: `Water / particles command ${i}`,
136
+ // the particles' this frame and next, and the clear of the frame's table
137
+ this.#commands = [0, 1, 2].map(i => device.createBuffer({ label: `Water / particles command ${i}`,
102
138
  size: INDIRECT_COMPUTE_COMMAND_DESCRIPTOR.size, usage: INDIRECT_COMPUTE_COMMAND_DESCRIPTOR.usage }));
103
139
  this.#rows = 0;
104
140
  this.#parity = 0;
@@ -121,11 +157,16 @@ export class GPUWaterParticles {
121
157
  }
122
158
 
123
159
  dispose() {
124
- for (const buffer of [...this.#particles, this.#children, this.#buckets, this.#slots, this.#bucket_amplitude,
125
- this.#bucket_weight, this.#visible, this.#staging, this.#entries, this.#body_bounds, ...(this.#commands ?? [])]) { buffer?.destroy(); }
160
+ for (const buffer of [...this.#particles, this.#children, this.#child_sums, this.#images, this.#fronts, this.#front_sums, this.#runs,
161
+ this.#draw, this.#buckets, this.#offsets, this.#slots, this.#bucket_amplitude, this.#bucket_weight, this.#bucket_nest, this.#visible,
162
+ this.#staging, this.#entries, this.#body_bounds, ...(this.#commands ?? [])]) {
163
+ buffer?.destroy();
164
+ }
126
165
  this.#particles = [];
127
- this.#children = this.#buckets = this.#slots = this.#bucket_amplitude = this.#staging = this.#entries = null;
128
- this.#bucket_weight = this.#visible = null;
166
+ this.#children = this.#child_sums = this.#images = this.#buckets = this.#offsets = this.#slots = this.#bucket_amplitude = null;
167
+ this.#staging = this.#entries = null;
168
+ this.#fronts = this.#front_sums = this.#runs = this.#draw = null;
169
+ this.#bucket_weight = this.#bucket_nest = this.#visible = null;
129
170
  this.#body_bounds = null;
130
171
  this.#commands = null;
131
172
  this.#device = null;
@@ -158,10 +199,14 @@ export class GPUWaterParticles {
158
199
  // a frame that does not step bins the particles where they are
159
200
  const next = stepping ? this.#particles[1 - this.#parity] : current;
160
201
  if (stepping) { this.#parity = 1 - this.#parity; }
161
- const [command_current, command_next] = this.#commands;
202
+ const [command_current, command_next, command_table] = this.#commands;
162
203
  const geometries = scene.geometries;
163
204
  let children = graph_import_buffer(graph, this.#children, 'Water / particle children');
205
+ let child_sums = graph_import_buffer(graph, this.#child_sums, 'Water / particle child sums');
164
206
  let buckets = graph_import_buffer(graph, this.#buckets, 'Water / particle buckets');
207
+ let offsets = graph_import_buffer(graph, this.#offsets, 'Water / particle offsets');
208
+ let fronts = graph_import_buffer(graph, this.#fronts, 'Water / particle fronts');
209
+ let front_sums = graph_import_buffer(graph, this.#front_sums, 'Water / particle front sums');
165
210
  const node = (name, execute, reads, writes) => {
166
211
  const data = {};
167
212
  const pass = graph.add(name, data, (d, resources, context) => execute(resources, context, d));
@@ -177,52 +222,70 @@ export class GPUWaterParticles {
177
222
  encoder.copyBufferToBuffer(current, 0, this.#children, 0, 4);
178
223
  build_indirect_compute_dispatch_command(64, encoder, current, 0, command_current, 0, true);
179
224
  shader_water_particles_update.dispatchIndirect({ encoder, command: command_current, bindings: {
180
- frame: { dt: step, capacity }, particles: current, children: this.#children, activity,
225
+ frame: { dt: step, capacity }, particles: current, children: this.#children, images: this.#images, activity,
181
226
  scene_database: scene.scene_database_buffer, geometries: geometries.buffer_metadata,
182
227
  blas_lookup: geometries.blas.buffer_metadata, blas_data: geometries.blas.buffer_data,
183
228
  meshlet_metadata: geometries.meshlets.buffer_metadata, meshlet_data: geometries.meshlets.buffer_data,
184
229
  } });
185
230
  }, {}, { children }).children;
186
- children = graph_prefix_scan_csdldf({ graph, data: children, element_max_count: capacity });
231
+ child_sums = graph_prefix_scan_csdldf({ graph, input: children, output: child_sums, element_max_count: capacity });
187
232
 
188
233
  // What they leave into the next array, then the frame's splashes after them.
189
234
  node('Water / particles split and emit', (resources, { encoder }) => {
190
235
  shader_water_particles_split.dispatchIndirect({ encoder, command: command_current, bindings: {
191
- capacity, particles: current, children: this.#children, next } });
192
- shader_water_particles_total.dispatch({ encoder, bindings: { capacity, children: this.#children, next } });
236
+ capacity, particles: current, children: this.#child_sums, images: this.#images, next } });
237
+ shader_water_particles_total.dispatch({ encoder, bindings: { capacity, children: this.#child_sums, next } });
193
238
  shader_water_particles_emit.dispatchIndirect({ encoder, command: commands, command_offset: emit_command,
194
239
  bindings: { capacity, scene_database: scene.scene_database_buffer, emit_rows, steep, activity,
195
240
  particle_bounds: this.#body_bounds, next } });
196
- shader_water_particles_finalize.dispatch({ encoder, bindings: { limits: { capacity, table_limit }, next, offsets: this.#buckets } });
197
- }, { children }, {});
241
+ shader_water_particles_finalize.dispatch({ encoder, bindings: { limits: { capacity, table_limit }, next, offsets: this.#buckets,
242
+ table_command: command_table } });
243
+ }, { child_sums }, {});
198
244
  }
199
245
 
200
- // The frame's hash: how crowded each cell is, then each particle into the cells its support overlaps as far as
201
- // its crowd leaves it drawn, offsets, entries in order.
202
- buckets = node('Water / particles bin', (resources, { encoder }) => {
246
+ // Each front's run of particles, so that a whole one is drawn as the seven it was emitted as.
247
+ fronts = node('Water / particles fronts', (resources, { encoder }) => {
203
248
  if (!stepping) {
204
249
  // the table size the last stepping frame chose for these particles
205
- shader_water_particles_finalize.dispatch({ encoder, bindings: { limits: { capacity, table_limit }, next, offsets: this.#buckets } });
250
+ shader_water_particles_finalize.dispatch({ encoder, bindings: { limits: { capacity, table_limit }, next, offsets: this.#buckets,
251
+ table_command: command_table } });
206
252
  }
207
253
  build_indirect_compute_dispatch_command(64, encoder, next, 0, command_next, 0, true);
208
- encoder.clearBuffer(this.#buckets, 16, table_limit * 4);
209
- encoder.clearBuffer(this.#bucket_amplitude);
210
- encoder.clearBuffer(this.#bucket_weight);
254
+ encoder.copyBufferToBuffer(next, 0, this.#fronts, 0, 4);
255
+ shader_water_particles_fronts.dispatchIndirect({ encoder, command: command_next, bindings: { next, fronts: this.#fronts } });
256
+ }, {}, { fronts }).fronts;
257
+ front_sums = graph_prefix_scan_csdldf({ graph, input: fronts, output: front_sums, element_max_count: capacity });
258
+
259
+ // The frame's hash: how each particle is drawn, how crowded each cell is and so how much of each run its crowd
260
+ // leaves drawn, then each packet drawn into the cells its support overlaps, offsets, entries in order.
261
+ buckets = node('Water / particles bin', (resources, { encoder }) => {
262
+ const draw = this.#draw, runs = this.#runs;
263
+ shader_water_particles_runs.dispatchIndirect({ encoder, command: command_next, bindings: { next, fronts: this.#front_sums, runs } });
264
+ shader_water_particles_groups.dispatchIndirect({ encoder, command: command_next, bindings: { next, fronts: this.#front_sums, runs, draw } });
265
+ shader_water_particles_clear.dispatchIndirect({ encoder, command: command_table, bindings: {
266
+ buckets: this.#buckets, bucket_amplitude: this.#bucket_amplitude, bucket_weight: this.#bucket_weight,
267
+ bucket_nest: this.#bucket_nest } });
211
268
  shader_water_particles_weigh.dispatchIndirect({ encoder, command: command_next, bindings: {
212
- next, activity, offsets: this.#buckets, bucket_weight: this.#bucket_weight } });
269
+ next, activity, offsets: this.#buckets, draw, bucket_weight: this.#bucket_weight, body_bounds: this.#body_bounds } });
270
+ shader_water_particles_nest.dispatchIndirect({ encoder, command: command_next, bindings: {
271
+ next, activity, offsets: this.#buckets, draw, body_bounds: this.#body_bounds, bucket_weight: this.#bucket_weight,
272
+ bucket_nest: this.#bucket_nest } });
273
+ shader_water_particles_share.dispatchIndirect({ encoder, command: command_next, bindings: {
274
+ next, activity, offsets: this.#buckets, bucket_weight: this.#bucket_weight, bucket_nest: this.#bucket_nest,
275
+ body_bounds: this.#body_bounds, draw, runs } });
213
276
  shader_water_particles_bin.dispatchIndirect({ encoder, command: command_next, bindings: {
214
277
  next, activity, buckets: this.#buckets, slots: this.#slots, bucket_amplitude: this.#bucket_amplitude,
215
- body_bounds: this.#body_bounds, bucket_weight: this.#bucket_weight, visible: this.#visible } });
216
- }, {}, { buckets }).buckets;
217
- buckets = graph_prefix_scan_csdldf({ graph, data: buckets, element_max_count: table_limit });
278
+ body_bounds: this.#body_bounds, draw, runs, visible: this.#visible } });
279
+ }, { front_sums }, { buckets }).buckets;
280
+ offsets = graph_prefix_scan_csdldf({ graph, input: buckets, output: offsets, element_max_count: table_limit });
218
281
  node('Water / particles order and bound', (resources, { encoder }) => {
219
- const bindings = { next, offsets: this.#buckets, slots: this.#slots };
282
+ const bindings = { next, offsets: this.#offsets, slots: this.#slots, draw: this.#draw };
220
283
  shader_water_particles_scatter.dispatchIndirect({ encoder, command: command_next, bindings: { ...bindings,
221
284
  visible: this.#visible, staging: this.#staging } });
222
285
  shader_water_particles_rank.dispatchIndirect({ encoder, command: command_next, bindings: { ...bindings,
223
286
  staging: this.#staging, entries: this.#entries } });
224
287
  shader_water_particles_bounds.dispatchIndirect({ encoder, command: command_next, bindings: { next, activity,
225
- offsets: this.#buckets, bucket_amplitude: this.#bucket_amplitude, body_bounds: this.#body_bounds } });
226
- }, { buckets }, {});
288
+ offsets: this.#offsets, bucket_amplitude: this.#bucket_amplitude, draw: this.#draw, body_bounds: this.#body_bounds } });
289
+ }, { offsets }, {});
227
290
  }
228
291
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WATER_PARTICLE_STRUCT.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,iDAeoB;AAEpB;;;;GAIG;AACH,uDAeyB;6BA/CI,sCAAsC"}
1
+ {"version":3,"file":"WATER_PARTICLE_STRUCT.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,iDAoBoB;AAEpB;;;;GAIG;AACH,uDAkByB;6BAvDI,sCAAsC"}
@@ -10,7 +10,7 @@ import { WebGPUStruct } from "../../../shader/type/WebGPUStruct.js";
10
10
  * without integration error and every particle of one front shares the origin and the age.
11
11
  */
12
12
  export const WATER_PARTICLE_STRUCT = WebGPUStruct.from({
13
- /** Centre of the front, or its mirror image after a reflection; metric local xz. */
13
+ /** Centre of the front, or the mirror image of it for a reflection; metric local xz. */
14
14
  origin: vec2f,
15
15
  /** Propagation direction, radians from local +x towards +z. */
16
16
  angle: f32,
@@ -24,6 +24,11 @@ export const WATER_PARTICLE_STRUCT = WebGPUStruct.from({
24
24
  dispersion: f32,
25
25
  /** The water_waves row of the body it lives on. */
26
26
  body: u32,
27
+ /**
28
+ * 1 once the first of its support has left its body's outline, or that of the particle it split from: its mirror
29
+ * image was emitted then, and it dies once the last of it has left too. 0 from emission.
30
+ */
31
+ reflected: u32,
27
32
  }, 'WaterParticle');
28
33
 
29
34
  /**
@@ -37,13 +42,16 @@ export const WATER_PARTICLE_ENTRY_STRUCT = WebGPUStruct.from({
37
42
  angle: f32,
38
43
  amplitude: f32,
39
44
  radius: f32,
40
- /** Tangential window: the distance to the front's neighbouring particle. */
41
- width: f32,
45
+ /** Half-angle of the window around the front's centre: the angle to the front's neighbouring particle. */
46
+ dispersion: f32,
42
47
  /** Carrier phase lag of the crests behind the envelope, radians. */
43
48
  phase: f32,
44
- /** water_waves row << 4 | level */
49
+ /** water_waves row and level, as water_particle_key packs them */
45
50
  key: u32,
46
51
  /** Index of the particle, which orders a bucket. */
47
52
  source: u32,
48
- reserved: u32,
53
+ /** How far the particle stands from its front's centre, metres. */
54
+ distance: f32,
55
+ /** Half the length of its envelope across its front, metres. */
56
+ half_length: f32,
49
57
  }, 'WaterParticleEntry');
@@ -1,19 +1,40 @@
1
- /** Levels of the particle hash: cell sizes 4 mm · 2^level, so supports up to 64 m. */
2
- export const WATER_PARTICLE_LEVELS: 16;
1
+ /**
2
+ * Levels of the particle hash: cell sizes 4 mm · 2^level, so supports up to 256 m, which a 2 m splash's stretched
3
+ * packets reach before they die.
4
+ */
5
+ export const WATER_PARTICLE_LEVELS: 18;
3
6
  /** Cell size of level 0, metres. A particle sits at the smallest level whose cell is at least its support's diameter. */
4
7
  export const WATER_PARTICLE_LEVEL0_CELL: number;
8
+ /**
9
+ * How fast a packet's envelope stretches as it disperses, as a fraction κ of its group speed, by its wavenumber k against
10
+ * k_m = √(g/(σ/ρ)), the wavenumber of the slowest crests (λ = 1.71 cm): from x = log₂(k/k_m) = -7 in steps of a quarter,
11
+ * held at both ends.
12
+ *
13
+ * Its half-length h, 2r when emitted, grows as h² = (2r)² + (κD/2)² over the distance D its front has travelled since:
14
+ * the spread of an unchirped packet's energy grows as the spread of its group speeds times time, in quadrature with
15
+ * where it began (Jeschke & Wojtan 2017 grow it linearly, eq. 14, its far limit). Each κ is the one whose peak
16
+ * √(2r/h) best matches exact linear theory, ω² = gk + (σ/ρ)k³, for the emitted packet at 5 to 225 wavelengths (FFT,
17
+ * worst ratio minimised): within 2% for capillary waves up to r = 8.5 mm and gravity waves from r = 6 cm, where κ
18
+ * tends to 1 and 0.9, and 5% from 4 cm. Between, around the slowest group speed (λ = 4.4 cm), a broad band's energy
19
+ * gathers at that speed and the peak falls as t^(−1/3), which no κ draws: up to 16% below r = 12 mm, 27% at 3 cm.
20
+ */
21
+ export const WATER_PARTICLE_STRETCH: number[];
5
22
  /**
6
23
  * The physics of one wave particle as pure functions (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §5).
7
24
  *
8
25
  * A particle of radius r carries a packet of wavelength 2r, k = π/r. Under the gravity–capillary
9
26
  * dispersion relation the packet's envelope travels at the group speed and its crests at the phase speed
10
- * (Jeschke & Wojtan 2017; Xue et al. 2025 give wave particles their own wavelength's dispersion). It loses
11
- * amplitude at the clean-surface viscous rate 2νk² plus the surface-film rate k√(νω)/(2√2) of natural
12
- * water — so a raindrop's ripple is gone in a fraction of a second while a big splash crosses a bay.
27
+ * (Jeschke & Wojtan 2017; Xue et al. 2025 give wave particles their own wavelength's dispersion). The packet holds a
28
+ * band of wavelengths around 2r, which the same relation moves apart: its envelope, two radii either side when emitted,
29
+ * stretches as it travels and its height falls to keep its energy (WATER_PARTICLE_STRETCH), as a splash's single ring
30
+ * becomes a widening train of ripples. It loses amplitude at the clean-surface viscous rate 2νk² plus the surface-film
31
+ * rate k√(νω)/(2√2) of natural water — so a raindrop's ripple is gone in a fraction of a second while a big splash
32
+ * crosses a bay.
13
33
  *
14
- * The particles of a front are W apart, W the front's arc between them; a cosine window of half-width W
15
- * along the front is a partition of unity over them, so the front's height is the packet's amplitude
16
- * whatever the spacing, and one front adds at most two particles at any point.
34
+ * The particles of a front are β apart in angle around its centre, and a packet's crests are arcs around that
35
+ * centre; a cosine window of half-angle β is a partition of unity over them at every radius, so the front's
36
+ * height is the packet's amplitude whatever the spacing, splitting a front changes none of it, and one front
37
+ * adds at most two particles at any point.
17
38
  *
18
39
  * @type {CodeChunk}
19
40
  */
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_water_particle.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/water/surface/particles/chunk_water_particle.js"],"names":[],"mappings":"AAKA,sFAAsF;AACtF,uCAAwC;AAExC,yHAAyH;AACzH,gDAAkD;AAElD;;;;;;;;;;;;;;GAcG;AACH,mCAFU,SAAS,CAsH6G;0BA9ItG,uCAAuC"}
1
+ {"version":3,"file":"chunk_water_particle.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/water/surface/particles/chunk_water_particle.js"],"names":[],"mappings":"AAKA;;;GAGG;AACH,uCAAwC;AAKxC,yHAAyH;AACzH,gDAAkD;AAElD;;;;;;;;;;;;GAYG;AACH,8CAIE;AAKF;;;;;;;;;;;;;;;;;;GAkBG;AACH,mCAFU,SAAS,CAmN6G;0BA3QtG,uCAAuC"}
@@ -3,30 +3,65 @@ import { chunk_pcg3d } from "../../../shader/chunk/random/pcg/chunk_pcg3d.js";
3
3
  import { WATER_PARTICLE_ENTRY_STRUCT, WATER_PARTICLE_STRUCT } from "./WATER_PARTICLE_STRUCT.js";
4
4
  import { chunk_water_spectrum } from "../spectrum/chunk_water_spectrum.js";
5
5
 
6
- /** Levels of the particle hash: cell sizes 4 mm · 2^level, so supports up to 64 m. */
7
- export const WATER_PARTICLE_LEVELS = 16;
6
+ /**
7
+ * Levels of the particle hash: cell sizes 4 mm · 2^level, so supports up to 256 m, which a 2 m splash's stretched
8
+ * packets reach before they die.
9
+ */
10
+ export const WATER_PARTICLE_LEVELS = 18;
11
+
12
+ /** Bits of a hash key that hold the level, below the body's row. */
13
+ const WATER_PARTICLE_LEVEL_BITS = Math.ceil(Math.log2(WATER_PARTICLE_LEVELS));
8
14
 
9
15
  /** Cell size of level 0, metres. A particle sits at the smallest level whose cell is at least its support's diameter. */
10
16
  export const WATER_PARTICLE_LEVEL0_CELL = 1 / 256;
11
17
 
18
+ /**
19
+ * How fast a packet's envelope stretches as it disperses, as a fraction κ of its group speed, by its wavenumber k against
20
+ * k_m = √(g/(σ/ρ)), the wavenumber of the slowest crests (λ = 1.71 cm): from x = log₂(k/k_m) = -7 in steps of a quarter,
21
+ * held at both ends.
22
+ *
23
+ * Its half-length h, 2r when emitted, grows as h² = (2r)² + (κD/2)² over the distance D its front has travelled since:
24
+ * the spread of an unchirped packet's energy grows as the spread of its group speeds times time, in quadrature with
25
+ * where it began (Jeschke & Wojtan 2017 grow it linearly, eq. 14, its far limit). Each κ is the one whose peak
26
+ * √(2r/h) best matches exact linear theory, ω² = gk + (σ/ρ)k³, for the emitted packet at 5 to 225 wavelengths (FFT,
27
+ * worst ratio minimised): within 2% for capillary waves up to r = 8.5 mm and gravity waves from r = 6 cm, where κ
28
+ * tends to 1 and 0.9, and 5% from 4 cm. Between, around the slowest group speed (λ = 4.4 cm), a broad band's energy
29
+ * gathers at that speed and the peak falls as t^(−1/3), which no κ draws: up to 16% below r = 12 mm, 27% at 3 cm.
30
+ */
31
+ export const WATER_PARTICLE_STRETCH = [
32
+ 0.9002, 0.9002, 0.8998, 0.8993, 0.8984, 0.8971, 0.8957, 0.8935, 0.8904, 0.8859, 0.8798, 0.8706, 0.8585, 0.8411, 0.8166,
33
+ 0.7819, 0.7323, 0.6669, 0.5795, 0.461, 0.216, 0.0922, 0.064, 0.0723, 0.1089, 0.1877, 0.3427, 0.6145, 0.9295, 1.0417,
34
+ 1.0734, 1.0739, 1.0622, 1.0469, 1.0313, 1.0175, 1.0059, 0.9969, 0.9899,
35
+ ];
36
+
37
+ /** log₂(k/k_m) of the stretch table's first entry; entries are a quarter apart. */
38
+ const WATER_PARTICLE_STRETCH_FIRST = -7;
39
+
12
40
  /**
13
41
  * The physics of one wave particle as pure functions (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §5).
14
42
  *
15
43
  * A particle of radius r carries a packet of wavelength 2r, k = π/r. Under the gravity–capillary
16
44
  * dispersion relation the packet's envelope travels at the group speed and its crests at the phase speed
17
- * (Jeschke & Wojtan 2017; Xue et al. 2025 give wave particles their own wavelength's dispersion). It loses
18
- * amplitude at the clean-surface viscous rate 2νk² plus the surface-film rate k√(νω)/(2√2) of natural
19
- * water — so a raindrop's ripple is gone in a fraction of a second while a big splash crosses a bay.
45
+ * (Jeschke & Wojtan 2017; Xue et al. 2025 give wave particles their own wavelength's dispersion). The packet holds a
46
+ * band of wavelengths around 2r, which the same relation moves apart: its envelope, two radii either side when emitted,
47
+ * stretches as it travels and its height falls to keep its energy (WATER_PARTICLE_STRETCH), as a splash's single ring
48
+ * becomes a widening train of ripples. It loses amplitude at the clean-surface viscous rate 2νk² plus the surface-film
49
+ * rate k√(νω)/(2√2) of natural water — so a raindrop's ripple is gone in a fraction of a second while a big splash
50
+ * crosses a bay.
20
51
  *
21
- * The particles of a front are W apart, W the front's arc between them; a cosine window of half-width W
22
- * along the front is a partition of unity over them, so the front's height is the packet's amplitude
23
- * whatever the spacing, and one front adds at most two particles at any point.
52
+ * The particles of a front are β apart in angle around its centre, and a packet's crests are arcs around that
53
+ * centre; a cosine window of half-angle β is a partition of unity over them at every radius, so the front's
54
+ * height is the packet's amplitude whatever the spacing, splitting a front changes none of it, and one front
55
+ * adds at most two particles at any point.
24
56
  *
25
57
  * @type {CodeChunk}
26
58
  */
27
59
  export const chunk_water_particle = CodeChunk.from(/* language=WGSL */ `
28
60
  const WATER_PARTICLE_LEVELS: u32 = ${WATER_PARTICLE_LEVELS}u;
61
+ const WATER_PARTICLE_LEVEL_BITS: u32 = ${WATER_PARTICLE_LEVEL_BITS}u;
29
62
  const WATER_PARTICLE_LEVEL0_CELL: f32 = ${WATER_PARTICLE_LEVEL0_CELL};
63
+ const WATER_PARTICLE_STRETCH = array<f32, ${WATER_PARTICLE_STRETCH.length}>(${WATER_PARTICLE_STRETCH.join(', ')});
64
+ const WATER_PARTICLE_STRETCH_FIRST: f32 = ${WATER_PARTICLE_STRETCH_FIRST}.0;
30
65
  // kinematic viscosity of water, m²/s
31
66
  const WATER_VISCOSITY: f32 = 1e-6;
32
67
  const WATER_PI: f32 = 3.14159265358979;
@@ -66,7 +101,7 @@ fn water_particle_position(particle: ${WATER_PARTICLE_STRUCT.wgsl_ref}) -> vec2<
66
101
  return particle.origin + water_particle_direction(particle.angle) * water_particle_distance(particle);
67
102
  }
68
103
 
69
- // The front's arc between neighbouring particles: the half-width of the tangential window.
104
+ // The front's arc between neighbouring particles, at the particle's own radius: what the window spans there.
70
105
  fn water_particle_width(particle: ${WATER_PARTICLE_STRUCT.wgsl_ref}) -> f32 {
71
106
  return max(particle.dispersion * water_particle_distance(particle), 1e-3 * particle.radius);
72
107
  }
@@ -77,9 +112,79 @@ fn water_particle_phase(particle: ${WATER_PARTICLE_STRUCT.wgsl_ref}) -> f32 {
77
112
  return water_particle_wavenumber(particle.radius) * lag;
78
113
  }
79
114
 
80
- // Radius of a circle around the particle holding its whole kernel: two radii across the front, the window along it.
81
- fn water_particle_support(radius: f32, width: f32) -> f32 {
82
- return length(vec2<f32>(2.0 * radius, width));
115
+ // How far from a splash's centre its ring starts: two radii, the packet's half-length, so it starts clear of the centre.
116
+ fn water_particle_launch_distance(radius: f32) -> f32 {
117
+ return 2.0 * radius;
118
+ }
119
+
120
+ // How fast the packet's envelope stretches, as a fraction of its group speed (WATER_PARTICLE_STRETCH): interpolated in
121
+ // log κ between quarter octaves of k against the wavenumber of the slowest crests.
122
+ fn water_particle_stretch(radius: f32) -> f32 {
123
+ let octave = log2(water_particle_wavenumber(radius) * sqrt(WATER_SURFACE_TENSION / WATER_GRAVITY));
124
+ let last = f32(${WATER_PARTICLE_STRETCH.length}u - 1u);
125
+ let t = clamp(4.0 * (octave - WATER_PARTICLE_STRETCH_FIRST), 0.0, last);
126
+ let i = u32(min(floor(t), last - 1.0));
127
+ return exp2(mix(log2(WATER_PARTICLE_STRETCH[i]), log2(WATER_PARTICLE_STRETCH[i + 1u]), t - f32(i)));
128
+ }
129
+
130
+ // Half the length of the packet's envelope across its front, for a front that stands distance from its centre: 2r when
131
+ // emitted, growing in quadrature with half the stretch over the distance travelled since. Held to half the largest support
132
+ // the hash holds, so a window no wider keeps the packet within the coarsest cells.
133
+ fn water_particle_half_length_at(radius: f32, distance: f32) -> f32 {
134
+ let travelled = max(distance - water_particle_launch_distance(radius), 0.0);
135
+ let stretched = length(vec2<f32>(2.0 * radius, 0.5 * water_particle_stretch(radius) * travelled));
136
+ return min(stretched, 0.5 * water_particle_support_limit());
137
+ }
138
+
139
+ fn water_particle_half_length(particle: ${WATER_PARTICLE_STRUCT.wgsl_ref}) -> f32 {
140
+ return water_particle_half_length_at(particle.radius, water_particle_distance(particle));
141
+ }
142
+
143
+ // Radius of a circle around the particle holding its whole kernel: the envelope's half-length h across the front, and
144
+ // along it the front's arc of half-angle β plus its outer edge's overhang. A point at radius ρ = D + u and angle ψ from
145
+ // a particle at distance D lies |d|² = u² + 4ρD·sin²(ψ/2) ≤ h² + (D + h)Dβ² ≤ h² + ((D + h/2)β)² from it, and
146
+ // width ≥ Dβ.
147
+ fn water_particle_support(half_length: f32, width: f32, dispersion: f32) -> f32 {
148
+ return length(vec2<f32>(half_length, width + 0.5 * half_length * dispersion));
149
+ }
150
+
151
+ // The largest support the hash holds: half its coarsest cell.
152
+ fn water_particle_support_limit() -> f32 {
153
+ return 0.5 * water_particle_cell_size(WATER_PARTICLE_LEVELS - 1u);
154
+ }
155
+
156
+ // Whether two particles are of one front: one splash's, neither reflected or faded apart, alike in all but angle.
157
+ fn water_particle_same_front(a: ${WATER_PARTICLE_STRUCT.wgsl_ref}, b: ${WATER_PARTICLE_STRUCT.wgsl_ref}) -> bool {
158
+ return a.body == b.body && all(a.origin == b.origin) && a.age == b.age && a.amplitude == b.amplitude
159
+ && a.radius == b.radius && a.dispersion == b.dispersion;
160
+ }
161
+
162
+ // How a particle is drawn, given its front's run of particles in the array and its place in it: 1 as itself; 0 not at
163
+ // all, or a group of 3^g as one packet with 3^g times its window, when its front is whole. Whole is every particle
164
+ // the front split into still there, in order and alike: as many as fill its circle. The step puts a particle's three
165
+ // in its place, the middle at its own angle, so a group of 3^g is 3^g in a row and its middle stands at the angle
166
+ // the group was emitted at; with curved crests the groups draw what the particles do. The largest group whose packet
167
+ // the hash holds: the seven a front was emitted as, until their windows outgrow the coarsest cell.
168
+ fn water_particle_group(particle: ${WATER_PARTICLE_STRUCT.wgsl_ref}, members: u32, offset: u32) -> u32 {
169
+ if (members != u32(round(WATER_TAU / particle.dispersion))) { return 1u; }
170
+ var group = 1u;
171
+ for (var g = 0u; g < 20u && members % (3u * group) == 0u; g++) { group *= 3u; }
172
+ let distance = water_particle_distance(particle);
173
+ let half_length = water_particle_half_length_at(particle.radius, distance);
174
+ for (var g = 0u; g < 20u && group > 1u; g++) {
175
+ let dispersion = particle.dispersion * f32(group);
176
+ let width = max(dispersion * distance, 1e-3 * particle.radius);
177
+ if (water_particle_support(half_length, width, dispersion) <= water_particle_support_limit()) { break; }
178
+ group /= 3u;
179
+ }
180
+ return select(0u, group, offset % group == group / 2u);
181
+ }
182
+
183
+ // The particle as its group draws it: one packet with the group's window.
184
+ fn water_particle_drawn(particle: ${WATER_PARTICLE_STRUCT.wgsl_ref}, group: u32) -> ${WATER_PARTICLE_STRUCT.wgsl_ref} {
185
+ var drawn = particle;
186
+ drawn.dispersion *= f32(group);
187
+ return drawn;
83
188
  }
84
189
 
85
190
  // The smallest hash level whose cell is at least the support's diameter, so the support overlaps at most
@@ -93,8 +198,13 @@ fn water_particle_cell_size(level: u32) -> f32 {
93
198
  return WATER_PARTICLE_LEVEL0_CELL * exp2(f32(level));
94
199
  }
95
200
 
201
+ // A hash entry's body and level in one word.
202
+ fn water_particle_key(body: u32, level: u32) -> u32 {
203
+ return (body << WATER_PARTICLE_LEVEL_BITS) | level;
204
+ }
205
+
96
206
  fn water_particle_bucket(body: u32, level: u32, cell: vec2<i32>, table_size: u32) -> u32 {
97
- let bits = pcg3d(vec3<u32>((body << 4u) | level, bitcast<u32>(cell.x), bitcast<u32>(cell.y)));
207
+ let bits = pcg3d(vec3<u32>(water_particle_key(body, level), bitcast<u32>(cell.x), bitcast<u32>(cell.y)));
98
208
  return bits.x & (table_size - 1u);
99
209
  }
100
210
 
@@ -105,39 +215,54 @@ struct WaterParticleField {
105
215
  displacement: vec2<f32>,
106
216
  // columns ∂D/∂x and ∂D/∂z: (∂Dx/∂x, ∂Dz/∂x), (∂Dx/∂z, ∂Dz/∂z)
107
217
  jacobian: mat2x2<f32>,
218
+ // the gradient of the displacement's signed length along the radius: the slope a quarter carrier cycle on, so that
219
+ // ½(|slope|² + |this|²) is the slope's mean square over a cycle
220
+ displacement_gradient: vec2<f32>,
108
221
  }
109
222
 
110
- // The packet at offset d from its particle. u across the front, v along it: envelope E(u) over two radii,
111
- // window T(v) over the width, carrier phase φ = πu/r − phase. Height a·E·T·cos φ; horizontal displacement
112
- // −a·E·T·sin φ along the direction (Gerstner-like orbits, Yuksel's longitudinal sign); with derivatives.
113
- fn water_particle_field(d: vec2<f32>, angle: f32, amplitude: f32, radius: f32, width: f32, phase: f32) -> WaterParticleField {
223
+ // The packet at offset d from its particle, which stands distance from its front's centre. ρ the radius from the
224
+ // centre and u = ρ − distance across the front, ψ the angle around the centre from the particle's direction:
225
+ // envelope E(u) over half_length either side, window T(ψ) over the dispersion β either side, carrier phase πu/r − phase.
226
+ // Height a·E·T·cos; horizontal displacement −a·E·T·sin along the radius (Gerstner-like orbits, Yuksel's longitudinal
227
+ // sign); with derivatives, ∇ψ = e_ψ/ρ.
228
+ fn water_particle_field(d: vec2<f32>, angle: f32, amplitude: f32, radius: f32, half_length: f32, dispersion: f32, distance: f32,
229
+ phase: f32) -> WaterParticleField {
114
230
  var field: WaterParticleField;
115
231
  let direction = water_particle_direction(angle);
116
232
  let tangent = vec2<f32>(-direction.y, direction.x);
117
- let u = dot(d, direction);
118
- let v = dot(d, tangent);
119
- if (abs(u) >= 2.0 * radius || abs(v) >= width) { return field; }
120
- let eu = 0.5 * WATER_PI * u / radius;
233
+ let q = d + direction * distance;
234
+ let rho = length(q);
235
+ // ρ − distance, without the cancellation
236
+ let u = (dot(d, d) + 2.0 * distance * dot(d, direction)) / max(rho + distance, 1e-30);
237
+ if (abs(u) >= half_length || !(rho > 0.0)) { return field; }
238
+ let psi = atan2(dot(d, tangent), distance + dot(d, direction));
239
+ if (abs(psi) >= dispersion) { return field; }
240
+ let radial = q / rho;
241
+ let around = vec2<f32>(-radial.y, radial.x);
242
+ let eu = WATER_PI * u / half_length;
121
243
  let envelope = 0.5 * (1.0 + cos(eu));
122
- let envelope_du = -0.25 * WATER_PI / radius * sin(eu);
123
- let tv = WATER_PI * v / width;
244
+ let envelope_du = -0.5 * WATER_PI / half_length * sin(eu);
245
+ let tv = WATER_PI * psi / dispersion;
124
246
  let window = 0.5 * (1.0 + cos(tv));
125
- let window_dv = -0.5 * WATER_PI / width * sin(tv);
247
+ let window_dpsi = -0.5 * WATER_PI / dispersion * sin(tv);
126
248
  let carrier = WATER_PI * u / radius - phase;
127
249
  let c = cos(carrier);
128
250
  let s = sin(carrier);
129
251
  let k = WATER_PI / radius;
130
252
  let z = amplitude * envelope * window * c;
131
253
  let z_u = amplitude * window * (envelope_du * c - envelope * s * k);
132
- let z_v = amplitude * envelope * window_dv * c;
254
+ let z_psi = amplitude * envelope * window_dpsi * c;
133
255
  let h = -amplitude * envelope * window * s;
134
256
  let h_u = -amplitude * window * (envelope_du * s + envelope * c * k);
135
- let h_v = -amplitude * envelope * window_dv * s;
136
- let gradient_h = h_u * direction + h_v * tangent;
257
+ let h_psi = -amplitude * envelope * window_dpsi * s;
258
+ let gradient_h = h_u * radial + (h_psi / rho) * around;
259
+ // the radius turns as the point moves around the centre: ∂e_ρ/∂x_j = e_ψ (e_ψ)_j / ρ
260
+ let turn = (h / rho) * around;
137
261
  field.height = z;
138
- field.slope = z_u * direction + z_v * tangent;
139
- field.displacement = h * direction;
140
- field.jacobian = mat2x2<f32>(direction * gradient_h.x, direction * gradient_h.y);
262
+ field.slope = z_u * radial + (z_psi / rho) * around;
263
+ field.displacement = h * radial;
264
+ field.jacobian = mat2x2<f32>(radial * gradient_h.x + turn * around.x, radial * gradient_h.y + turn * around.y);
265
+ field.displacement_gradient = gradient_h;
141
266
  return field;
142
267
  }
143
268
  `, [chunk_water_spectrum, chunk_pcg3d, WATER_PARTICLE_STRUCT.declaration_chunk, WATER_PARTICLE_ENTRY_STRUCT.declaration_chunk]);
@@ -2,7 +2,12 @@
2
2
  export const WATER_PARTICLE_FADE_SECONDS: 0.15;
3
3
  /**
4
4
  * One frame of one wave particle (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §5.1): it ages, spreads over its
5
- * widening front, damps, reflects off its body's authored outline, and dies or splits.
5
+ * widening front, damps, meets its body's authored outline, and dies or splits.
6
+ *
7
+ * At the outline the water shows the packet plus the shore's share of its mirror image in the outline (the image
8
+ * method, as Jeschke & Wojtan 2017 §4.4 keep a "ghost" of a reflected packet): the image is emitted the step the first
9
+ * of the packet's support leaves the body, and the packet carries on until the last of it has left it too. The body's
10
+ * outline clips what of either lies beyond it, so the water changes only as the two move.
6
11
  *
7
12
  * Whether a point is over the body is a down-ray into the body's own BLAS, so the outline is exactly the
8
13
  * authored mesh's, holes for islands included. Bindings: `geometries`, `blas_lookup`, `blas_data`,
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_water_particle_step.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/water/surface/particles/chunk_water_particle_step.js"],"names":[],"mappings":"AAOA,qHAAqH;AACrH,+CAAgD;AAEhD;;;;;;;;;GASG;AACH,wCAFU,SAAS,CAsGsC;0BAxH/B,uCAAuC"}
1
+ {"version":3,"file":"chunk_water_particle_step.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/water/surface/particles/chunk_water_particle_step.js"],"names":[],"mappings":"AAQA,qHAAqH;AACrH,+CAAgD;AAEhD;;;;;;;;;;;;;;GAcG;AACH,wCAFU,SAAS,CAsN8E;0BA9OvE,uCAAuC"}