@woosh/meep-engine 3.64.1 → 3.67.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 (372) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/build/bundle-worker-image-decoder.js +1 -1
  3. package/build/bundle-worker-terrain.js +1 -1
  4. package/package.json +1 -1
  5. package/src/core/binary/BinaryBuffer.d.ts +5 -0
  6. package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
  7. package/src/core/binary/BinaryBuffer.js +39 -5
  8. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts +65 -6
  9. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts.map +1 -1
  10. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.js +451 -101
  11. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts +4 -2
  12. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts.map +1 -1
  13. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +4 -2
  14. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts +8 -1
  15. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts.map +1 -1
  16. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.js +45 -10
  17. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
  18. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +237 -119
  19. package/src/engine/graphics/ecs/grass/GrassSpecies.d.ts +143 -0
  20. package/src/engine/graphics/ecs/grass/GrassSpecies.d.ts.map +1 -0
  21. package/src/engine/graphics/ecs/grass/GrassSpecies.js +189 -0
  22. package/src/engine/graphics/ecs/grass/GrassSurface.d.ts +25 -0
  23. package/src/engine/graphics/ecs/grass/GrassSurface.d.ts.map +1 -0
  24. package/src/engine/graphics/ecs/grass/GrassSurface.js +32 -0
  25. package/src/engine/graphics/ecs/grass/GroundCover.d.ts +68 -0
  26. package/src/engine/graphics/ecs/grass/GroundCover.d.ts.map +1 -0
  27. package/src/engine/graphics/ecs/grass/GroundCover.js +85 -0
  28. package/src/engine/graphics3/GrassSurfaceSystem.d.ts +153 -0
  29. package/src/engine/graphics3/GrassSurfaceSystem.d.ts.map +1 -0
  30. package/src/engine/graphics3/GrassSurfaceSystem.js +1076 -0
  31. package/src/engine/graphics3/GroundCoverSystem.d.ts +33 -0
  32. package/src/engine/graphics3/GroundCoverSystem.d.ts.map +1 -0
  33. package/src/engine/graphics3/GroundCoverSystem.js +58 -0
  34. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  35. package/src/engine/network/NetworkSession.js +372 -110
  36. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  37. package/src/engine/network/orchestrator/NetworkPeer.js +6 -1
  38. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  39. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +9 -2
  40. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
  41. package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +325 -140
  42. package/src/engine/network/sim/SimActionExecutor.d.ts +4 -1
  43. package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
  44. package/src/engine/network/sim/SimActionExecutor.js +65 -9
  45. package/src/engine/network/state/PredictionHistory.d.ts.map +1 -1
  46. package/src/engine/network/state/PredictionHistory.js +6 -1
  47. package/src/engine/network/time/AdaptiveRenderDelay.d.ts +25 -14
  48. package/src/engine/network/time/AdaptiveRenderDelay.d.ts.map +1 -1
  49. package/src/engine/network/time/AdaptiveRenderDelay.js +38 -20
  50. package/src/engine/network/time/RenderPlayout.d.ts +23 -3
  51. package/src/engine/network/time/RenderPlayout.d.ts.map +1 -1
  52. package/src/engine/network/time/RenderPlayout.js +40 -4
  53. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  54. package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.d.ts +5 -1
  55. package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.d.ts.map +1 -1
  56. package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.js +27 -1
  57. package/src/format/lut/cube/CubeLut.d.ts +38 -0
  58. package/src/format/lut/cube/CubeLut.d.ts.map +1 -0
  59. package/src/format/lut/cube/CubeLut.js +23 -0
  60. package/src/format/lut/cube/cube_read.d.ts +23 -0
  61. package/src/format/lut/cube/cube_read.d.ts.map +1 -0
  62. package/src/format/lut/cube/cube_read.js +199 -0
  63. package/src/format/lut/cube/cube_write.d.ts +15 -0
  64. package/src/format/lut/cube/cube_write.d.ts.map +1 -0
  65. package/src/format/lut/cube/cube_write.js +90 -0
  66. package/src/shade/device/shader/ShaderModuleCompiler.d.ts +2 -0
  67. package/src/shade/device/shader/ShaderModuleCompiler.d.ts.map +1 -1
  68. package/src/shade/device/shader/ShaderModuleCompiler.js +25 -2
  69. package/src/shade/playground/grass_surfaces/index.html +75 -0
  70. package/src/shade/playground/grass_surfaces/main.d.ts +2 -0
  71. package/src/shade/playground/grass_surfaces/main.d.ts.map +1 -0
  72. package/src/shade/playground/grass_surfaces/main.js +593 -0
  73. package/src/shade/playground/grass_surfaces/read_grass_surfaces.d.ts +62 -0
  74. package/src/shade/playground/grass_surfaces/read_grass_surfaces.d.ts.map +1 -0
  75. package/src/shade/playground/grass_surfaces/read_grass_surfaces.js +188 -0
  76. package/src/shade/playground/probe_clipmap/README.md +1 -0
  77. package/src/shade/playground/probe_clipmap/index.html +5 -0
  78. package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
  79. package/src/shade/playground/probe_clipmap/main.js +7 -0
  80. package/src/shade/playground/probe_clipmap_box/README.md +5 -1
  81. package/src/shade/playground/probe_clipmap_box/index.html +12 -0
  82. package/src/shade/playground/probe_clipmap_box/main.d.ts.map +1 -1
  83. package/src/shade/playground/probe_clipmap_box/main.js +15 -0
  84. package/src/shade/playground/probe_clipmap_box/scene.d.ts +8 -1
  85. package/src/shade/playground/probe_clipmap_box/scene.d.ts.map +1 -1
  86. package/src/shade/playground/probe_clipmap_box/scene.js +74 -6
  87. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  88. package/src/shade/renderer/Renderer.js +59 -55
  89. package/src/shade/renderer/deferred/tonemap/ColorGrade.d.ts +73 -4
  90. package/src/shade/renderer/deferred/tonemap/ColorGrade.d.ts.map +1 -1
  91. package/src/shade/renderer/deferred/tonemap/ColorGrade.js +113 -7
  92. package/src/shade/renderer/deferred/tonemap/TONEMAP_PURKINJE_SHIFT.d.ts +12 -0
  93. package/src/shade/renderer/deferred/tonemap/TONEMAP_PURKINJE_SHIFT.d.ts.map +1 -0
  94. package/src/shade/renderer/deferred/tonemap/TONEMAP_PURKINJE_SHIFT.js +12 -0
  95. package/src/shade/renderer/deferred/tonemap/ToneMapper.d.ts +15 -1
  96. package/src/shade/renderer/deferred/tonemap/ToneMapper.d.ts.map +1 -1
  97. package/src/shade/renderer/deferred/tonemap/ToneMapper.js +31 -3
  98. package/src/shade/renderer/deferred/tonemap/chunk_tonemap_purkinje.d.ts +25 -0
  99. package/src/shade/renderer/deferred/tonemap/chunk_tonemap_purkinje.d.ts.map +1 -0
  100. package/src/shade/renderer/deferred/tonemap/chunk_tonemap_purkinje.js +51 -0
  101. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.d.ts +2 -2
  102. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.d.ts.map +1 -1
  103. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.js +6 -3
  104. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.d.ts +3 -2
  105. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.d.ts.map +1 -1
  106. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.js +7 -3
  107. package/src/shade/renderer/extension/ViewTextures.d.ts +12 -5
  108. package/src/shade/renderer/extension/ViewTextures.d.ts.map +1 -1
  109. package/src/shade/renderer/extension/ViewTextures.js +19 -5
  110. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +3 -1
  111. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts.map +1 -1
  112. package/src/shade/renderer/fluid/GPUFluidCascadeStack.js +6 -1
  113. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +7 -0
  114. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts.map +1 -1
  115. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.js +10 -0
  116. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +7 -1
  117. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  118. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +46 -15
  119. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts +3 -2
  120. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts.map +1 -1
  121. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.js +3 -2
  122. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.d.ts +22 -0
  123. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.d.ts.map +1 -0
  124. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.js +247 -0
  125. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +50 -0
  126. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  127. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +101 -0
  128. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +2 -1
  129. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -1
  130. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +2 -1
  131. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts +8 -0
  132. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts.map +1 -1
  133. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.js +12 -0
  134. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts +12 -6
  135. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts.map +1 -1
  136. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.js +35 -29
  137. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.d.ts.map +1 -1
  138. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.js +4 -2
  139. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.d.ts.map +1 -1
  140. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.js +6 -4
  141. package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.d.ts.map +1 -1
  142. package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.js +2 -1
  143. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts +6 -5
  144. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts.map +1 -1
  145. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.js +15 -14
  146. package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.d.ts.map +1 -1
  147. package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.js +4 -2
  148. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +19 -2
  149. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  150. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +128 -10
  151. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +19 -1
  152. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
  153. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +27 -2
  154. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.d.ts +19 -11
  155. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.d.ts.map +1 -1
  156. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.js +35 -11
  157. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
  158. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +3 -1
  159. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.d.ts +40 -0
  160. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.d.ts.map +1 -0
  161. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.js +174 -0
  162. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.d.ts +4 -4
  163. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.js +10 -10
  164. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.d.ts +31 -0
  165. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.d.ts.map +1 -0
  166. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.js +54 -0
  167. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts +8 -4
  168. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -1
  169. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +10 -21
  170. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts +7 -2
  171. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts.map +1 -1
  172. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.js +33 -29
  173. package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.d.ts +28 -0
  174. package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.d.ts.map +1 -0
  175. package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.js +138 -0
  176. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts +13 -9
  177. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts.map +1 -1
  178. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.js +18 -11
  179. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.js +1 -1
  180. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.d.ts.map +1 -1
  181. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.js +4 -2
  182. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.d.ts.map +1 -1
  183. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.js +2 -3
  184. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts +5 -3
  185. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts.map +1 -1
  186. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.js +15 -30
  187. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -1
  188. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
  189. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +4 -2
  190. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts +11 -0
  191. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts.map +1 -1
  192. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.js +29 -2
  193. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.d.ts +40 -0
  194. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.d.ts.map +1 -0
  195. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.js +126 -0
  196. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.d.ts +36 -0
  197. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.d.ts.map +1 -0
  198. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.js +221 -0
  199. package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.d.ts +40 -0
  200. package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.d.ts.map +1 -0
  201. package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.js +86 -0
  202. package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts +135 -0
  203. package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts.map +1 -0
  204. package/src/shade/renderer/grass/blade/GPUGrassBlades.js +676 -0
  205. package/src/shade/renderer/grass/blade/GRASS_BLADE.d.ts +145 -0
  206. package/src/shade/renderer/grass/blade/GRASS_BLADE.d.ts.map +1 -0
  207. package/src/shade/renderer/grass/blade/GRASS_BLADE.js +179 -0
  208. package/src/shade/renderer/grass/blade/chunk_grass_blade.d.ts +63 -0
  209. package/src/shade/renderer/grass/blade/chunk_grass_blade.d.ts.map +1 -0
  210. package/src/shade/renderer/grass/blade/chunk_grass_blade.js +244 -0
  211. package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.d.ts +58 -0
  212. package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.d.ts.map +1 -0
  213. package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.js +174 -0
  214. package/src/shade/renderer/grass/blade/grass_blade_id_draw.d.ts +25 -0
  215. package/src/shade/renderer/grass/blade/grass_blade_id_draw.d.ts.map +1 -0
  216. package/src/shade/renderer/grass/blade/grass_blade_id_draw.js +133 -0
  217. package/src/shade/renderer/grass/blade/grass_blade_mechanics.d.ts +80 -0
  218. package/src/shade/renderer/grass/blade/grass_blade_mechanics.d.ts.map +1 -0
  219. package/src/shade/renderer/grass/blade/grass_blade_mechanics.js +92 -0
  220. package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts +29 -0
  221. package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts.map +1 -0
  222. package/src/shade/renderer/grass/blade/grass_blade_resolve.js +175 -0
  223. package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.d.ts +14 -0
  224. package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.d.ts.map +1 -0
  225. package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.js +45 -0
  226. package/src/shade/renderer/grass/blade/shader_grass_blade_expand.d.ts +61 -0
  227. package/src/shade/renderer/grass/blade/shader_grass_blade_expand.d.ts.map +1 -0
  228. package/src/shade/renderer/grass/blade/shader_grass_blade_expand.js +340 -0
  229. package/src/shade/renderer/grass/blade/shader_grass_cell_count.d.ts +46 -0
  230. package/src/shade/renderer/grass/blade/shader_grass_cell_count.d.ts.map +1 -0
  231. package/src/shade/renderer/grass/blade/shader_grass_cell_count.js +280 -0
  232. package/src/shade/renderer/grass/population/chunk_grass_population.d.ts +60 -0
  233. package/src/shade/renderer/grass/population/chunk_grass_population.d.ts.map +1 -0
  234. package/src/shade/renderer/grass/population/chunk_grass_population.js +171 -0
  235. package/src/shade/renderer/grass/press/GPUGrassPress.d.ts +99 -0
  236. package/src/shade/renderer/grass/press/GPUGrassPress.d.ts.map +1 -0
  237. package/src/shade/renderer/grass/press/GPUGrassPress.js +436 -0
  238. package/src/shade/renderer/grass/press/GRASS_PRESS.d.ts +179 -0
  239. package/src/shade/renderer/grass/press/GRASS_PRESS.d.ts.map +1 -0
  240. package/src/shade/renderer/grass/press/GRASS_PRESS.js +217 -0
  241. package/src/shade/renderer/grass/press/chunk_grass_press.d.ts +65 -0
  242. package/src/shade/renderer/grass/press/chunk_grass_press.d.ts.map +1 -0
  243. package/src/shade/renderer/grass/press/chunk_grass_press.js +296 -0
  244. package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts +31 -0
  245. package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts.map +1 -0
  246. package/src/shade/renderer/grass/press/shader_grass_press_mark.js +169 -0
  247. package/src/shade/renderer/grass/press/shader_grass_press_stamp.d.ts +27 -0
  248. package/src/shade/renderer/grass/press/shader_grass_press_stamp.d.ts.map +1 -0
  249. package/src/shade/renderer/grass/press/shader_grass_press_stamp.js +183 -0
  250. package/src/shade/renderer/grass/surface/GPUGrassSurfaces.d.ts +193 -0
  251. package/src/shade/renderer/grass/surface/GPUGrassSurfaces.d.ts.map +1 -0
  252. package/src/shade/renderer/grass/surface/GPUGrassSurfaces.js +1253 -0
  253. package/src/shade/renderer/grass/surface/GRASS_SURFACE.d.ts +211 -0
  254. package/src/shade/renderer/grass/surface/GRASS_SURFACE.d.ts.map +1 -0
  255. package/src/shade/renderer/grass/surface/GRASS_SURFACE.js +241 -0
  256. package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.d.ts +82 -0
  257. package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.d.ts.map +1 -0
  258. package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.js +111 -0
  259. package/src/shade/renderer/grass/surface/chunk_grass_column_cross.d.ts +39 -0
  260. package/src/shade/renderer/grass/surface/chunk_grass_column_cross.d.ts.map +1 -0
  261. package/src/shade/renderer/grass/surface/chunk_grass_column_cross.js +85 -0
  262. package/src/shade/renderer/grass/surface/chunk_grass_directory.d.ts +29 -0
  263. package/src/shade/renderer/grass/surface/chunk_grass_directory.d.ts.map +1 -0
  264. package/src/shade/renderer/grass/surface/chunk_grass_directory.js +112 -0
  265. package/src/shade/renderer/grass/surface/chunk_grass_slot.d.ts +27 -0
  266. package/src/shade/renderer/grass/surface/chunk_grass_slot.d.ts.map +1 -0
  267. package/src/shade/renderer/grass/surface/chunk_grass_slot.js +50 -0
  268. package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.d.ts +21 -0
  269. package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.d.ts.map +1 -0
  270. package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.js +41 -0
  271. package/src/shade/renderer/grass/surface/chunk_grass_surface_window.d.ts +32 -0
  272. package/src/shade/renderer/grass/surface/chunk_grass_surface_window.d.ts.map +1 -0
  273. package/src/shade/renderer/grass/surface/chunk_grass_surface_window.js +136 -0
  274. package/src/shade/renderer/grass/surface/chunk_grass_surfel.d.ts +37 -0
  275. package/src/shade/renderer/grass/surface/chunk_grass_surfel.d.ts.map +1 -0
  276. package/src/shade/renderer/grass/surface/chunk_grass_surfel.js +85 -0
  277. package/src/shade/renderer/grass/surface/chunk_grass_tile.d.ts +25 -0
  278. package/src/shade/renderer/grass/surface/chunk_grass_tile.d.ts.map +1 -0
  279. package/src/shade/renderer/grass/surface/chunk_grass_tile.js +52 -0
  280. package/src/shade/renderer/grass/surface/shader_grass_directory_fill.d.ts +23 -0
  281. package/src/shade/renderer/grass/surface/shader_grass_directory_fill.d.ts.map +1 -0
  282. package/src/shade/renderer/grass/surface/shader_grass_directory_fill.js +87 -0
  283. package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts +43 -0
  284. package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts.map +1 -0
  285. package/src/shade/renderer/grass/surface/shader_grass_surface_bake.js +265 -0
  286. package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.d.ts +13 -0
  287. package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.d.ts.map +1 -0
  288. package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.js +49 -0
  289. package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.d.ts +62 -0
  290. package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.d.ts.map +1 -0
  291. package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.js +162 -0
  292. package/src/shade/renderer/grass/surface/shader_grass_surface_retire.d.ts +40 -0
  293. package/src/shade/renderer/grass/surface/shader_grass_surface_retire.d.ts.map +1 -0
  294. package/src/shade/renderer/grass/surface/shader_grass_surface_retire.js +155 -0
  295. package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.d.ts +19 -0
  296. package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.d.ts.map +1 -0
  297. package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.js +58 -0
  298. package/src/shade/renderer/grass/surface/shader_grass_surface_want.d.ts +30 -0
  299. package/src/shade/renderer/grass/surface/shader_grass_surface_want.d.ts.map +1 -0
  300. package/src/shade/renderer/grass/surface/shader_grass_surface_want.js +251 -0
  301. package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.d.ts +21 -0
  302. package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.d.ts.map +1 -0
  303. package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.js +75 -0
  304. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts +35 -9
  305. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts.map +1 -1
  306. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.js +81 -11
  307. package/src/shade/renderer/postprocess/eye/shader_autoexposure_adapt.d.ts.map +1 -1
  308. package/src/shade/renderer/postprocess/eye/shader_autoexposure_adapt.js +4 -1
  309. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts.map +1 -1
  310. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.js +4 -23
  311. package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.d.ts +12 -0
  312. package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.d.ts.map +1 -0
  313. package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.js +29 -0
  314. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  315. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +22 -0
  316. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  317. package/src/shade/renderer/scene/GPUSceneContext.js +3 -0
  318. package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.d.ts +27 -0
  319. package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.d.ts.map +1 -0
  320. package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.js +38 -0
  321. package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.d.ts +28 -0
  322. package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.d.ts.map +1 -0
  323. package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.js +58 -0
  324. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.d.ts.map +1 -1
  325. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +8 -0
  326. package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.d.ts +6 -0
  327. package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.d.ts.map +1 -1
  328. package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.js +7 -0
  329. package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.d.ts +4 -4
  330. package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.d.ts.map +1 -1
  331. package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.js +86 -5
  332. package/src/shade/renderer/shader/chunk/color/tonemap/purkinje/chunk_apply_purkinje_shift.d.ts +65 -0
  333. package/src/shade/renderer/shader/chunk/color/tonemap/purkinje/chunk_apply_purkinje_shift.d.ts.map +1 -0
  334. package/src/shade/renderer/shader/chunk/color/tonemap/purkinje/chunk_apply_purkinje_shift.js +136 -0
  335. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts +37 -0
  336. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts.map +1 -0
  337. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.js +148 -0
  338. package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.d.ts +20 -0
  339. package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.d.ts.map +1 -0
  340. package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.js +169 -0
  341. package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.d.ts +18 -0
  342. package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.d.ts.map +1 -1
  343. package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.js +28 -0
  344. package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.d.ts +13 -0
  345. package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.d.ts.map +1 -0
  346. package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.js +22 -0
  347. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  348. package/src/shade/renderer/water/GPUWaterRenderer.js +4 -0
  349. package/src/shade/renderer/wind/GPUSceneWind.d.ts +52 -5
  350. package/src/shade/renderer/wind/GPUSceneWind.d.ts.map +1 -1
  351. package/src/shade/renderer/wind/GPUSceneWind.js +164 -8
  352. package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts +3 -1
  353. package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts.map +1 -1
  354. package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.js +3 -1
  355. package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts +2 -1
  356. package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts.map +1 -1
  357. package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.js +18 -13
  358. package/src/shade/renderer/wind/chunk_wind_field_sample_previous.d.ts +13 -0
  359. package/src/shade/renderer/wind/chunk_wind_field_sample_previous.d.ts.map +1 -0
  360. package/src/shade/renderer/wind/chunk_wind_field_sample_previous.js +23 -0
  361. package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts +1 -0
  362. package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts.map +1 -1
  363. package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.js +6 -1
  364. package/src/shade/renderer/wind/wind_field_add_resources.d.ts +11 -0
  365. package/src/shade/renderer/wind/wind_field_add_resources.d.ts.map +1 -1
  366. package/src/shade/renderer/wind/wind_field_add_resources.js +15 -0
  367. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +1 -1
  368. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  369. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +2 -0
  370. package/src/shade/renderer/shader/chunk/color/tonemap/purkinjie/chunk_apply_purkinjie_shift.d.ts +0 -11
  371. package/src/shade/renderer/shader/chunk/color/tonemap/purkinjie/chunk_apply_purkinjie_shift.d.ts.map +0 -1
  372. package/src/shade/renderer/shader/chunk/color/tonemap/purkinjie/chunk_apply_purkinjie_shift.js +0 -56
