@woosh/meep-engine 3.39.0 → 3.41.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 (561) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/geom/3d/quaternion/swing_twist_clamp.d.ts +24 -0
  4. package/src/core/geom/3d/quaternion/swing_twist_clamp.d.ts.map +1 -0
  5. package/src/core/geom/3d/quaternion/swing_twist_clamp.js +62 -0
  6. package/src/core/geom/3d/quaternion/swing_twist_compose.d.ts +15 -0
  7. package/src/core/geom/3d/quaternion/swing_twist_compose.d.ts.map +1 -0
  8. package/src/core/geom/3d/quaternion/swing_twist_compose.js +36 -0
  9. package/src/core/geom/3d/quaternion/swing_twist_error.d.ts +39 -0
  10. package/src/core/geom/3d/quaternion/swing_twist_error.d.ts.map +1 -0
  11. package/src/core/geom/3d/quaternion/swing_twist_error.js +85 -0
  12. package/src/core/geom/vec3/v3_rigid_align_paired_unit_vectors.d.ts +11 -6
  13. package/src/core/geom/vec3/v3_rigid_align_paired_unit_vectors.d.ts.map +1 -1
  14. package/src/core/geom/vec3/v3_rigid_align_paired_unit_vectors.js +27 -13
  15. package/src/core/math/linalg/eigen/matrix_symmetric_4x4_eigen.d.ts +25 -0
  16. package/src/core/math/linalg/eigen/matrix_symmetric_4x4_eigen.d.ts.map +1 -0
  17. package/src/core/math/linalg/eigen/matrix_symmetric_4x4_eigen.js +166 -0
  18. package/src/core/math/linalg/eigen/matrix_top_eigenvector_power_iteration.d.ts +5 -3
  19. package/src/core/math/linalg/eigen/matrix_top_eigenvector_power_iteration.d.ts.map +1 -1
  20. package/src/core/math/linalg/eigen/matrix_top_eigenvector_power_iteration.js +5 -3
  21. package/src/engine/EngineHarness.d.ts.map +1 -1
  22. package/src/engine/EngineHarness.js +17 -4
  23. package/src/engine/animation/curve/AnimationCurve.d.ts +3 -0
  24. package/src/engine/animation/curve/AnimationCurve.d.ts.map +1 -1
  25. package/src/engine/animation/curve/AnimationCurve.js +6 -1
  26. package/src/engine/asset/loaders/image/avif/threaded_image_encoder.js +1 -1
  27. package/src/engine/ecs/EntityManager.d.ts +9 -1
  28. package/src/engine/ecs/EntityManager.d.ts.map +1 -1
  29. package/src/engine/ecs/EntityManager.js +26 -27
  30. package/src/engine/ecs/gpu/GPUStateAuthority.d.ts +20 -0
  31. package/src/engine/ecs/gpu/GPUStateAuthority.d.ts.map +1 -1
  32. package/src/engine/ecs/gpu/GPUStateAuthority.js +21 -0
  33. package/src/engine/ecs/gpu/GPU_AUTHORITY_EVENT_HOLD_CHANGE.d.ts +13 -0
  34. package/src/engine/ecs/gpu/GPU_AUTHORITY_EVENT_HOLD_CHANGE.d.ts.map +1 -0
  35. package/src/engine/ecs/gpu/GPU_AUTHORITY_EVENT_HOLD_CHANGE.js +12 -0
  36. package/src/engine/ecs/gpu/gpu_authority_grant.d.ts +6 -0
  37. package/src/engine/ecs/gpu/gpu_authority_grant.d.ts.map +1 -1
  38. package/src/engine/ecs/gpu/gpu_authority_grant.js +7 -1
  39. package/src/engine/ecs/gpu/gpu_authority_held.d.ts +14 -0
  40. package/src/engine/ecs/gpu/gpu_authority_held.d.ts.map +1 -0
  41. package/src/engine/ecs/gpu/gpu_authority_held.js +23 -0
  42. package/src/engine/ecs/gpu/gpu_authority_hold.d.ts +23 -0
  43. package/src/engine/ecs/gpu/gpu_authority_hold.d.ts.map +1 -0
  44. package/src/engine/ecs/gpu/gpu_authority_hold.js +41 -0
  45. package/src/engine/ecs/gpu/gpu_authority_unhold.d.ts +14 -0
  46. package/src/engine/ecs/gpu/gpu_authority_unhold.d.ts.map +1 -0
  47. package/src/engine/ecs/gpu/gpu_authority_unhold.js +32 -0
  48. package/src/engine/ecs/ik/IKGoal.d.ts +59 -0
  49. package/src/engine/ecs/ik/IKGoal.d.ts.map +1 -0
  50. package/src/engine/ecs/ik/IKGoal.js +83 -0
  51. package/src/engine/ecs/ik/IKGoalSystem.d.ts +75 -0
  52. package/src/engine/ecs/ik/IKGoalSystem.d.ts.map +1 -0
  53. package/src/engine/ecs/ik/IKGoalSystem.js +1456 -0
  54. package/src/engine/ecs/ik/PLAN.md +179 -0
  55. package/src/engine/ecs/speaker/VoiceSystem.d.ts +2 -2
  56. package/src/engine/ecs/speaker/VoiceSystem.d.ts.map +1 -1
  57. package/src/engine/ecs/storage/BinaryBufferSerializer.d.ts.map +1 -1
  58. package/src/engine/ecs/storage/BinaryBufferSerializer.js +4 -5
  59. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +7 -3
  60. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  61. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +5 -2
  62. package/src/engine/ecs/system/orderSystemsByDeclaredAccess.d.ts +33 -0
  63. package/src/engine/ecs/system/orderSystemsByDeclaredAccess.d.ts.map +1 -0
  64. package/src/engine/ecs/system/orderSystemsByDeclaredAccess.js +282 -0
  65. package/src/engine/ecs/transform/T64WorldCache.js +139 -139
  66. package/src/engine/ecs/transform/t64_evaluate_local.d.ts +25 -0
  67. package/src/engine/ecs/transform/t64_evaluate_local.d.ts.map +1 -0
  68. package/src/engine/ecs/transform/t64_evaluate_local.js +35 -0
  69. package/src/engine/ecs/transform/t64_evaluate_world.d.ts +5 -3
  70. package/src/engine/ecs/transform/t64_evaluate_world.d.ts.map +1 -1
  71. package/src/engine/ecs/transform/t64_evaluate_world.js +128 -126
  72. package/src/engine/graphics/ecs/water/Water.d.ts +14 -17
  73. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  74. package/src/engine/graphics/ecs/water/Water.js +100 -110
  75. package/src/engine/graphics/ecs/water/WaterSerializationAdapter.d.ts.map +1 -1
  76. package/src/engine/graphics/ecs/water/WaterSerializationAdapter.js +36 -38
  77. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_3_4.d.ts +6 -0
  78. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_3_4.d.ts.map +1 -0
  79. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_3_4.js +10 -0
  80. package/src/engine/graphics/ecs/water/WaterWaves.d.ts +3 -3
  81. package/src/engine/graphics/ecs/water/WaterWaves.js +46 -46
  82. package/src/engine/graphics/texture/sampler/sampler2d_to_avif.d.ts.map +1 -1
  83. package/src/engine/graphics/texture/sampler/sampler2d_to_avif.js +8 -5
  84. package/src/engine/graphics3/AnimationGraphSystem.d.ts +2 -0
  85. package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
  86. package/src/engine/graphics3/AnimationGraphSystem.js +337 -329
  87. package/src/engine/graphics3/AnimationSystem.d.ts +2 -0
  88. package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
  89. package/src/engine/graphics3/AnimationSystem.js +360 -352
  90. package/src/engine/graphics3/WaterSystem.d.ts +21 -74
  91. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  92. package/src/engine/graphics3/WaterSystem.js +174 -367
  93. package/src/engine/physics/cloth/MEASUREMENTS.md +130 -0
  94. package/src/engine/physics/cloth/PLAN.md +16 -1
  95. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +5 -6
  96. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -1
  97. package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +5 -6
  98. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +4 -7
  99. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  100. package/src/engine/physics/cloth/ecs/ClothInstance.js +4 -7
  101. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +4 -3
  102. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  103. package/src/engine/physics/cloth/ecs/ClothSystem.js +4 -3
  104. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  105. package/src/engine/physics/cloth/ecs/ClothWorld.js +10 -0
  106. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +24 -24
  107. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  108. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +46 -43
  109. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +1 -1
  110. package/src/engine/physics/cloth/ecs/cloth_write_back.js +1 -1
  111. package/src/engine/physics/constraint/solve_constraints.d.ts +0 -35
  112. package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
  113. package/src/engine/physics/constraint/solve_constraints.js +1 -83
  114. package/src/engine/physics/ecs/ContactProbe.d.ts +73 -0
  115. package/src/engine/physics/ecs/ContactProbe.d.ts.map +1 -0
  116. package/src/engine/physics/ecs/ContactProbe.js +103 -0
  117. package/src/engine/physics/ecs/ContactProbeSystem.d.ts +44 -0
  118. package/src/engine/physics/ecs/ContactProbeSystem.d.ts.map +1 -0
  119. package/src/engine/physics/ecs/ContactProbeSystem.js +397 -0
  120. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +1 -1
  121. package/src/engine/physics/fluid/ecs/FluidComponent.js +1 -1
  122. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  123. package/src/engine/physics/inverse_kinematics/frame_fabrik/FrameFabrikProblem.d.ts +205 -0
  124. package/src/engine/physics/inverse_kinematics/frame_fabrik/FrameFabrikProblem.d.ts.map +1 -0
  125. package/src/engine/physics/inverse_kinematics/frame_fabrik/FrameFabrikProblem.js +245 -0
  126. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_limit_from_joint.d.ts +21 -0
  127. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_limit_from_joint.d.ts.map +1 -0
  128. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_limit_from_joint.js +63 -0
  129. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.d.ts +33 -0
  130. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.d.ts.map +1 -0
  131. package/src/engine/physics/inverse_kinematics/frame_fabrik/frame_fabrik_solve.js +874 -0
  132. package/src/engine/physics/inverse_kinematics/joint_hinge_mid_axis.d.ts +27 -0
  133. package/src/engine/physics/inverse_kinematics/joint_hinge_mid_axis.d.ts.map +1 -0
  134. package/src/engine/physics/inverse_kinematics/joint_hinge_mid_axis.js +77 -0
  135. package/src/engine/physics/inverse_kinematics/two_bone_path_solve.d.ts +36 -0
  136. package/src/engine/physics/inverse_kinematics/two_bone_path_solve.d.ts.map +1 -0
  137. package/src/engine/physics/inverse_kinematics/two_bone_path_solve.js +97 -0
  138. package/src/engine/physics/inverse_kinematics/two_joint_ik.d.ts +33 -11
  139. package/src/engine/physics/inverse_kinematics/two_joint_ik.d.ts.map +1 -1
  140. package/src/engine/physics/inverse_kinematics/two_joint_ik.js +158 -67
  141. package/src/format/image/avif/api/convert_to_rgba.d.ts +2 -2
  142. package/src/format/image/avif/api/convert_to_rgba.d.ts.map +1 -1
  143. package/src/format/image/avif/api/convert_to_rgba.js +10 -9
  144. package/src/format/image/avif/api/decode_avif.d.ts +2 -2
  145. package/src/format/image/avif/api/decode_avif.d.ts.map +1 -1
  146. package/src/format/image/avif/api/decode_avif.js +1 -1
  147. package/src/shade/playground/ssr_reprojection/README.md +111 -103
  148. package/src/shade/playground/ssr_reprojection/SpatialFilterProbe.js +68 -68
  149. package/src/shade/playground/ssr_reprojection/index.html +80 -79
  150. package/src/shade/playground/ssr_reprojection/main.js +256 -247
  151. package/src/shade/playground/ssr_variance/capture.js +96 -96
  152. package/src/shade/playground/ssr_variance/reference.js +78 -78
  153. package/src/shade/playground/vsm/README.md +96 -0
  154. package/src/shade/playground/vsm/VSMDebugOverlay.d.ts +49 -0
  155. package/src/shade/playground/vsm/VSMDebugOverlay.d.ts.map +1 -0
  156. package/src/shade/playground/vsm/VSMDebugOverlay.js +351 -0
  157. package/src/shade/playground/vsm/clipmap_panel.d.ts +8 -0
  158. package/src/shade/playground/vsm/clipmap_panel.d.ts.map +1 -0
  159. package/src/shade/playground/vsm/clipmap_panel.js +138 -0
  160. package/src/shade/playground/vsm/index.html +170 -0
  161. package/src/shade/playground/vsm/main.d.ts +2 -0
  162. package/src/shade/playground/vsm/main.d.ts.map +1 -0
  163. package/src/shade/playground/vsm/main.js +389 -0
  164. package/src/shade/playground/vsm/scenes.d.ts +52 -0
  165. package/src/shade/playground/vsm/scenes.d.ts.map +1 -0
  166. package/src/shade/playground/vsm/scenes.js +320 -0
  167. package/src/shade/playground/vsm/verify_vsm.d.ts +38 -0
  168. package/src/shade/playground/vsm/verify_vsm.d.ts.map +1 -0
  169. package/src/shade/playground/vsm/verify_vsm.js +305 -0
  170. package/src/shade/playground/water_refraction/README.md +57 -9
  171. package/src/shade/playground/water_refraction/main.js +12 -3
  172. package/src/shade/playground/water_refraction/world.d.ts +1 -0
  173. package/src/shade/playground/water_refraction/world.d.ts.map +1 -1
  174. package/src/shade/playground/water_refraction/world.js +15 -5
  175. package/src/shade/renderer/Renderer.d.ts +19 -0
  176. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  177. package/src/shade/renderer/Renderer.js +72 -1
  178. package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.d.ts.map +1 -1
  179. package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.js +10 -1
  180. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +18 -4
  181. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  182. package/src/shade/renderer/animation/GPUAnimationManager.js +269 -23
  183. package/src/shade/renderer/animation/POSE_ACCUMULATOR_LAYOUT.d.ts +12 -4
  184. package/src/shade/renderer/animation/POSE_ACCUMULATOR_LAYOUT.d.ts.map +1 -1
  185. package/src/shade/renderer/animation/POSE_ACCUMULATOR_LAYOUT.js +12 -4
  186. package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts.map +1 -1
  187. package/src/shade/renderer/animation/chunk_pose_accumulator.js +14 -1
  188. package/src/shade/renderer/animation/pose/PoseChannelIndex.d.ts +78 -0
  189. package/src/shade/renderer/animation/pose/PoseChannelIndex.d.ts.map +1 -0
  190. package/src/shade/renderer/animation/pose/PoseChannelIndex.js +274 -0
  191. package/src/shade/renderer/animation/pose/PosePlayback.d.ts +40 -3
  192. package/src/shade/renderer/animation/pose/PosePlayback.d.ts.map +1 -1
  193. package/src/shade/renderer/animation/pose/PosePlayback.js +77 -3
  194. package/src/shade/renderer/animation/pose/pose_evaluate_local.d.ts +21 -3
  195. package/src/shade/renderer/animation/pose/pose_evaluate_local.d.ts.map +1 -1
  196. package/src/shade/renderer/animation/pose/pose_evaluate_local.js +79 -11
  197. package/src/shade/renderer/animation/shader_animation_apply.js +1 -1
  198. package/src/shade/renderer/animation/shader_animation_pose_resolve.d.ts +3 -2
  199. package/src/shade/renderer/animation/shader_animation_pose_resolve.d.ts.map +1 -1
  200. package/src/shade/renderer/animation/shader_animation_pose_resolve.js +187 -176
  201. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +7 -0
  202. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  203. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +11 -0
  204. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts +3 -1
  205. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts.map +1 -1
  206. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.js +10 -1
  207. package/src/shade/renderer/buffer/table/serde/table_wgsl_gen_read_code.d.ts.map +1 -1
  208. package/src/shade/renderer/buffer/table/serde/table_wgsl_gen_read_code.js +28 -0
  209. package/src/shade/renderer/buffer/table/serde/table_wgsl_gen_write_code.d.ts.map +1 -1
  210. package/src/shade/renderer/buffer/table/serde/table_wgsl_gen_write_code.js +31 -1
  211. package/src/shade/renderer/geometry/MeshletGeometry.d.ts +3 -0
  212. package/src/shade/renderer/geometry/MeshletGeometry.d.ts.map +1 -1
  213. package/src/shade/renderer/geometry/MeshletGeometry.js +1 -0
  214. package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.d.ts.map +1 -1
  215. package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.js +62 -4
  216. package/src/shade/renderer/light/environment/rgbe/parse_rgbe.d.ts +1 -1
  217. package/src/shade/renderer/light/environment/rgbe/parse_rgbe.js +2 -2
  218. package/src/shade/renderer/light/environment/rgbe/rgbe_byte_to_rgb_half.d.ts +2 -2
  219. package/src/shade/renderer/light/environment/rgbe/rgbe_byte_to_rgb_half.d.ts.map +1 -1
  220. package/src/shade/renderer/light/environment/rgbe/rgbe_byte_to_rgb_half.js +6 -14
  221. package/src/shade/renderer/light/environment/sh_exponential/chunk_sh_exp_workgroup_sum.d.ts.map +1 -1
  222. package/src/shade/renderer/light/environment/sh_exponential/chunk_sh_exp_workgroup_sum.js +5 -1
  223. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  224. package/src/shade/renderer/medium/ParticipatingMedium.d.ts +3 -0
  225. package/src/shade/renderer/medium/ParticipatingMedium.d.ts.map +1 -1
  226. package/src/shade/renderer/medium/ParticipatingMedium.js +7 -0
  227. package/src/shade/renderer/object_property/chunk_write_object_property.d.ts +3 -1
  228. package/src/shade/renderer/object_property/chunk_write_object_property.d.ts.map +1 -1
  229. package/src/shade/renderer/object_property/chunk_write_object_property.js +5 -2
  230. package/src/shade/renderer/object_property/chunk_write_object_property_node3d.d.ts +4 -0
  231. package/src/shade/renderer/object_property/chunk_write_object_property_node3d.d.ts.map +1 -1
  232. package/src/shade/renderer/object_property/chunk_write_object_property_node3d.js +6 -1
  233. package/src/shade/renderer/postprocess/eye/shader_autoexposure_build_histogram.d.ts.map +1 -1
  234. package/src/shade/renderer/postprocess/eye/shader_autoexposure_build_histogram.js +5 -35
  235. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  236. package/src/shade/renderer/postprocess/ssr/SSR.d.ts +12 -4
  237. package/src/shade/renderer/postprocess/ssr/SSR.d.ts.map +1 -1
  238. package/src/shade/renderer/postprocess/ssr/SSR.js +36 -8
  239. package/src/shade/renderer/postprocess/ssr/SSR_DENOISE_TILE_SIZE.d.ts +3 -0
  240. package/src/shade/renderer/postprocess/ssr/SSR_DENOISE_TILE_SIZE.d.ts.map +1 -0
  241. package/src/shade/renderer/postprocess/ssr/SSR_DENOISE_TILE_SIZE.js +2 -0
  242. package/src/shade/renderer/postprocess/ssr/chunk_ssr_denoise_tile_active.d.ts +8 -0
  243. package/src/shade/renderer/postprocess/ssr/chunk_ssr_denoise_tile_active.d.ts.map +1 -0
  244. package/src/shade/renderer/postprocess/ssr/chunk_ssr_denoise_tile_active.js +40 -0
  245. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
  246. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +150 -137
  247. package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_classify.d.ts +3 -0
  248. package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_classify.d.ts.map +1 -0
  249. package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_classify.js +44 -0
  250. package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_dilate.d.ts +5 -0
  251. package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_dilate.d.ts.map +1 -0
  252. package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_dilate.js +35 -0
  253. package/src/shade/renderer/postprocess/ssr/ssr_graph_denoise_tiles.d.ts +26 -0
  254. package/src/shade/renderer/postprocess/ssr/ssr_graph_denoise_tiles.d.ts.map +1 -0
  255. package/src/shade/renderer/postprocess/ssr/ssr_graph_denoise_tiles.js +42 -0
  256. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts +1 -0
  257. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts.map +1 -1
  258. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.js +113 -105
  259. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts +2 -0
  260. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
  261. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +177 -167
  262. package/src/shade/renderer/rasterize/DEPTH_STENCIL_STATE_SHADOW.d.ts.map +1 -1
  263. package/src/shade/renderer/rasterize/DEPTH_STENCIL_STATE_SHADOW.js +10 -0
  264. package/src/shade/renderer/rasterize/RasterizationJob.d.ts +1 -2
  265. package/src/shade/renderer/rasterize/RasterizationJob.d.ts.map +1 -1
  266. package/src/shade/renderer/rasterize/RasterizationJob.js +1 -2
  267. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts +5 -6
  268. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts.map +1 -1
  269. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.js +5 -6
  270. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +2 -2
  271. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  272. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +1 -1
  273. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.d.ts.map +1 -1
  274. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +11 -0
  275. package/src/shade/renderer/scene/optimization/geometry/geometry_deduplicate.d.ts +1 -1
  276. package/src/shade/renderer/scene/optimization/geometry/geometry_deduplicate.d.ts.map +1 -1
  277. package/src/shade/renderer/scene/optimization/geometry/geometry_deduplicate.js +135 -73
  278. package/src/shade/renderer/scene/optimization/geometry/internal/cover_greedy.d.ts +7 -0
  279. package/src/shade/renderer/scene/optimization/geometry/internal/cover_greedy.d.ts.map +1 -1
  280. package/src/shade/renderer/scene/optimization/geometry/internal/cover_greedy.js +29 -1
  281. package/src/shade/renderer/scene/optimization/geometry/internal/face_neighbourhood_hash.d.ts +19 -0
  282. package/src/shade/renderer/scene/optimization/geometry/internal/face_neighbourhood_hash.d.ts.map +1 -0
  283. package/src/shade/renderer/scene/optimization/geometry/internal/face_neighbourhood_hash.js +167 -0
  284. package/src/shade/renderer/scene/optimization/geometry/internal/neighbourhood_anchor_index.d.ts +25 -0
  285. package/src/shade/renderer/scene/optimization/geometry/internal/neighbourhood_anchor_index.d.ts.map +1 -0
  286. package/src/shade/renderer/scene/optimization/geometry/internal/neighbourhood_anchor_index.js +124 -0
  287. package/src/shade/renderer/scene/optimization/geometry/internal/seed_correspondence_from_face_pair.d.ts +19 -0
  288. package/src/shade/renderer/scene/optimization/geometry/internal/seed_correspondence_from_face_pair.d.ts.map +1 -0
  289. package/src/shade/renderer/scene/optimization/geometry/internal/seed_correspondence_from_face_pair.js +48 -0
  290. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts +17 -1
  291. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
  292. package/src/shade/renderer/scene/rows/GPUSceneRows.js +29 -3
  293. package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/build_lut_fog_parameters_jendersie_deon.d.ts.map +1 -1
  294. package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/build_lut_fog_parameters_jendersie_deon.js +4 -5
  295. package/src/shade/renderer/shader/chunk/brdf/dfg/generate_dfg_texture.d.ts.map +1 -1
  296. package/src/shade/renderer/shader/chunk/brdf/dfg/generate_dfg_texture.js +1 -5
  297. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_importance.d.ts +30 -0
  298. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_importance.d.ts.map +1 -0
  299. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_importance.js +54 -0
  300. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.d.ts.map +1 -1
  301. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.js +3 -2
  302. package/src/shade/renderer/shadow/map/DIRECTIONAL_SHADOWMAP_STRUCT.d.ts +19 -0
  303. package/src/shade/renderer/shadow/map/DIRECTIONAL_SHADOWMAP_STRUCT.d.ts.map +1 -0
  304. package/src/shade/renderer/shadow/map/DIRECTIONAL_SHADOWMAP_STRUCT.js +27 -0
  305. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts +1 -0
  306. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts.map +1 -1
  307. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +4 -0
  308. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts +54 -0
  309. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  310. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +502 -10
  311. package/src/shade/renderer/shadow/map/Shadowmap.d.ts +3 -2
  312. package/src/shade/renderer/shadow/map/Shadowmap.d.ts.map +1 -1
  313. package/src/shade/renderer/shadow/map/Shadowmap.js +3 -2
  314. package/src/shade/renderer/shadow/map/shader/chunk_sample_shadowmap_atlas_for_light.d.ts +8 -0
  315. package/src/shade/renderer/shadow/map/shader/chunk_sample_shadowmap_atlas_for_light.d.ts.map +1 -1
  316. package/src/shade/renderer/shadow/map/shader/chunk_sample_shadowmap_atlas_for_light.js +34 -3
  317. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.d.ts +3 -2
  318. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.d.ts.map +1 -1
  319. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.js +17 -2
  320. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_point2.d.ts.map +1 -1
  321. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_point2.js +137 -133
  322. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_FIRST_TEXEL_SIZE.d.ts +15 -0
  323. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_FIRST_TEXEL_SIZE.d.ts.map +1 -0
  324. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_FIRST_TEXEL_SIZE.js +14 -0
  325. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_PAGE_BUDGET.d.ts +16 -0
  326. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_PAGE_BUDGET.d.ts.map +1 -0
  327. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_PAGE_BUDGET.js +15 -0
  328. package/src/shade/renderer/shadow/vsm/PLAN.md +440 -0
  329. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +43 -0
  330. package/src/shade/renderer/shadow/vsm/VSMMoverTracker.d.ts +42 -0
  331. package/src/shade/renderer/shadow/vsm/VSMMoverTracker.d.ts.map +1 -0
  332. package/src/shade/renderer/shadow/vsm/VSMMoverTracker.js +153 -0
  333. package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts +327 -0
  334. package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts.map +1 -0
  335. package/src/shade/renderer/shadow/vsm/VSMPageManager.js +1408 -0
  336. package/src/shade/renderer/shadow/vsm/VSM_COVER_LEVEL_STEP.d.ts +14 -0
  337. package/src/shade/renderer/shadow/vsm/VSM_COVER_LEVEL_STEP.d.ts.map +1 -0
  338. package/src/shade/renderer/shadow/vsm/VSM_COVER_LEVEL_STEP.js +13 -0
  339. package/src/shade/renderer/shadow/vsm/VSM_FEEDBACK_LAYOUT.d.ts +63 -0
  340. package/src/shade/renderer/shadow/vsm/VSM_FEEDBACK_LAYOUT.d.ts.map +1 -0
  341. package/src/shade/renderer/shadow/vsm/VSM_FEEDBACK_LAYOUT.js +70 -0
  342. package/src/shade/renderer/shadow/vsm/VSM_LEVEL_LIMIT.d.ts +11 -0
  343. package/src/shade/renderer/shadow/vsm/VSM_LEVEL_LIMIT.d.ts.map +1 -0
  344. package/src/shade/renderer/shadow/vsm/VSM_LEVEL_LIMIT.js +10 -0
  345. package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.d.ts +54 -0
  346. package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.d.ts.map +1 -0
  347. package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.js +75 -0
  348. package/src/shade/renderer/shadow/vsm/VSM_RECORD_STRUCT.d.ts +23 -0
  349. package/src/shade/renderer/shadow/vsm/VSM_RECORD_STRUCT.d.ts.map +1 -0
  350. package/src/shade/renderer/shadow/vsm/VSM_RECORD_STRUCT.js +85 -0
  351. package/src/shade/renderer/shadow/vsm/VSM_SLOT_STRUCT.d.ts +16 -0
  352. package/src/shade/renderer/shadow/vsm/VSM_SLOT_STRUCT.d.ts.map +1 -0
  353. package/src/shade/renderer/shadow/vsm/VSM_SLOT_STRUCT.js +29 -0
  354. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts +136 -25
  355. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts.map +1 -1
  356. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.js +282 -116
  357. package/src/shade/renderer/shadow/vsm/graph_vsm_feedback.d.ts +39 -0
  358. package/src/shade/renderer/shadow/vsm/graph_vsm_feedback.d.ts.map +1 -0
  359. package/src/shade/renderer/shadow/vsm/graph_vsm_feedback.js +289 -0
  360. package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_virtual.d.ts +18 -0
  361. package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_virtual.d.ts.map +1 -0
  362. package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_virtual.js +65 -0
  363. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_addressing.d.ts +17 -0
  364. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_addressing.d.ts.map +1 -0
  365. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_addressing.js +75 -0
  366. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.d.ts +14 -0
  367. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.d.ts.map +1 -0
  368. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.js +45 -0
  369. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_find_page.d.ts +17 -0
  370. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_find_page.d.ts.map +1 -0
  371. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_find_page.js +100 -0
  372. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_page_view_projection.d.ts +15 -0
  373. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_page_view_projection.d.ts.map +1 -0
  374. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_page_view_projection.js +47 -0
  375. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_demand.d.ts +26 -0
  376. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_demand.d.ts.map +1 -0
  377. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_demand.js +156 -0
  378. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_gather_counts.d.ts +13 -0
  379. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_gather_counts.d.ts.map +1 -0
  380. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_gather_counts.js +65 -0
  381. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.d.ts +30 -0
  382. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.d.ts.map +1 -0
  383. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.js +184 -0
  384. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.d.ts +23 -0
  385. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.d.ts.map +1 -0
  386. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.js +109 -0
  387. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_stale.d.ts +56 -0
  388. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_stale.d.ts.map +1 -0
  389. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_stale.js +211 -0
  390. package/src/shade/renderer/texture/format/decode_typed_gpu_data.d.ts +1 -1
  391. package/src/shade/renderer/texture/format/decode_typed_gpu_data.d.ts.map +1 -1
  392. package/src/shade/renderer/texture/format/decode_typed_gpu_data.js +3 -13
  393. package/src/shade/renderer/texture/format/infer_format_from_parameters.d.ts.map +1 -1
  394. package/src/shade/renderer/texture/format/infer_format_from_parameters.js +2 -3
  395. package/src/shade/renderer/texture/texture_write_to_gpu.d.ts.map +1 -1
  396. package/src/shade/renderer/texture/texture_write_to_gpu.js +16 -16
  397. package/src/shade/renderer/texture/virtual/VTPhysicalCache.d.ts +4 -90
  398. package/src/shade/renderer/texture/virtual/VTPhysicalCache.d.ts.map +1 -1
  399. package/src/shade/renderer/texture/virtual/VTPhysicalCache.js +6 -210
  400. package/src/shade/renderer/texture/virtual/VTPhysicalSlots.d.ts +119 -0
  401. package/src/shade/renderer/texture/virtual/VTPhysicalSlots.d.ts.map +1 -0
  402. package/src/shade/renderer/texture/virtual/VTPhysicalSlots.js +245 -0
  403. package/src/shade/renderer/texture/virtual/build_chunk_vt_lookup.d.ts +1 -1
  404. package/src/shade/renderer/texture/virtual/build_chunk_vt_lookup.d.ts.map +1 -1
  405. package/src/shade/renderer/texture/virtual/build_chunk_vt_lookup.js +3 -19
  406. package/src/shade/renderer/texture/virtual/chunk_vt_page_table_entry.d.ts +13 -0
  407. package/src/shade/renderer/texture/virtual/chunk_vt_page_table_entry.d.ts.map +1 -0
  408. package/src/shade/renderer/texture/virtual/chunk_vt_page_table_entry.js +34 -0
  409. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +7 -2
  410. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  411. package/src/shade/renderer/water/GPUWaterRenderer.js +49 -49
  412. package/src/shade/renderer/water/chunk_water_transport.js +3 -3
  413. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +11 -25
  414. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
  415. package/src/shade/renderer/water/medium/GPUWaterBodies.js +64 -116
  416. package/src/shade/renderer/water/medium/WATER_BODIES_STRUCT.d.ts +1 -20
  417. package/src/shade/renderer/water/medium/WATER_BODIES_STRUCT.d.ts.map +1 -1
  418. package/src/shade/renderer/water/medium/WATER_BODIES_STRUCT.js +10 -42
  419. package/src/shade/renderer/water/medium/chunk_water_bodies.d.ts +3 -0
  420. package/src/shade/renderer/water/medium/chunk_water_bodies.d.ts.map +1 -0
  421. package/src/shade/renderer/water/medium/chunk_water_bodies.js +3 -0
  422. package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts +1 -5
  423. package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts.map +1 -1
  424. package/src/shade/renderer/water/medium/shader_water_bodies_derive.js +32 -30
  425. package/src/shade/renderer/water/medium/shader_water_meshlets.d.ts +4 -0
  426. package/src/shade/renderer/water/medium/shader_water_meshlets.d.ts.map +1 -0
  427. package/src/shade/renderer/water/medium/shader_water_meshlets.js +69 -0
  428. package/src/shade/renderer/water/optics/chunk_water_inscatter.d.ts.map +1 -1
  429. package/src/shade/renderer/water/optics/chunk_water_inscatter.js +124 -123
  430. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts.map +1 -1
  431. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.js +75 -74
  432. package/src/shade/renderer/water/shader_water.d.ts +1 -1
  433. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  434. package/src/shade/renderer/water/shader_water.js +490 -406
  435. package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts +12 -85
  436. package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts.map +1 -1
  437. package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.js +128 -408
  438. package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.d.ts +6 -0
  439. package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.d.ts.map +1 -0
  440. package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.js +23 -0
  441. package/src/shade/renderer/water/surface/chunk_water_tessellation.d.ts +9 -0
  442. package/src/shade/renderer/water/surface/chunk_water_tessellation.d.ts.map +1 -0
  443. package/src/shade/renderer/water/surface/chunk_water_tessellation.js +144 -0
  444. package/src/shade/renderer/water/surface/chunk_water_wave.d.ts +3 -5
  445. package/src/shade/renderer/water/surface/chunk_water_wave.d.ts.map +1 -1
  446. package/src/shade/renderer/water/surface/chunk_water_wave.js +40 -48
  447. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +14 -0
  448. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -0
  449. package/src/shade/renderer/water/surface/graph_water_tessellation.js +34 -0
  450. package/src/shade/renderer/water/surface/shader_water_tiles.d.ts +4 -0
  451. package/src/shade/renderer/water/surface/shader_water_tiles.d.ts.map +1 -0
  452. package/src/shade/renderer/water/surface/shader_water_tiles.js +123 -0
  453. package/src/shade/renderer/water/surface/shader_water_wave_batch.d.ts +6 -0
  454. package/src/shade/renderer/water/surface/shader_water_wave_batch.d.ts.map +1 -0
  455. package/src/shade/renderer/water/surface/shader_water_wave_batch.js +85 -0
  456. package/src/shade/renderer/water/surface/shader_water_wave_domain.d.ts +6 -0
  457. package/src/shade/renderer/water/surface/shader_water_wave_domain.d.ts.map +1 -0
  458. package/src/shade/renderer/water/surface/shader_water_wave_domain.js +83 -0
  459. package/src/shade/renderer/water/water_height_texture_from_sampler.d.ts.map +1 -1
  460. package/src/shade/renderer/water/water_height_texture_from_sampler.js +4 -3
  461. package/src/engine/ecs/ik/IKConstraint.d.ts +0 -52
  462. package/src/engine/ecs/ik/IKConstraint.d.ts.map +0 -1
  463. package/src/engine/ecs/ik/IKConstraint.js +0 -95
  464. package/src/engine/ecs/ik/IKProblem.d.ts +0 -45
  465. package/src/engine/ecs/ik/IKProblem.d.ts.map +0 -1
  466. package/src/engine/ecs/ik/IKProblem.js +0 -58
  467. package/src/engine/ecs/ik/IKSolver.d.ts +0 -8
  468. package/src/engine/ecs/ik/IKSolver.d.ts.map +0 -1
  469. package/src/engine/ecs/ik/IKSolver.js +0 -9
  470. package/src/engine/ecs/ik/InverseKinematics.d.ts +0 -48
  471. package/src/engine/ecs/ik/InverseKinematics.d.ts.map +0 -1
  472. package/src/engine/ecs/ik/InverseKinematics.js +0 -119
  473. package/src/engine/ecs/ik/InverseKinematicsSerializationAdapter.d.ts +0 -19
  474. package/src/engine/ecs/ik/InverseKinematicsSerializationAdapter.d.ts.map +0 -1
  475. package/src/engine/ecs/ik/InverseKinematicsSerializationAdapter.js +0 -72
  476. package/src/engine/ecs/ik/InverseKinematicsSystem.d.ts +0 -54
  477. package/src/engine/ecs/ik/InverseKinematicsSystem.d.ts.map +0 -1
  478. package/src/engine/ecs/ik/InverseKinematicsSystem.js +0 -212
  479. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts +0 -8
  480. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts.map +0 -1
  481. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +0 -153
  482. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.d.ts +0 -5
  483. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.d.ts.map +0 -1
  484. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.js +0 -120
  485. package/src/engine/ecs/ik/ik_bone_chain.d.ts +0 -64
  486. package/src/engine/ecs/ik/ik_bone_chain.d.ts.map +0 -1
  487. package/src/engine/ecs/ik/ik_bone_chain.js +0 -142
  488. package/src/engine/ecs/ik/ik_probe_terrain_contact.d.ts +0 -42
  489. package/src/engine/ecs/ik/ik_probe_terrain_contact.d.ts.map +0 -1
  490. package/src/engine/ecs/ik/ik_probe_terrain_contact.js +0 -123
  491. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts +0 -18
  492. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts.map +0 -1
  493. package/src/engine/ecs/ik/ik_write_local_rotation.js +0 -32
  494. package/src/engine/graphics/ecs/water/WATER_SIZE.d.ts +0 -2
  495. package/src/engine/graphics/ecs/water/WATER_SIZE.d.ts.map +0 -1
  496. package/src/engine/graphics/ecs/water/WATER_SIZE.js +0 -1
  497. package/src/shade/renderer/light/GPUViewLightContext.d.ts +0 -22
  498. package/src/shade/renderer/light/GPUViewLightContext.d.ts.map +0 -1
  499. package/src/shade/renderer/light/GPUViewLightContext.js +0 -62
  500. package/src/shade/renderer/shadow/map/csm/CSM_SHADOWMAP_STRUCT.d.ts +0 -14
  501. package/src/shade/renderer/shadow/map/csm/CSM_SHADOWMAP_STRUCT.d.ts.map +0 -1
  502. package/src/shade/renderer/shadow/map/csm/CSM_SHADOWMAP_STRUCT.js +0 -20
  503. package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.d.ts +0 -27
  504. package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.d.ts.map +0 -1
  505. package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.js +0 -147
  506. package/src/shade/renderer/shadow/vsm/GPUVirtualShadowTextureResidence.d.ts +0 -7
  507. package/src/shade/renderer/shadow/vsm/GPUVirtualShadowTextureResidence.d.ts.map +0 -1
  508. package/src/shade/renderer/shadow/vsm/GPUVirtualShadowTextureResidence.js +0 -10
  509. package/src/shade/renderer/shadow/vsm/VSM_RESIDENCE_WORKGROUP_TILE_RESOLUTION.d.ts +0 -2
  510. package/src/shade/renderer/shadow/vsm/VSM_RESIDENCE_WORKGROUP_TILE_RESOLUTION.d.ts.map +0 -1
  511. package/src/shade/renderer/shadow/vsm/VSM_RESIDENCE_WORKGROUP_TILE_RESOLUTION.js +0 -1
  512. package/src/shade/renderer/shadow/vsm/VSM_UNIFORMS_STRUCT.d.ts +0 -3
  513. package/src/shade/renderer/shadow/vsm/VSM_UNIFORMS_STRUCT.d.ts.map +0 -1
  514. package/src/shade/renderer/shadow/vsm/VSM_UNIFORMS_STRUCT.js +0 -8
  515. package/src/shade/renderer/shadow/vsm/VirtualShadowmapRenderer.d.ts +0 -27
  516. package/src/shade/renderer/shadow/vsm/VirtualShadowmapRenderer.d.ts.map +0 -1
  517. package/src/shade/renderer/shadow/vsm/VirtualShadowmapRenderer.js +0 -102
  518. package/src/shade/renderer/shadow/vsm/debug_inspect_coarse_bounds_buffer.d.ts +0 -8
  519. package/src/shade/renderer/shadow/vsm/debug_inspect_coarse_bounds_buffer.d.ts.map +0 -1
  520. package/src/shade/renderer/shadow/vsm/debug_inspect_coarse_bounds_buffer.js +0 -34
  521. package/src/shade/renderer/shadow/vsm/debug_inspect_residence_buffer.d.ts +0 -10
  522. package/src/shade/renderer/shadow/vsm/debug_inspect_residence_buffer.d.ts.map +0 -1
  523. package/src/shade/renderer/shadow/vsm/debug_inspect_residence_buffer.js +0 -64
  524. package/src/shade/renderer/shadow/vsm/decode_tile_address.d.ts +0 -11
  525. package/src/shade/renderer/shadow/vsm/decode_tile_address.d.ts.map +0 -1
  526. package/src/shade/renderer/shadow/vsm/decode_tile_address.js +0 -26
  527. package/src/shade/renderer/shadow/vsm/render/vms_render_tiles.d.ts +0 -2
  528. package/src/shade/renderer/shadow/vsm/render/vms_render_tiles.d.ts.map +0 -1
  529. package/src/shade/renderer/shadow/vsm/render/vms_render_tiles.js +0 -11
  530. package/src/shade/renderer/shadow/vsm/vms_pipeline_compute_coarse_bounds.d.ts +0 -20
  531. package/src/shade/renderer/shadow/vsm/vms_pipeline_compute_coarse_bounds.d.ts.map +0 -1
  532. package/src/shade/renderer/shadow/vsm/vms_pipeline_compute_coarse_bounds.js +0 -184
  533. package/src/shade/renderer/shadow/vsm/vsm_residence_pipeline.d.ts +0 -25
  534. package/src/shade/renderer/shadow/vsm/vsm_residence_pipeline.d.ts.map +0 -1
  535. package/src/shade/renderer/shadow/vsm/vsm_residence_pipeline.js +0 -230
  536. package/src/shade/renderer/shadow/vsm/vsm_tile_allocation_pipeline.d.ts +0 -19
  537. package/src/shade/renderer/shadow/vsm/vsm_tile_allocation_pipeline.d.ts.map +0 -1
  538. package/src/shade/renderer/shadow/vsm/vsm_tile_allocation_pipeline.js +0 -127
  539. package/src/shade/renderer/texture/encode/ENCODE_NOTES_2026_09_02.md +0 -462
  540. package/src/shade/renderer/water/optics/chunk_water_light_transmittance.d.ts +0 -23
  541. package/src/shade/renderer/water/optics/chunk_water_light_transmittance.d.ts.map +0 -1
  542. package/src/shade/renderer/water/optics/chunk_water_light_transmittance_dry.d.ts +0 -18
  543. package/src/shade/renderer/water/optics/chunk_water_light_transmittance_dry.d.ts.map +0 -1
  544. package/src/shade/renderer/water/surface/WATER_SURFACE_VERTEX_STRUCT.d.ts +0 -12
  545. package/src/shade/renderer/water/surface/WATER_SURFACE_VERTEX_STRUCT.d.ts.map +0 -1
  546. package/src/shade/renderer/water/surface/WATER_SURFACE_VERTEX_STRUCT.js +0 -27
  547. package/src/shade/renderer/water/surface/WATER_WAVE_PARAMETERS_STRUCT.d.ts +0 -14
  548. package/src/shade/renderer/water/surface/WATER_WAVE_PARAMETERS_STRUCT.d.ts.map +0 -1
  549. package/src/shade/renderer/water/surface/WATER_WAVE_PARAMETERS_STRUCT.js +0 -49
  550. package/src/shade/renderer/water/surface/chunk_water_wave_grid.d.ts +0 -9
  551. package/src/shade/renderer/water/surface/chunk_water_wave_grid.d.ts.map +0 -1
  552. package/src/shade/renderer/water/surface/chunk_water_wave_grid.js +0 -47
  553. package/src/shade/renderer/water/surface/shader_water_surface_write.d.ts +0 -10
  554. package/src/shade/renderer/water/surface/shader_water_surface_write.d.ts.map +0 -1
  555. package/src/shade/renderer/water/surface/shader_water_surface_write.js +0 -51
  556. package/src/shade/renderer/water/surface/shader_water_wave_step.d.ts +0 -12
  557. package/src/shade/renderer/water/surface/shader_water_wave_step.d.ts.map +0 -1
  558. package/src/shade/renderer/water/surface/shader_water_wave_step.js +0 -54
  559. package/src/shade/renderer/water/surface/water_surface_grid_indices.d.ts +0 -13
  560. package/src/shade/renderer/water/surface/water_surface_grid_indices.d.ts.map +0 -1
  561. package/src/shade/renderer/water/surface/water_surface_grid_indices.js +0 -39
