@woosh/meep-engine 3.17.2 → 3.18.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 (263) hide show
  1. package/editor/actions/concrete/ComponentAddAction.d.ts +1 -0
  2. package/editor/actions/concrete/ComponentAddAction.d.ts.map +1 -1
  3. package/editor/actions/concrete/ComponentAddAction.js +4 -0
  4. package/editor/actions/concrete/ComponentRemoveAction.d.ts +1 -0
  5. package/editor/actions/concrete/ComponentRemoveAction.d.ts.map +1 -1
  6. package/editor/actions/concrete/ComponentRemoveAction.js +4 -0
  7. package/editor/actions/concrete/EntityCreateAction.d.ts +1 -0
  8. package/editor/actions/concrete/EntityCreateAction.d.ts.map +1 -1
  9. package/editor/actions/concrete/EntityCreateAction.js +7 -0
  10. package/editor/actions/concrete/EntityRemoveAction.d.ts +1 -0
  11. package/editor/actions/concrete/EntityRemoveAction.d.ts.map +1 -1
  12. package/editor/actions/concrete/EntityRemoveAction.js +4 -0
  13. package/editor/actions/concrete/PatchTerrainHeightAction.d.ts +10 -0
  14. package/editor/actions/concrete/PatchTerrainHeightAction.d.ts.map +1 -1
  15. package/editor/actions/concrete/PatchTerrainHeightAction.js +107 -85
  16. package/editor/actions/concrete/TransformModifyAction.d.ts +1 -0
  17. package/editor/actions/concrete/TransformModifyAction.d.ts.map +1 -1
  18. package/editor/actions/concrete/TransformModifyAction.js +4 -0
  19. package/editor/particles/effect/ParticleEffectDocument.d.ts.map +1 -1
  20. package/editor/particles/effect/ParticleEffectDocument.js +10 -6
  21. package/editor/particles/effect/ParticleReferenceSimulation.d.ts.map +1 -1
  22. package/editor/particles/effect/ParticleReferenceSimulation.js +98 -4
  23. package/editor/particles/effect/make_starter_particle_effect.d.ts.map +1 -1
  24. package/editor/particles/effect/make_starter_particle_effect.js +0 -2
  25. package/editor/tools/engine/ToolEngine.d.ts +30 -0
  26. package/editor/tools/engine/ToolEngine.d.ts.map +1 -1
  27. package/editor/tools/engine/ToolEngine.js +257 -188
  28. package/editor/view/ecs/EntityList.d.ts.map +1 -1
  29. package/editor/view/ecs/EntityList.js +6 -5
  30. package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts.map +1 -1
  31. package/editor/view/particles/effect/ParticleEmitterInspectorView.js +17 -9
  32. package/package.json +1 -1
  33. package/src/CODEC_LAYOUT_VERIFICATION.md +1 -2
  34. package/src/core/binary/meshopt/MESHOPT_VERTEX_BLOCK.d.ts +56 -0
  35. package/src/core/binary/meshopt/MESHOPT_VERTEX_BLOCK.d.ts.map +1 -0
  36. package/src/core/binary/meshopt/MESHOPT_VERTEX_BLOCK.js +73 -0
  37. package/src/core/binary/meshopt/meshopt_decode_vertex_buffer.d.ts.map +1 -1
  38. package/src/core/binary/meshopt/meshopt_decode_vertex_buffer.js +18 -63
  39. package/src/core/binary/meshopt/meshopt_encode_byte_group.d.ts +53 -0
  40. package/src/core/binary/meshopt/meshopt_encode_byte_group.d.ts.map +1 -0
  41. package/src/core/binary/meshopt/meshopt_encode_byte_group.js +140 -0
  42. package/src/core/binary/meshopt/meshopt_encode_data_block.d.ts +32 -0
  43. package/src/core/binary/meshopt/meshopt_encode_data_block.d.ts.map +1 -0
  44. package/src/core/binary/meshopt/meshopt_encode_data_block.js +77 -0
  45. package/src/core/binary/meshopt/meshopt_encode_index_sequence.d.ts +46 -0
  46. package/src/core/binary/meshopt/meshopt_encode_index_sequence.d.ts.map +1 -0
  47. package/src/core/binary/meshopt/meshopt_encode_index_sequence.js +146 -0
  48. package/src/core/binary/meshopt/meshopt_encode_vertex_buffer.d.ts +40 -0
  49. package/src/core/binary/meshopt/meshopt_encode_vertex_buffer.d.ts.map +1 -0
  50. package/src/core/binary/meshopt/meshopt_encode_vertex_buffer.js +700 -0
  51. package/src/core/binary/meshopt/meshopt_write_uint_var.d.ts +24 -0
  52. package/src/core/binary/meshopt/meshopt_write_uint_var.d.ts.map +1 -0
  53. package/src/core/binary/meshopt/meshopt_write_uint_var.js +39 -0
  54. package/src/core/math/random/seededRandom_Mulberry32.d.ts.map +1 -1
  55. package/src/core/math/random/seededRandom_Mulberry32.js +4 -2
  56. package/src/core/process/undo/Action.d.ts +19 -0
  57. package/src/core/process/undo/Action.d.ts.map +1 -1
  58. package/src/core/process/undo/Action.js +17 -0
  59. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +78 -0
  60. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -0
  61. package/src/engine/graphics3/GPUParticleEmitterSystem.js +310 -0
  62. package/src/engine/graphics3/GraphicsEngine.d.ts +17 -0
  63. package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -1
  64. package/src/engine/graphics3/GraphicsEngine.js +30 -10
  65. package/src/engine/graphics3/particles/particle_gpu_records.d.ts.map +1 -1
  66. package/src/engine/graphics3/particles/particle_gpu_records.js +0 -2
  67. package/src/engine/interpolation/InterpolationSystem.d.ts +7 -0
  68. package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
  69. package/src/engine/interpolation/InterpolationSystem.js +10 -0
  70. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  71. package/src/engine/network/NetworkSession.js +14 -34
  72. package/src/engine/network/time/RenderPlayout.d.ts +76 -0
  73. package/src/engine/network/time/RenderPlayout.d.ts.map +1 -0
  74. package/src/engine/network/time/RenderPlayout.js +163 -0
  75. package/src/engine/network/transport/adapters/WebSocketTransport.d.ts.map +1 -1
  76. package/src/engine/network/transport/adapters/WebSocketTransport.js +11 -4
  77. package/src/engine/physics/ecs/PhysicsSystem.d.ts +4 -12
  78. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  79. package/src/engine/physics/ecs/PhysicsSystem.js +39 -13
  80. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  81. package/src/engine/sound/simulation/core/VolumeField.d.ts.map +1 -1
  82. package/src/engine/sound/simulation/core/VolumeField.js +4 -1
  83. package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +23 -2
  84. package/src/shade/playground/particle_system/README.md +139 -139
  85. package/src/shade/playground/particle_system/particle_prototype.d.ts.map +1 -1
  86. package/src/shade/playground/particle_system/particle_prototype.js +0 -2
  87. package/src/shade/playground/particle_system/particle_scene.d.ts +6 -9
  88. package/src/shade/playground/particle_system/particle_scene.d.ts.map +1 -1
  89. package/src/shade/playground/particle_system/particle_scene.js +6 -13
  90. package/src/shade/playground/ssr_reprojection/README.md +103 -0
  91. package/src/shade/playground/ssr_reprojection/SpatialFilterProbe.d.ts +17 -0
  92. package/src/shade/playground/ssr_reprojection/SpatialFilterProbe.d.ts.map +1 -0
  93. package/src/shade/playground/ssr_reprojection/SpatialFilterProbe.js +68 -0
  94. package/src/shade/playground/ssr_reprojection/index.html +79 -0
  95. package/src/shade/playground/ssr_reprojection/main.d.ts +2 -0
  96. package/src/shade/playground/ssr_reprojection/main.d.ts.map +1 -0
  97. package/src/shade/playground/ssr_reprojection/main.js +245 -0
  98. package/src/shade/playground/ssr_reprojection/scene.d.ts +18 -0
  99. package/src/shade/playground/ssr_reprojection/scene.d.ts.map +1 -0
  100. package/src/shade/playground/ssr_reprojection/scene.js +51 -0
  101. package/src/shade/renderer/Renderer.d.ts +2 -23
  102. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  103. package/src/shade/renderer/Renderer.js +185 -218
  104. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +5 -8
  105. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  106. package/src/shade/renderer/animation/GPUAnimationManager.js +12 -12
  107. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  108. package/src/shade/renderer/buffer/table/GPUTypedTable.js +6 -0
  109. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
  110. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +7 -0
  111. package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_sample_specular.d.ts +4 -0
  112. package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_sample_specular.d.ts.map +1 -0
  113. package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_sample_specular.js +51 -0
  114. package/src/shade/renderer/global_illumination/brick4/gpu/draw/shader_brick4_specular.d.ts.map +1 -1
  115. package/src/shade/renderer/global_illumination/brick4/gpu/draw/shader_brick4_specular.js +5 -35
  116. package/src/shade/renderer/particles/DESIGN.md +703 -514
  117. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +16 -4
  118. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  119. package/src/shade/renderer/particles/GPUParticleSystem.js +1189 -991
  120. package/src/shade/renderer/particles/ParticleConstants.d.ts +64 -0
  121. package/src/shade/renderer/particles/ParticleConstants.d.ts.map +1 -1
  122. package/src/shade/renderer/particles/ParticleConstants.js +71 -0
  123. package/src/shade/renderer/particles/bounds/chunk_particle_bounds.d.ts +57 -0
  124. package/src/shade/renderer/particles/bounds/chunk_particle_bounds.d.ts.map +1 -0
  125. package/src/shade/renderer/particles/bounds/chunk_particle_bounds.js +181 -0
  126. package/src/shade/renderer/particles/bounds/chunk_particle_bounds_unknown.d.ts +7 -0
  127. package/src/shade/renderer/particles/bounds/chunk_particle_bounds_unknown.d.ts.map +1 -0
  128. package/src/shade/renderer/particles/bounds/chunk_particle_bounds_unknown.js +12 -0
  129. package/src/shade/renderer/particles/bounds/graph_particle_bounds.d.ts +33 -0
  130. package/src/shade/renderer/particles/bounds/graph_particle_bounds.d.ts.map +1 -0
  131. package/src/shade/renderer/particles/bounds/graph_particle_bounds.js +67 -0
  132. package/src/shade/renderer/particles/bounds/shader_particle_bounds.d.ts +40 -0
  133. package/src/shade/renderer/particles/bounds/shader_particle_bounds.d.ts.map +1 -0
  134. package/src/shade/renderer/particles/bounds/shader_particle_bounds.js +187 -0
  135. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts +15 -2
  136. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts.map +1 -1
  137. package/src/shade/renderer/particles/coherence/graph_particle_bucket.js +14 -8
  138. package/src/shade/renderer/particles/data/PARTICLE_COUNTERS.d.ts +58 -4
  139. package/src/shade/renderer/particles/data/PARTICLE_COUNTERS.d.ts.map +1 -1
  140. package/src/shade/renderer/particles/data/PARTICLE_COUNTERS.js +79 -4
  141. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STATE.d.ts +23 -1
  142. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STATE.d.ts.map +1 -1
  143. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STATE.js +35 -2
  144. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts +4 -2
  145. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts.map +1 -1
  146. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js +5 -8
  147. package/src/shade/renderer/particles/data/particle_emitter_record.d.ts.map +1 -1
  148. package/src/shade/renderer/particles/data/particle_emitter_record.js +0 -6
  149. package/src/shade/renderer/particles/graph_particles.d.ts +25 -3
  150. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  151. package/src/shade/renderer/particles/graph_particles.js +108 -31
  152. package/src/shade/renderer/particles/graph_particles_avboit.d.ts +6 -4
  153. package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
  154. package/src/shade/renderer/particles/graph_particles_avboit.js +5 -5
  155. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +5 -0
  156. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
  157. package/src/shade/renderer/particles/runtime/EmitterRegistry.js +27 -6
  158. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts +4 -0
  159. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts.map +1 -1
  160. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.js +6 -1
  161. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +35 -27
  162. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
  163. package/src/shade/renderer/particles/runtime/ParticleEmitter.js +424 -425
  164. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_warmup.d.ts +20 -0
  165. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_warmup.d.ts.map +1 -0
  166. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts +4 -0
  167. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts.map +1 -1
  168. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.js +38 -2
  169. package/src/shade/renderer/particles/shaders/chunk_particle_spawn_budget.d.ts +22 -0
  170. package/src/shade/renderer/particles/shaders/chunk_particle_spawn_budget.d.ts.map +1 -0
  171. package/src/shade/renderer/particles/shaders/chunk_particle_spawn_budget.js +42 -0
  172. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +1 -1
  173. package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.d.ts.map +1 -1
  174. package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.js +53 -22
  175. package/src/shade/renderer/particles/shaders/shader_particle_emitter_tick.d.ts.map +1 -1
  176. package/src/shade/renderer/particles/shaders/shader_particle_emitter_tick.js +213 -216
  177. package/src/shade/renderer/particles/shaders/shader_particle_reclaim.d.ts +50 -0
  178. package/src/shade/renderer/particles/shaders/shader_particle_reclaim.d.ts.map +1 -0
  179. package/src/shade/renderer/particles/shaders/shader_particle_render.js +1 -1
  180. package/src/shade/renderer/particles/warmup/chunk_particle_warmup_step.d.ts +36 -0
  181. package/src/shade/renderer/particles/warmup/chunk_particle_warmup_step.d.ts.map +1 -0
  182. package/src/shade/renderer/particles/warmup/chunk_particle_warmup_step.js +102 -0
  183. package/src/shade/renderer/particles/warmup/graph_particle_warmup.d.ts +102 -0
  184. package/src/shade/renderer/particles/warmup/graph_particle_warmup.d.ts.map +1 -0
  185. package/src/shade/renderer/particles/warmup/graph_particle_warmup.js +329 -0
  186. package/src/shade/renderer/particles/warmup/shader_particle_warmup.d.ts +112 -0
  187. package/src/shade/renderer/particles/warmup/shader_particle_warmup.d.ts.map +1 -0
  188. package/src/shade/renderer/particles/warmup/shader_particle_warmup.js +318 -0
  189. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance.d.ts +35 -0
  190. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance.d.ts.map +1 -0
  191. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance.js +108 -0
  192. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.d.ts +3 -0
  193. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.d.ts.map +1 -0
  194. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.js +70 -0
  195. package/src/shade/renderer/particles/warmup/warmup_schedule.d.ts +62 -0
  196. package/src/shade/renderer/particles/warmup/warmup_schedule.d.ts.map +1 -0
  197. package/src/shade/renderer/particles/warmup/warmup_schedule.js +55 -0
  198. package/src/shade/renderer/postprocess/PostProcess.d.ts.map +1 -1
  199. package/src/shade/renderer/postprocess/PostProcess.js +2 -1
  200. package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +286 -0
  201. package/src/shade/renderer/postprocess/ssr/SSR.d.ts +57 -21
  202. package/src/shade/renderer/postprocess/ssr/SSR.d.ts.map +1 -1
  203. package/src/shade/renderer/postprocess/ssr/SSR.js +230 -129
  204. package/src/shade/renderer/postprocess/ssr/SSRReprojectionMode.d.ts +11 -0
  205. package/src/shade/renderer/postprocess/ssr/SSRReprojectionMode.d.ts.map +1 -0
  206. package/src/shade/renderer/postprocess/ssr/SSRReprojectionMode.js +6 -0
  207. package/src/shade/renderer/postprocess/ssr/chunk_ssr_metadata.d.ts +4 -0
  208. package/src/shade/renderer/postprocess/ssr/chunk_ssr_metadata.d.ts.map +1 -0
  209. package/src/shade/renderer/postprocess/ssr/chunk_ssr_metadata.js +32 -0
  210. package/src/shade/renderer/postprocess/ssr/chunk_ssr_spatial_variance.d.ts +4 -0
  211. package/src/shade/renderer/postprocess/ssr/chunk_ssr_spatial_variance.d.ts.map +1 -0
  212. package/src/shade/renderer/postprocess/ssr/chunk_ssr_spatial_variance.js +41 -0
  213. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.d.ts +3 -0
  214. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.d.ts.map +1 -0
  215. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.js +30 -0
  216. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_sample_history.d.ts +4 -0
  217. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_sample_history.d.ts.map +1 -0
  218. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_sample_history.js +70 -0
  219. package/src/shade/renderer/postprocess/ssr/resolve/build_ssr_resolve_shader.d.ts +21 -0
  220. package/src/shade/renderer/postprocess/ssr/resolve/build_ssr_resolve_shader.d.ts.map +1 -0
  221. package/src/shade/renderer/postprocess/ssr/resolve/build_ssr_resolve_shader.js +363 -0
  222. package/src/shade/renderer/postprocess/ssr/resolve/chunk_get_neighbour_weight.js +1 -1
  223. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_Brick4.d.ts +2 -0
  224. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_Brick4.d.ts.map +1 -0
  225. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_Brick4.js +24 -0
  226. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_IBL.d.ts +1 -6
  227. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_IBL.d.ts.map +1 -1
  228. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_IBL.js +16 -332
  229. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_LPV.d.ts +1 -6
  230. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_LPV.d.ts.map +1 -1
  231. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_LPV.js +25 -358
  232. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts +0 -5
  233. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts.map +1 -1
  234. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.js +201 -276
  235. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts +1 -0
  236. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
  237. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +167 -143
  238. package/src/shade/renderer/shader/graph/graph_create_buffer.d.ts +15 -0
  239. package/src/shade/renderer/shader/graph/graph_create_buffer.d.ts.map +1 -0
  240. package/src/shade/renderer/shader/graph/graph_create_buffer.js +20 -0
  241. package/src/shade/renderer/view/GPUViewContext.d.ts +3 -4
  242. package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
  243. package/src/shade/renderer/view/GPUViewContext.js +5 -5
  244. package/src/core/binary/meshopt/__meshopt_test_streams.d.ts +0 -24
  245. package/src/core/binary/meshopt/__meshopt_test_streams.d.ts.map +0 -1
  246. package/src/core/binary/meshopt/__meshopt_test_streams.js +0 -237
  247. package/src/core/geom/3d/atlas/atlas_test_fixtures.d.ts +0 -84
  248. package/src/core/geom/3d/atlas/atlas_test_fixtures.d.ts.map +0 -1
  249. package/src/core/geom/3d/atlas/atlas_test_fixtures.js +0 -266
  250. package/src/engine/asset/loaders/gltf_test_fixtures.d.ts +0 -97
  251. package/src/engine/asset/loaders/gltf_test_fixtures.d.ts.map +0 -1
  252. package/src/engine/asset/loaders/gltf_test_fixtures.js +0 -359
  253. package/src/shade/renderer/animation/skin_test_fixtures.d.ts +0 -86
  254. package/src/shade/renderer/animation/skin_test_fixtures.d.ts.map +0 -1
  255. package/src/shade/renderer/animation/skin_test_fixtures.js +0 -250
  256. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_test_fixtures.d.ts +0 -16
  257. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_test_fixtures.d.ts.map +0 -1
  258. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_test_fixtures.js +0 -27
  259. package/src/shade/renderer/particles/particle_test_fixtures.d.ts +0 -151
  260. package/src/shade/renderer/particles/particle_test_fixtures.d.ts.map +0 -1
  261. package/src/shade/renderer/particles/particle_test_fixtures.js +0 -229
  262. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_world_sphere.js +0 -23
  263. package/src/shade/renderer/postprocess/ssr/reproject/shader_ffx_denoiser_reflections_reproject.js +0 -457