@@ -0,0 +1,174 @@
1
+ import { CLIPMAP_LEVEL_LIMIT, CLIPMAP_LEVEL_STRUCT } from "../../../shader/chunk/clipmap/CLIPMAP_LEVEL_STRUCT.js";
2
+ import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
3
+ import { chunk_probe_clipmap, PROBE_LEVELS_RESOURCE } from "./chunk_probe_clipmap.js";
4
+ import { PROBE_RECEIVER_BIAS } from "./PROBE_CLIPMAP.js";
5
+
6
+ /**
7
+ * The cages a reader anywhere inside a world box can read (PROBE_CLIPMAP_PROPOSAL_2026_10_27.md §8.3, §9.1), for
8
+ * a want that knows its readers by their bounds alone: a meshlet's, whose fragments pick probes.
9
+ *
10
+ * ```wgsl
11
+ * struct ProbeClipmapBoxCages { first: vec3<i32>, dims: vec3<u32> }
12
+ * fn probe_clipmap_box_cascades(box_min: vec3<f32>, box_max: vec3<f32>, cascade_count: u32, anchor: vec3<f32>, select_half: f32) -> vec2<u32>
13
+ * fn probe_clipmap_box_cages(box_min: vec3<f32>, box_max: vec3<f32>, cascade: u32, anchor: vec3<f32>, select_half: f32) -> ProbeClipmapBoxCages
14
+ * fn probe_clipmap_box_cage_count(box_min: vec3<f32>, box_max: vec3<f32>, cascade_count: u32, anchor: vec3<f32>, select_half: f32) -> u32
15
+ * fn probe_clipmap_cage_is_read(cascade: u32, cage: vec3<i32>, anchor: vec3<f32>, select_half: f32) -> bool
16
+ * fn probe_clipmap_cage_meets_box(cascade: u32, cage: vec3<i32>, local_min: vec3<f32>, local_max: vec3<f32>, transform: mat4x4<f32>) -> bool
17
+ * ```
18
+ *
19
+ * A reader at p reads the cage of p moved by at most {@link PROBE_RECEIVER_BIAS} of a spacing, in the cascade
20
+ * `probe_clipmap_select_in` answers for p and, in its blend skirt, in the next. So over a box:
21
+ *
22
+ * - `probe_clipmap_box_cascades`: the cascades its points can read, the first and one past the last, equal
23
+ * where the box lies outside every selection box. From the cascade its point nearest the anchor selects to
24
+ * the one its farthest does, and one more where the farthest lies in that one's skirt.
25
+ * - `probe_clipmap_box_cages`: in one of those, the block of cages such a reader can read: those of the box's
26
+ * part inside the cascade's selection box, grown by the bias, and kept to the cascade's cage window. `dims`
27
+ * holds a zero where there is none.
28
+ * - `probe_clipmap_box_cage_count`: the cages of every block.
29
+ *
30
+ * The blocks are a superset of what any surface inside the box reads. Two tests a thread a cage can afford
31
+ * narrow them, each still a superset:
32
+ *
33
+ * - `probe_clipmap_cage_is_read`: whether a point within the bias of the cage selects its cascade, or the
34
+ * finer one in its skirt; a block holds cages no point reads where its box crosses a selection box's face.
35
+ * - `probe_clipmap_cage_meets_box`: whether the cage, grown by the bias, meets the box as it lies in its own
36
+ * space, by its three axes: a flat box turned away from the world's axes fills its world box with cages
37
+ * it never crosses.
38
+ *
39
+ * Reads `probe_levels`.
40
+ *
41
+ * @type {CodeChunk}
42
+ */
43
+ export const chunk_probe_clipmap_box_cages = CodeChunk.from(
44
+ //language=WGSL
45
+ `
46
+ struct ProbeClipmapBoxCages {
47
+ // the least cage of the block
48
+ first: vec3<i32>,
49
+ // its cages along each axis
50
+ dims: vec3<u32>,
51
+ }
52
+
53
+ fn probe_clipmap_box_max3(v: vec3<f32>) -> f32 {
54
+ return max(max(v.x, v.y), v.z);
55
+ }
56
+
57
+ // the finest cascade whose selection box holds a point \`reach\` from the anchor along its longest axis, or the count
58
+ fn probe_clipmap_cascade_at_reach(reach: f32, cascade_count: u32, select_half: f32) -> u32 {
59
+ for (var i = 0u; i < ${CLIPMAP_LEVEL_LIMIT}u; i++) {
60
+ if (i >= cascade_count) {
61
+ break;
62
+ }
63
+
64
+ if (select_half * probe_levels[i].cell_size >= reach) {
65
+ return i;
66
+ }
67
+ }
68
+
69
+ return cascade_count;
70
+ }
71
+
72
+ fn probe_clipmap_box_cascades(box_min: vec3<f32>, box_max: vec3<f32>, cascade_count: u32, anchor: vec3<f32>, select_half: f32) -> vec2<u32> {
73
+ let reach_near = probe_clipmap_box_max3(abs(clamp(anchor, box_min, box_max) - anchor));
74
+ let reach_far = probe_clipmap_box_max3(max(abs(box_min - anchor), abs(box_max - anchor)));
75
+
76
+ let first = probe_clipmap_cascade_at_reach(reach_near, cascade_count, select_half);
77
+
78
+ if (first >= cascade_count) {
79
+ return vec2<u32>(cascade_count);
80
+ }
81
+
82
+ let last = min(probe_clipmap_cascade_at_reach(reach_far, cascade_count, select_half), cascade_count - 1u);
83
+ // past the last one's skirt line its farthest points read the next as well
84
+ let skirt = reach_far > (select_half - PROBE_BLEND_SKIRT) * probe_levels[last].cell_size;
85
+
86
+ return vec2<u32>(first, min(last + select(1u, 2u, skirt), cascade_count));
87
+ }
88
+
89
+ fn probe_clipmap_box_cages(box_min: vec3<f32>, box_max: vec3<f32>, cascade: u32, anchor: vec3<f32>, select_half: f32) -> ProbeClipmapBoxCages {
90
+ let level = probe_levels[cascade];
91
+ let cell = level.cell_size;
92
+ let bias = ${PROBE_RECEIVER_BIAS} * cell;
93
+
94
+ // the box's part whose points select this cascade or a finer one
95
+ let half = vec3<f32>(select_half * cell);
96
+ let a = max(box_min, anchor - half);
97
+ let b = min(box_max, anchor + half);
98
+
99
+ // their cages, the bias either way, inside the cage window
100
+ let first = max(vec3<i32>(floor((a - bias) / cell)), level.corner);
101
+ let last = min(vec3<i32>(floor((b + bias) / cell)), level.corner + level.size - vec3<i32>(1));
102
+
103
+ var out: ProbeClipmapBoxCages;
104
+
105
+ out.first = first;
106
+ out.dims = vec3<u32>(max(last - first + vec3<i32>(1), vec3<i32>(0)));
107
+
108
+ if (any(a > b)) {
109
+ out.dims = vec3<u32>(0u);
110
+ }
111
+
112
+ return out;
113
+ }
114
+
115
+ fn probe_clipmap_box_cage_count(box_min: vec3<f32>, box_max: vec3<f32>, cascade_count: u32, anchor: vec3<f32>, select_half: f32) -> u32 {
116
+ let cascades = probe_clipmap_box_cascades(box_min, box_max, cascade_count, anchor, select_half);
117
+
118
+ var count = 0u;
119
+
120
+ for (var i = 0u; i < ${CLIPMAP_LEVEL_LIMIT}u; i++) {
121
+ let cascade = cascades.x + i;
122
+
123
+ if (cascade >= cascades.y) {
124
+ break;
125
+ }
126
+
127
+ let cages = probe_clipmap_box_cages(box_min, box_max, cascade, anchor, select_half);
128
+
129
+ count += cages.dims.x * cages.dims.y * cages.dims.z;
130
+ }
131
+
132
+ return count;
133
+ }
134
+
135
+ fn probe_clipmap_cage_is_read(cascade: u32, cage: vec3<i32>, anchor: vec3<f32>, select_half: f32) -> bool {
136
+ let cell = probe_levels[cascade].cell_size;
137
+ // the points that read the cage lie within the bias of it
138
+ let half = (0.5 + ${PROBE_RECEIVER_BIAS}) * cell;
139
+ let from_anchor = abs((vec3<f32>(cage) + 0.5) * cell - anchor);
140
+
141
+ // one of them selects this cascade or a finer one
142
+ var read = probe_clipmap_box_max3(max(from_anchor - half, vec3<f32>(0.0))) <= select_half * cell;
143
+
144
+ if (cascade > 0u) {
145
+ // and not every one selects a finer one short of its skirt
146
+ read = read && probe_clipmap_box_max3(from_anchor + half) > (select_half - PROBE_BLEND_SKIRT) * probe_levels[cascade - 1u].cell_size;
147
+ }
148
+
149
+ return read;
150
+ }
151
+
152
+ fn probe_clipmap_cage_meets_box(cascade: u32, cage: vec3<i32>, local_min: vec3<f32>, local_max: vec3<f32>, transform: mat4x4<f32>) -> bool {
153
+ let cell = probe_levels[cascade].cell_size;
154
+ let half = (0.5 + ${PROBE_RECEIVER_BIAS}) * cell;
155
+ let local_half = 0.5 * (local_max - local_min);
156
+ let offset = (vec3<f32>(cage) + 0.5) * cell - (transform * vec4<f32>(0.5 * (local_min + local_max), 1.0)).xyz;
157
+
158
+ // each of the box's own axes by name: a dynamic index would put the matrix in local memory
159
+ let x = transform[0].xyz;
160
+ let y = transform[1].xyz;
161
+ let z = transform[2].xyz;
162
+
163
+ // along an axis, the cage's reach and the box's, against how far apart their centres are: the axis is
164
+ // left at the transform's scale, which every term carries
165
+ return abs(dot(offset, x)) <= half * (abs(x.x) + abs(x.y) + abs(x.z)) + local_half.x * dot(x, x)
166
+ && abs(dot(offset, y)) <= half * (abs(y.x) + abs(y.y) + abs(y.z)) + local_half.y * dot(y, y)
167
+ && abs(dot(offset, z)) <= half * (abs(z.x) + abs(z.y) + abs(z.z)) + local_half.z * dot(z, z);
168
+ }
169
+ `, [
170
+ chunk_probe_clipmap,
171
+ CLIPMAP_LEVEL_STRUCT.declaration_chunk,
172
+ ]);
173
+
174
+ chunk_probe_clipmap_box_cages.requireResource(PROBE_LEVELS_RESOURCE);
@@ -3,13 +3,13 @@
3
3
  *