@@ -1,406 +1,490 @@
1
- import { GPUShaderStage } from "../../descriptor/GPUShaderStage.js";
2
- import { DepthStencilState } from "../../descriptor/pipeline/render/DepthStencilState.js";
3
- import { RenderPipelineDescriptor } from "../../descriptor/pipeline/render/RenderPipelineDescriptor.js";
4
- import { CAMERA_UNIFORM_STRUCT } from "../camera/CAMERA_UNIFORM_STRUCT.js";
5
- import { SHADING_LIGHT_RESOURCE_GROUP } from "../deferred/SHADING_LIGHT_RESOURCE_GROUP.js";
6
- import { BRICK4_DATA_STRUCT } from "../global_illumination/brick4/gpu/BRICK4_DATA_STRUCT.js";
7
- import { chunk_F_dielectric } from "../shader/chunk/brdf/fresnel/chunk_F_dielectric.js";
8
- import { chunk_direction_view_to_world } from "../shader/chunk/camera/chunk_direction_view_to_world.js";
9
- import { chunk_direction_world_to_view } from "../shader/chunk/camera/chunk_direction_world_to_view.js";
10
- import { chunk_ray_at } from "../shader/chunk/geometry/ray/chunk_ray_at.js";
11
- import { chunk_ffx_sssr_advance_ray } from "../shader/chunk/screen_space/chunk_ffx_sssr_advance_ray.js";
12
- import { chunk_ffx_sssr_load_depth } from "../shader/chunk/screen_space/chunk_ffx_sssr_load_depth.js";
13
- import { chunk_ffx_sssr_validate_hit } from "../shader/chunk/screen_space/chunk_ffx_sssr_validate_hit.js";
14
- import { chunk_project_direction } from "../shader/chunk/screen_space/chunk_project_direction.js";
15
- import { chunk_screen_space_newton_ray } from "../shader/chunk/screen_space/chunk_screen_space_newton_ray.js";
16
- import { chunk_texture_sample_bilinear_uv } from "../shader/chunk/texture/sample/chunk_texture_sample_bilinear_uv.js";
17
- import { CodeChunk } from "../shader/compiler/CodeChunk.js";
18
- import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
19
- import { ShaderDescriptor } from "../shader/ShaderDescriptor.js";
20
- import { f32, u32 } from "../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
21
- import { WebGPUArray } from "../shader/type/WebGPUArray.js";
22
- import { WebGPUStruct } from "../shader/type/WebGPUStruct.js";
23
- import { VIEW_UNIFORM_STRUCT } from "../view/VIEW_UNIFORM_STRUCT.js";
24
- import { chunk_water_gi_brick4, chunk_water_gi_ibl } from "./chunk_water_gi.js";
25
- import { WATER_BODIES_STRUCT } from "./medium/WATER_BODIES_STRUCT.js";
26
- import { chunk_water_inscatter } from "./optics/chunk_water_inscatter.js";
27
- import { chunk_water_receiver_downwelling } from "./optics/chunk_water_receiver_downwelling.js";
28
- import { chunk_water_optics } from "./optics/chunk_water_optics.js";
29
- import { WATER_SURFACE_VERTEX_STRUCT } from "./surface/WATER_SURFACE_VERTEX_STRUCT.js";
30
- import { chunk_water_receiver_radiance, chunk_water_receiver_texel, chunk_water_refraction_confidence,
31
- chunk_water_transport, WATER_LEVEL_TOLERANCE_DECLARATION } from './chunk_water_transport.js';
32
-
33
- export const WATER_DRAW_STRUCT = WebGPUStruct.from({
34
- level: f32, ior: f32, roughness: f32, surface_id: u32,
35
- // row of this body in the water bodies table
36
- body_index: u32,
37
- // how far to integrate the water when no receiver is seen through it: where its clearest channel's
38
- // transmittance falls to a thousandth, bounded by the trace distance (water_missing_receiver_path)
39
- missing_receiver_path: f32,
40
- }, "WaterDraw").pack();
41
-
42
- export const WATER_TRACE_STRUCT = WebGPUStruct.from({
43
- max_distance: f32, distance_tolerance: f32, max_updates: u32, fallback_steps: u32,
44
- mode: u32, reflections: u32,
45
- // steps of the water body's in-scatter along each refracted view ray
46
- inscatter_segments: u32,
47
- }, "WaterTrace").pack();
48
-
49
- function water_resources(finalize = false) {
50
- const resources = new ShaderResourceSetDescriptor();
51
- const group = resources.createGroup()
52
- .addUniform("camera", CAMERA_UNIFORM_STRUCT)
53
- .addUniform("water", WATER_DRAW_STRUCT)
54
- .addUniform("trace", WATER_TRACE_STRUCT)
55
- .addTexture("tDepth")
56
- .addTexture("tNormal", "uint")
57
- .addTexture("tHZB")
58
- .addTexture("tScene")
59
- // the surface interface: the producer's vertices
60
- .addStorageBuffer("surface_vertices", WebGPUArray.from(WATER_SURFACE_VERTEX_STRUCT), false);
61
- if (finalize) {
62
- group.addTexture('receiver').addTexture('trace_metadata').addTexture('visibility_distance')
63
- .addUniform("water_bodies", WATER_BODIES_STRUCT);
64
- }
65
- return resources;
66
- }
67
- const resources = water_resources();
68
-
69
- /** Optics under IBL (and LPV, which has no transparent variant): the lights and the environment. */
70
- export const WATER_FINALIZE_RESOURCES_IBL = water_resources(true);
71
- WATER_FINALIZE_RESOURCES_IBL.addGroup(SHADING_LIGHT_RESOURCE_GROUP);
72
-
73
- /** Optics under Brick4: the lights, and the light map with the view its sampling jitters by. */
74
- export const WATER_FINALIZE_RESOURCES_BRICK4 = water_resources(true);
75
- WATER_FINALIZE_RESOURCES_BRICK4.addGroup(SHADING_LIGHT_RESOURCE_GROUP);
76
- WATER_FINALIZE_RESOURCES_BRICK4.createGroup()
77
- .addStorageBuffer("brick4", BRICK4_DATA_STRUCT, false)
78
- .addUniform("view", VIEW_UNIFORM_STRUCT);
79
-
80
- const surface_body = CodeChunk.from(/* language=WGSL */ `
81
- struct WaterVertexOut {
82
- // Receivers and optics are separate modules drawing this mesh; optics tests depth 'equal'
83
- // against the receivers' depth, and both must cover the same edge pixels. Only @invariant
84
- // makes the position bit-identical across programs.
85
- @invariant @builtin(position) clip: vec4<f32>,
86
- @location(0) world: vec3<f32>,
87
- @location(1) normal: vec3<f32>,
88
- // slope variance of the waves the surface's mesh does not resolve
89
- @location(2) unresolved_variance: f32,
90
- }
91
-
92
- // Pulls the producer's vertex: in an indexed draw the vertex index is the index-buffer entry.
93
- @vertex
94
- fn vs_main(@builtin(vertex_index) vi: u32) -> WaterVertexOut {
95
- let vertex = surface_vertices[vi];
96
- let world = vertex.position.xyz;
97
- return WaterVertexOut(camera.view_projection_matrix * vec4<f32>(world, 1.0), world,
98
- vertex.normal.xyz, vertex.position.w);
99
- }
100
-
101
- // The interface at one water fragment, in view space. Receivers trace through it and optics
102
- // shade it, so both passes take it from here.
103
- struct WaterInterface {
104
- origin: vec3<f32>,
105
- incident: vec3<f32>,
106
- // Faces the camera's side of the interface.
107
- normal: vec3<f32>,
108
- above: bool,
109
- ior: f32,
110
- // Screen-space travel bound.
111
- limit: f32,
112
- }
113
-
114
- fn water_interface(world: vec3<f32>, surface_normal: vec3<f32>) -> WaterInterface {
115
- let origin = (camera.view_matrix * vec4f(world, 1.0)).xyz;
116
- let above = camera.view_matrix_inverse[3].y >= world.y;
117
- var normal_ws = normalize(surface_normal);
118
- if (!above) { normal_ws = -normal_ws; }
119
- return WaterInterface(origin, normalize(origin), normalize(direction_world_to_view(normal_ws, camera)), above,
120
- max(water.ior, 1.0), min(max(trace.max_distance, 0.1), camera.clip_near_far.y));
121
- }
122
- `, [chunk_direction_world_to_view]);
123
-
124
- export const chunk_water_screen_ray = CodeChunk.from(/* language=WGSL */ `
125
- fn water_hzb_mip_size(depth_size: vec2f, hzb_size: vec2f, mip: i32) -> vec2f {
126
- if (mip <= 0) { return depth_size; }
127
- return max(vec2f(1.0), floor(hzb_size / exp2(f32(mip-1))));
128
- }
129
- // Reuse the renderer's FFX cell intersection and depth loads, but walk the actual
130
- // integer mip grids. Its SSR driver halves floating sizes and assumes power-of-two
131
- // reductions; Meep's HZB conservatively resamples arbitrary viewport dimensions.
132
- fn water_hzb_crossing(origin: vec3f, direction: vec3f, budget: u32,
133
- valid: ptr<function,bool>, iterations: ptr<function,u32>) -> vec3f {
134
- let size = vec2f(textureDimensions(tDepth,0));
135
- let pyramid_size = vec2f(textureDimensions(tHZB,0));
136
- let last_mip = i32(textureNumLevels(tHZB));
137
- let inverse_direction = select(vec3f(F32_MAX), 1.0/direction, abs(direction)>vec3f(1e-12));
138
- let floor_offset = select(vec2f(1.0), vec2f(0.0), direction.xy<vec2f(0.0));
139
- let uv_offset = select(0.005/size, -0.005/size, direction.xy<vec2f(0.0));
140
- var mip = 0;
141
- var position = origin;
142
- var travel = 0.0;
143
- *valid = false;
144
- // Water is absent from the opaque depth buffer: skipping the initial pixel
145
- // can skip the entire receiver for almost zero projected displacement.
146
- for (var i=0u; i<min(budget,128u); i++) {
147
- *iterations = i+1u;
148
- if (!screen_space_ray_in_bounds(position.xy) || is_background(position.z)) { break; }
149
- let resolution = water_hzb_mip_size(size,pyramid_size,mip);
150
- let pixel = resolution * position.xy;
151
- let depth = ffx_sssr_load_depth(vec2i(pixel),mip);
152
- let skipped = ffx_sssr_advance_ray(origin,direction,inverse_direction,pixel,
153
- 1.0/resolution,floor_offset,uv_offset,depth,&position,&travel);
154
- if (!skipped && mip==0) { *valid=true; break; }
155
- mip = clamp(mip+select(-1,1,skipped),0,last_mip);
156
- }
157
- return position;
158
- }
159
- // HZB returns a depth-slab crossing, not the intersection of the ray with the
160
- // receiver's plane. Refine that crossing before using its UV or optical path.
161
- fn water_exact_receiver(ray: Ray, input: ScreenSpaceRayHit) -> ScreenSpaceRayHit {
162
- var hit = input;
163
- if (hit.status != 0u) { return hit; }
164
- let receiver = screen_space_ray_load_receiver(hit.uv, tDepth, tNormal,
165
- camera.projection_matrix_inverse, camera.view_matrix);
166
- let travel = plane_ray_raycast(ray.origin, ray.direction, receiver.plane);
167
- // Keep the analytic distance rather than the projection of the texel center onto the ray.
168
- if (travel > 1e-4 && travel <= ray.tmax) {
169
- hit.distance = travel;
170
- hit.uv = project_position(ray_at(ray.origin, ray.direction, travel), camera.projection_matrix).xy;
171
- // Reprojection can change texel ownership at a silhouette. Validate that lookup
172
- // again; the analytic travel above already checked the ray's bounded interval.
173
- let checked = screen_space_ray_validate(Ray(ray.origin,ray.direction,1e20),hit.uv,tDepth,tNormal,
174
- camera.projection_matrix,camera.projection_matrix_inverse,camera.view_matrix,trace.distance_tolerance);
175
- hit.status = checked.status;
176
- hit.residual = checked.residual;
177
- } else { hit.status = 4u; }
178
- return hit;
179
- }
180
- fn water_refine_receiver(ray: Ray, seed: vec2f) -> ScreenSpaceRayHit {
181
- // The traversal already selected the first depth footprint. Intersect its plane
182
- // once and validate ownership; another Newton search could jump past that footprint
183
- // to a later root that the traversal has already ruled out.
184
- return water_exact_receiver(ray, ScreenSpaceRayHit(seed, 0.0, 1e20, 0u, 0u));
185
- }
186
- fn water_hzb_hit(ray: Ray, budget: u32) -> ScreenSpaceRayHit {
187
- var miss = ScreenSpaceRayHit(vec2f(0.0), 0.0, 1e20, 0u, 5u);
188
- if (budget == 0u || !screen_space_ray_projectable(ray.origin, camera.projection_matrix)
189
- || !screen_space_ray_projectable(ray.origin + ray.direction, camera.projection_matrix)) { return miss; }
190
- let origin = project_position(ray.origin, camera.projection_matrix);
191
- let direction = project_direction(ray.origin, ray.direction, origin, camera.projection_matrix);
192
- // Only rays advancing into reverse-Z are supported by this adapter.
193
- if (direction.z >= -1e-8 || !screen_space_ray_in_bounds(origin.xy)) { return miss; }
194
- var valid = false;
195
- var iterations = 0u;
196
- let candidate = water_hzb_crossing(origin, direction, budget, &valid, &iterations);
197
- if (!valid) { miss.iterations = iterations; return miss; }
198
- var hit = water_refine_receiver(ray, candidate.xy);
199
- hit.iterations = iterations;
200
- return hit;
201
- }
202
- `, [chunk_screen_space_newton_ray, chunk_ffx_sssr_advance_ray, chunk_ffx_sssr_load_depth, chunk_project_direction,
203
- chunk_ray_at]);
204
-
205
- const body = CodeChunk.from(/* language=WGSL */ `
206
- struct WaterReceiver {
207
- @location(0) receiver: vec4<f32>,
208
- @location(1) metadata: vec4<f32>,
209
- // Receiver UV, bounded path, classified status + Newton updates / 32. Readback is opt-in.
210
- }
211
-
212
- // A screen-space receiver must lie below the surface point the ray entered at: the refracted ray runs
213
- // downward from it, so any point on the ray is lower, and one that is not is a root off the ray.
214
- fn water_receiver_submerged(uv: vec2f, surface_y: f32) -> bool {
215
- let receiver = water_receiver_texel(tDepth, tNormal, vec2i(uv * vec2f(textureDimensions(tDepth, 0))),
216
- camera.projection_matrix_inverse, camera.view_matrix_inverse);
217
- return receiver.position.y <= surface_y + WATER_LEVEL_TOLERANCE;
218
- }
219
-
220
- @fragment
221
- fn fs_main(in: WaterVertexOut) -> WaterReceiver {
222
- let coord = vec2<i32>(in.clip.xy);
223
- let dimensions = vec2f(textureDimensions(tDepth, 0));
224
- let uv = in.clip.xy / dimensions;
225
- let scene_depth = textureLoad(tDepth, coord, 0).r;
226
- if (scene_depth >= in.clip.z) { discard; }
227
- // the opaque scene behind this pixel, and how deep under the surface point it lies: shore water
228
- // fades in over its first 10 cm, whatever is under it
229
- var behind_vs = vec3f(0.0);
230
- var water_depth = 1e20;
231
- if (!is_background(scene_depth)) {
232
- behind_vs = inv_project_position(vec3f(uv, scene_depth), camera.projection_matrix_inverse);
233
- water_depth = in.world.y - (camera.view_matrix_inverse * vec4f(behind_vs, 1.0)).y;
234
- }
235
- let coverage = smoothstep(0.0, 0.1, water_depth);
236
- let surface = water_interface(in.world, in.normal);
237
- let above = surface.above;
238
- let limit = surface.limit;
239
- let direction = refract(surface.incident, surface.normal, 1.0 / surface.ior);
240
- let ray = Ray(surface.origin, normalize(direction), limit);
241
- var hit = ScreenSpaceRayHit(uv, limit, 1e20, 0u, 8u);
242
- var newton_updates = 0u;
243
- var newton_failure = 0u;
244
- if (above && trace.mode == 0u) {
245
- // Mayer et al. §2.2: a root within one pixel of the ray is accepted as is. Like the paper,
246
- // this can converge past a thin occluder; traversal is only the fallback for failures.
247
- hit = screen_space_newton_ray(ray, uv, tDepth, tNormal, camera.projection_matrix,
248
- camera.projection_matrix_inverse, camera.view_matrix, trace.max_updates, trace.distance_tolerance);
249
- newton_updates = hit.iterations;
250
- newton_failure = hit.status;
251
- }
252
- // Reject foreground receivers before deciding whether traversal is needed.
253
- if (hit.status == 0u && !water_receiver_submerged(hit.uv, in.world.y)) { hit.status = 5u; newton_failure = 5u; }
254
- if (above && trace.mode != 2u && hit.status != 0u) {
255
- let fallback = water_hzb_hit(ray, trace.fallback_steps);
256
- if (fallback.status == 0u && water_receiver_submerged(fallback.uv, in.world.y)) { hit = fallback; hit.status = 6u; }
257
- }
258
- // Compute the control event for every pixel, independently of Newton/HZB success. With nothing
259
- // behind the water on screen, integrate it to where it has taken all but a thousandth.
260
- var control_path = min(water.missing_receiver_path, limit);
261
- var control_status = select(8u, 9u, !above);
262
- if (!is_background(scene_depth)) {
263
- if (water_depth >= -WATER_LEVEL_TOLERANCE || !above) {
264
- control_path = min(distance(ray.origin, behind_vs), limit);
265
- control_status = select(7u, 9u, !above);
266
- }
267
- }
268
- if (trace.mode == 2u || !above || (hit.status != 0u && hit.status != 6u)) {
269
- // Never use an unvalidated Newton iterate as a color lookup.
270
- hit.uv = uv;
271
- // A missing screen receiver is missing visibility, not 300 metres of water.
272
- hit.distance = control_path;
273
- hit.status = control_status;
274
- }
275
- var status = hit.status;
276
- if (status == 6u) { status = 8u + newton_failure; }
277
- else if (status == 7u) { status = 16u + newton_failure; }
278
- else if (status == 8u) { status = 24u + newton_failure; }
279
- else if (status == 9u) { status = 31u; }
280
- return WaterReceiver(vec4f(hit.uv, hit.distance, f32(status) + f32(newton_updates)/32.0),
281
- vec4f(control_path, min(hit.residual, 65504.0), coverage, f32(water.surface_id)));
282
- }
283
- `, [surface_body, chunk_water_screen_ray, chunk_direction_view_to_world,
284
- chunk_water_receiver_texel, WATER_LEVEL_TOLERANCE_DECLARATION]);
285
-
286
- const finalize_body = CodeChunk.from(/* language=WGSL */ `
287
- struct WaterOptics {
288
- @location(0) transmission: vec4f,
289
- @location(1) radiance: vec4f,
290
- @location(2) background: vec4f,
291
- }
292
- @fragment
293
- fn fs_main(in: WaterVertexOut) -> WaterOptics {
294
- let coord = vec2i(in.clip.xy);
295
- let metadata = textureLoad(trace_metadata, coord, 0);
296
- // Equal-depth surfaces must retain the same deterministic owner as receiver selection.
297
- if (metadata.w != f32(water.surface_id)) { discard; }
298
- let dimensions = vec2f(textureDimensions(tDepth, 0));
299
- let uv = in.clip.xy / dimensions;
300
- let receiver_data = textureLoad(receiver, coord, 0);
301
- let surface = water_interface(in.world, in.normal);
302
- let body = water_bodies.bodies[water.body_index];
303
- let origin = surface.origin;
304
- let above = surface.above;
305
- let ior = surface.ior;
306
- let limit = surface.limit;
307
- let nov = clamp(dot(-surface.incident, surface.normal), 0.0, 1.0);
308
- // exact dielectric Fresnel: water is most reflective at grazing angles, where Schlick's is not right
309
- let fresnel = F_dielectric(nov, ior);
310
- let reflection_direction = reflect(surface.incident, surface.normal);
311
- // a reflection that misses on screen falls back to the GI mode, as SSR's resolve does
312
- var reflection = water_gi_specular(in.world, direction_view_to_world(surface.normal, camera),
313
- direction_view_to_world(-surface.incident, camera), water.roughness);
314
- if (trace.reflections != 0u && above) {
315
- let reflected = water_hzb_hit(Ray(ray_at(origin, reflection_direction, 0.02), reflection_direction, limit),
316
- trace.fallback_steps);
317
- if (reflected.status == 0u) {
318
- let reflected_point = ray_at(origin, reflection_direction, reflected.distance + 0.02);
319
- let projected = project_position(reflected_point, camera.projection_matrix);
320
- // Reflection uses the renderer's usual back-face, thickness, self-hit and
321
- // vignette validation. Its two-pixel rule must not reject normal-incidence refraction.
322
- let confidence = ffx_sssr_validate_hit(vec3f(reflected.uv, projected.z), uv,
323
- reflection_direction, dimensions, max(trace.distance_tolerance, 0.02), 0.05);
324
- let radiance = water_receiver_radiance(tScene, tDepth, tNormal, reflected.uv,
325
- camera.projection_matrix_inverse, camera.view_matrix_inverse, in.world.y, false);
326
- reflection = mix(reflection, radiance.rgb,
327
- confidence * min(radiance.a * 2.0, 1.0) * smoothstep(0.05, 0.5, reflected.distance)
328
- * smoothstep(1.0, 4.0, length((reflected.uv - uv) * dimensions)));
329
- }
330
- }
331
- let original = textureLoad(tScene, coord, 0);
332
- let valid = receiver_data.w < 16.0 && above && trace.mode != 2u;
333
- var confidence = select(0.0, water_refraction_confidence(receiver_data.xy, uv, dimensions,
334
- texture_sample_bilinear_uv(visibility_distance, uv, 0u).r), valid);
335
- // Mayer's fade selects one UV, rather than crossfading two images of the same edge.
336
- let lookup = water_refraction_lookup(uv, receiver_data.xy, confidence);
337
- // The surface height here stands for the one above the displaced receiver: they differ by the
338
- // wave height across a few metres, against a tolerance the gather already allows.
339
- let gathered = water_receiver_radiance(tScene, tDepth, tNormal, lookup,
340
- camera.projection_matrix_inverse, camera.view_matrix_inverse, in.world.y, above);
341
- var path = metadata.x;
342
- var color = original.rgb;
343
- // the receiver seen through the surface: refracted, or the pixel's own when there is none
344
- var receiver_coord = coord;
345
- if (confidence > 0.0 && gathered.a > 0.0) {
346
- path = min(water_receiver_path(tDepth, tNormal, lookup, camera.projection_matrix_inverse,
347
- camera.view_matrix, origin), limit);
348
- color = gathered.rgb;
349
- receiver_coord = vec2i(lookup * dimensions);
350
- } else { confidence = 0.0; }
351
- // The opaque scene was shaded dry: what reaches the receiver is what survives the water above it
352
- // (WATER_OPTICS_PLAN_2026_10_02.md §4.3). Seen from under the surface, the receiver is above it.
353
- let receiver_texel = water_receiver_texel(tDepth, tNormal, receiver_coord, camera.projection_matrix_inverse,
354
- camera.view_matrix_inverse);
355
- if (above && !is_background(receiver_texel.depth)) {
356
- let camera_ws = camera.view_matrix_inverse[3].xyz;
357
- color *= water_receiver_downwelling(body, receiver_texel.position, receiver_texel.normal,
358
- max(in.world.y - receiver_texel.position.y, 0.0), normalize(camera_ws - receiver_texel.position));
359
- }
360
- // Light in the water body (WATER_OPTICS_PLAN_2026_10_02.md §4.4): the receiver attenuated along
361
- // the refracted path, and the sun and sky scattered back up it; both cross the surface by the
362
- // n² law. A view from under the surface is outside this model: attenuation only.
363
- let extinction = body.extinction.xyz;
364
- var transmitted = exp(-extinction * max(path, 0.0));
365
- var scattered = vec3f(0.0);
366
- if (above) {
367
- let exit = water_exit_factor(nov, ior);
368
- let direction = normalize(direction_view_to_world(refract(surface.incident, surface.normal, 1.0 / ior), camera));
369
- transmitted *= exit;
370
- scattered = exit * water_inscatter(body, in.world, direction, max(path, 0.0), trace.inscatter_segments);
371
- }
372
- let event = water_event(transmitted, fresnel * reflection + scattered);
373
- let optical = water_transport(event, original.rgb, color, metadata.z);
374
- return WaterOptics(vec4f(optical.transmission, metadata.z), vec4f(optical.radiance, confidence),
375
- vec4f(optical.background, original.a));
376
- }
377
- `, [surface_body, chunk_water_screen_ray, chunk_F_dielectric,
378
- chunk_ffx_sssr_validate_hit, chunk_texture_sample_bilinear_uv,
379
- chunk_direction_view_to_world, chunk_ray_at, chunk_water_optics, chunk_water_inscatter,
380
- chunk_water_receiver_downwelling, chunk_water_receiver_texel,
381
- chunk_water_transport, chunk_water_receiver_radiance, chunk_water_refraction_confidence]);
382
-
383
- export const water_shader = ShaderDescriptor.from({ label: "Water / receivers", resources, body });
384
- /** The optics pass under IBL, and under LPV, which has no transparent variant. */
385
- export const water_finalize_shader_ibl = ShaderDescriptor.from({ label: 'Water / coherent optics IBL',
386
- resources: WATER_FINALIZE_RESOURCES_IBL, body: CodeChunk.from('', [finalize_body, chunk_water_gi_ibl]) });
387
- /** The optics pass under Brick4. */
388
- export const water_finalize_shader_brick4 = ShaderDescriptor.from({ label: 'Water / coherent optics Brick4',
389
- resources: WATER_FINALIZE_RESOURCES_BRICK4, body: CodeChunk.from('', [finalize_body, chunk_water_gi_brick4]) });
390
- export const WATER_RESOURCES = resources;
391
-
392
- /** Nearest-interface selection writes only water-owned depth and optics, never opaque G-buffer. */
393
- function water_pipeline(shader, targets, finalize) {
394
- const code = shader.source;
395
- return RenderPipelineDescriptor.from({
396
- label: shader.label,
397
- layout: shader.resources.generatePipelineLayout(GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT),
398
- vertex: { module: { code }, entryPoint: "vs_main" },
399
- fragment: { module: { code }, entryPoint: "fs_main", targets: targets.map(format => ({ format })) },
400
- depthStencil: DepthStencilState.from({ format: "depth32float", depthWriteEnabled: !finalize, depthCompare: finalize ? 'equal' : 'greater' }),
401
- primitive: { topology: "triangle-list", cullMode: "none" },
402
- });
403
- }
404
- export function create_water_pipeline() { return water_pipeline(water_shader, ['rgba32float', 'rgba32float'], false); }
405
- export function create_water_finalize_pipeline_ibl() { return water_pipeline(water_finalize_shader_ibl, ['rgba32float', 'rgba16float', 'rgba16float'], true); }
406
- export function create_water_finalize_pipeline_brick4() { return water_pipeline(water_finalize_shader_brick4, ['rgba32float', 'rgba16float', 'rgba16float'], true); }
1
+ import { GPUShaderStage } from "../../descriptor/GPUShaderStage.js";
2
+ import { DepthStencilState } from "../../descriptor/pipeline/render/DepthStencilState.js";
3
+ import { RenderPipelineDescriptor } from "../../descriptor/pipeline/render/RenderPipelineDescriptor.js";
4
+ import { CAMERA_UNIFORM_STRUCT } from "../camera/CAMERA_UNIFORM_STRUCT.js";
5
+ import { SHADING_LIGHT_RESOURCE_GROUP } from "../deferred/SHADING_LIGHT_RESOURCE_GROUP.js";
6
+ import { BRICK4_DATA_STRUCT } from "../global_illumination/brick4/gpu/BRICK4_DATA_STRUCT.js";
7
+ import { chunk_F_dielectric } from "../shader/chunk/brdf/fresnel/chunk_F_dielectric.js";
8
+ import { chunk_direction_view_to_world } from "../shader/chunk/camera/chunk_direction_view_to_world.js";
9
+ import { chunk_direction_world_to_view } from "../shader/chunk/camera/chunk_direction_world_to_view.js";
10
+ import { chunk_ray_at } from "../shader/chunk/geometry/ray/chunk_ray_at.js";
11
+ import { chunk_ffx_sssr_advance_ray } from "../shader/chunk/screen_space/chunk_ffx_sssr_advance_ray.js";
12
+ import { chunk_ffx_sssr_load_depth } from "../shader/chunk/screen_space/chunk_ffx_sssr_load_depth.js";
13
+ import { chunk_ffx_sssr_validate_hit } from "../shader/chunk/screen_space/chunk_ffx_sssr_validate_hit.js";
14
+ import { chunk_project_direction } from "../shader/chunk/screen_space/chunk_project_direction.js";
15
+ import { chunk_screen_space_newton_ray } from "../shader/chunk/screen_space/chunk_screen_space_newton_ray.js";
16
+ import { chunk_texture_sample_bilinear_uv } from "../shader/chunk/texture/sample/chunk_texture_sample_bilinear_uv.js";
17
+ import { CodeChunk } from "../shader/compiler/CodeChunk.js";
18
+ import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
19
+ import { ShaderDescriptor } from "../shader/ShaderDescriptor.js";
20
+ import { f32, u32 } from "../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
21
+ import { WebGPUArray } from "../shader/type/WebGPUArray.js";
22
+ import { WebGPUStruct } from "../shader/type/WebGPUStruct.js";
23
+ import { VIEW_UNIFORM_STRUCT } from "../view/VIEW_UNIFORM_STRUCT.js";
24
+ import { chunk_water_gi_brick4, chunk_water_gi_ibl } from "./chunk_water_gi.js";
25
+ import { WATER_BODIES_TABLE, WATER_WAVES_TABLE } from "./medium/chunk_water_bodies.js";
26
+ import { MESHLET_METADATA_STRUCT } from "../geometry/meshlet/encoding/MESHLET_METADATA_STRUCT.js";
27
+ import { COLLECTION_U32_STRUCT_READ } from "../gpu_primitive/COLLECTION_U32_STRUCT_READ.js";
28
+ import { chunk_lower_bound_branchless } from "../shader/chunk/math/chunk_lower_bound_branchless.js";
29
+ import { chunk_water_tessellation, WATER_TILE_STRUCT, WATER_TESSELLATION_STRUCT, WATER_TILE_CELLS } from "./surface/chunk_water_tessellation.js";
30
+ import { chunk_read_meshlet_vertex_by_draw_index } from "../shader/chunk/geometry/meshlet/chunk_read_meshlet_vertex_by_draw_index.js";
31
+ import { chunk_scene_database_access } from "../scene/chunk_scene_database_access.js";
32
+ import { chunk_mat3_inverse } from "../shader/chunk/geometry/mat3/chunk_mat3_inverse.js";
33
+ import { NODE3D_GLOBAL_FLAG_MIRRORED } from "../scene/NODE3D_STRUCT.js";
34
+ import { chunk_water_inscatter } from "./optics/chunk_water_inscatter.js";
35
+ import { chunk_water_receiver_downwelling } from "./optics/chunk_water_receiver_downwelling.js";
36
+ import { chunk_water_optics } from "./optics/chunk_water_optics.js";
37
+ import { chunk_water_receiver_radiance, chunk_water_receiver_texel, chunk_water_refraction_confidence,
38
+ chunk_water_transport, WATER_LEVEL_TOLERANCE_DECLARATION } from './chunk_water_transport.js';
39
+
40
+ export const WATER_GRID_STRUCT = WebGPUStruct.from({ resolution: u32 }, 'WaterGrid');
41
+
42
+ export const WATER_TRACE_STRUCT = WebGPUStruct.from({
43
+ max_distance: f32, distance_tolerance: f32, max_updates: u32, fallback_steps: u32,
44
+ mode: u32, reflections: u32,
45
+ // steps of the water body's in-scatter along each refracted view ray
46
+ inscatter_segments: u32,
47
+ }, "WaterTrace").pack();
48
+
49
+ function water_resources(finalize = false) {
50
+ const resources = new ShaderResourceSetDescriptor();
51
+ const group = resources.createGroup()
52
+ .addUniform("camera", CAMERA_UNIFORM_STRUCT)
53
+ .addUniform("trace", WATER_TRACE_STRUCT)
54
+ .addTexture("tDepth")
55
+ .addTexture("tNormal", "uint")
56
+ .addTexture("tHZB")
57
+ .addTexture("tScene")
58
+ .addStorageBuffer('scene_database', WebGPUArray.u32)
59
+ .addStorageBuffer('water_tiles', WebGPUArray.from(WATER_TILE_STRUCT))
60
+ .addStorageBuffer('water_tile_sums', COLLECTION_U32_STRUCT_READ)
61
+ .addUniform('tessellation', WATER_TESSELLATION_STRUCT)
62
+ .addStorageBuffer('meshlet_metadata', WebGPUArray.from(MESHLET_METADATA_STRUCT))
63
+ .addStorageBuffer('meshlet_data', WebGPUArray.from(f32))
64
+ .addStorageBuffer('wave_state', WebGPUArray.from(f32))
65
+ .addUniform('wave_grid', WATER_GRID_STRUCT);
66
+ if (finalize) {
67
+ group.addTexture('receiver').addTexture('trace_metadata').addTexture('visibility_distance');
68
+ }
69
+ return resources;
70
+ }
71
+ const resources = water_resources();
72
+
73
+ /** Optics under IBL (and LPV, which has no transparent variant): the lights and the environment. */
74
+ export const WATER_FINALIZE_RESOURCES_IBL = water_resources(true);
75
+ WATER_FINALIZE_RESOURCES_IBL.addGroup(SHADING_LIGHT_RESOURCE_GROUP);
76
+
77
+ /** Optics under Brick4: the lights, and the light map with the view its sampling jitters by. */
78
+ export const WATER_FINALIZE_RESOURCES_BRICK4 = water_resources(true);
79
+ WATER_FINALIZE_RESOURCES_BRICK4.addGroup(SHADING_LIGHT_RESOURCE_GROUP);
80
+ WATER_FINALIZE_RESOURCES_BRICK4.createGroup()
81
+ .addStorageBuffer("brick4", BRICK4_DATA_STRUCT, false)
82
+ .addUniform("view", VIEW_UNIFORM_STRUCT);
83
+
84
+ const surface_body = CodeChunk.from(/* language=WGSL */ `
85
+ struct WaterVertexOut {
86
+ // Receivers and optics are separate modules drawing this mesh; optics tests depth 'equal'
87
+ // against the receivers' depth, and both must cover the same edge pixels. Only @invariant
88
+ // makes the position bit-identical across programs.
89
+ @invariant @builtin(position) clip: vec4<f32>,
90
+ @location(0) world: vec3<f32>,
91
+ @location(1) normal: vec3<f32>,
92
+ // slope variance of the waves the surface's mesh does not resolve
93
+ @location(2) unresolved_variance: f32,
94
+ @location(3) @interpolate(flat) body_index: u32,
95
+ @location(4) rest_normal: vec3<f32>,
96
+ }
97
+
98
+ fn water_wave_height(row: u32, cell: vec2i) -> f32 {
99
+ let n = i32(wave_grid.resolution);
100
+ let c = clamp(cell, vec2i(0), vec2i(n - 1));
101
+ return wave_state[row * u32(n * n) + u32(c.y * n + c.x)];
102
+ }
103
+
104
+ // One instance per occupied view tile and source triangle. All overlap candidates survive
105
+ // classification; receiver depth selects the nearest displaced interface.
106
+ @vertex
107
+ fn vs_main(@builtin(vertex_index) vi: u32, @builtin(instance_index) ii: u32) -> WaterVertexOut {
108
+ let row = lower_bound_branchless(&water_tile_sums.elements, ii + 1u, water_tile_sums.count);
109
+ let definition = water_tiles[row];
110
+ let body = ${WATER_BODIES_TABLE.marshalling_method_read}(&scene_database, definition.body);
111
+ let header = meshlet_metadata[definition.meshlet];
112
+ let node = scene_read_node(&scene_database, body.node);
113
+ var previous = 0u;
114
+ if (row > 0u) { previous = water_tile_sums.elements[row - 1u]; }
115
+ let patch_index = ii - previous;
116
+ let tile = definition.origin + vec2i(i32(patch_index % definition.size.x), i32(patch_index / definition.size.x));
117
+ let cell = vi / 18u;
118
+ let lattice = tile * ${WATER_TILE_CELLS} + vec2i(i32(cell % ${WATER_TILE_CELLS}u), i32(cell / ${WATER_TILE_CELLS}u));
119
+ let pixel = vec2f(lattice) * definition.pixels;
120
+ let ndc0 = pixel / tessellation.resolution * vec2f(2,-2) + vec2f(-1,1);
121
+ // Form both endpoints from their integer lattice coordinate. Adding the pitch to
122
+ // an already rounded pixel coordinate gives neighbouring cells different edges.
123
+ let ndc1 = (vec2f(lattice + vec2i(1)) * definition.pixels) / tessellation.resolution * vec2f(2,-2) + vec2f(-1,1);
124
+ let a = read_meshlet_vertex_by_draw_index(header, definition.triangle * 3u);
125
+ let b = read_meshlet_vertex_by_draw_index(header, definition.triangle * 3u + 1u);
126
+ let c = read_meshlet_vertex_by_draw_index(header, definition.triangle * 3u + 2u);
127
+ let simulated = body.wave != ~0u;
128
+ let ca = tessellation.view_projection_matrix * (node.global * vec4f(water_reference_position(a.position, definition.anchor, simulated), 1));
129
+ let cb = tessellation.view_projection_matrix * (node.global * vec4f(water_reference_position(b.position, definition.anchor, simulated), 1));
130
+ let cc = tessellation.view_projection_matrix * (node.global * vec4f(water_reference_position(c.position, definition.anchor, simulated), 1));
131
+ let polygon = water_cell_polygon(ca, cb, cc, min(ndc0,ndc1), max(ndc0,ndc1));
132
+ let fan = (vi % 18u) / 3u;
133
+ if (polygon.count < fan + 3u) { return WaterVertexOut(vec4f(0,0,0,1),vec3f(0),vec3f(0,1,0),0,definition.body,vec3f(0,1,0)); }
134
+ let corner = select(vi % 3u, 2u - vi % 3u, (node.global_flags & ${NODE3D_GLOBAL_FLAG_MIRRORED}u) != 0u);
135
+ var index = 0u;
136
+ if (corner != 0u) { index = fan + corner; }
137
+ let barycentric = polygon.points[index];
138
+ var position = water_corner_position(a.position,b.position,c.position,ca,cb,cc,barycentric,
139
+ polygon.boundaries[index],min(ndc0,ndc1),max(ndc0,ndc1));
140
+ var normal = normalize(a.normal * barycentric.x + b.normal * barycentric.y + c.normal * barycentric.z);
141
+ let rest_normal = normal;
142
+ var variance = 0.0;
143
+ if (body.wave != ~0u) {
144
+ let params = ${WATER_WAVES_TABLE.marshalling_method_read}(&scene_database, body.wave);
145
+ let spacing = max((params.extent.zw - params.extent.xy) / f32(wave_grid.resolution - 1u), vec2f(1e-20));
146
+ let grid = clamp((position.xz - params.extent.xy) / spacing, vec2f(0.0), vec2f(f32(wave_grid.resolution - 1u)));
147
+ let cell = vec2i(grid);
148
+ let blend = fract(grid);
149
+ let h00 = water_wave_height(body.wave, cell);
150
+ let h10 = water_wave_height(body.wave, cell + vec2i(1, 0));
151
+ let h01 = water_wave_height(body.wave, cell + vec2i(0, 1));
152
+ let h11 = water_wave_height(body.wave, cell + vec2i(1, 1));
153
+ position.y += mix(mix(h00, h10, blend.x), mix(h01, h11, blend.x), blend.y);
154
+ let slope = vec2f(mix(h10 - h00, h11 - h01, blend.y), mix(h01 - h00, h11 - h10, blend.x)) / spacing;
155
+ normal = normalize(vec3f(normal.x - normal.y * slope.x, normal.y, normal.z - normal.y * slope.y));
156
+ variance = params.unresolved_variance;
157
+ }
158
+ let world = (node.global * vec4f(position, 1.0)).xyz;
159
+ let linear = mat3x3f(node.global[0].xyz, node.global[1].xyz, node.global[2].xyz);
160
+ let inverse_transpose = transpose(mat3_inverse(linear));
161
+ let normal_ws = normalize(inverse_transpose * normal);
162
+ let rest_normal_ws = normalize(inverse_transpose * rest_normal);
163
+ return WaterVertexOut(camera.view_projection_matrix * vec4f(world, 1.0), world, normal_ws, variance, definition.body,rest_normal_ws);
164
+ }
165
+
166
+ // The interface at one water fragment, in view space. Receivers trace through it and optics
167
+ // shade it, so both passes take it from here.
168
+ struct WaterInterface {
169
+ origin: vec3<f32>,
170
+ incident: vec3<f32>,
171
+ // Faces the camera's side of the interface.
172
+ normal: vec3<f32>,
173
+ ior: f32,
174
+ // Screen-space travel bound.
175
+ limit: f32,
176
+ }
177
+
178
+ fn water_interface(world: vec3<f32>, surface_normal: vec3<f32>, ior: f32, above: bool) -> WaterInterface {
179
+ let origin = (camera.view_matrix * vec4f(world, 1.0)).xyz;
180
+ let view = normalize(camera.view_matrix_inverse[3].xyz - world);
181
+ let shading = normalize(select(-surface_normal, surface_normal, above));
182
+ // At a crest the interpolated shading normal can leave the rasterized face's
183
+ // visible hemisphere. Keep Snell/Fresnel on that face's side, continuously at grazing.
184
+ let normal_ws = normalize(shading + view * max(1e-4 - dot(shading,view), 0.0));
185
+ return WaterInterface(origin, normalize(origin), normalize(direction_world_to_view(normal_ws, camera)),
186
+ max(ior, 1.0), min(max(trace.max_distance, 0.1), camera.clip_near_far.y));
187
+ }
188
+ `, [chunk_direction_world_to_view, WATER_BODIES_TABLE.chunk_read, WATER_WAVES_TABLE.chunk_read,
189
+ chunk_read_meshlet_vertex_by_draw_index, chunk_scene_database_access, chunk_mat3_inverse,
190
+ chunk_lower_bound_branchless, chunk_water_tessellation]);
191
+
192
+ export const chunk_water_screen_ray = CodeChunk.from(/* language=WGSL */ `
193
+ fn water_hzb_mip_size(depth_size: vec2f, hzb_size: vec2f, mip: i32) -> vec2f {
194
+ if (mip <= 0) { return depth_size; }
195
+ return max(vec2f(1.0), floor(hzb_size / exp2(f32(mip-1))));
196
+ }
197
+ // Reuse the renderer's FFX cell intersection and depth loads, but walk the actual
198
+ // integer mip grids. Its SSR driver halves floating sizes and assumes power-of-two
199
+ // reductions; Meep's HZB conservatively resamples arbitrary viewport dimensions.
200
+ fn water_hzb_crossing(origin: vec3f, direction: vec3f, budget: u32,
201
+ valid: ptr<function,bool>, iterations: ptr<function,u32>) -> vec3f {
202
+ let size = vec2f(textureDimensions(tDepth,0));
203
+ let pyramid_size = vec2f(textureDimensions(tHZB,0));
204
+ let last_mip = i32(textureNumLevels(tHZB));
205
+ let inverse_direction = select(vec3f(F32_MAX), 1.0/direction, abs(direction)>vec3f(1e-12));
206
+ let floor_offset = select(vec2f(1.0), vec2f(0.0), direction.xy<vec2f(0.0));
207
+ let uv_offset = select(0.005/size, -0.005/size, direction.xy<vec2f(0.0));
208
+ var mip = 0;
209
+ var position = origin;
210
+ var travel = 0.0;
211
+ *valid = false;
212
+ // Water is absent from the opaque depth buffer: skipping the initial pixel
213
+ // can skip the entire receiver for almost zero projected displacement.
214
+ for (var i=0u; i<min(budget,128u); i++) {
215
+ *iterations = i+1u;
216
+ if (!screen_space_ray_in_bounds(position.xy) || is_background(position.z)) { break; }
217
+ let resolution = water_hzb_mip_size(size,pyramid_size,mip);
218
+ let pixel = resolution * position.xy;
219
+ let depth = ffx_sssr_load_depth(vec2i(pixel),mip);
220
+ let skipped = ffx_sssr_advance_ray(origin,direction,inverse_direction,pixel,
221
+ 1.0/resolution,floor_offset,uv_offset,depth,&position,&travel);
222
+ if (!skipped && mip==0) { *valid=true; break; }
223
+ mip = clamp(mip+select(-1,1,skipped),0,last_mip);
224
+ }
225
+ return position;
226
+ }
227
+ // HZB returns a depth-slab crossing, not the intersection of the ray with the
228
+ // receiver's plane. Refine that crossing before using its UV or optical path.
229
+ fn water_exact_receiver(ray: Ray, input: ScreenSpaceRayHit) -> ScreenSpaceRayHit {
230
+ var hit = input;
231
+ if (hit.status != 0u) { return hit; }
232
+ let receiver = screen_space_ray_load_receiver(hit.uv, tDepth, tNormal,
233
+ camera.projection_matrix_inverse, camera.view_matrix);
234
+ let travel = plane_ray_raycast(ray.origin, ray.direction, receiver.plane);
235
+ // Keep the analytic distance rather than the projection of the texel center onto the ray.
236
+ if (travel > 1e-4 && travel <= ray.tmax) {
237
+ hit.distance = travel;
238
+ hit.uv = project_position(ray_at(ray.origin, ray.direction, travel), camera.projection_matrix).xy;
239
+ // Reprojection can change texel ownership at a silhouette. Validate that lookup
240
+ // again; the analytic travel above already checked the ray's bounded interval.
241
+ let checked = screen_space_ray_validate(Ray(ray.origin,ray.direction,1e20),hit.uv,tDepth,tNormal,
242
+ camera.projection_matrix,camera.projection_matrix_inverse,camera.view_matrix,trace.distance_tolerance);
243
+ hit.status = checked.status;
244
+ hit.residual = checked.residual;
245
+ } else { hit.status = 4u; }
246
+ return hit;
247
+ }
248
+ fn water_refine_receiver(ray: Ray, seed: vec2f) -> ScreenSpaceRayHit {
249
+ // The traversal already selected the first depth footprint. Intersect its plane
250
+ // once and validate ownership; another Newton search could jump past that footprint
251
+ // to a later root that the traversal has already ruled out.
252
+ return water_exact_receiver(ray, ScreenSpaceRayHit(seed, 0.0, 1e20, 0u, 0u));
253
+ }
254
+ fn water_hzb_hit(ray: Ray, budget: u32) -> ScreenSpaceRayHit {
255
+ var miss = ScreenSpaceRayHit(vec2f(0.0), 0.0, 1e20, 0u, 5u);
256
+ if (budget == 0u || !screen_space_ray_projectable(ray.origin, camera.projection_matrix)
257
+ || !screen_space_ray_projectable(ray.origin + ray.direction, camera.projection_matrix)) { return miss; }
258
+ let origin = project_position(ray.origin, camera.projection_matrix);
259
+ let direction = project_direction(ray.origin, ray.direction, origin, camera.projection_matrix);
260
+ // Only rays advancing into reverse-Z are supported by this adapter.
261
+ if (direction.z >= -1e-8 || !screen_space_ray_in_bounds(origin.xy)) { return miss; }
262
+ var valid = false;
263
+ var iterations = 0u;
264
+ let candidate = water_hzb_crossing(origin, direction, budget, &valid, &iterations);
265
+ if (!valid) { miss.iterations = iterations; return miss; }
266
+ var hit = water_refine_receiver(ray, candidate.xy);
267
+ hit.iterations = iterations;
268
+ return hit;
269
+ }
270
+ `, [chunk_screen_space_newton_ray, chunk_ffx_sssr_advance_ray, chunk_ffx_sssr_load_depth, chunk_project_direction,
271
+ chunk_ray_at]);
272
+
273
+ const body = CodeChunk.from(/* language=WGSL */ `
274
+ struct WaterReceiver {
275
+ @location(0) receiver: vec4<f32>,
276
+ @location(1) metadata: vec4<f32>,
277
+ // Receiver UV, bounded path, classified status + Newton updates / 32. Readback is opt-in.
278
+ }
279
+
280
+ // A screen-space receiver must lie below the surface point the ray entered at: the refracted ray runs
281
+ // downward from it, so any point on the ray is lower, and one that is not is a root off the ray.
282
+ fn water_receiver_submerged(uv: vec2f, surface: vec3f, normal: vec3f) -> bool {
283
+ let receiver = water_receiver_texel(tDepth, tNormal, vec2i(uv * vec2f(textureDimensions(tDepth, 0))),
284
+ camera.projection_matrix_inverse, camera.view_matrix_inverse);
285
+ return dot(receiver.position - surface, normal) <= WATER_LEVEL_TOLERANCE;
286
+ }
287
+
288
+ @fragment
289
+ fn fs_main(in: WaterVertexOut, @builtin(front_facing) above: bool) -> WaterReceiver {
290
+ let water = ${WATER_BODIES_TABLE.marshalling_method_read}(&scene_database, in.body_index);
291
+ let coord = vec2<i32>(in.clip.xy);
292
+ let dimensions = vec2f(textureDimensions(tDepth, 0));
293
+ let uv = in.clip.xy / dimensions;
294
+ let scene_depth = textureLoad(tDepth, coord, 0).r;
295
+ if (scene_depth >= in.clip.z) { discard; }
296
+ // the opaque scene behind this pixel, and how deep under the surface point it lies: shore water
297
+ // fades in over its first 10 cm, whatever is under it
298
+ var behind_vs = vec3f(0.0);
299
+ var water_depth = 1e20;
300
+ if (!is_background(scene_depth)) {
301
+ behind_vs = inv_project_position(vec3f(uv, scene_depth), camera.projection_matrix_inverse);
302
+ // Measure shore thickness relative to the authored surface. Wave crests
303
+ // becoming tangent to the view do not turn deep water into a shore fade.
304
+ // Both sides retain coverage; back faces use bounded below-interface transport.
305
+ water_depth = abs(dot(in.world - (camera.view_matrix_inverse * vec4f(behind_vs, 1.0)).xyz, normalize(in.rest_normal)));
306
+ }
307
+ let coverage = smoothstep(0.0, 0.1, water_depth);
308
+ let surface = water_interface(in.world, in.normal, water.ior, above);
309
+ let interface_normal = direction_view_to_world(surface.normal, camera);
310
+ let limit = surface.limit;
311
+ let direction = refract(surface.incident, surface.normal, 1.0 / surface.ior);
312
+ let ray = Ray(surface.origin, normalize(direction), limit);
313
+ var hit = ScreenSpaceRayHit(uv, limit, 1e20, 0u, 8u);
314
+ var newton_updates = 0u;
315
+ var newton_failure = 0u;
316
+ if (above && trace.mode == 0u) {
317
+ // Mayer et al. §2.2: a root within one pixel of the ray is accepted as is. Like the paper,
318
+ // this can converge past a thin occluder; traversal is only the fallback for failures.
319
+ hit = screen_space_newton_ray(ray, uv, tDepth, tNormal, camera.projection_matrix,
320
+ camera.projection_matrix_inverse, camera.view_matrix, trace.max_updates, trace.distance_tolerance);
321
+ newton_updates = hit.iterations;
322
+ newton_failure = hit.status;
323
+ }
324
+ // Reject foreground receivers before deciding whether traversal is needed.
325
+ if (hit.status == 0u && !water_receiver_submerged(hit.uv, in.world, interface_normal)) { hit.status = 5u; newton_failure = 5u; }
326
+ if (above && trace.mode != 2u && hit.status != 0u) {
327
+ let fallback = water_hzb_hit(ray, trace.fallback_steps);
328
+ if (fallback.status == 0u && water_receiver_submerged(fallback.uv, in.world, interface_normal)) { hit = fallback; hit.status = 6u; }
329
+ }
330
+ // Compute the control event for every pixel, independently of Newton/HZB success. With nothing
331
+ // behind the water on screen, integrate it to where it has taken all but a thousandth.
332
+ let clearest = min(min(water.extinction.x, water.extinction.y), water.extinction.z);
333
+ var control_path = min(log(1000.0) / max(clearest, 1e-30), limit);
334
+ var control_status = select(8u, 9u, !above);
335
+ if (!is_background(scene_depth)) {
336
+ if (water_depth >= -WATER_LEVEL_TOLERANCE || !above) {
337
+ control_path = min(distance(ray.origin, behind_vs), limit);
338
+ control_status = select(7u, 9u, !above);
339
+ }
340
+ }
341
+ if (trace.mode == 2u || !above || (hit.status != 0u && hit.status != 6u)) {
342
+ // Never use an unvalidated Newton iterate as a color lookup.
343
+ hit.uv = uv;
344
+ // A missing screen receiver is missing visibility, not 300 metres of water.
345
+ hit.distance = control_path;
346
+ hit.status = control_status;
347
+ }
348
+ var status = hit.status;
349
+ if (status == 6u) { status = 8u + newton_failure; }
350
+ else if (status == 7u) { status = 16u + newton_failure; }
351
+ else if (status == 8u) { status = 24u + newton_failure; }
352
+ else if (status == 9u) { status = 31u; }
353
+ return WaterReceiver(vec4f(hit.uv, hit.distance, f32(status) + f32(newton_updates)/32.0),
354
+ vec4f(control_path, min(hit.residual, 65504.0), coverage, f32(in.body_index + 1u)));
355
+ }
356
+ `, [surface_body, chunk_water_screen_ray, chunk_direction_view_to_world,
357
+ chunk_water_receiver_texel, WATER_LEVEL_TOLERANCE_DECLARATION]);
358
+
359
+ const finalize_body = CodeChunk.from(/* language=WGSL */ `
360
+ struct WaterOptics {
361
+ @location(0) transmission: vec4f,
362
+ @location(1) radiance: vec4f,
363
+ @location(2) background: vec4f,
364
+ }
365
+ @fragment
366
+ fn fs_main(in: WaterVertexOut, @builtin(front_facing) above: bool) -> WaterOptics {
367
+ let water = ${WATER_BODIES_TABLE.marshalling_method_read}(&scene_database, in.body_index);
368
+ let coord = vec2i(in.clip.xy);
369
+ let metadata = textureLoad(trace_metadata, coord, 0);
370
+ // Equal-depth surfaces must retain the same deterministic owner as receiver selection.
371
+ if (metadata.w != f32(in.body_index + 1u)) { discard; }
372
+ let dimensions = vec2f(textureDimensions(tDepth, 0));
373
+ let uv = in.clip.xy / dimensions;
374
+ let receiver_data = textureLoad(receiver, coord, 0);
375
+ let surface = water_interface(in.world, in.normal, water.ior, above);
376
+ let interface_normal = direction_view_to_world(surface.normal, camera);
377
+ let body = water;
378
+ let origin = surface.origin;
379
+ let ior = surface.ior;
380
+ let limit = surface.limit;
381
+ let nov = clamp(dot(-surface.incident, surface.normal), 0.0, 1.0);
382
+ // exact dielectric Fresnel: water is most reflective at grazing angles, where Schlick's is not right
383
+ let fresnel = F_dielectric(nov, ior);
384
+ let reflection_direction = reflect(surface.incident, surface.normal);
385
+ // a reflection that misses on screen falls back to the GI mode, as SSR's resolve does
386
+ var reflection = water_gi_specular(in.world, direction_view_to_world(surface.normal, camera),
387
+ direction_view_to_world(-surface.incident, camera), clamp(sqrt(water.roughness * water.roughness + in.unresolved_variance), 0.0, 1.0));
388
+ if (trace.reflections != 0u && above) {
389
+ let reflected = water_hzb_hit(Ray(ray_at(origin, reflection_direction, 0.02), reflection_direction, limit),
390
+ trace.fallback_steps);
391
+ if (reflected.status == 0u) {
392
+ let reflected_point = ray_at(origin, reflection_direction, reflected.distance + 0.02);
393
+ let projected = project_position(reflected_point, camera.projection_matrix);
394
+ // Reflection uses the renderer's usual back-face, thickness, self-hit and
395
+ // vignette validation. Its two-pixel rule must not reject normal-incidence refraction.
396
+ let confidence = ffx_sssr_validate_hit(vec3f(reflected.uv, projected.z), uv,
397
+ reflection_direction, dimensions, max(trace.distance_tolerance, 0.02), 0.05);
398
+ let radiance = water_receiver_radiance(tScene, tDepth, tNormal, reflected.uv,
399
+ camera.projection_matrix_inverse, camera.view_matrix_inverse, in.world, interface_normal, false);
400
+ reflection = mix(reflection, radiance.rgb,
401
+ confidence * min(radiance.a * 2.0, 1.0) * smoothstep(0.05, 0.5, reflected.distance)
402
+ * smoothstep(1.0, 4.0, length((reflected.uv - uv) * dimensions)));
403
+ }
404
+ }
405
+ let original = textureLoad(tScene, coord, 0);
406
+ let valid = receiver_data.w < 16.0 && above && trace.mode != 2u;
407
+ var confidence = select(0.0, water_refraction_confidence(receiver_data.xy, uv, dimensions,
408
+ texture_sample_bilinear_uv(visibility_distance, uv, 0u).r), valid);
409
+ // Mayer's fade selects one UV, rather than crossfading two images of the same edge.
410
+ let lookup = water_refraction_lookup(uv, receiver_data.xy, confidence);
411
+ // The surface height here stands for the one above the displaced receiver: they differ by the
412
+ // wave height across a few metres, against a tolerance the gather already allows.
413
+ let gathered = water_receiver_radiance(tScene, tDepth, tNormal, lookup,
414
+ camera.projection_matrix_inverse, camera.view_matrix_inverse, in.world, interface_normal, above);
415
+ var path = metadata.x;
416
+ var color = original.rgb;
417
+ // the receiver seen through the surface: refracted, or the pixel's own when there is none
418
+ var receiver_coord = coord;
419
+ if (confidence > 0.0 && gathered.a > 0.0) {
420
+ path = min(water_receiver_path(tDepth, tNormal, lookup, camera.projection_matrix_inverse,
421
+ camera.view_matrix, origin), limit);
422
+ color = gathered.rgb;
423
+ receiver_coord = vec2i(lookup * dimensions);
424
+ } else { confidence = 0.0; }
425
+ // The opaque scene was shaded dry: what reaches the receiver is what survives the water above it
426
+ // (WATER_OPTICS_PLAN_2026_10_02.md §4.3). Seen from under the surface, the receiver is above it.
427
+ let receiver_texel = water_receiver_texel(tDepth, tNormal, receiver_coord, camera.projection_matrix_inverse,
428
+ camera.view_matrix_inverse);
429
+ if (above && !is_background(receiver_texel.depth)) {
430
+ let camera_ws = camera.view_matrix_inverse[3].xyz;
431
+ let up = normalize(in.rest_normal);
432
+ color *= water_receiver_downwelling(body, receiver_texel.position, receiver_texel.normal, up,
433
+ max(dot(in.world - receiver_texel.position, up), 0.0), normalize(camera_ws - receiver_texel.position));
434
+ }
435
+ // Light in the water body (WATER_OPTICS_PLAN_2026_10_02.md §4.4): the receiver attenuated along
436
+ // the refracted path, and the sun and sky scattered back up it; both cross the surface by the
437
+ // n² law. A view from under the surface is outside this model: attenuation only.
438
+ let extinction = body.extinction.xyz;
439
+ var transmitted = exp(-extinction * max(path, 0.0));
440
+ var scattered = vec3f(0.0);
441
+ if (above) {
442
+ let exit = water_exit_factor(nov, ior);
443
+ let direction = normalize(direction_view_to_world(refract(surface.incident, surface.normal, 1.0 / ior), camera));
444
+ transmitted *= exit;
445
+ scattered = exit * water_inscatter(body, in.world, direction, normalize(in.rest_normal), max(path, 0.0), trace.inscatter_segments);
446
+ }
447
+ let event = water_event(transmitted, fresnel * reflection + scattered);
448
+ let optical = water_transport(event, original.rgb, color, metadata.z);
449
+ return WaterOptics(vec4f(optical.transmission, metadata.z), vec4f(optical.radiance, confidence),
450
+ vec4f(optical.background, original.a));
451
+ }
452
+ `, [surface_body, chunk_water_screen_ray, chunk_F_dielectric,
453
+ chunk_ffx_sssr_validate_hit, chunk_texture_sample_bilinear_uv,
454
+ chunk_direction_view_to_world, chunk_ray_at, chunk_water_optics, chunk_water_inscatter,
455
+ chunk_water_receiver_downwelling, chunk_water_receiver_texel,
456
+ chunk_water_transport, chunk_water_receiver_radiance, chunk_water_refraction_confidence]);
457
+
458
+ export const water_shader = ShaderDescriptor.from({ label: "Water / receivers", resources, body });
459
+ /** The optics pass under IBL, and under LPV, which has no transparent variant. */
460
+ export const water_finalize_shader_ibl = ShaderDescriptor.from({ label: 'Water / coherent optics IBL',
461
+ resources: WATER_FINALIZE_RESOURCES_IBL, body: CodeChunk.from('', [finalize_body, chunk_water_gi_ibl]) });
462
+ /** The optics pass under Brick4. */
463
+ export const water_finalize_shader_brick4 = ShaderDescriptor.from({ label: 'Water / coherent optics Brick4',
464
+ resources: WATER_FINALIZE_RESOURCES_BRICK4, body: CodeChunk.from('', [finalize_body, chunk_water_gi_brick4]) });
465
+ export const WATER_RESOURCES = resources;
466
+
467
+ /** Nearest-interface selection writes only water-owned depth and optics, never opaque G-buffer. */
468
+ function water_pipeline(shader, targets, finalize) {
469
+ const code = shader.source;
470
+ const layout = shader.resources.generatePipelineLayout(GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT);
471
+ // Tile reconstruction spends six storage slots. Lighting spends four in the fragment stage.
472
+ // Keep their visibility precise so the Brick4 variant fits the guaranteed stage budget.
473
+ const vertex_only = new Set(['water_tiles', 'water_tile_sums', 'tessellation', 'meshlet_metadata', 'meshlet_data', 'wave_state', 'wave_grid']);
474
+ shader.resources.groups.forEach((group, gi) => group.resources.forEach((resource, ri) => {
475
+ layout.bindGroupLayouts[gi].entries[ri].visibility = vertex_only.has(resource.name) ? GPUShaderStage.VERTEX
476
+ : resource.name === 'camera' || resource.name === 'scene_database' ? GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT
477
+ : GPUShaderStage.FRAGMENT;
478
+ }));
479
+ return RenderPipelineDescriptor.from({
480
+ label: shader.label,
481
+ layout,
482
+ vertex: { module: { code }, entryPoint: "vs_main" },
483
+ fragment: { module: { code }, entryPoint: "fs_main", targets: targets.map(format => ({ format })) },
484
+ depthStencil: DepthStencilState.from({ format: "depth32float", depthWriteEnabled: !finalize, depthCompare: finalize ? 'equal' : 'greater' }),
485
+ primitive: { topology: "triangle-list", cullMode: "none" },
486
+ });
487
+ }
488
+ export function create_water_pipeline() { return water_pipeline(water_shader, ['rgba32float', 'rgba32float'], false); }
489
+ export function create_water_finalize_pipeline_ibl() { return water_pipeline(water_finalize_shader_ibl, ['rgba32float', 'rgba16float', 'rgba16float'], true); }
490
+ export function create_water_finalize_pipeline_brick4() { return water_pipeline(water_finalize_shader_brick4, ['rgba32float', 'rgba16float', 'rgba16float'], true); }