@@ -30,6 +30,70 @@ export const PARTICLE_RECORD_HEADER_EMITTER: number;
30
30
  * @type {number}
31
31
  */
32
32
  export const PARTICLE_EMITTER_TICK_WORKGROUP_SIZE: number;
33
+ /**
34
+ * Most ticks a warm-up runs an emitter's simulation forward in, whatever it owes — see `warmup/`.
35
+ *
36
+ * A warm-up is the ordinary loop (spawn, init, advance) run over a transient population until the
37
+ * emitter has been running for its `prewarm`. Each tick is a handful of dispatches, so this bounds
38
+ * the frame that pays for it; the tick length stretches to cover the debt rather than the count
39
+ * growing to cover it ({@link ./warmup/warmup_schedule.js}). Thirty-two ticks of a three-second
40
+ * warm-up are ninety-millisecond steps — coarse, and smeared by the jitter below so it does not
41
+ * read as thirty-two bands; a stiff program will not reproduce under it and nothing here claims to.
42
+ *
43
+ * @type {number}
44
+ */
45
+ export const PARTICLE_WARMUP_MAX_TICKS: number;
46
+ /**
47
+ * Shortest a warm-up tick gets, in seconds — a frame at sixty. A warm-up shorter than
48
+ * {@link PARTICLE_WARMUP_MAX_TICKS} of these runs fewer ticks rather than finer ones: there is nothing
49
+ * to be gained from integrating a two-hundred-millisecond warm-up at a finer grain than the frame
50
+ * loop will from then on.
51
+ *
52
+ * @type {number}
53
+ */
54
+ export const PARTICLE_WARMUP_TICK_SECONDS: number;
55
+ /**
56
+ * How far a warm-up tick's length is jittered per particle, as a fraction of the tick: each
57
+ * particle advances by `dt * (1 + this * (u - 0.5))` for a `u` hashed from its slot and the tick.
58
+ *
59
+ * Without it every particle born in one tick has exactly the age of that tick at the end, and a
60
+ * warm-up of N ticks arrives as N cohorts — visible banding on exactly the effects that wanted
61
+ * warming. A program does not care what `DELTA_TIME` it is handed, so the smear is free. Half a
62
+ * tick each way is enough to close the gaps between cohorts and not enough to reorder them.
63
+ *
64
+ * @type {number}
65
+ */
66
+ export const PARTICLE_WARMUP_DT_JITTER: number;
67
+ /**
68
+ * Per-emitter counterpart of {@link PARTICLE_WARMUP_DT_JITTER}: an emitter's own clock runs at
69
+ * `1 + this * (u - 0.5)` times the tick, for a `u` the host hashes from its row. Two emitters warmed
70
+ * in the same batch then do not spawn on the same beat, which is what aligns their bands with each
71
+ * other even after the per-particle smear has hidden each one's own.
72
+ *
73
+ * @type {number}
74
+ */
75
+ export const PARTICLE_WARMUP_EMITTER_JITTER: number;
76
+ /**
77
+ * Words per entry of the warm-up queue the host hands the GPU: see
78
+ * {@link ./warmup/shader_particle_warmup.js WARMUP_QUEUE_ENTRY}.
79
+ * @type {number}
80
+ */
81
+ export const PARTICLE_WARMUP_QUEUE_WORDS: number;
82
+ /**
83
+ * Lanes the warm-up's per-particle passes launch. A bounded launch with a grid-stride loop, so the
84
+ * loop's passes are sized by a constant rather than by a count that changes every tick and would
85
+ * otherwise need an indirect-args pass of its own per tick. Equal to
86
+ * {@link PARTICLE_VM_WIDE_LAUNCH_LANES} so that the wide register file, sized by that, fits the
87
+ * warm-up's wide advance pass without a second file.
88
+ *
89
+ * @type {number}
90
+ */
91
+ export const PARTICLE_WARMUP_LAUNCH_LANES: number;
92
+ /**
93
+ * Threads per workgroup in the warm-up passes.
94
+ * @type {number}
95
+ */
96
+ export const PARTICLE_WARMUP_WORKGROUP_SIZE: number;
33
97
  /**
34
98
  * Words per entry of the spawn-command list the host hands the GPU: `[emitter row, count]`.
35
99
  * @type {number}
@@ -1 +1 @@
1
- {"version":3,"file":"ParticleConstants.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/ParticleConstants.js"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;GASG;AACH,yCAFU,MAAM,CAE6B;AAE7C;;;;GAIG;AACH,6CAFU,MAAM,CAEgC;AAEhD;;;;;;GAMG;AACH,mDAFU,MAAM,CAEuC;AAEvD;;;GAGG;AACH,2CAFU,MAAM,CAE8B;AAE9C;;;;;;;;;GASG;AACH,4CAFU,MAAM,CAE+B;AAE/C;;;GAGG;AACH,8CAFU,MAAM,CAEiC;AAEjD;;;;;;GAMG;AACH,yCAFU,MAAM,CAE+B;AAE/C;;;GAGG;AACH,8CAFU,MAAM,CAEiC;AAEjD;;;;;;;;;;;;;;;GAeG;AACH,yCAFU,MAAM,CAE8B;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,8CAFU,MAAM,CAEkC;AAElD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,4CAFU,MAAM,CAEkC;;AASlD;;;;;;;;;;;;;;;GAeG;AACH,2CAFU,MAAM,CAEiC;AAEjD;;;;;;;;;;;;;;;GAeG;AACH,+CAFU,MAAM,CAEmC;AAEnD;;;;;;;;;;;;GAYG;AACH,oCAFU,MAAM,CAEgC;AAEhD;;;;;;;;;;GAUG;AACH,uCAFU,MAAM,CAE4B"}
1
+ {"version":3,"file":"ParticleConstants.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/ParticleConstants.js"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;GASG;AACH,yCAFU,MAAM,CAE6B;AAE7C;;;;GAIG;AACH,6CAFU,MAAM,CAEgC;AAEhD;;;;;;GAMG;AACH,mDAFU,MAAM,CAEuC;AAEvD;;;;;;;;;;;GAWG;AACH,wCAFU,MAAM,CAE4B;AAE5C;;;;;;;GAOG;AACH,2CAFU,MAAM,CAEmC;AAEnD;;;;;;;;;;GAUG;AACH,wCAFU,MAAM,CAE6B;AAE7C;;;;;;;GAOG;AACH,6CAFU,MAAM,CAEkC;AAElD;;;;GAIG;AACH,0CAFU,MAAM,CAE6B;AAE7C;;;;;;;;GAQG;AACH,2CAFU,MAAM,CAEiC;AAEjD;;;GAGG;AACH,6CAFU,MAAM,CAEiC;AAEjD;;;GAGG;AACH,2CAFU,MAAM,CAE8B;AAE9C;;;;;;;;;GASG;AACH,4CAFU,MAAM,CAE+B;AAE/C;;;GAGG;AACH,8CAFU,MAAM,CAEiC;AAEjD;;;;;;GAMG;AACH,yCAFU,MAAM,CAE+B;AAE/C;;;GAGG;AACH,8CAFU,MAAM,CAEiC;AAEjD;;;;;;;;;;;;;;;GAeG;AACH,yCAFU,MAAM,CAE8B;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,8CAFU,MAAM,CAEkC;AAElD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,4CAFU,MAAM,CAEkC;;AASlD;;;;;;;;;;;;;;;GAeG;AACH,2CAFU,MAAM,CAEiC;AAEjD;;;;;;;;;;;;;;;GAeG;AACH,+CAFU,MAAM,CAEmC;AAEnD;;;;;;;;;;;;GAYG;AACH,oCAFU,MAAM,CAEgC;AAEhD;;;;;;;;;;GAUG;AACH,uCAFU,MAAM,CAE4B"}
@@ -34,6 +34,77 @@ export const PARTICLE_RECORD_HEADER_EMITTER = 0;
34
34
  */