4
4
  * ```wgsl
5
5
  * struct ProbeClipmapHitMaterial { found: bool, albedo: vec3<f32>, emissive: vec3<f32> }
6
- * fn probe_clipmap_hit_material(position: vec3<f32>, normal: vec3<f32>, cascade: u32) -> ProbeClipmapHitMaterial
6
+ * fn probe_clipmap_hit_material(position: vec3<f32>, normal: vec3<f32>, cascade: u32, atlas_shift: u32) -> ProbeClipmapHitMaterial
7
7
  * ```
8
8
  *
9
9
  * The hit is at `position` in brick cascade `cascade`, its field's normal `normal`: the brick holding it,
10
10
  * looked up in the brick map at the hit's cascade as the march found it, and its material there
11
11
  * (`brick_material_surface`), albedo and emissive. A hit whose brick carries no material for its surface
12
- * is black, `found` false.
12
+ * is black, `found` false. `atlas_shift` is the brick atlas's footprint, as `chunk_brick_clipmap_sample` takes it.
13
13
  *
14
14
  * @type {CodeChunk}
15
15
  */
@@ -18,7 +18,7 @@ export const chunk_probe_clipmap_hit_material: CodeChunk;
18
18
  * The material a probe ray's hit takes its light with, from one texel of the brick material:
