@woosh/meep-engine 3.41.0 → 3.43.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 (384) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/bundle-worker-terrain.js +1 -1
  3. package/editor/selection/editor_pick.d.ts.map +1 -1
  4. package/editor/selection/editor_pick.js +2 -1
  5. package/editor/tools/TransformToolV2.d.ts.map +1 -1
  6. package/editor/tools/TransformToolV2.js +7 -1
  7. package/editor/tools/engine/ToolEngine.d.ts.map +1 -1
  8. package/editor/tools/engine/ToolEngine.js +10 -0
  9. package/editor/tools/v2/TransformControls.d.ts.map +1 -1
  10. package/editor/tools/v2/TransformControls.js +7 -20
  11. package/editor/tools/v2/handle/gizmo_drag_plane.d.ts.map +1 -1
  12. package/editor/tools/v2/handle/gizmo_drag_plane.js +4 -0
  13. package/editor/view/ecs/EntityEditor.d.ts.map +1 -1
  14. package/editor/view/ecs/EntityEditor.js +3 -1
  15. package/editor/view/node-graph/NodeGraphView.d.ts.map +1 -1
  16. package/editor/view/node-graph/NodeGraphView.js +28 -12
  17. package/package.json +91 -96
  18. package/samples/engine/first-scene/index.html +4 -1
  19. package/samples/engine/first-scene/main.js +14 -9
  20. package/src/core/binary/utf8/utf8_decode.js +3 -3
  21. package/src/core/bvh2/binary/2/bvh32_query_user_data_ray.d.ts.map +1 -1
  22. package/src/core/bvh2/binary/2/bvh32_query_user_data_ray.js +112 -113
  23. package/src/core/bvh2/bvh3/ebvh_nodes_sort_sah_local4.js +2 -2
  24. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +14 -14
  25. package/src/core/collection/RingBuffer.d.ts.map +1 -1
  26. package/src/core/collection/RingBuffer.js +4 -0
  27. package/src/core/collection/array/array_contains_duplicates.d.ts.map +1 -1
  28. package/src/core/collection/array/array_contains_duplicates.js +2 -1
  29. package/src/core/collection/array/array_copy.d.ts.map +1 -1
  30. package/src/core/collection/array/array_copy.js +23 -0
  31. package/src/core/collection/array/typed/sparse_typed_array_hash.d.ts +2 -2
  32. package/src/core/collection/array/typed/sparse_typed_array_hash.d.ts.map +1 -1
  33. package/src/core/collection/array/typed/sparse_typed_array_hash.js +9 -8
  34. package/src/core/collection/array/typed/uint16_array_hash.d.ts +2 -2
  35. package/src/core/collection/array/typed/uint16_array_hash.js +4 -4
  36. package/src/core/collection/array/typed/uint8_array_hash.d.ts +2 -2
  37. package/src/core/collection/array/typed/uint8_array_hash.js +4 -4
  38. package/src/core/collection/array/weightedRandomFromArray.d.ts +1 -0
  39. package/src/core/collection/array/weightedRandomFromArray.d.ts.map +1 -1
  40. package/src/core/collection/array/weightedRandomFromArray.js +9 -1
  41. package/src/core/collection/heap/BinaryHeap.d.ts.map +1 -1
  42. package/src/core/collection/heap/BinaryHeap.js +4 -0
  43. package/src/core/collection/list/List.d.ts.map +1 -1
  44. package/src/core/collection/list/List.js +4 -2
  45. package/src/core/collection/set/ArraySet.js +1 -1
  46. package/src/core/collection/set/HashSet.d.ts +1 -1
  47. package/src/core/collection/set/HashSet.d.ts.map +1 -1
  48. package/src/core/collection/set/HashSet.js +4 -2
  49. package/src/core/debug/matchers/IsEqual.js +1 -1
  50. package/src/core/debug/matchers/IsIterableContaining.d.ts.map +1 -1
  51. package/src/core/debug/matchers/IsIterableContaining.js +61 -74
  52. package/src/core/events/signal/SignalBinding.js +101 -101
  53. package/src/core/function/extractFunctionBody.js +13 -13
  54. package/src/core/function/objectsEqual.d.ts.map +1 -1
  55. package/src/core/function/objectsEqual.js +15 -14
  56. package/src/core/geom/3d/frustum/frustum3_compute_closest_point.d.ts.map +1 -1
  57. package/src/core/geom/3d/frustum/frustum3_compute_closest_point.js +207 -172
  58. package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts.map +1 -1
  59. package/src/core/geom/3d/gjk/gjk_epa_penetration.js +5 -4
  60. package/src/core/geom/3d/line/line3_compute_segment_point_distance_eikonal.d.ts.map +1 -1
  61. package/src/core/geom/3d/line/line3_compute_segment_point_distance_eikonal.js +8 -2
  62. package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts +20 -0
  63. package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
  64. package/src/core/geom/3d/triangle/tri3_ray_intersection.js +182 -0
  65. package/src/core/math/noise/curl_noise_3dt.d.ts.map +1 -1
  66. package/src/core/math/noise/curl_noise_3dt.js +20 -10
  67. package/src/core/math/noise/sdnoise.d.ts +16 -5
  68. package/src/core/math/noise/sdnoise.d.ts.map +1 -1
  69. package/src/core/math/noise/sdnoise.js +43 -9
  70. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts +16 -1
  71. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts.map +1 -1
  72. package/src/core/math/spline/spline3_hermite_nearest_point.js +44 -3
  73. package/src/engine/Engine.d.ts.map +1 -1
  74. package/src/engine/Engine.js +6 -2
  75. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +9 -0
  76. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
  77. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +26 -0
  78. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
  79. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +2 -0
  80. package/src/engine/control/first-person/abilities/AbilitySet.d.ts.map +1 -1
  81. package/src/engine/control/first-person/abilities/AbilitySet.js +9 -0
  82. package/src/engine/control/first-person/abilities/LedgeGrab.d.ts.map +1 -1
  83. package/src/engine/control/first-person/abilities/LedgeGrab.js +6 -0
  84. package/src/engine/control/first-person/abilities/Slide.d.ts.map +1 -1
  85. package/src/engine/control/first-person/abilities/Slide.js +1 -0
  86. package/src/engine/control/first-person/abilities/WallRun.d.ts +4 -1
  87. package/src/engine/control/first-person/abilities/WallRun.d.ts.map +1 -1
  88. package/src/engine/control/first-person/abilities/WallRun.js +13 -1
  89. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts +1 -1
  90. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts.map +1 -1
  91. package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.js +6 -5
  92. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts +3 -3
  93. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts.map +1 -1
  94. package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.js +9 -8
  95. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts.map +1 -1
  96. package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.js +13 -4
  97. package/src/engine/ecs/EntityManager.d.ts.map +1 -1
  98. package/src/engine/ecs/EntityManager.js +18 -15
  99. package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescription.d.ts.map +1 -1
  100. package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescription.js +2 -1
  101. package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescriptionTable.d.ts.map +1 -1
  102. package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescriptionTable.js +1 -0
  103. package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
  104. package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +3 -0
  105. package/src/engine/ecs/parent/EntityNode.js +3 -3
  106. package/src/engine/ecs/speaker/VoiceSystem.d.ts.map +1 -1
  107. package/src/engine/ecs/speaker/VoiceSystem.js +4 -0
  108. package/src/engine/ecs/storage/BinaryBufferDeSerializer.js +5 -5
  109. package/src/engine/ecs/storage/binary/BinarySerializationRegistry.d.ts.map +1 -1
  110. package/src/engine/ecs/storage/binary/BinarySerializationRegistry.js +3 -2
  111. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter2.js +1 -1
  112. package/src/engine/ecs/storage/binary/object-v2/BinaryObjectDeSerializer.d.ts.map +1 -1
  113. package/src/engine/ecs/storage/binary/object-v2/BinaryObjectDeSerializer.js +8 -1
  114. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  115. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +8 -0
  116. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
  117. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +5 -2
  118. package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.d.ts.map +1 -1
  119. package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.js +3 -0
  120. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.d.ts.map +1 -1
  121. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +1 -0
  122. package/src/engine/ecs/terrain/overlay/TerrainOverlay.js +1 -1
  123. package/src/engine/ecs/terrain/tiles/TerrainTile.d.ts.map +1 -1
  124. package/src/engine/ecs/terrain/tiles/TerrainTile.js +13 -1
  125. package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts.map +1 -1
  126. package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +1 -0
  127. package/src/engine/graphics/ecs/light/LightSerializationAdapter.d.ts.map +1 -1
  128. package/src/engine/graphics/ecs/light/LightSerializationAdapter.js +13 -1
  129. package/src/engine/graphics/ecs/light/LightSerializationUpgrader_0_1.d.ts +5 -0
  130. package/src/engine/graphics/ecs/light/LightSerializationUpgrader_0_1.d.ts.map +1 -0
  131. package/src/engine/graphics/ecs/light/LightSerializationUpgrader_0_1.js +27 -0
  132. package/src/engine/graphics/ecs/water/Water.d.ts +11 -0
  133. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  134. package/src/engine/graphics/ecs/water/Water.js +17 -0
  135. package/src/engine/graphics/ecs/water/WaterSerializationAdapter.d.ts.map +1 -1
  136. package/src/engine/graphics/ecs/water/WaterSerializationAdapter.js +3 -1
  137. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_4_5.d.ts +9 -0
  138. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_4_5.d.ts.map +1 -0
  139. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_4_5.js +24 -0
  140. package/src/engine/graphics/ecs/water/WaterWaves.d.ts +30 -9
  141. package/src/engine/graphics/ecs/water/WaterWaves.d.ts.map +1 -1
  142. package/src/engine/graphics/ecs/water/WaterWaves.js +41 -9
  143. package/src/engine/graphics/ecs/water/WaterWavesSerializationAdapter.d.ts.map +1 -1
  144. package/src/engine/graphics/ecs/water/WaterWavesSerializationAdapter.js +30 -26
  145. package/src/engine/graphics/ecs/water/WaterWavesSerializationUpgrader_0_1.d.ts +6 -0
  146. package/src/engine/graphics/ecs/water/WaterWavesSerializationUpgrader_0_1.d.ts.map +1 -0
  147. package/src/engine/graphics/ecs/water/WaterWavesSerializationUpgrader_0_1.js +22 -0
  148. package/src/engine/graphics/geometry/buffered/query/bvh32_geometry_raycast.d.ts.map +1 -1
  149. package/src/engine/graphics/geometry/buffered/query/bvh32_geometry_raycast.js +3 -5
  150. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts +20 -0
  151. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts.map +1 -1
  152. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.js +36 -0
  153. package/src/engine/graphics3/WaterSystem.d.ts +12 -3
  154. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  155. package/src/engine/graphics3/WaterSystem.js +78 -46
  156. package/src/engine/input/devices/PointerDevice.d.ts.map +1 -1
  157. package/src/engine/input/devices/PointerDevice.js +29 -4
  158. package/src/engine/intelligence/behavior/selector/WeightedRandomBehavior.d.ts +1 -0
  159. package/src/engine/intelligence/behavior/selector/WeightedRandomBehavior.d.ts.map +1 -1
  160. package/src/engine/intelligence/behavior/selector/WeightedRandomBehavior.js +14 -3
  161. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  162. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts.map +1 -1
  163. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +12 -3
  164. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts.map +1 -1
  165. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +8 -2
  166. package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.d.ts +19 -0
  167. package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.d.ts.map +1 -1
  168. package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.js +41 -2
  169. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.d.ts.map +1 -1
  170. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.js +9 -3
  171. package/src/engine/physics/fluid/solver/v3_mac_advect_sl_velocity.d.ts.map +1 -1
  172. package/src/engine/physics/fluid/solver/v3_mac_advect_sl_velocity.js +26 -10
  173. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +3 -6
  174. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -1
  175. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.js +22 -9
  176. package/src/engine/ui/DraggableAspect.d.ts +5 -1
  177. package/src/engine/ui/DraggableAspect.d.ts.map +1 -1
  178. package/src/engine/ui/DraggableAspect.js +61 -4
  179. package/src/format/image/avif/heif/ItemProperty.d.ts +1 -1
  180. package/src/format/image/avif/heif/ItemProperty.js +1 -1
  181. package/src/format/image/png/chunk/png_chunk_decode_iTXt.d.ts.map +1 -1
  182. package/src/format/image/png/chunk/png_chunk_decode_iTXt.js +17 -6
  183. package/src/shade/device/mock/SoftwareGPUDevice.d.ts +2 -4
  184. package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
  185. package/src/shade/device/mock/SoftwareGPUDevice.js +20 -13
  186. package/src/shade/playground/skinned_blas_refit/sweep_views.d.ts.map +1 -1
  187. package/src/shade/playground/skinned_blas_refit/sweep_views.js +2 -1
  188. package/src/shade/playground/vgeo_runtime/README.md +5 -4
  189. package/src/shade/playground/water_refraction/README.md +10 -11
  190. package/src/shade/playground/water_refraction/main.js +9 -8
  191. package/src/shade/playground/water_refraction/world.js +1 -1
  192. package/src/shade/playground/water_surface/README.md +43 -0
  193. package/src/shade/playground/water_surface/index.html +30 -0
  194. package/src/shade/playground/water_surface/main.d.ts +2 -0
  195. package/src/shade/playground/water_surface/main.d.ts.map +1 -0
  196. package/src/shade/playground/water_surface/main.js +154 -0
  197. package/src/shade/playground/water_surface/world.d.ts +44 -0
  198. package/src/shade/playground/water_surface/world.d.ts.map +1 -0
  199. package/src/shade/playground/water_surface/world.js +160 -0
  200. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  201. package/src/shade/renderer/Renderer.js +6 -5
  202. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  203. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +5 -0
  204. package/src/shade/renderer/atmosphere/GPUSky.d.ts +12 -0
  205. package/src/shade/renderer/atmosphere/GPUSky.d.ts.map +1 -1
  206. package/src/shade/renderer/atmosphere/GPUSky.js +162 -147
  207. package/src/shade/renderer/binding/BufferBinding.js +2 -2
  208. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  209. package/src/shade/renderer/buffer/table/GPUTypedTable.js +5 -3
  210. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.d.ts +10 -3
  211. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.d.ts.map +1 -1
  212. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.js +17 -9
  213. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +3 -0
  214. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +1 -1
  215. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +16 -0
  216. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +2 -0
  217. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +1 -1
  218. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +11 -0
  219. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts +1 -1
  220. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  221. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +9 -3
  222. package/src/shade/renderer/geometry/util/geometry_simplify_redundant_topology.d.ts.map +1 -1
  223. package/src/shade/renderer/geometry/util/geometry_simplify_redundant_topology.js +2 -2
  224. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  225. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +85 -0
  226. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
  227. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +12 -6
  228. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -1
  229. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +7 -0
  230. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -1
  231. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +3 -1
  232. package/src/shade/renderer/lightmap/bake/shader_lightmap_denoise_sh.d.ts.map +1 -1
  233. package/src/shade/renderer/lightmap/bake/shader_lightmap_denoise_sh.js +10 -3
  234. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  235. package/src/shade/renderer/particles/DESIGN.md +13 -9
  236. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +1 -1
  237. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +1 -1
  238. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  239. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +3 -2
  240. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  241. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +3 -2
  242. package/src/shade/renderer/scene/GPUSceneContext.d.ts +9 -1
  243. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  244. package/src/shade/renderer/scene/GPUSceneContext.js +23 -1
  245. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +2 -1
  246. package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128_inverse.d.ts +13 -0
  247. package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128_inverse.d.ts.map +1 -0
  248. package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128_inverse.js +42 -0
  249. package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128x4_inverse_workgroup.d.ts +15 -0
  250. package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128x4_inverse_workgroup.d.ts.map +1 -0
  251. package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128x4_inverse_workgroup.js +39 -0
  252. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  253. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +2 -0
  254. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +4 -1
  255. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  256. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +74 -3
  257. package/src/shade/renderer/volumetrics/NOTES.md +1023 -957
  258. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.d.ts +5 -4
  259. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.d.ts.map +1 -1
  260. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.js +5 -4
  261. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.d.ts +1 -1
  262. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.js +1 -1
  263. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.d.ts +1 -1
  264. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.js +1 -1
  265. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts +41 -0
  266. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts.map +1 -0
  267. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.js +112 -0
  268. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +9 -23
  269. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
  270. package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +18 -126
  271. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.d.ts +22 -0
  272. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.d.ts.map +1 -0
  273. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.js +228 -0
  274. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  275. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +0 -53
  276. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +15 -0
  277. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  278. package/src/shade/renderer/water/GPUWaterRenderer.js +110 -30
  279. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +16 -8
  280. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
  281. package/src/shade/renderer/water/medium/GPUWaterBodies.js +31 -26
  282. package/src/shade/renderer/water/medium/shader_water_meshlets.d.ts +0 -1
  283. package/src/shade/renderer/water/medium/shader_water_meshlets.d.ts.map +1 -1
  284. package/src/shade/renderer/water/medium/shader_water_meshlets.js +1 -39
  285. package/src/shade/renderer/water/shader_water.d.ts +0 -1
  286. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  287. package/src/shade/renderer/water/shader_water.js +201 -72
  288. package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts +70 -0
  289. package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts.map +1 -0
  290. package/src/shade/renderer/water/surface/GPUWaterSurface.js +199 -0
  291. package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.d.ts +5 -2
  292. package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.d.ts.map +1 -1
  293. package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.js +32 -12
  294. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts +23 -0
  295. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts.map +1 -0
  296. package/src/shade/renderer/water/surface/chunk_water_surface_sample.js +227 -0
  297. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +65 -11
  298. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -1
  299. package/src/shade/renderer/water/surface/graph_water_tessellation.js +163 -28
  300. package/src/shade/renderer/water/surface/lod/WATER_LOD.d.ts +51 -0
  301. package/src/shade/renderer/water/surface/lod/WATER_LOD.d.ts.map +1 -0
  302. package/src/shade/renderer/water/surface/lod/WATER_LOD.js +95 -0
  303. package/src/shade/renderer/water/surface/lod/chunk_water_lod.d.ts +10 -0
  304. package/src/shade/renderer/water/surface/lod/chunk_water_lod.d.ts.map +1 -0
  305. package/src/shade/renderer/water/surface/lod/chunk_water_lod.js +127 -0
  306. package/src/shade/renderer/water/surface/lod/chunk_water_lod_cell.d.ts +17 -0
  307. package/src/shade/renderer/water/surface/lod/chunk_water_lod_cell.d.ts.map +1 -0
  308. package/src/shade/renderer/water/surface/lod/chunk_water_lod_cell.js +246 -0
  309. package/src/shade/renderer/water/surface/lod/shader_water_lod.d.ts +118 -0
  310. package/src/shade/renderer/water/surface/lod/shader_water_lod.d.ts.map +1 -0
  311. package/src/shade/renderer/water/surface/lod/shader_water_lod.js +727 -0
  312. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts +60 -0
  313. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -0
  314. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +274 -0
  315. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts +17 -0
  316. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts.map +1 -0
  317. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js +57 -0
  318. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts +43 -0
  319. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts.map +1 -0
  320. package/src/shade/renderer/water/surface/particles/chunk_water_particle.js +268 -0
  321. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts +20 -0
  322. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -0
  323. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +239 -0
  324. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts +153 -0
  325. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts.map +1 -0
  326. package/src/shade/renderer/water/surface/particles/shader_water_particles.js +874 -0
  327. package/src/shade/renderer/water/surface/shader_water_cull.d.ts +42 -0
  328. package/src/shade/renderer/water/surface/shader_water_cull.d.ts.map +1 -0
  329. package/src/shade/renderer/water/surface/shader_water_cull.js +269 -0
  330. package/src/shade/renderer/water/surface/shader_water_waves_combine.d.ts +15 -0
  331. package/src/shade/renderer/water/surface/shader_water_waves_combine.d.ts.map +1 -0
  332. package/src/shade/renderer/water/surface/shader_water_waves_combine.js +73 -0
  333. package/src/shade/renderer/water/surface/shader_water_waves_derive.d.ts +11 -0
  334. package/src/shade/renderer/water/surface/shader_water_waves_derive.d.ts.map +1 -0
  335. package/src/shade/renderer/water/surface/shader_water_waves_derive.js +78 -0
  336. package/src/shade/renderer/water/surface/spectrum/GPUWaterSpectrum.d.ts +35 -0
  337. package/src/shade/renderer/water/surface/spectrum/GPUWaterSpectrum.d.ts.map +1 -0
  338. package/src/shade/renderer/water/surface/spectrum/GPUWaterSpectrum.js +103 -0
  339. package/src/shade/renderer/water/surface/spectrum/WATER_BAND_STATE.d.ts +22 -0
  340. package/src/shade/renderer/water/surface/spectrum/WATER_BAND_STATE.d.ts.map +1 -0
  341. package/src/shade/renderer/water/surface/spectrum/WATER_BAND_STATE.js +57 -0
  342. package/src/shade/renderer/water/surface/spectrum/WATER_SPECTRUM.d.ts +22 -0
  343. package/src/shade/renderer/water/surface/spectrum/WATER_SPECTRUM.d.ts.map +1 -0
  344. package/src/shade/renderer/water/surface/spectrum/WATER_SPECTRUM.js +25 -0
  345. package/src/shade/renderer/water/surface/spectrum/chunk_water_jonswap.d.ts +14 -0
  346. package/src/shade/renderer/water/surface/spectrum/chunk_water_jonswap.d.ts.map +1 -0
  347. package/src/shade/renderer/water/surface/spectrum/chunk_water_jonswap.js +48 -0
  348. package/src/shade/renderer/water/surface/spectrum/chunk_water_spectrum.d.ts +23 -0
  349. package/src/shade/renderer/water/surface/spectrum/chunk_water_spectrum.d.ts.map +1 -0
  350. package/src/shade/renderer/water/surface/spectrum/chunk_water_spectrum.js +169 -0
  351. package/src/shade/renderer/water/surface/spectrum/shader_water_spectrum.d.ts +26 -0
  352. package/src/shade/renderer/water/surface/spectrum/shader_water_spectrum.d.ts.map +1 -0
  353. package/src/shade/renderer/water/surface/spectrum/shader_water_spectrum.js +161 -0
  354. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  355. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +29 -9
  356. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  357. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +14 -3
  358. package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.d.ts +0 -28
  359. package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.d.ts.map +0 -1
  360. package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.js +0 -86
  361. package/src/engine/ecs/storage/binary/object-v2/serializerTestHarness.d.ts +0 -29
  362. package/src/engine/ecs/storage/binary/object-v2/serializerTestHarness.d.ts.map +0 -1
  363. package/src/engine/ecs/storage/binary/object-v2/serializerTestHarness.js +0 -44
  364. package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts +0 -4
  365. package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts.map +0 -1
  366. package/src/shade/renderer/water/medium/shader_water_bodies_derive.js +0 -32
  367. package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts +0 -25
  368. package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts.map +0 -1
  369. package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.js +0 -128
  370. package/src/shade/renderer/water/surface/chunk_water_tessellation.d.ts +0 -9
  371. package/src/shade/renderer/water/surface/chunk_water_tessellation.d.ts.map +0 -1
  372. package/src/shade/renderer/water/surface/chunk_water_tessellation.js +0 -144
  373. package/src/shade/renderer/water/surface/chunk_water_wave.d.ts +0 -13
  374. package/src/shade/renderer/water/surface/chunk_water_wave.d.ts.map +0 -1
  375. package/src/shade/renderer/water/surface/chunk_water_wave.js +0 -40
  376. package/src/shade/renderer/water/surface/shader_water_tiles.d.ts +0 -4
  377. package/src/shade/renderer/water/surface/shader_water_tiles.d.ts.map +0 -1
  378. package/src/shade/renderer/water/surface/shader_water_tiles.js +0 -123
  379. package/src/shade/renderer/water/surface/shader_water_wave_batch.d.ts +0 -6
  380. package/src/shade/renderer/water/surface/shader_water_wave_batch.d.ts.map +0 -1
  381. package/src/shade/renderer/water/surface/shader_water_wave_batch.js +0 -85
  382. package/src/shade/renderer/water/surface/shader_water_wave_domain.d.ts +0 -6
  383. package/src/shade/renderer/water/surface/shader_water_wave_domain.d.ts.map +0 -1
  384. package/src/shade/renderer/water/surface/shader_water_wave_domain.js +0 -83