35
35
  export const PARTICLE_EMITTER_TICK_WORKGROUP_SIZE = 64;
36
36
 
37
+ /**
38
+ * Most ticks a warm-up runs an emitter's simulation forward in, whatever it owes — see `warmup/`.
39
+ *
40
+ * A warm-up is the ordinary loop (spawn, init, advance) run over a transient population until the
41
+ * emitter has been running for its `prewarm`. Each tick is a handful of dispatches, so this bounds
42
+ * the frame that pays for it; the tick length stretches to cover the debt rather than the count
43
+ * growing to cover it ({@link ./warmup/warmup_schedule.js}). Thirty-two ticks of a three-second
44
+ * warm-up are ninety-millisecond steps — coarse, and smeared by the jitter below so it does not
45
+ * read as thirty-two bands; a stiff program will not reproduce under it and nothing here claims to.
46
+ *
47
+ * @type {number}
48
+ */
49
+ export const PARTICLE_WARMUP_MAX_TICKS = 32;
50
+
51
+ /**
52
+ * Shortest a warm-up tick gets, in seconds — a frame at sixty. A warm-up shorter than
53
+ * {@link PARTICLE_WARMUP_MAX_TICKS} of these runs fewer ticks rather than finer ones: there is nothing
54
+ * to be gained from integrating a two-hundred-millisecond warm-up at a finer grain than the frame
55
+ * loop will from then on.
56
+ *
57
+ * @type {number}
58
+ */
59
+ export const PARTICLE_WARMUP_TICK_SECONDS = 1 / 60;
60
+
61
+ /**
62
+ * How far a warm-up tick's length is jittered per particle, as a fraction of the tick: each
63
+ * particle advances by `dt * (1 + this * (u - 0.5))` for a `u` hashed from its slot and the tick.
64
+ *
65
+ * Without it every particle born in one tick has exactly the age of that tick at the end, and a
66
+ * warm-up of N ticks arrives as N cohorts — visible banding on exactly the effects that wanted
67
+ * warming. A program does not care what `DELTA_TIME` it is handed, so the smear is free. Half a
68
+ * tick each way is enough to close the gaps between cohorts and not enough to reorder them.
69
+ *
70
+ * @type {number}
71
+ */
72
+ export const PARTICLE_WARMUP_DT_JITTER = 0.5;
73
+
74
+ /**
75
+ * Per-emitter counterpart of {@link PARTICLE_WARMUP_DT_JITTER}: an emitter's own clock runs at
76
+ * `1 + this * (u - 0.5)` times the tick, for a `u` the host hashes from its row. Two emitters warmed
77
+ * in the same batch then do not spawn on the same beat, which is what aligns their bands with each
78
+ * other even after the per-particle smear has hidden each one's own.
79
+ *
80
+ * @type {number}
81
+ */
82
+ export const PARTICLE_WARMUP_EMITTER_JITTER = 0.1;
83
+
84
+ /**
85
+ * Words per entry of the warm-up queue the host hands the GPU: see
86
+ * {@link ./warmup/shader_particle_warmup.js WARMUP_QUEUE_ENTRY}.
87
+ * @type {number}
88
+ */
89
+ export const PARTICLE_WARMUP_QUEUE_WORDS = 4;
90
+
91
+ /**
92
+ * Lanes the warm-up's per-particle passes launch. A bounded launch with a grid-stride loop, so the
93
+ * loop's passes are sized by a constant rather than by a count that changes every tick and would
94
+ * otherwise need an indirect-args pass of its own per tick. Equal to
95
+ * {@link PARTICLE_VM_WIDE_LAUNCH_LANES} so that the wide register file, sized by that, fits the
96
+ * warm-up's wide advance pass without a second file.
97
+ *
98
+ * @type {number}
99
+ */
100
+ export const PARTICLE_WARMUP_LAUNCH_LANES = 8192;
101
+
102
+ /**
103
+ * Threads per workgroup in the warm-up passes.
104
+ * @type {number}
105
+ */
106
+ export const PARTICLE_WARMUP_WORKGROUP_SIZE = 64;
107
+
37
108
  /**
38
109
  * Words per entry of the spawn-command list the host hands the GPU: `[emitter row, count]`.
39
110
  * @type {number}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * The per-emitter bounds accumulator: where a measured box is built up, and how it is read back.
3
+ *
4
+ * An emitter has no bounds it could declare. Its particles are simulated in world space by arbitrary
5
+ * bytecode — they go where the program sends them, at whatever size it gives them, for as long as it
6
+ * keeps them alive — so the only bound an author could write down and still be right is an infinite
7
+ * one, which culls nothing and reserves every depth slice. What CAN be known is where the particles
8
+ * actually are, and that is what the two passes in {@link ./shader_particle_bounds.js} measure.
9
+ *
10
+ * One accumulator per emitter table row, six words of the counters buffer (see
11
+ * {@link ../data/PARTICLE_COUNTERS.js} for why it lives there rather than in a binding of its own),
12
+ * holding `min.xyz` then `max.xyz` as plain f32 bit patterns.
13
+ *
14
+ * ## Why f32 in the buffer, and not an order-preserving encoding
15
+ *
16
+ * `aabb_atomic_min_f32` / `aabb_atomic_max_f32` are the engine's, shared with the skinned-mesh
17
+ * bounds refresh, and they CAS-spin over the plain float so the words are readable as floats at
18
+ * every moment of the frame. The sign-flip encoding that would let `atomicMin` do it in one
19
+ * instruction leaves the buffer in a form only a decoder understands, and the publish pass reads
20
+ * these words in the same frame the accumulate pass writes them.
21
+ *
22
+ * The spin is cheaper than it looks at particle counts: both helpers load first and return without a
23
+ * CAS when the box already holds the contribution. It is the record-breaking argument — over `n`
24
+ * particles in arbitrary order, the number that actually extend an axis is `O(log n)` in
25
+ * expectation, so `n` threads produce `n` loads and a handful of exchanges per word rather than `n`
26
+ * of each. What is left is the load traffic, and a subgroup reduction ahead of the atomic is the
27
+ * lever if it ever matters; the pass is separate partly so there is somewhere to pull it.
28
+ *
29
+ * ## What this chunk needs from its shader
30
+ *
31
+ * The `counters` binding, by that name and read-write, the way
32
+ * {@link ../shaders/chunk_particle_billboard_vertex.js} takes `pool` and `camera`. Both bounds
33
+ * passes bind it — that is the point of the accumulator living there.
34
+ *
35
+ * @type {CodeChunk}
36
+ */
37
+ export const chunk_particle_bounds_store: CodeChunk;
38
+ /**
39
+ * One live particle's contribution to its emitter's box: where its quad is, and how far the quad
40
+ * reaches from there.
41
+ *
42
+ * Read in exactly the terms {@link ../shaders/chunk_particle_billboard_vertex.js} reads a particle
43
+ * in — same record offsets, same defaults for an unbound channel, same radius as the corner
44
+ * expansion it performs — because the box has to hold what is drawn, not what is simulated. An
45
+ * emitter with no `position` binding really does draw every particle at the world origin, and this
46
+ * really does book the origin for it; the box stays a true statement about where the quads are, and
47
+ * an author who sees their effect culled at the origin has been told something accurate about their
48
+ * bindings.
49
+ *
50
+ * Five words of a record, no VM and no scene: that is the whole reason the measurement is a pass of
51
+ * its own rather than a tail on `particle_simulate_one`.
52
+ *
53
+ * @type {CodeChunk}
54
+ */
55
+ export const chunk_particle_bounds_of_record: CodeChunk;
56
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
57
+ //# sourceMappingURL=chunk_particle_bounds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_particle_bounds.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/bounds/chunk_particle_bounds.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,0CAFU,SAAS,CAwEyC;AAE5D;;;;;;;;;;;;;;;;GAgBG;AACH,8CAFU,SAAS,CA4CsC;0BApL/B,oCAAoC"}
@@ -0,0 +1,181 @@
1
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
+ import { chunk_aabb_atomic_f32 } from "../../animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.js";
3
+ import { AABB3_STRUCT } from "../../shader/chunk/geometry/aabb3/AABB3_STRUCT.js";
4
+ import {
5
+ PARTICLE_BOUNDS_BASE,
6
+ PARTICLE_BOUNDS_MINUS_INF,
7
+ PARTICLE_BOUNDS_PLUS_INF,
8
+ PARTICLE_BOUNDS_WORDS,
9
+ } from "../data/PARTICLE_COUNTERS.js";
10
+ import { EMITTER_ATTRIBUTE_ABSENT } from "../data/PARTICLE_EMITTER_STRUCT.js";
11
+ import { chunk_particle_emitter } from "../data/chunk_particle_emitter.js";
12
+ import { chunk_particle_render_math } from "../shaders/chunk_particle_render_math.js";
13
+
14
+ /**
15
+ * The per-emitter bounds accumulator: where a measured box is built up, and how it is read back.
16
+ *
17
+ * An emitter has no bounds it could declare. Its particles are simulated in world space by arbitrary
18
+ * bytecode — they go where the program sends them, at whatever size it gives them, for as long as it
19
+ * keeps them alive — so the only bound an author could write down and still be right is an infinite
20
+ * one, which culls nothing and reserves every depth slice. What CAN be known is where the particles
21
+ * actually are, and that is what the two passes in {@link ./shader_particle_bounds.js} measure.
22
+ *
23
+ * One accumulator per emitter table row, six words of the counters buffer (see
24
+ * {@link ../data/PARTICLE_COUNTERS.js} for why it lives there rather than in a binding of its own),
25
+ * holding `min.xyz` then `max.xyz` as plain f32 bit patterns.
26
+ *
27
+ * ## Why f32 in the buffer, and not an order-preserving encoding
28
+ *
29
+ * `aabb_atomic_min_f32` / `aabb_atomic_max_f32` are the engine's, shared with the skinned-mesh
30
+ * bounds refresh, and they CAS-spin over the plain float so the words are readable as floats at
31
+ * every moment of the frame. The sign-flip encoding that would let `atomicMin` do it in one
32
+ * instruction leaves the buffer in a form only a decoder understands, and the publish pass reads
33
+ * these words in the same frame the accumulate pass writes them.
34
+ *
35
+ * The spin is cheaper than it looks at particle counts: both helpers load first and return without a
36
+ * CAS when the box already holds the contribution. It is the record-breaking argument — over `n`
37
+ * particles in arbitrary order, the number that actually extend an axis is `O(log n)` in
38
+ * expectation, so `n` threads produce `n` loads and a handful of exchanges per word rather than `n`
39
+ * of each. What is left is the load traffic, and a subgroup reduction ahead of the atomic is the
40
+ * lever if it ever matters; the pass is separate partly so there is somewhere to pull it.
41
+ *
42
+ * ## What this chunk needs from its shader
43
+ *
44
+ * The `counters` binding, by that name and read-write, the way
45
+ * {@link ../shaders/chunk_particle_billboard_vertex.js} takes `pool` and `camera`. Both bounds
46
+ * passes bind it — that is the point of the accumulator living there.
47
+ *
48
+ * @type {CodeChunk}
49
+ */
50
+ export const chunk_particle_bounds_store = CodeChunk.from(/* language=wgsl */ `
51
+ const PARTICLE_BOUNDS_BASE : u32 = ${PARTICLE_BOUNDS_BASE}u;
52
+ const PARTICLE_BOUNDS_WORDS : u32 = ${PARTICLE_BOUNDS_WORDS}u;
53
+
54
+ // The empty interval, as bit patterns because WGSL has no literal for either infinity. The same two
55
+ // words the host writes over a newly grown region, from the same constants.
56
+ const PARTICLE_BOUNDS_PLUS_INF : u32 = ${PARTICLE_BOUNDS_PLUS_INF}u;
57
+ const PARTICLE_BOUNDS_MINUS_INF : u32 = ${PARTICLE_BOUNDS_MINUS_INF}u;
58
+
59
+ fn particle_bounds_base(row : u32) -> u32 {
60
+ return PARTICLE_BOUNDS_BASE + row * PARTICLE_BOUNDS_WORDS;
61
+ }
62
+
63
+ // Book one particle's quad into its emitter's accumulator: the sphere of radius \`radius\` about
64
+ // \`center\`, as an axis-aligned box.
65
+ //
66
+ // A sphere rather than the quad itself because the quad's plane is the camera's, and this box is
67
+ // read on a later frame with the camera somewhere else. See \`particle_billboard_radius\`.
68
+ fn particle_bounds_contribute(row : u32, center : vec3<f32>, radius : f32) {
69
+ let base = particle_bounds_base(row);
70
+
71
+ let lo = center - vec3<f32>(radius);
72
+ let hi = center + vec3<f32>(radius);
73
+
74
+ aabb_atomic_min_f32(&counters[base + 0u], lo.x);
75
+ aabb_atomic_min_f32(&counters[base + 1u], lo.y);
76
+ aabb_atomic_min_f32(&counters[base + 2u], lo.z);
77
+ aabb_atomic_max_f32(&counters[base + 3u], hi.x);
78
+ aabb_atomic_max_f32(&counters[base + 4u], hi.y);
79
+ aabb_atomic_max_f32(&counters[base + 5u], hi.z);
80
+ }
81
+
82
+ // What the frame accumulated for one row. Empty (see \`particle_bounds_is_empty\`) when nothing
83
+ // contributed — the emitter had no live particles.
84
+ fn particle_bounds_read(row : u32) -> ${AABB3_STRUCT.wgsl_ref} {
85
+ let base = particle_bounds_base(row);
86
+
87
+ let lo = vec3<f32>(
88
+ bitcast<f32>(atomicLoad(&counters[base + 0u])),
89
+ bitcast<f32>(atomicLoad(&counters[base + 1u])),
90
+ bitcast<f32>(atomicLoad(&counters[base + 2u])),
91
+ );
92
+ let hi = vec3<f32>(
93
+ bitcast<f32>(atomicLoad(&counters[base + 3u])),
94
+ bitcast<f32>(atomicLoad(&counters[base + 4u])),
95
+ bitcast<f32>(atomicLoad(&counters[base + 5u])),
96
+ );
97
+
98
+ return ${AABB3_STRUCT.make({ min: "lo", max: "hi" })};
99
+ }
100
+
101
+ // Start a row's next frame of measurement. All six axes are set together and no contribution ever
102
+ // touches one without the others, so "min above max on any axis" is exactly "nothing contributed".
103
+ //
104
+ // Unconditional in the publish pass, which is what lets a row that changes hands start clean: the
105
+ // last publish before it was freed left it empty, and it stays that way until somebody measures.
106
+ fn particle_bounds_reset(row : u32) {
107
+ let base = particle_bounds_base(row);
108
+
109
+ atomicStore(&counters[base + 0u], PARTICLE_BOUNDS_PLUS_INF);
110
+ atomicStore(&counters[base + 1u], PARTICLE_BOUNDS_PLUS_INF);
111
+ atomicStore(&counters[base + 2u], PARTICLE_BOUNDS_PLUS_INF);
112
+ atomicStore(&counters[base + 3u], PARTICLE_BOUNDS_MINUS_INF);
113
+ atomicStore(&counters[base + 4u], PARTICLE_BOUNDS_MINUS_INF);
114
+ atomicStore(&counters[base + 5u], PARTICLE_BOUNDS_MINUS_INF);
115
+ }
116
+
117
+ fn particle_bounds_is_empty(box : ${AABB3_STRUCT.wgsl_ref}) -> bool {
118
+ return any(box.min > box.max);
119
+ }
120
+ `, [chunk_aabb_atomic_f32, AABB3_STRUCT.declaration_chunk]);
121
+
122
+ /**
123
+ * One live particle's contribution to its emitter's box: where its quad is, and how far the quad
124
+ * reaches from there.
125
+ *
126
+ * Read in exactly the terms {@link ../shaders/chunk_particle_billboard_vertex.js} reads a particle
127
+ * in — same record offsets, same defaults for an unbound channel, same radius as the corner
128
+ * expansion it performs — because the box has to hold what is drawn, not what is simulated. An
129
+ * emitter with no `position` binding really does draw every particle at the world origin, and this
130
+ * really does book the origin for it; the box stays a true statement about where the quads are, and
131
+ * an author who sees their effect culled at the origin has been told something accurate about their
132
+ * bindings.
133
+ *
134
+ * Five words of a record, no VM and no scene: that is the whole reason the measurement is a pass of
135
+ * its own rather than a tail on `particle_simulate_one`.
136
+ *
137
+ * @type {CodeChunk}
138
+ */
139
+ export const chunk_particle_bounds_of_record = CodeChunk.from(/* language=wgsl */ `
140
+ const PARTICLE_BOUNDS_ATTRIBUTE_ABSENT : u32 = ${EMITTER_ATTRIBUTE_ABSENT}u;
141
+
142
+ struct ParticleBoundsSample {
143
+ center : vec3<f32>,
144
+ radius : f32,
145
+ }
146
+
147
+ fn particle_bounds_read_vec3(pool : ptr<storage, array<u32>>, base : u32, offset : u32) -> vec3<f32> {
148
+ return vec3<f32>(
149
+ bitcast<f32>((*pool)[base + offset]),
150
+ bitcast<f32>((*pool)[base + offset + 1u]),
151
+ bitcast<f32>((*pool)[base + offset + 2u]),
152
+ );
153
+ }
154
+
155
+ fn particle_bounds_of_record(
156
+ em : ParticleEmitter,
157
+ pool : ptr<storage, array<u32>>,
158
+ record_base : u32,
159
+ ) -> ParticleBoundsSample {
160
+ var center = vec3<f32>(0.0);
161
+ if (em.render_position != PARTICLE_BOUNDS_ATTRIBUTE_ABSENT) {
162
+ center = particle_bounds_read_vec3(pool, record_base, em.render_position);
163
+ }
164
+
165
+ var size = 1.0;
166
+ if (em.render_size != PARTICLE_BOUNDS_ATTRIBUTE_ABSENT) {
167
+ size = bitcast<f32>((*pool)[record_base + em.render_size]);
168
+ }
169
+
170
+ var velocity = vec3<f32>(0.0);
171
+ if (em.render_velocity != PARTICLE_BOUNDS_ATTRIBUTE_ABSENT) {
172
+ velocity = particle_bounds_read_vec3(pool, record_base, em.render_velocity);
173
+ }
174
+
175
+ var sample : ParticleBoundsSample;
176
+ sample.center = center;
177
+ sample.radius = particle_billboard_radius(size, velocity, particle_emitter_projection(em.flags));
178
+
179
+ return sample;
180
+ }
181
+ `, [chunk_particle_emitter, chunk_particle_render_math]);
@@ -0,0 +1,7 @@
1
+ /** Infinite bounds mean no live particles have supplied a measurement. Test before any geometry
2
+ * arithmetic: multiplying infinity by a zero plane component or adding opposite infinities is NaN.
3
+ * @type {CodeChunk}
4
+ */
5
+ export const chunk_particle_bounds_unknown: CodeChunk;
6
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
7
+ //# sourceMappingURL=chunk_particle_bounds_unknown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_particle_bounds_unknown.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/bounds/chunk_particle_bounds_unknown.js"],"names":[],"mappings":"AAEA;;;GAGG;AACH,4CAFU,SAAS,CAOhB;0BAXuB,oCAAoC"}
@@ -0,0 +1,12 @@
1
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
+
3
+ /** Infinite bounds mean no live particles have supplied a measurement. Test before any geometry
4
+ * arithmetic: multiplying infinity by a zero plane component or adding opposite infinities is NaN.
5
+ * @type {CodeChunk}
6
+ */
7
+ export const chunk_particle_bounds_unknown = CodeChunk.from(/* wgsl */ `
8
+ fn particle_bounds_unknown(bounds_min : vec3<f32>) -> bool {
9
+ // Compare stored bits: a constant bitcast to an infinite f32 is a WGSL creation error.
10
+ return bitcast<u32>(bounds_min.x) == 0xff800000u;
11
+ }
12
+ `);
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Frame-graph wiring for the measured emitter bounds: the frame's alive list reduced to one
3
+ * world-space box per emitter, published where the culling and occupancy passes read it.
4
+ *
5
+ * Runs at the end of the frame, after emit and simulate have both finished appending to the alive
6
+ * list and after the coherence reset has written `dispatch_args` from the resulting count. Two
7
+ * passes, in this order and no other: the accumulate has to see every live particle before the
8
+ * publish takes what it measured.
9
+ *
10
+ * @param {object} params
11
+ * @param {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} params.graph
12
+ * @param {number} params.emitter_database graph handle; the publish pass writes the state rows
13
+ * @param {number} params.pool graph handle of the particle pool
14
+ * @param {number} params.alive graph handle of this frame's compacted alive list
15
+ * @param {number} params.counters graph handle of the atomic counters, which carry the accumulator
16
+ * @param {number} params.dispatch_args graph handle of one workgroup per live particle
17
+ * @param {number} params.emitter_group_count workgroups that walk every page group of the emitter
18
+ * table; zero when the table has no pages, and then there is nothing to publish
19
+ * @returns {{counters: number, emitter_database: number}} the threaded handles downstream passes must read
20
+ */
21
+ export function graph_particle_bounds({ graph, emitter_database, pool, alive, counters, dispatch_args, emitter_group_count, }: {
22
+ graph: import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph;
23
+ emitter_database: number;
24
+ pool: number;
25
+ alive: number;
26
+ counters: number;
27
+ dispatch_args: number;
28
+ emitter_group_count: number;
29
+ }): {
30
+ counters: number;
31
+ emitter_database: number;
32
+ };
33
+ //# sourceMappingURL=graph_particle_bounds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph_particle_bounds.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/bounds/graph_particle_bounds.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAVqG,KAAK,EAA/F,OAAO,8DAA8D,EAAE,UAAU;IAClE,gBAAgB,EAA/B,MAAM;IACS,IAAI,EAAnB,MAAM;IACS,KAAK,EAApB,MAAM;IACS,QAAQ,EAAvB,MAAM;IACS,aAAa,EAA5B,MAAM;IACS,mBAAmB,EAAlC,MAAM;IAEJ;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAC,CAwCxD"}
@@ -0,0 +1,67 @@
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { graph_compute_indirect_pass } from "../../shader/graph/compute/graph_compute_indirect_pass.js";
3
+ import { graph_compute_pass } from "../../shader/graph/compute/graph_compute_pass.js";
4
+ import {
5
+ shader_particle_bounds_accumulate,
6
+ shader_particle_bounds_publish,
7
+ } from "./shader_particle_bounds.js";
8
+
9
+ /**
10
+ * Frame-graph wiring for the measured emitter bounds: the frame's alive list reduced to one
11
+ * world-space box per emitter, published where the culling and occupancy passes read it.
12
+ *
13
+ * Runs at the end of the frame, after emit and simulate have both finished appending to the alive
14
+ * list and after the coherence reset has written `dispatch_args` from the resulting count. Two
15
+ * passes, in this order and no other: the accumulate has to see every live particle before the
16
+ * publish takes what it measured.
17
+ *
18
+ * @param {object} params
19
+ * @param {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} params.graph
20
+ * @param {number} params.emitter_database graph handle; the publish pass writes the state rows
21
+ * @param {number} params.pool graph handle of the particle pool
22
+ * @param {number} params.alive graph handle of this frame's compacted alive list
23
+ * @param {number} params.counters graph handle of the atomic counters, which carry the accumulator
24
+ * @param {number} params.dispatch_args graph handle of one workgroup per live particle
25
+ * @param {number} params.emitter_group_count workgroups that walk every page group of the emitter
26
+ * table; zero when the table has no pages, and then there is nothing to publish
27
+ * @returns {{counters: number, emitter_database: number}} the threaded handles downstream passes must read
28
+ */
29
+ export function graph_particle_bounds({
30
+ graph,
31
+ emitter_database,
32
+ pool,
33
+ alive,
34
+ counters,
35
+ dispatch_args,
36
+ emitter_group_count,
37
+ }) {
38
+ assert.defined(graph, "graph");
39
+ assert.isNonNegativeInteger(emitter_group_count, "emitter_group_count");
40
+
41
+ if (emitter_group_count === 0) {
42
+ // No emitter table pages: no rows to accumulate into and none to publish. The alive list is
43
+ // empty for the same reason, so the accumulate pass would be a no-op even if it ran.
44
+ return { counters, emitter_database };
45
+ }
46
+
47
+ // One thread per live particle. Indirect, from the count the coherence reset read on the GPU —
48
+ // a host-side particle count is a frame stale at best.
49
+ const accumulated = graph_compute_indirect_pass({
50
+ graph,
51
+ shader: shader_particle_bounds_accumulate,
52
+ bindings: { emitter_database, pool, alive, counters },
53
+ command: dispatch_args,
54
+ });
55
+
56
+ const published = graph_compute_pass({
57
+ graph,
58
+ shader: shader_particle_bounds_publish,
59
+ bindings: { emitter_database, counters: accumulated.counters },
60
+ group_count: [emitter_group_count, 1, 1],
61
+ });
62
+
63
+ return {
64
+ counters: published.counters,
65
+ emitter_database: published.emitter_database,
66
+ };
67
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * One thread per live particle: merge its quad into its emitter's accumulator.
3
+ *
4
+ * The alive list holds real slots only — the padding sentinel belongs to the simulation-order list,
5
+ * and an orphan was killed by the simulate pass that built this list — so every entry is a particle
6
+ * whose emitter row is live and whose record has this frame's values in it.
7
+ *
8
+ * It decodes a whole emitter record to reach four of its fields, which the bucketing histogram
9
+ * deliberately does not (`chunk_particle_emitter_program_id`). The difference is what is being paid
10
+ * for: emitters are counted in tens, so the records are a working set that stays resident for the
11
+ * whole dispatch, while the pool reads are a gather over the free list and are what this pass costs.
12
+ * The billboard vertex stage reads a record the same way, per vertex.
13
+ *
14
+ * @type {ComputeShader}
15
+ */
16
+ export const shader_particle_bounds_accumulate: ComputeShader;
17
+ /**
18
+ * One thread per emitter table row: publish what the accumulate pass measured into
19
+ * `bounds_min` / `bounds_max` of the emitter's state row, and reset the accumulator.
20
+ *
21
+ * The state row rather than the accumulator directly, because the readers — the tick's frustum test
22
+ * next frame, the AVBOIT occupancy later in this one — should not each have to know the
23
+ * accumulator's layout or repeat the empty case below. It is also where the rest of an emitter's
24
+ * GPU-owned state lives, for the reason {@link ../data/PARTICLE_EMITTER_STATE.js} gives.
25
+ *
26
+ * ## The empty case
27
+ *
28
+ * No measured particles means unknown bounds, represented by an infinite box. The tick lets such
29
+ * an emitter spawn until a finite population can be measured; occupancy skips it because there is
30
+ * nothing to splat. This also lets an exhausted effect restart without requiring authored bounds
31
+ * or prewarm. Readers recognize the sentinel before doing geometry arithmetic on infinities.
32
+ *
33
+ * @type {ComputeShader}
34
+ */
35
+ export const shader_particle_bounds_publish: ComputeShader;
36
+ import { PARTICLE_SIMULATE_WORKGROUP_SIZE } from "../ParticleConstants.js";
37
+ import { PARTICLE_EMITTER_TICK_WORKGROUP_SIZE } from "../ParticleConstants.js";
38
+ import { ComputeShader } from "../../shader/ComputeShader.js";
39
+ export { PARTICLE_SIMULATE_WORKGROUP_SIZE, PARTICLE_EMITTER_TICK_WORKGROUP_SIZE };
40
+ //# sourceMappingURL=shader_particle_bounds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_particle_bounds.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/bounds/shader_particle_bounds.js"],"names":[],"mappings":"AA8DA;;;;;;;;;;;;;;GAcG;AACH,gDAFU,aAAa,CAgCpB;AAkBH;;;;;;;;;;;;;;;;;GAiBG;AACH,6CAFU,aAAa,CA6CpB;iDA/KI,yBAAyB;qDAAzB,yBAAyB;8BARF,+BAA+B"}