19
19
  *
20
20
  * ```wgsl
21
- * fn probe_clipmap_hit_material_pick(position: vec3<f32>, normal: vec3<f32>, cascade: u32, u: f32) -> ProbeClipmapHitMaterial
21
+ * fn probe_clipmap_hit_material_pick(position: vec3<f32>, normal: vec3<f32>, cascade: u32, u: f32, atlas_shift: u32) -> ProbeClipmapHitMaterial
22
22
  * ```
23
23
  *
24
24
  * As {@link chunk_probe_clipmap_hit_material} finds the hit's brick, one of the texels its blend weighs
@@ -33,7 +33,7 @@ export const chunk_probe_clipmap_hit_material_pick: CodeChunk;
33
33
  * surface, for the debug views: the GI's light takes none of it yet.
34
34
  *
35
35
  * ```wgsl
36
- * fn probe_clipmap_hit_metal_rough(position: vec3<f32>, normal: vec3<f32>, cascade: u32) -> vec3<f32> // (metalness, roughness, 1 if found)
36
+ * fn probe_clipmap_hit_metal_rough(position: vec3<f32>, normal: vec3<f32>, cascade: u32, atlas_shift: u32) -> vec3<f32> // (metalness, roughness, 1 if found)
37
37
  * ```
38
38
  *