@@ -0,0 +1,42 @@
1
+ /** Workgroup size of the culling pass and of the passes over its lists. */
2
+ export const WATER_CULL_WORKGROUP_SIZE: 64;
3
+ /** Bits of a wave row's activity word. */
4
+ export const WaterActivity: Readonly<{
5
+ /** Its displaced surface may meet the frame's view. */
6
+ Visible: 1;
7
+ /** It is simulated this frame: visible, or simulated while hidden. */
8
+ Active: 2;
9
+ }>;
10
+ /** What the culling pass is told about the frame. */
11
+ export const WATER_CULL_STRUCT: WebGPUStruct;
12
+ /** A list the culling pass appends rows to. */
13
+ export const WATER_LIST_APPEND_STRUCT: WebGPUStruct;
14
+ /** Bytes of a list's header: its count, padded to its elements' alignment. */
15
+ export const WATER_LIST_HEADER_BYTES: 16;
16
+ /**
17
+ * The frame's culling pass (WATER_SURFACE_DISTANCE_LOD_PROPOSAL_2026_10_06.md §3.1), one thread a water body, before
18
+ * anything simulates. Against the frustum of the view the frame is recorded for, with a prior bound on the body's
19
+ * displacement, it decides whether the body is visible and whether it is simulated this frame, and lists it for the
20
+ * passes that follow. On the way it does the per-body work that used to be passes of its own over every row: weights
21
+ * when the wind or the fetch changed, the wind's turn for a body that is simulated, optics when they were edited.
22
+ * A visible body ORs the bands it can draw into the frame's band mask.
23
+ */
24
+ export const shader_water_cull: ComputeShader;
25
+ /** Commands the finalize pass writes, in order, 16 bytes apart. */
26
+ export const WaterSurfaceCommand: Readonly<{
27
+ SpectrumRows: 0;
28
+ SpectrumColumns: 1;
29
+ Active: 2;
30
+ Emit: 3;
31
+ }>;
32
+ export const WATER_SURFACE_COMMAND_STRIDE: 16;
33
+ export const WATER_SURFACE_COMMAND_COUNT: 4;
34
+ /**
35
+ * After the culling pass: which bands this frame's spectrum evaluates — those the visible bodies can draw that do not
36
+ * already hold this time (all of them once, when a device's envelopes are seeded) — and the indirect commands for the
37
+ * spectrum and for the passes over the active and emit lists. Commands sit 16 bytes apart.
38
+ */
39
+ export const shader_water_cull_finalize: ComputeShader;
40
+ import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
41
+ import { ComputeShader } from "../../shader/ComputeShader.js";
42
+ //# sourceMappingURL=shader_water_cull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_water_cull.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/water/surface/shader_water_cull.js"],"names":[],"mappings":"AAoCA,2EAA2E;AAC3E,2CAA4C;AAE5C,0CAA0C;AAC1C;IACI,uDAAuD;;IAEvD,sEAAsE;;GAEvE;AAEH,qDAAqD;AACrD,6CAOuB;AAEvB,+CAA+C;AAC/C,oDAGE;AAEF,8EAA8E;AAC9E,yCAA0C;AA6C1C;;;;;;;GAOG;AACH,8CAsGiG;AAEjG,mEAAmE;AACnE;;;;;GAKG;AACH,8CAA+C;AAC/C,4CAA6C;AAW7C;;;;GAIG;AACH,uDAuBM;6BA9PuB,mCAAmC;8BAVlC,+BAA+B"}
@@ -0,0 +1,269 @@
1
+ import { CAMERA_UNIFORM_STRUCT } from "../../camera/CAMERA_UNIFORM_STRUCT.js";
2
+ import { GEOMETRY_METADATA_STRUCT } from "../../geometry/GEOMETRY_METADATA_STRUCT.js";
3
+ import { COLLECTION_U32_STRUCT_READ } from "../../gpu_primitive/COLLECTION_U32_STRUCT_READ.js";
4
+ import { chunk_scene_database_access_rw } from "../../scene/chunk_scene_database_access.js";
5
+ import { ComputeShader } from "../../shader/ComputeShader.js";
6
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
7
+ import { chunk_aabb3_intersects_frustum } from "../../shader/chunk/geometry/aabb3/chunk_aabb3_intersects_frustum.js";
8
+ import { chunk_aabb3_project } from "../../shader/chunk/geometry/aabb3/chunk_aabb3_project.js";
9
+ import { chunk_array_to_aabb3 } from "../../shader/chunk/geometry/aabb3/chunk_array_to_aabb3.js";
10
+ import { chunk_mat4_linear_determinant } from "../../shader/chunk/geometry/mat4/chunk_mat4_linear_determinant.js";
11
+ import { chunk_folded_workgroup_index } from "../../shader/chunk/grid/chunk_folded_workgroup_index.js";
12
+ import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
13
+ import { atomic_u32, f32, u32 } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
14
+ import { WebGPUArray } from "../../shader/type/WebGPUArray.js";
15
+ import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
16
+ import { WGSLAttribute } from "../../shader/type/WGSLAttribute.js";
17
+ import { WGSLAttributes } from "../../shader/type/WGSLAttributes.js";
18
+ import { WGSLStructField } from "../../shader/type/WGSLStructField.js";
19
+ import { chunk_water_medium_derived } from "../medium/chunk_water_medium_derived.js";
20
+ import { chunk_water_medium_scattering } from "../medium/chunk_water_medium_scattering.js";
21
+ import { WATER_BODIES_TABLE, WATER_WAVES_TABLE } from "../medium/chunk_water_bodies.js";
22
+ import { chunk_water_lod } from "./lod/chunk_water_lod.js";
23
+ import { WATER_LOD_VIEW_STRUCT } from "./lod/WATER_LOD.js";
24
+ import { WATER_PARTICLE_LEVELS } from "./particles/chunk_water_particle.js";
25
+ import { chunk_water_waves_derive } from "./shader_water_waves_derive.js";
26
+ import { WATER_PARTICLE_BODY_BOUNDS_STRIDE } from "./shader_water_waves_combine.js";
27
+ import {
28
+ WATER_BAND_REQUESTS_STRUCT,
29
+ WATER_BAND_STATE_ATOMIC_STRUCT,
30
+ WATER_BAND_STATE_STRUCT,
31
+ WATER_SPECTRUM_ALL_BANDS
32
+ } from "./spectrum/WATER_BAND_STATE.js";
33
+ import { chunk_water_spectrum } from "./spectrum/chunk_water_spectrum.js";
34
+ import { WATER_SPECTRUM_COLUMN_GROUPS_PER_BAND, WATER_SPECTRUM_ROW_GROUPS_PER_BAND } from "./spectrum/shader_water_spectrum.js";
35
+ import { WATER_WAVE_IMPULSE_LIMIT } from "./WATER_WAVE_RECORD_STRUCT.js";
36
+
37
+ /** Workgroup size of the culling pass and of the passes over its lists. */
38
+ export const WATER_CULL_WORKGROUP_SIZE = 64;
39
+
40
+ /** Bits of a wave row's activity word. */
41
+ export const WaterActivity = Object.freeze({
42
+ /** Its displaced surface may meet the frame's view. */
43
+ Visible: 1,
44
+ /** It is simulated this frame: visible, or simulated while hidden. */
45
+ Active: 2,
46
+ });
47
+
48
+ /** What the culling pass is told about the frame. */
49
+ export const WATER_CULL_STRUCT = WebGPUStruct.from({
50
+ /** Seconds the frame steps. */
51
+ dt: f32,
52
+ /** Non-zero when the frame steps the simulation: splashes are emitted. */
53
+ stepping: u32,
54
+ /** Non-zero when the frame bins wave particles: active bodies' particle bounds start again from zero. */
55
+ binning: u32,
56
+ }, 'WaterCull').pack();
57
+
58
+ /** A list the culling pass appends rows to. */
59
+ export const WATER_LIST_APPEND_STRUCT = WebGPUStruct.fromFields(
60
+ WGSLStructField.from("count", atomic_u32),
61
+ WGSLStructField.from("elements", WebGPUArray.from(u32), WGSLAttribute.from(WGSLAttributes.Align, 16)),
62
+ );
63
+
64
+ /** Bytes of a list's header: its count, padded to its elements' alignment. */
65
+ export const WATER_LIST_HEADER_BYTES = 16;
66
+
67
+ /**
68
+ * The prior bound of WATER_SURFACE_DISTANCE_LOD_PROPOSAL_2026_10_06.md §3.1: what a body's displaced surface can reach
69
+ * this frame before its bands and particles are evaluated, metric local. Ambient waves by twice their bands'
70
+ * envelopes, particles by the bounds their last binning left (exact for a paused body, whose particles stand still),
71
+ * and each queued splash by its ring: seven packets, each at most a tenth of its radius high.
72
+ */
73
+ const chunk_water_cull_bound = CodeChunk.from(/* language=WGSL */ `
74
+ const WATER_RING_BOUND: f32 = 0.7;
75
+
76
+ // Σ weight × envelope, height then horizontal
77
+ fn water_cull_ambient(weights: array<f32, WATER_SPECTRUM_BANDS>, blend: f32) -> vec2<f32> {
78
+ var sum = vec2<f32>(0.0);
79
+ for (var band = 0u; band < WATER_SPECTRUM_BANDS; band++) {
80
+ sum += weights[band] * vec2<f32>(bitcast<f32>(band_state.envelope[2u * band]), bitcast<f32>(band_state.envelope[2u * band + 1u]));
81
+ }
82
+ // during a turn of the wind two orientations show, weighted by the sine and cosine of the blend's quarter turn
83
+ let turning = blend < 1.0;
84
+ return sum * select(1.0, sin(1.57079633 * blend) + cos(1.57079633 * blend), turning);
85
+ }
86
+ `);
87
+
88
+ const resources = new ShaderResourceSetDescriptor();
89
+ resources.createGroup()
90
+ .addUniform('cull', WATER_CULL_STRUCT)
91
+ .addUniform('lod', WATER_LOD_VIEW_STRUCT)
92
+ .addUniform('camera', CAMERA_UNIFORM_STRUCT)
93
+ .addStorageBuffer('scene_database', WebGPUArray.u32, true)
94
+ .addStorageBuffer('geometries', WebGPUArray.from(GEOMETRY_METADATA_STRUCT))
95
+ .addStorageBuffer('band_state', WATER_BAND_STATE_STRUCT)
96
+ .addStorageBuffer('band_requests', WATER_BAND_REQUESTS_STRUCT, true)
97
+ .addStorageBuffer('particle_bounds', WebGPUArray.u32, true)
98
+ .addStorageBuffer('steep', WebGPUArray.u32)
99
+ .addStorageBuffer('activity', WebGPUArray.u32, true)
100
+ .addStorageBuffer('visible_rows', WATER_LIST_APPEND_STRUCT, true)
101
+ .addStorageBuffer('active_rows', WATER_LIST_APPEND_STRUCT, true)
102
+ .addStorageBuffer('emit_rows', WATER_LIST_APPEND_STRUCT, true);
103
+
104
+ const bodies = WATER_BODIES_TABLE, waves = WATER_WAVES_TABLE;
105
+ const pg = bodies.page_iterator_symbol_prefix(64, true);
106
+ const read = field => `${waves.marshalling_method_read_field(field, true)}(&scene_database, row)`;
107
+ const body = field => `${bodies.marshalling_method_read_field(field, true)}(&scene_database, body_row)`;
108
+ const STRIDE = WATER_PARTICLE_BODY_BOUNDS_STRIDE;
109
+
110
+ /**
111
+ * The frame's culling pass (WATER_SURFACE_DISTANCE_LOD_PROPOSAL_2026_10_06.md §3.1), one thread a water body, before
112
+ * anything simulates. Against the frustum of the view the frame is recorded for, with a prior bound on the body's
113
+ * displacement, it decides whether the body is visible and whether it is simulated this frame, and lists it for the
114
+ * passes that follow. On the way it does the per-body work that used to be passes of its own over every row: weights
115
+ * when the wind or the fetch changed, the wind's turn for a body that is simulated, optics when they were edited.
116
+ * A visible body ORs the bands it can draw into the frame's band mask.
117
+ */
118
+ export const shader_water_cull = ComputeShader.from({ label: 'Water / cull', resources,
119
+ body: CodeChunk.from(/* language=WGSL */ `
120
+ @compute @workgroup_size(64)
121
+ fn main(@builtin(workgroup_id) group: vec3u, @builtin(local_invocation_index) lane: u32) {
122
+ if (!${pg}_setup(&scene_database, folded_workgroup_index(group), lane)) { return; }
123
+ let slot = ${pg}_slot_in_page(lane);
124
+ if (slot >= ${pg}_ELEMENTS_PER_PAGE || !${pg}_is_occupied(slot)) { return; }
125
+ let body_row = ${pg}_slot_to_index(slot);
126
+ // a hidden body costs this thread: read what deciding takes, and the whole row only when its optics changed
127
+ if (${body('dirty')} != 0u) {
128
+ var body = ${bodies.marshalling_method_read_rw}(&scene_database, body_row);
129
+ body.backscattering = vec4f(water_medium_backscattering(body.medium), 0.0);
130
+ body.extinction = vec4f(body.medium.absorption + water_medium_scattering(body.medium), 0.0);
131
+ body.diffuse_transmittance = water_diffuse_fresnel_transmittance(body.ior);
132
+ body.dirty = 0u;
133
+ ${bodies.marshalling_method_write}(&scene_database, body_row, body);
134
+ }
135
+ let row = ${body('wave')};
136
+ let node = ${body('node')};
137
+ activity[row] = 0u;
138
+ if (node == 0u || node == ~0u) { return; }
139
+ let global = scene_read_node_rw(&scene_database, node).global;
140
+ if (abs(mat4_linear_determinant(global)) < 1e-20) { return; }
141
+ let scale = max(vec3<f32>(length(global[0].xyz), length(global[1].xyz), length(global[2].xyz)), vec3<f32>(1e-20));
142
+ let box = geometries[${body('geometry')}].bounding_box;
143
+
144
+ // weights, when the wind or the fetch they were derived for changed; none without wind
145
+ let wind = ${read('wind')};
146
+ let direction = wind.xy / max(length(wind.xy), 1e-20);
147
+ let fetch = water_waves_fetch(box, scale, direction, ${read('upwind_fetch')});
148
+ var weights: array<f32, WATER_SPECTRUM_BANDS>;
149
+ if (any(${read('derived_for')} != vec2<f32>(wind.z, fetch))) {
150
+ let derived = water_waves_derive(wind.z, fetch);
151
+ weights = derived.weights;
152
+ ${waves.marshalling_method_write_field('weights')}(&scene_database, row, weights);
153
+ ${waves.marshalling_method_write_field('slope_variance')}(&scene_database, row, derived.slope_variance);
154
+ ${waves.marshalling_method_write_field('derived_for')}(&scene_database, row, vec2<f32>(wind.z, fetch));
155
+ } else if (wind.z > 0.0) {
156
+ weights = ${read('weights')};
157
+ }
158
+
159
+ // the prior bound, metric; a steep body is kept calm
160
+ var vertical = 0.0;
161
+ var horizontal = 0.0;
162
+ let queued = min(${read('impulse_count')}, ${WATER_WAVE_IMPULSE_LIMIT}u);
163
+ if (steep[row] == 0u) {
164
+ var particles = 0.0;
165
+ let base = row * ${STRIDE}u;
166
+ if (particle_bounds[base] != 0u) {
167
+ for (var level = 0u; level < ${WATER_PARTICLE_LEVELS}u; level++) { particles += bitcast<f32>(particle_bounds[base + 1u + level]); }
168
+ }
169
+ if (queued > 0u) {
170
+ let impulses = ${read('impulses')};
171
+ for (var j = 0u; j < queued; j++) { particles += WATER_RING_BOUND * clamp(impulses[j].z, 1e-3, 16.0); }
172
+ }
173
+ var ambient = vec2<f32>(0.0);
174
+ if (wind.z > 0.0) { ambient = water_cull_ambient(weights, ${read('wind_blend')}); }
175
+ vertical = 2.0 * ambient.x + particles;
176
+ horizontal = 2.0 * ambient.y + particles;
177
+ }
178
+ var grown = box;
179
+ let up = vertical / scale.y;
180
+ let side = horizontal / min(scale.x, scale.z);
181
+ grown[1] -= up; grown[4] += up;
182
+ grown[0] -= side; grown[2] -= side; grown[3] += side; grown[5] += side;
183
+ let is_visible = aabb3_intersects_frustum(aabb3_project(array_to_aabb3(grown), global), camera.frustum);
184
+ let is_active = is_visible || ${read('simulate_hidden')} != 0u;
185
+
186
+ if (is_visible && wind.z > 0.0) {
187
+ // the bands this body can draw: waves longer than 8 of the finest cells it can be drawn with
188
+ let rest = aabb3_project(array_to_aabb3(box), global);
189
+ let eye = camera.view_matrix_inverse[3].xyz;
190
+ let nearest = length(max(max(rest.min - eye, eye - rest.max), vec3<f32>(0.0)));
191
+ let finest = 8.0 * water_lod_footprint_min(lod, nearest);
192
+ var mask = 0u;
193
+ for (var band = 0u; band < WATER_SPECTRUM_BANDS; band++) {
194
+ if (weights[band] > 0.0 && water_band_wavelength(band) > finest) { mask |= 1u << band; }
195
+ }
196
+ if (mask != 0u) { atomicOr(&band_requests.needed, mask); }
197
+ }
198
+ if (is_active) {
199
+ let turn = water_wind_turn(WaterWindTurn(${read('wind_from')}, ${read('wind_to')}, ${read('wind_blend')}),
200
+ direction, select(0.0, cull.dt, cull.stepping != 0u));
201
+ ${waves.marshalling_method_write_field('wind_from')}(&scene_database, row, turn.previous);
202
+ ${waves.marshalling_method_write_field('wind_to')}(&scene_database, row, turn.current);
203
+ ${waves.marshalling_method_write_field('wind_blend')}(&scene_database, row, turn.blend);
204
+ // this frame's binning rebuilds the bounds of the bodies it bins; a paused body keeps its own
205
+ if (cull.binning != 0u) {
206
+ for (var word = 0u; word < ${STRIDE}u; word++) { particle_bounds[row * ${STRIDE}u + word] = 0u; }
207
+ }
208
+ active_rows.elements[atomicAdd(&active_rows.count, 1u)] = row;
209
+ }
210
+ if (is_visible) { visible_rows.elements[atomicAdd(&visible_rows.count, 1u)] = body_row; }
211
+ if (cull.stepping != 0u && queued != 0u) { emit_rows.elements[atomicAdd(&emit_rows.count, 1u)] = row; }
212
+ activity[row] = select(0u, ${WaterActivity.Visible}u, is_visible) | select(0u, ${WaterActivity.Active}u, is_active);
213
+ }
214
+ `, [bodies.chunk_iterate(64, true), bodies.chunk_write, bodies.chunk_read_rw,
215
+ ...['dirty', 'wave', 'node', 'geometry'].map(field => bodies.chunk_read_field(field, true)), ...['wind', 'upwind_fetch', 'weights', 'derived_for', 'wind_blend',
216
+ 'impulses', 'impulse_count', 'simulate_hidden', 'wind_from', 'wind_to'].map(field => waves.chunk_read_field(field, true)),
217
+ ...['weights', 'slope_variance', 'derived_for', 'wind_from', 'wind_to', 'wind_blend'].map(field => waves.wgsl_gen_write_field_code(field)),
218
+ chunk_water_cull_bound, chunk_water_spectrum, chunk_water_waves_derive, chunk_water_lod, chunk_water_medium_derived,
219
+ chunk_water_medium_scattering, chunk_scene_database_access_rw, chunk_folded_workgroup_index, chunk_aabb3_project,
220
+ chunk_array_to_aabb3, chunk_aabb3_intersects_frustum, chunk_mat4_linear_determinant]) });
221
+
222
+ /** Commands the finalize pass writes, in order, 16 bytes apart. */
223
+ export const WaterSurfaceCommand = Object.freeze({
224
+ SpectrumRows: 0,
225
+ SpectrumColumns: 1,
226
+ Active: 2,
227
+ Emit: 3,
228
+ });
229
+ export const WATER_SURFACE_COMMAND_STRIDE = 16;
230
+ export const WATER_SURFACE_COMMAND_COUNT = 4;
231
+
232
+ const finalize_resources = new ShaderResourceSetDescriptor();
233
+ finalize_resources.setImmediate('frame', WebGPUStruct.from({ fresh: u32, seed: u32 }, 'WaterCullFinalize'));
234
+ finalize_resources.createGroup()
235
+ .addStorageBuffer('band_state', WATER_BAND_STATE_ATOMIC_STRUCT, true)
236
+ .addStorageBuffer('band_requests', WATER_BAND_REQUESTS_STRUCT, true)
237
+ .addStorageBuffer('active_rows', COLLECTION_U32_STRUCT_READ)
238
+ .addStorageBuffer('emit_rows', COLLECTION_U32_STRUCT_READ)
239
+ .addStorageBuffer('commands', WebGPUArray.u32, true);
240
+
241
+ /**
242
+ * After the culling pass: which bands this frame's spectrum evaluates — those the visible bodies can draw that do not
243
+ * already hold this time (all of them once, when a device's envelopes are seeded) — and the indirect commands for the
244
+ * spectrum and for the passes over the active and emit lists. Commands sit 16 bytes apart.
245
+ */
246
+ export const shader_water_cull_finalize = ComputeShader.from({ label: 'Water / cull finalize', resources: finalize_resources,
247
+ body: CodeChunk.from(/* language=WGSL */ `
248
+ // a dispatch of groups workgroups along x, at word index · ${WATER_SURFACE_COMMAND_STRIDE / 4}
249
+ fn water_command(index: u32, groups: u32) {
250
+ let at = index * ${WATER_SURFACE_COMMAND_STRIDE / 4}u;
251
+ commands[at] = groups;
252
+ commands[at + 1u] = 1u;
253
+ commands[at + 2u] = 1u;
254
+ }
255
+
256
+ @compute @workgroup_size(1)
257
+ fn main() {
258
+ let valid = select(atomicLoad(&band_state.valid), 0u, frame.fresh != 0u);
259
+ let needed = select(atomicExchange(&band_requests.needed, 0u), ${WATER_SPECTRUM_ALL_BANDS}u, frame.seed != 0u);
260
+ let todo = needed & ~valid;
261
+ atomicStore(&band_state.todo, todo);
262
+ atomicStore(&band_state.valid, valid | todo);
263
+ let bands = countOneBits(todo);
264
+ water_command(${WaterSurfaceCommand.SpectrumRows}u, bands * ${WATER_SPECTRUM_ROW_GROUPS_PER_BAND}u);
265
+ water_command(${WaterSurfaceCommand.SpectrumColumns}u, bands * ${WATER_SPECTRUM_COLUMN_GROUPS_PER_BAND}u);
266
+ water_command(${WaterSurfaceCommand.Active}u, (active_rows.count + ${WATER_CULL_WORKGROUP_SIZE - 1}u) / ${WATER_CULL_WORKGROUP_SIZE}u);
267
+ water_command(${WaterSurfaceCommand.Emit}u, (emit_rows.count + ${WATER_CULL_WORKGROUP_SIZE - 1}u) / ${WATER_CULL_WORKGROUP_SIZE}u);
268
+ }
269
+ `) });
@@ -0,0 +1,15 @@
1
+ /** Words a wave row owns in the particle bounds buffer: its occupied-level mask, then a bound per level. */
2
+ export const WATER_PARTICLE_BODY_BOUNDS_STRIDE: number;
3
+ /**
4
+ * The displacement bounds of each body simulated this frame (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §6), one
5
+ * thread a row of the culling pass's active list: the weighted sum of its bands' envelopes — each band's largest
6
+ * extremum at any time evaluated, so at least this frame's, since bilinear filtering cannot leave a tile's texel range —
7
+ * times sin + cos of a wind turn's blend while one is under way, plus the body's particle bounds, each a level's
8
+ * largest bound on Σ|a| over the cells the body occupies. Both bound height and horizontal displacement alike.
9
+ *
10
+ * The bounds only cull now, so they follow the waves as they are. A body the tessellation found steep (a waterfall)
11
+ * is kept calm: it is drawn as its authored triangles.
12
+ */
13
+ export const shader_water_waves_combine: ComputeShader;
14
+ import { ComputeShader } from "../../shader/ComputeShader.js";
15
+ //# sourceMappingURL=shader_water_waves_combine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_water_waves_combine.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/water/surface/shader_water_waves_combine.js"],"names":[],"mappings":"AAaA,4GAA4G;AAC5G,uDAA2E;AAY3E;;;;;;;;;GASG;AACH,uDAoCgG;8BAxElE,+BAA+B"}
@@ -0,0 +1,73 @@
1
+ import { ComputeShader } from "../../shader/ComputeShader.js";
2
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
3
+ import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
4
+ import { WebGPUArray } from "../../shader/type/WebGPUArray.js";
5
+ import { u32 } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
6
+ import { COLLECTION_U32_STRUCT_READ } from "../../gpu_primitive/COLLECTION_U32_STRUCT_READ.js";
7
+ import { chunk_folded_workgroup_index } from "../../shader/chunk/grid/chunk_folded_workgroup_index.js";
8
+ import { chunk_scene_database_access_rw } from "../../scene/chunk_scene_database_access.js";
9
+ import { WATER_WAVES_TABLE as table } from "../medium/chunk_water_bodies.js";
10
+ import { chunk_water_spectrum } from "./spectrum/chunk_water_spectrum.js";
11
+ import { WATER_BAND_STATE_STRUCT } from "./spectrum/WATER_BAND_STATE.js";
12
+ import { WATER_PARTICLE_LEVELS } from "./particles/chunk_water_particle.js";
13
+
14
+ /** Words a wave row owns in the particle bounds buffer: its occupied-level mask, then a bound per level. */
15
+ export const WATER_PARTICLE_BODY_BOUNDS_STRIDE = 1 + WATER_PARTICLE_LEVELS;
16
+
17
+ const resources = new ShaderResourceSetDescriptor();
18
+ resources.createGroup()
19
+ .addStorageBuffer('scene_database', WebGPUArray.u32, true)
20
+ .addStorageBuffer('active_rows', COLLECTION_U32_STRUCT_READ)
21
+ .addStorageBuffer('band_state', WATER_BAND_STATE_STRUCT)
22
+ .addStorageBuffer('particle_bounds', WebGPUArray.from(u32))
23
+ .addStorageBuffer('steep', WebGPUArray.from(u32));
24
+
25
+ const field = name => table.marshalling_method_read_field(name, true);
26
+
27
+ /**
28
+ * The displacement bounds of each body simulated this frame (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §6), one
29
+ * thread a row of the culling pass's active list: the weighted sum of its bands' envelopes — each band's largest
30
+ * extremum at any time evaluated, so at least this frame's, since bilinear filtering cannot leave a tile's texel range —
31
+ * times sin + cos of a wind turn's blend while one is under way, plus the body's particle bounds, each a level's
32
+ * largest bound on Σ|a| over the cells the body occupies. Both bound height and horizontal displacement alike.
33
+ *
34
+ * The bounds only cull now, so they follow the waves as they are. A body the tessellation found steep (a waterfall)
35
+ * is kept calm: it is drawn as its authored triangles.
36
+ */
37
+ export const shader_water_waves_combine = ComputeShader.from({ label: 'Water / waves combine', resources,
38
+ body: CodeChunk.from(/* language=WGSL */ `
39
+ @compute @workgroup_size(64)
40
+ fn main(@builtin(workgroup_id) group: vec3u, @builtin(local_invocation_index) lane: u32) {
41
+ let index = folded_workgroup_index(group) * 64u + lane;
42
+ if (index >= active_rows.count) { return; }
43
+ let row = active_rows.elements[index];
44
+ let node = ${field('node')}(&scene_database, row);
45
+ var bounds = vec4<f32>(0.0);
46
+ var levels = 0u;
47
+ if (node != 0u && node != ~0u && steep[row] == 0u) {
48
+ let global = scene_read_node_rw(&scene_database, node).global;
49
+ let scale = max(vec3<f32>(length(global[0].xyz), length(global[1].xyz), length(global[2].xyz)), vec3<f32>(1e-20));
50
+ let weights = ${field('weights')}(&scene_database, row);
51
+ var height = 0.0;
52
+ var horizontal = 0.0;
53
+ for (var band = 0u; band < WATER_SPECTRUM_BANDS; band++) {
54
+ height += weights[band] * bitcast<f32>(band_state.envelope[2u * band]);
55
+ horizontal += weights[band] * bitcast<f32>(band_state.envelope[2u * band + 1u]);
56
+ }
57
+ // during a turn of the wind two independent orientations show, weighted by the sine and cosine of the
58
+ // blend's quarter turn, and both can peak at one point
59
+ let blend = ${field('wind_blend')}(&scene_database, row);
60
+ let both = select(1.0, sin(1.57079633 * blend) + cos(1.57079633 * blend), blend < 1.0);
61
+ let base = row * ${WATER_PARTICLE_BODY_BOUNDS_STRIDE}u;
62
+ levels = particle_bounds[base];
63
+ var particles = 0.0;
64
+ for (var level = 0u; level < ${WATER_PARTICLE_LEVELS}u; level++) { particles += bitcast<f32>(particle_bounds[base + 1u + level]); }
65
+ let vertical = (both * height + particles) / scale.y;
66
+ bounds = vec4<f32>(-vertical, vertical, (both * horizontal + particles) / min(scale.x, scale.z), 0.0);
67
+ }
68
+ ${table.marshalling_method_write_field('displacement_bounds')}(&scene_database, row, bounds);
69
+ ${table.marshalling_method_write_field('particle_levels')}(&scene_database, row, levels);
70
+ }
71
+ `, [...['node', 'weights', 'wind_blend'].map(name => table.chunk_read_field(name, true)),
72
+ table.wgsl_gen_write_field_code('displacement_bounds'), table.wgsl_gen_write_field_code("particle_levels"),
73
+ chunk_scene_database_access_rw, chunk_water_spectrum, chunk_folded_workgroup_index]) });
@@ -0,0 +1,11 @@
1
+ /** Seconds a change of wind direction takes to turn the waves. */
2
+ export const WATER_WIND_TURN_SECONDS: 4;
3
+ /**
4
+ * A body's ambient waves from its wind and its fetch, as weights on the shared spectral bands
5
+ * (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §4.2).
6
+ *
7
+ * @type {CodeChunk}
8
+ */
9
+ export const chunk_water_waves_derive: CodeChunk;
10
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
11
+ //# sourceMappingURL=shader_water_waves_derive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_water_waves_derive.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/water/surface/shader_water_waves_derive.js"],"names":[],"mappings":"AAGA,kEAAkE;AAClE,wCAAyC;AAEzC;;;;;GAKG;AACH,uCAFU,SAAS,CAmEO;0BA7EA,oCAAoC"}
@@ -0,0 +1,78 @@
1
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
+ import { chunk_water_jonswap } from "./spectrum/chunk_water_jonswap.js";
3
+
4
+ /** Seconds a change of wind direction takes to turn the waves. */
5
+ export const WATER_WIND_TURN_SECONDS = 4;
6
+
7
+ /**
8
+ * A body's ambient waves from its wind and its fetch, as weights on the shared spectral bands
9
+ * (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §4.2).
10
+ *
11
+ * @type {CodeChunk}
12
+ */
13
+ export const chunk_water_waves_derive = CodeChunk.from(/* language=WGSL */ `
14
+ // How far the wind crosses the body along a unit direction of its metric local xz: the chord through the
15
+ // centre of the ellipse inscribed in its box, so a square does not gain fetch at 45° and a long narrow lake
16
+ // is long only along its length, plus the authored open water beyond it.
17
+ fn water_waves_fetch(box: array<f32, 6>, scale: vec3<f32>, direction: vec2<f32>, upwind: f32) -> f32 {
18
+ let semi = 0.5 * vec2<f32>(box[3] - box[0], box[5] - box[2]) * scale.xz;
19
+ // the point t·direction lies on the ellipse where t² ((dx / a)² + (dz / b)²) = 1
20
+ let crossing = length(semi.yx * direction);
21
+ let chord = select(0.0, 2.0 * semi.x * semi.y / crossing, crossing > 0.0);
22
+ return chord + max(upwind, 0.0);
23
+ }
24
+
25
+ struct WaterWavesDerived {
26
+ weights: array<f32, WATER_SPECTRUM_BANDS>,
27
+ slope_variance: f32,
28
+ }
29
+
30
+ // Each band's weight is the sea's saturation projected onto the band's hat, weighted as the band's height
31
+ // variance is (k⁻² per unit log k), so a body's variance in each octave is its spectrum's wherever the peak
32
+ // falls between nodes. Eight midpoint samples over the hat's two octaves.
33
+ fn water_waves_derive(wind_speed: f32, fetch: f32) -> WaterWavesDerived {
34
+ var derived: WaterWavesDerived;
35
+ if (!(wind_speed > 0.0) || !(fetch > 0.0)) { return derived; }
36
+ let sea = water_jonswap(wind_speed, fetch);
37
+ var slope = 0.0;
38
+ for (var band = 0u; band < WATER_SPECTRUM_BANDS; band++) {
39
+ let node = WATER_TAU / water_band_wavelength(band);
40
+ var projected = 0.0;
41
+ var norm = 0.0;
42
+ for (var i = 0u; i < 8u; i++) {
43
+ let u = -1.0 + (f32(i) + 0.5) * 0.25;
44
+ let weight = (1.0 - abs(u)) * exp2(-2.0 * u);
45
+ projected += weight * water_jonswap_saturation(sea, node * exp2(u));
46
+ norm += weight;
47
+ }
48
+ let saturation = projected / norm;
49
+ derived.weights[band] = sqrt(saturation);
50
+ // a band's unit-saturation slope variance is ∫ hat d(ln k) = ln 2
51
+ slope += saturation * 0.69314718;
52
+ }
53
+ derived.slope_variance = slope;
54
+ return derived;
55
+ }
56
+
57
+ struct WaterWindTurn {
58
+ previous: vec2<f32>,
59
+ current: vec2<f32>,
60
+ blend: f32,
61
+ }
62
+
63
+ // Follow the authored direction: a change starts a turn from the direction the waves show, which then advances
64
+ // by dt / ${WATER_WIND_TURN_SECONDS} s. A change during a turn waits for it to finish, so a wind that keeps turning
65
+ // is followed one turn behind, and an orientation only ever leaves the waves at no weight. A row seen for the
66
+ // first time starts settled.
67
+ fn water_wind_turn(last: WaterWindTurn, authored: vec2<f32>, dt: f32) -> WaterWindTurn {
68
+ var turn = last;
69
+ if (all(turn.current == vec2<f32>(0.0))) { return WaterWindTurn(authored, authored, 1.0); }
70
+ if (turn.blend >= 1.0 && dot(turn.current, authored) < 0.99999) {
71
+ turn.previous = turn.current;
72
+ turn.current = authored;
73
+ turn.blend = 0.0;
74
+ }
75
+ turn.blend = min(turn.blend + max(dt, 0.0) / ${WATER_WIND_TURN_SECONDS}.0, 1.0);
76
+ return turn;
77
+ }
78
+ `, [chunk_water_jonswap]);
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The shared ambient-wave basis on the device: the bands a frame asks for animated to the frame's time, as two
3
+ * `rgba16float` array textures (displacement and derivatives, one layer a band), and the band state — which bands
4
+ * hold which time, and each band's envelope (WATER_SURFACE_DISTANCE_LOD_PROPOSAL_2026_10_06.md §3.1).
5
+ * One instance serves every water body of a device; its cost is a band's worth of work for each band a body in
6
+ * view can draw, whatever the number of bodies.
7
+ */
8
+ export class GPUWaterSpectrum {
9
+ /** @returns {GPUTextureView} (Dx, h, Dz, ∂Dx/∂z) per band layer */
10
+ get displacement(): GPUTextureView;
11
+ /** @returns {GPUTextureView} (∂h/∂x, ∂h/∂z, ∂Dx/∂x, ∂Dz/∂z) per band layer */
12
+ get derivatives(): GPUTextureView;
13
+ /** @returns {GPUBuffer} {@link WATER_BAND_STATE_STRUCT}: band masks and envelopes */
14
+ get band_state(): GPUBuffer;
15
+ /** @returns {GPUBuffer} {@link WATER_BAND_REQUESTS_STRUCT}: the bands the frame's visible bodies ask for */
16
+ get band_requests(): GPUBuffer;
17
+ dispose(): void;
18
+ /**
19
+ * Allocate on first use for a device, so the views exist before the frame's passes bind them.
20
+ * @param {GPUDevice} device
21
+ */
22
+ prepare(device: GPUDevice): void;
23
+ /**
24
+ * Animate the bands in the band state's `todo` mask to `time` seconds, dispatched from the commands the culling
25
+ * pass's finalize wrote.
26
+ * @param {import("../../../../device/ShadeGPUCommandContext.js").ShadeGPUCommandContext} encoder
27
+ * @param {number} time
28
+ * @param {GPUBuffer} commands
29
+ * @param {number} rows_offset byte offset of the row pass's command
30
+ * @param {number} columns_offset byte offset of the column pass's command
31
+ */
32
+ encode(encoder: import("../../../../device/ShadeGPUCommandContext.js").ShadeGPUCommandContext, time: number, commands: GPUBuffer, rows_offset: number, columns_offset: number): void;
33
+ #private;
34
+ }
35
+ //# sourceMappingURL=GPUWaterSpectrum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GPUWaterSpectrum.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/water/surface/spectrum/GPUWaterSpectrum.js"],"names":[],"mappings":"AASA;;;;;;GAMG;AACH;IAWI,mEAAmE;IACnE,mCAAsD;IACtD,8EAA8E;IAC9E,kCAAoD;IACpD,qFAAqF;IACrF,4BAA6C;IAC7C,4GAA4G;IAC5G,+BAAmD;IA4BnD,gBASC;IAED;;;OAGG;IACH,iCAGC;IAED;;;;;;;;OAQG;IACH,gBANW,OAAO,8CAA8C,EAAE,sBAAsB,QAC7E,MAAM,oCAEN,MAAM,kBACN,MAAM,QAYhB;;CACJ"}
@@ -0,0 +1,103 @@
1
+ import { assert } from "../../../../../core/assert.js";
2
+ import {
3
+ shader_water_spectrum_columns,
4
+ shader_water_spectrum_rows,
5
+ WATER_SPECTRUM_ROW_VALUE_COUNT
6
+ } from "./shader_water_spectrum.js";
7
+ import { WATER_BAND_REQUESTS_STRUCT, WATER_BAND_STATE_STRUCT } from "./WATER_BAND_STATE.js";
8
+ import { WATER_SPECTRUM_BAND_COUNT, WATER_SPECTRUM_LOOP_SECONDS, WATER_SPECTRUM_TILE_SIZE } from "./WATER_SPECTRUM.js";
9
+
10
+ /**
11
+ * The shared ambient-wave basis on the device: the bands a frame asks for animated to the frame's time, as two
12
+ * `rgba16float` array textures (displacement and derivatives, one layer a band), and the band state — which bands
13
+ * hold which time, and each band's envelope (WATER_SURFACE_DISTANCE_LOD_PROPOSAL_2026_10_06.md §3.1).
14
+ * One instance serves every water body of a device; its cost is a band's worth of work for each band a body in
15
+ * view can draw, whatever the number of bodies.
16
+ */
17
+ export class GPUWaterSpectrum {
18
+ #device = null;
19
+ #rows = null;
20
+ #displacement = null;
21
+ #derivatives = null;
22
+ #displacement_view = null;
23
+ #derivatives_view = null;
24
+ #storage_views = null;
25
+ #band_state = null;
26
+ #band_requests = null;
27
+
28
+ /** @returns {GPUTextureView} (Dx, h, Dz, ∂Dx/∂z) per band layer */
29
+ get displacement() { return this.#displacement_view; }
30
+ /** @returns {GPUTextureView} (∂h/∂x, ∂h/∂z, ∂Dx/∂x, ∂Dz/∂z) per band layer */
31
+ get derivatives() { return this.#derivatives_view; }
32
+ /** @returns {GPUBuffer} {@link WATER_BAND_STATE_STRUCT}: band masks and envelopes */
33
+ get band_state() { return this.#band_state; }
34
+ /** @returns {GPUBuffer} {@link WATER_BAND_REQUESTS_STRUCT}: the bands the frame's visible bodies ask for */
35
+ get band_requests() { return this.#band_requests; }
36
+
37
+ /**
38
+ * @param {GPUDevice} device
39
+ */
40
+ #allocate(device) {
41
+ if (this.#device === device) { return; }
42
+ this.dispose();
43
+ this.#device = device;
44
+ this.#rows = device.createBuffer({ label: 'Water / spectrum rows', size: WATER_SPECTRUM_ROW_VALUE_COUNT * 16,
45
+ usage: GPUBufferUsage.STORAGE });
46
+ const texture = label => device.createTexture({ label,
47
+ size: [WATER_SPECTRUM_TILE_SIZE, WATER_SPECTRUM_TILE_SIZE, WATER_SPECTRUM_BAND_COUNT],
48
+ format: 'rgba16float', dimension: '2d',
49
+ usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING });
50
+ this.#displacement = texture('Water / spectrum displacement');
51
+ this.#derivatives = texture('Water / spectrum derivatives');
52
+ this.#displacement_view = this.#displacement.createView({ dimension: '2d-array' });
53
+ this.#derivatives_view = this.#derivatives.createView({ dimension: '2d-array' });
54
+ this.#storage_views = [this.#displacement.createView({ dimension: '2d-array' }),
55
+ this.#derivatives.createView({ dimension: '2d-array' })];
56
+ // zero on creation: no band valid, no envelope yet
57
+ this.#band_state = device.createBuffer({ label: 'Water / spectrum band state', size: WATER_BAND_STATE_STRUCT.size,
58
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC });
59
+ this.#band_requests = device.createBuffer({ label: 'Water / spectrum band requests', size: WATER_BAND_REQUESTS_STRUCT.size,
60
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST });
61
+ }
62
+
63
+ dispose() {
64
+ this.#rows?.destroy();
65
+ this.#displacement?.destroy();
66
+ this.#derivatives?.destroy();
67
+ this.#band_state?.destroy();
68
+ this.#band_requests?.destroy();
69
+ this.#device = null;
70
+ this.#rows = this.#displacement = this.#derivatives = this.#band_state = this.#band_requests = null;
71
+ this.#displacement_view = this.#derivatives_view = this.#storage_views = null;
72
+ }
73
+
74
+ /**
75
+ * Allocate on first use for a device, so the views exist before the frame's passes bind them.
76
+ * @param {GPUDevice} device
77
+ */
78
+ prepare(device) {
79
+ assert.defined(device, 'device');
80
+ this.#allocate(device);
81
+ }
82
+
83
+ /**
84
+ * Animate the bands in the band state's `todo` mask to `time` seconds, dispatched from the commands the culling
85
+ * pass's finalize wrote.
86
+ * @param {import("../../../../device/ShadeGPUCommandContext.js").ShadeGPUCommandContext} encoder
87
+ * @param {number} time
88
+ * @param {GPUBuffer} commands
89
+ * @param {number} rows_offset byte offset of the row pass's command
90
+ * @param {number} columns_offset byte offset of the column pass's command
91
+ */
92
+ encode(encoder, time, commands, rows_offset, columns_offset) {
93
+ assert.isFinite(time, 'time');
94
+ assert.notNull(this.#device, 'prepare() first');
95
+ // the phase is taken from the time within the loop, so f32 keeps it exact however long the run
96
+ const loop_fraction = (time % WATER_SPECTRUM_LOOP_SECONDS) / WATER_SPECTRUM_LOOP_SECONDS;
97
+ const rows = this.#rows, band_state = this.#band_state;
98
+ shader_water_spectrum_rows.dispatchIndirect({ encoder, command: commands, command_offset: rows_offset,
99
+ bindings: { rows, loop_fraction, band_state } });
100
+ shader_water_spectrum_columns.dispatchIndirect({ encoder, command: commands, command_offset: columns_offset,
101
+ bindings: { rows, displacement: this.#storage_views[0], derivatives: this.#storage_views[1], band_state } });
102
+ }
103
+ }