39
39
  * @type {CodeChunk}
@@ -48,26 +48,26 @@ brick_at.requireResource(BRICK_MAP_TEXTURE_RESOURCE);
48
48
  *
49
49
  * ```wgsl
50
50
  * struct ProbeClipmapHitMaterial { found: bool, albedo: vec3<f32>, emissive: vec3<f32> }
51
- * fn probe_clipmap_hit_material(position: vec3<f32>, normal: vec3<f32>, cascade: u32) -> ProbeClipmapHitMaterial
51
+ * fn probe_clipmap_hit_material(position: vec3<f32>, normal: vec3<f32>, cascade: u32, atlas_shift: u32) -> ProbeClipmapHitMaterial
52
52
  * ```
53
53
  *
54
54
  * The hit is at `position` in brick cascade `cascade`, its field's normal `normal`: the brick holding it,
55
55
  * looked up in the brick map at the hit's cascade as the march found it, and its material there
56
56
  * (`brick_material_surface`), albedo and emissive. A hit whose brick carries no material for its surface
57
- * is black, `found` false.
57
+ * is black, `found` false. `atlas_shift` is the brick atlas's footprint, as `chunk_brick_clipmap_sample` takes it.
58
58
  *
59
59
  * @type {CodeChunk}
60
60
  */
61
61
  export const chunk_probe_clipmap_hit_material = CodeChunk.from(
62
62
  //language=WGSL
63
63
  `
64
- fn probe_clipmap_hit_material(position: vec3<f32>, normal: vec3<f32>, cascade: u32) -> ProbeClipmapHitMaterial {
64
+ fn probe_clipmap_hit_material(position: vec3<f32>, normal: vec3<f32>, cascade: u32, atlas_shift: u32) -> ProbeClipmapHitMaterial {
65
65
  var out: ProbeClipmapHitMaterial;
66
66
 
67
67
  let brick = probe_clipmap_hit_brick(position, cascade);
68
68
 
69
69
  if (brick_clipmap_entry_holds_slot(brick.entry)) {
70
- let seen = brick_material_surface(brick.entry, brick.local, normal);
70
+ let seen = brick_material_surface(brick.entry, brick.local, normal, atlas_shift);
71
71
 
72
72
  out.found = seen.found;
73
73
  out.albedo = seen.albedo;
@@ -82,7 +82,7 @@ fn probe_clipmap_hit_material(position: vec3<f32>, normal: vec3<f32>, cascade: u
82
82
  * The material a probe ray's hit takes its light with, from one texel of the brick material:
83
83
  *
84
84
  * ```wgsl
85
- * fn probe_clipmap_hit_material_pick(position: vec3<f32>, normal: vec3<f32>, cascade: u32, u: f32) -> ProbeClipmapHitMaterial
85
+ * fn probe_clipmap_hit_material_pick(position: vec3<f32>, normal: vec3<f32>, cascade: u32, u: f32, atlas_shift: u32) -> ProbeClipmapHitMaterial
86
86
  * ```
87
87
  *
88
88
  * As {@link chunk_probe_clipmap_hit_material} finds the hit's brick, one of the texels its blend weighs
@@ -94,13 +94,13 @@ fn probe_clipmap_hit_material(position: vec3<f32>, normal: vec3<f32>, cascade: u
94
94
  export const chunk_probe_clipmap_hit_material_pick = CodeChunk.from(
95
95
  //language=WGSL
96
96
  `
97
- fn probe_clipmap_hit_material_pick(position: vec3<f32>, normal: vec3<f32>, cascade: u32, u: f32) -> ProbeClipmapHitMaterial {
97
+ fn probe_clipmap_hit_material_pick(position: vec3<f32>, normal: vec3<f32>, cascade: u32, u: f32, atlas_shift: u32) -> ProbeClipmapHitMaterial {
98
98
  var out: ProbeClipmapHitMaterial;
99
99
 
100
100
  let brick = probe_clipmap_hit_brick(position, cascade);
101
101
 
102
102
  if (brick_clipmap_entry_holds_slot(brick.entry)) {
103
- let seen = brick_material_surface_pick(brick.entry, brick.local, normal, u);
103
+ let seen = brick_material_surface_pick(brick.entry, brick.local, normal, u, atlas_shift);
104
104
 
105
105
  out.found = seen.found;
106
106
  out.albedo = seen.albedo;
@@ -116,7 +116,7 @@ fn probe_clipmap_hit_material_pick(position: vec3<f32>, normal: vec3<f32>, casca
116
116
  * surface, for the debug views: the GI's light takes none of it yet.
117
117
  *
118
118
  * ```wgsl
119
- * fn probe_clipmap_hit_metal_rough(position: vec3<f32>, normal: vec3<f32>, cascade: u32) -> vec3<f32> // (metalness, roughness, 1 if found)
119
+ * fn probe_clipmap_hit_metal_rough(position: vec3<f32>, normal: vec3<f32>, cascade: u32, atlas_shift: u32) -> vec3<f32> // (metalness, roughness, 1 if found)
120
120
  * ```
121
121
  *
122
122
  * @type {CodeChunk}
@@ -124,14 +124,14 @@ fn probe_clipmap_hit_material_pick(position: vec3<f32>, normal: vec3<f32>, casca
124
124
  export const chunk_probe_clipmap_hit_metal_rough = CodeChunk.from(
125
125
  //language=WGSL
126
126
  `
127
- fn probe_clipmap_hit_metal_rough(position: vec3<f32>, normal: vec3<f32>, cascade: u32) -> vec3<f32> {
127
+ fn probe_clipmap_hit_metal_rough(position: vec3<f32>, normal: vec3<f32>, cascade: u32, atlas_shift: u32) -> vec3<f32> {
128
128
  let brick = probe_clipmap_hit_brick(position, cascade);
129
129
 
130
130
  if (!brick_clipmap_entry_holds_slot(brick.entry)) {
131
131
  return vec3<f32>(0.0);
132
132
  }
133
133
 
134
- let seen = brick_material_metal_rough(brick.entry, brick.local, normal);
134
+ let seen = brick_material_metal_rough(brick.entry, brick.local, normal, atlas_shift);
135
135
 
136
136
  return vec3<f32>(seen.metal_rough, select(0.0, 1.0, seen.found));
137
137
  }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * A one-step sphere parallax for a probe's radiance tap (PROBE_CLIPMAP_PROPOSAL_2026_10_27.md §9.3, "Parallax
3
+ * correction"): the direction along which a probe sees what a ray from another point reaches.
4
+ *
5
+ * ```wgsl
6
+ * fn probe_clipmap_parallax(slot: u32, probe: vec3<f32>, spacing: f32, position: vec3<f32>, direction: vec3<f32>) -> vec3<f32>
7
+ * ```
8
+ *
9
+ * - `probe` is where the slot's probe stands, `spacing` its cascade's; `direction` is unit.
10
+ * - The ray from `position` along `direction` is met with a sphere about the probe whose radius is the probe's
11
+ * mean depth along `direction`, one bilinear tap of its depth tile. The far root is taken, so a point inside
12
+ * the sphere always meets it. The result is the unit direction from the probe to where they meet.
13
+ * - Where the ray misses the sphere, or meets it only behind the point, the result is `direction`.
14
+ *
15
+ * **Misses.** The depth is the visibility's (§8.2): a ray that missed, and a hit further than
16
+ * `PROBE_DEPTH_LIMIT` spacings, are both stored as the limit. The sphere therefore never stands further than
17
+ * the limit, and whatever lies past it, the sky included, is taken to be that near. A point a distance d from
18
+ * the probe has its direction toward such a thing turned by up to asin(d / (limit · spacing)), where the right
19
+ * turn for the sky is none. The probes of a cage each turn by their own angle, so their taps of one distant
20
+ * thing land on different texels. The depth cannot tell a miss from a hit at the limit, and its two moments say
21
+ * what share of a texel's rays went past the limit but not how far: a parallax that is right past the limit
22
+ * needs a distance the probe does not store.
23
+ *
24
+ * `probe_clipmap_sample_radiance` does not take this parallax, for that reason: it taps along the lobe. The
25
+ * chunk is kept for a reader whose probes see nothing past the limit.
26
+ *
27
+ * @type {CodeChunk}
28
+ */
29
+ export const chunk_probe_clipmap_parallax: CodeChunk;
30
+ import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
31
+ //# sourceMappingURL=chunk_probe_clipmap_parallax.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_probe_clipmap_parallax.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,2CAFU,SAAS,CAwBZ;0BArDmB,uCAAuC"}
@@ -0,0 +1,54 @@
1
+ import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
2
+ import { chunk_probe_clipmap_pick } from "./chunk_probe_clipmap_pick.js";
3
+
4
+ /**
5
+ * A one-step sphere parallax for a probe's radiance tap (PROBE_CLIPMAP_PROPOSAL_2026_10_27.md §9.3, "Parallax
6
+ * correction"): the direction along which a probe sees what a ray from another point reaches.
7
+ *
8
+ * ```wgsl
9
+ * fn probe_clipmap_parallax(slot: u32, probe: vec3<f32>, spacing: f32, position: vec3<f32>, direction: vec3<f32>) -> vec3<f32>
10
+ * ```
11
+ *
12
+ * - `probe` is where the slot's probe stands, `spacing` its cascade's; `direction` is unit.
13
+ * - The ray from `position` along `direction` is met with a sphere about the probe whose radius is the probe's
14
+ * mean depth along `direction`, one bilinear tap of its depth tile. The far root is taken, so a point inside
15
+ * the sphere always meets it. The result is the unit direction from the probe to where they meet.
16
+ * - Where the ray misses the sphere, or meets it only behind the point, the result is `direction`.
17
+ *
18
+ * **Misses.** The depth is the visibility's (§8.2): a ray that missed, and a hit further than
19
+ * `PROBE_DEPTH_LIMIT` spacings, are both stored as the limit. The sphere therefore never stands further than
20
+ * the limit, and whatever lies past it, the sky included, is taken to be that near. A point a distance d from
21
+ * the probe has its direction toward such a thing turned by up to asin(d / (limit · spacing)), where the right
22
+ * turn for the sky is none. The probes of a cage each turn by their own angle, so their taps of one distant
23
+ * thing land on different texels. The depth cannot tell a miss from a hit at the limit, and its two moments say
24
+ * what share of a texel's rays went past the limit but not how far: a parallax that is right past the limit
25
+ * needs a distance the probe does not store.
26
+ *
27
+ * `probe_clipmap_sample_radiance` does not take this parallax, for that reason: it taps along the lobe. The
28
+ * chunk is kept for a reader whose probes see nothing past the limit.
29
+ *
30
+ * @type {CodeChunk}
31
+ */
32
+ export const chunk_probe_clipmap_parallax = CodeChunk.from(
33
+ //language=WGSL
34
+ `
35
+ fn probe_clipmap_parallax(slot: u32, probe: vec3<f32>, spacing: f32, position: vec3<f32>, direction: vec3<f32>) -> vec3<f32> {
36
+ // a miss reads the limit here, as a hit at the limit does: see the chunk's notes on misses
37
+ let radius = probe_clipmap_depth_moments(slot, direction).x * spacing;
38
+ let origin = position - probe;
39
+ let b = dot(direction, origin);
40
+ let discriminant = b * b - (dot(origin, origin) - radius * radius);
41
+
42
+ if (discriminant >= 0.0) {
43
+ let t = sqrt(discriminant) - b;
44
+
45
+ if (t > 0.0) {
46
+ return normalize(origin + t * direction);
47
+ }
48
+ }
49
+
50
+ return direction;
51
+ }
52
+ `, [
53
+ chunk_probe_clipmap_pick,
54
+ ]);
@@ -13,10 +13,14 @@
13
13
  * picked by, at the visibility it was picked at. The trilinear part cancels.
14
14
  * - **The sample vector** is Lagarde's dominant direction, `normalize(mix(r, n, α))` with r the
15
15
  * reflection of the view and α the roughness squared.
16
- * - **A radiance tap** a probe, along the sample vector after a one-step sphere parallax: the reflected ray
17
- * is met with a sphere about the probe whose radius is its mean depth along the vector. The depth is held
18
- * at the cage's diagonal (§8.2), past which no parallax is taken. One bilinear tap of the tile, through
19
- * its skirt and the depth's sampler.
16
+ * - **A radiance tap** a probe, along the sample vector: one bilinear tap of the tile, through its skirt and
17
+ * the depth's sampler. Every picked probe is tapped along the same direction, as if what it sees there were
18
+ * infinitely far.
19
+ * - **No parallax** is taken toward what a probe sees along the vector. The only distance a probe stores is its
20
+ * visibility depth, where a miss and a hit past `PROBE_DEPTH_LIMIT` both read the limit, so a sphere of
21
+ * that depth turns the taps of the sky and of everything distant, each probe's by its own angle
22
+ * (`chunk_probe_clipmap_parallax`, kept beside this chunk and not linked by it; §9.3, "Parallax
23
+ * correction"). A reflection of something nearer than the limit is therefore placed as if it were far.
20
24
  * - **The rough end** is the probes' SH, mixed by the same shares and resolved for the GGX lobe
21
25
  * (`sh3_color_get_radiance_with_GGX`, as Brick4 resolves its probes). The two are blended by
22
26
  * `roughness_to_mip_ratio`: SH alone from roughness 0.7.
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_probe_clipmap_sample_radiance.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js"],"names":[],"mappings":"AA4BA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,kDAFU,SAAS,CAmIZ;0BA1KmB,uCAAuC"}
1
+ {"version":3,"file":"chunk_probe_clipmap_sample_radiance.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js"],"names":[],"mappings":"AA4BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,kDAFU,SAAS,CAoHZ;0BA/JmB,uCAAuC"}
@@ -41,10 +41,14 @@ import { PROBE_RECEIVER_BIAS_VIEW } from "./PROBE_CLIPMAP.js";
41
41
  * picked by, at the visibility it was picked at. The trilinear part cancels.
42
42
  * - **The sample vector** is Lagarde's dominant direction, `normalize(mix(r, n, α))` with r the
43
43
  * reflection of the view and α the roughness squared.
44
- * - **A radiance tap** a probe, along the sample vector after a one-step sphere parallax: the reflected ray
45
- * is met with a sphere about the probe whose radius is its mean depth along the vector. The depth is held
46
- * at the cage's diagonal (§8.2), past which no parallax is taken. One bilinear tap of the tile, through
47
- * its skirt and the depth's sampler.
44
+ * - **A radiance tap** a probe, along the sample vector: one bilinear tap of the tile, through its skirt and
45
+ * the depth's sampler. Every picked probe is tapped along the same direction, as if what it sees there were
46
+ * infinitely far.
47
+ * - **No parallax** is taken toward what a probe sees along the vector. The only distance a probe stores is its
48
+ * visibility depth, where a miss and a hit past `PROBE_DEPTH_LIMIT` both read the limit, so a sphere of
49
+ * that depth turns the taps of the sky and of everything distant, each probe's by its own angle
50
+ * (`chunk_probe_clipmap_parallax`, kept beside this chunk and not linked by it; §9.3, "Parallax
51
+ * correction"). A reflection of something nearer than the limit is therefore placed as if it were far.
48
52
  * - **The rough end** is the probes' SH, mixed by the same shares and resolved for the GGX lobe
49
53
  * (`sh3_color_get_radiance_with_GGX`, as Brick4 resolves its probes). The two are blended by
50
54
  * `roughness_to_mip_ratio`: SH alone from roughness 0.7.
@@ -97,23 +101,8 @@ fn probe_clipmap_lobe(slot: u32, share: f32, position: vec3<f32>, normal: vec3<f
97
101
  out.weight = share * probe_visibility_weight(toward, lobe, visibility) / probe_visibility_weight(toward, normal, visibility);
98
102
  out.sh = probe_record_sh_decode(record.sh);
99
103
 
100
- // the reflected ray met with a sphere about the probe, its radius the probe's mean depth along the lobe
101
- let radius = probe_clipmap_depth_moments(slot, lobe).x * spacing;
102
- let origin = position - probe;
103
- let b = dot(lobe, origin);
104
- let discriminant = b * b - (dot(origin, origin) - radius * radius);
105
-
106
- var direction = lobe;
107
-
108
- if (discriminant >= 0.0) {
109
- let t = sqrt(discriminant) - b;
110
-
111
- if (t > 0.0) {
112
- direction = normalize(origin + t * lobe);
113
- }
114
- }
115
-
116
- out.radiance = probe_clipmap_radiance(slot, direction).rgb;
104
+ // along the lobe itself: no parallax toward what the probe sees there (chunk_probe_clipmap_parallax, on misses)
105
+ out.radiance = probe_clipmap_radiance(slot, lobe).rgb;
117
106
 
118
107
  return out;
119
108
  }
@@ -4,8 +4,13 @@
4
4
  *
5
5
  * ```wgsl
6
6
  * fn probe_clipmap_want(wants: bool, position: vec3<f32>, bias_direction: vec3<f32>, cascade_count: u32, resolution: u32, anchor: vec3<f32>, select_half: f32, wanted_capacity: u32)
7
+ * fn probe_clipmap_want_cage(wants: bool, cascade: u32, cage: vec3<i32>, resolution: u32, wanted_capacity: u32)
7
8
  * ```
8
9
  *
10
+ * `probe_clipmap_want_cage` wants one cage by name, the cage whose least point is `cage` in `cascade`, for a
11
+ * caller that knows its cages without a point to read them from; the cascade's cage window must hold it
12
+ * (`clipmap_contains`). `probe_clipmap_want` is the two it reads from a point.
13
+ *
9
14
  * The cages are the pick's: the cascade `probe_clipmap_select_in` answers for the point, by the windows'
10
15
  * `anchor` and `select_half` as the pick reads them, the cage of the point biased along `bias_direction` by
11
16
  * that cascade's spacing, and in the cascade's blend skirt the next cascade's cage too, biased by its own. A cage a bias moved out of its window is not wanted. Each cage
@@ -16,8 +21,8 @@
16
21
  * workgroup's table and sets its bits; the rest want it through that lane. Measured on the AMD iGPU at
17
22
  * 1280×720 on Sponza before the claims, the bits' atomics were 140 of want's 345 µs and the appends 90.
18
23
  *
19
- * Every lane of the workgroup calls it once, wanting or not, from uniform control flow: the appends are
20
- * the subgroup's.
24
+ * Every lane of the workgroup calls `probe_clipmap_want` once, or `probe_clipmap_want_cage` at most twice, which
25
+ * the claim table is sized for, wanting or not, from uniform control flow: the appends are the subgroup's.
21
26
  *
22
27
  * @type {CodeChunk}
23
28
  */
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_probe_clipmap_want.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.js"],"names":[],"mappings":"AA0BA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,uCAFU,SAAS,CAgFZ;0BA9HmB,uCAAuC"}
1
+ {"version":3,"file":"chunk_probe_clipmap_want.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.js"],"names":[],"mappings":"AA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,uCAFU,SAAS,CA+EZ;0BAlImB,uCAAuC"}
@@ -13,7 +13,7 @@ import { PROBE_THREAD_WORKGROUP_SIZE } from "./PROBE_CLIPMAP.js";
13
13
  /**
14
14
  * Slots of a workgroup's claim table: twice the claims its lanes make at most, a cage in each of two
15
15
  * cascades a lane, so a probe finds a slot within a few. Sized for {@link PROBE_THREAD_WORKGROUP_SIZE}
16
- * lanes: want's 8×8 tiles, and the hits' wants' 64.
16
+ * lanes: want's 8×8 tiles, and the hits' wants' 64; the meshlets' wants' lanes are twice as many, a cage each.
17
17
  * @type {number}
18
18
  */
19
19
  const WANT_CLAIM_SLOTS = 2 * 2 * PROBE_THREAD_WORKGROUP_SIZE;
@@ -30,8 +30,13 @@ const WANT_CLAIM_PROBES = 16;
30
30
  *
31
31
  * ```wgsl
32
32
  * fn probe_clipmap_want(wants: bool, position: vec3<f32>, bias_direction: vec3<f32>, cascade_count: u32, resolution: u32, anchor: vec3<f32>, select_half: f32, wanted_capacity: u32)
33
+ * fn probe_clipmap_want_cage(wants: bool, cascade: u32, cage: vec3<i32>, resolution: u32, wanted_capacity: u32)
33
34
  * ```
34
35
  *
36
+ * `probe_clipmap_want_cage` wants one cage by name, the cage whose least point is `cage` in `cascade`, for a
37
+ * caller that knows its cages without a point to read them from; the cascade's cage window must hold it
38
+ * (`clipmap_contains`). `probe_clipmap_want` is the two it reads from a point.
39
+ *
35
40
  * The cages are the pick's: the cascade `probe_clipmap_select_in` answers for the point, by the windows'
36
41
  * `anchor` and `select_half` as the pick reads them, the cage of the point biased along `bias_direction` by
37
42
  * that cascade's spacing, and in the cascade's blend skirt the next cascade's cage too, biased by its own. A cage a bias moved out of its window is not wanted. Each cage
@@ -42,8 +47,8 @@ const WANT_CLAIM_PROBES = 16;
42
47
  * workgroup's table and sets its bits; the rest want it through that lane. Measured on the AMD iGPU at
43
48
  * 1280×720 on Sponza before the claims, the bits' atomics were 140 of want's 345 µs and the appends 90.
44
49
  *
45
- * Every lane of the workgroup calls it once, wanting or not, from uniform control flow: the appends are
46
- * the subgroup's.
50
+ * Every lane of the workgroup calls `probe_clipmap_want` once, or `probe_clipmap_want_cage` at most twice, which
51
+ * the claim table is sized for, wanting or not, from uniform control flow: the appends are the subgroup's.
47
52
  *
48
53
  * @type {CodeChunk}
49
54
  */
@@ -80,46 +85,45 @@ fn probe_want_claim(key: u32) -> bool {
80
85
  return true;
81
86
  }
82
87
 
83
- fn probe_clipmap_want(wants: bool, position: vec3<f32>, bias_direction: vec3<f32>, cascade_count: u32, resolution: u32, anchor: vec3<f32>, select_half: f32, wanted_capacity: u32) {
84
- let selection = probe_clipmap_select_in(&probe_levels, cascade_count, anchor, select_half, position);
85
-
86
- let held = wants && selection.level != CLIPMAP_LEVEL_NONE;
87
- let finest = select(0u, selection.level, held);
88
- let next = min(finest + 1u, cascade_count - 1u);
89
-
90
- var cage_finest: vec3<i32>;
91
- var cage_next: vec3<i32>;
92
-
88
+ fn probe_clipmap_want_cage(wants: bool, cascade: u32, cage: vec3<i32>, resolution: u32, wanted_capacity: u32) {
93
89
  // storage wraps by the window's side, a power of two: the low bits of a point, negative ones too
94
90
  let wrap = vec3<u32>(resolution - 1u);
95
91
 
96
- let wants_finest = held && probe_clipmap_cage(finest, position, bias_direction, &cage_finest)
97
- && probe_want_claim(probe_clipmap_key(finest, vec3<u32>(cage_finest) & wrap, resolution));
98
- let wants_next = held && selection.edge_weight > 0.0 && finest + 1u < cascade_count
99
- && probe_clipmap_cage(next, position, bias_direction, &cage_next)
100
- && probe_want_claim(probe_clipmap_key(next, vec3<u32>(cage_next) & wrap, resolution));
101
-
102
- // every lane through all sixteen corners, so that the appends stay in uniform control flow
103
- for (var k = 0u; k < 16u; k++) {
104
- let coarse = k >= 8u;
105
- let cascade = select(finest, next, coarse);
106
- let wanted = select(wants_finest, wants_next, coarse);
107
- let corner = vec3<i32>(vec3<u32>(k & 1u, (k >> 1u) & 1u, (k >> 2u) & 1u));
108
- let point = select(cage_finest, cage_next, coarse) + corner;
92
+ let claimed = wants && probe_want_claim(probe_clipmap_key(cascade, vec3<u32>(cage) & wrap, resolution));
109
93
 
110
- let storage = vec3<u32>(point) & wrap;
111
- let key = probe_clipmap_key(cascade, storage, resolution);
94
+ // every lane through all eight corners, so that the appends stay in uniform control flow
95
+ for (var k = 0u; k < 8u; k++) {
96
+ let corner = vec3<i32>(vec3<u32>(k & 1u, (k >> 1u) & 1u, (k >> 2u) & 1u));
97
+ let key = probe_clipmap_key(cascade, vec3<u32>(cage + corner) & wrap, resolution);
112
98
  let bit = 1u << (key & 31u);
113
99
 
114
100
  var first = false;
115
101
 
116
- if (wanted) {
102
+ if (claimed) {
117
103
  first = (atomicOr(&probe_wanted_bits[key >> 5u], bit) & bit) == 0u;
118
104
  }
119
105
 
120
106
  collection_u32_append(&probe_wanted, first, key, wanted_capacity);
121
107
  }
122
108
  }
109
+
110
+ fn probe_clipmap_want(wants: bool, position: vec3<f32>, bias_direction: vec3<f32>, cascade_count: u32, resolution: u32, anchor: vec3<f32>, select_half: f32, wanted_capacity: u32) {
111
+ let selection = probe_clipmap_select_in(&probe_levels, cascade_count, anchor, select_half, position);
112
+
113
+ let held = wants && selection.level != CLIPMAP_LEVEL_NONE;
114
+ let finest = select(0u, selection.level, held);
115
+ let next = min(finest + 1u, cascade_count - 1u);
116
+
117
+ var cage_finest: vec3<i32>;
118
+ var cage_next: vec3<i32>;
119
+
120
+ let wants_finest = held && probe_clipmap_cage(finest, position, bias_direction, &cage_finest);
121
+ let wants_next = held && selection.edge_weight > 0.0 && finest + 1u < cascade_count
122
+ && probe_clipmap_cage(next, position, bias_direction, &cage_next);
123
+
124
+ probe_clipmap_want_cage(wants_finest, finest, cage_finest, resolution, wanted_capacity);
125
+ probe_clipmap_want_cage(wants_next, next, cage_next, resolution, wanted_capacity);
126
+ }
123
127
  `, [
124
128
  chunk_probe_clipmap,
125
129
  chunk_probe_clipmap_select_in,
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Record the wants of a list of meshlets whose fragments pick probes (PROBE_CLIPMAP_PROPOSAL_2026_10_27.md §8.3):
3
+ * the meshlets a forward pass draws, which no pixel of the G-buffer stands for. Each wants the cages a reader
4
+ * anywhere inside its world box can read, a thread a cage: its cages are counted
5
+ * (`shader_probe_clipmap_want_meshlet_count`), the counts summed (`graph_prefix_scan_csdldf`), and the sums
6
+ * launch the wants (`shader_probe_clipmap_want_meshlets`), as the meshes' expansion to meshlets is launched.
7
+ *
8
+ * The wants go into the clipmap's late set (`GPUProbeClipmap.write_want_bindings`), so the pass belongs after the
9
+ * clipmap's lifetime in the frame, and its probes are admitted by the next frame's.
10
+ *
11
+ * @param {Object} options
12
+ * @param {import("../../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} options.graph
13
+ * @param {import("./GPUProbeClipmap.js").GPUProbeClipmap} options.clipmap the clipmap the fragments pick from
14
+ * @param {import("../../../scene/GPUSceneContext.js").GPUSceneContext} options.scene the meshlets' scene
15
+ * @param {number} options.camera graph handle of the view's camera uniform
16
+ * @param {number} options.meshlet_collection graph handle of the list, `MESHLET_COLLECTION_STRUCT`
17
+ * @param {number} options.meshlet_iterator_command graph handle of the indirect dispatch that walks the list, a
18
+ * workgroup of `COMPUTE_SHADER_DEFAULT_GROUP_SIZE` meshlets, folded
19
+ */
20
+ export function graph_probe_clipmap_want_meshlets({ graph, clipmap, scene, camera, meshlet_collection, meshlet_iterator_command }: {
21
+ graph: import("../../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph;
22
+ clipmap: import("./GPUProbeClipmap.js").GPUProbeClipmap;
23
+ scene: import("../../../scene/GPUSceneContext.js").GPUSceneContext;
24
+ camera: number;
25
+ meshlet_collection: number;
26
+ meshlet_iterator_command: number;
27
+ }): void;
28
+ //# sourceMappingURL=graph_probe_clipmap_want_meshlets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph_probe_clipmap_want_meshlets.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.js"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;;GAkBG;AACH;IARyG,KAAK,EAAnG,OAAO,iEAAiE,EAAE,UAAU;IAC5B,OAAO,EAA/D,OAAO,sBAAsB,EAAE,eAAe;IACuB,KAAK,EAA1E,OAAO,mCAAmC,EAAE,eAAe;IAC3C,MAAM,EAAtB,MAAM;IACU,kBAAkB,EAAlC,MAAM;IACU,wBAAwB,EAAxC,MAAM;SAoGhB"}