@woosh/meep-engine 3.17.1 → 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 (265) 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/engine/sound/simulation/core/OcclusionSolver.d.ts +0 -29
  254. package/src/engine/sound/simulation/core/OcclusionSolver.d.ts.map +0 -1
  255. package/src/shade/renderer/animation/skin_test_fixtures.d.ts +0 -86
  256. package/src/shade/renderer/animation/skin_test_fixtures.d.ts.map +0 -1
  257. package/src/shade/renderer/animation/skin_test_fixtures.js +0 -250
  258. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_test_fixtures.d.ts +0 -16
  259. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_test_fixtures.d.ts.map +0 -1
  260. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_test_fixtures.js +0 -27
  261. package/src/shade/renderer/particles/particle_test_fixtures.d.ts +0 -151
  262. package/src/shade/renderer/particles/particle_test_fixtures.d.ts.map +0 -1
  263. package/src/shade/renderer/particles/particle_test_fixtures.js +0 -229
  264. package/src/shade/renderer/particles/shaders/chunk_particle_emitter_world_sphere.js +0 -23
  265. package/src/shade/renderer/postprocess/ssr/reproject/shader_ffx_denoiser_reflections_reproject.js +0 -457
@@ -0,0 +1,102 @@
1
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
+ import { chunk_hash_to_float01 } from "../../shader/chunk/random/chunk_hash_to_float01.js";
3
+ import { chunk_hash_lowbias32_vec3u } from "../../shader/chunk/random/lowbias/chunk_hash_lowbias32_vec3u.js";
4
+ import {
5
+ PARTICLE_RECORD_HEADER_EMITTER,
6
+ PARTICLE_RECORD_WORD_COUNT,
7
+ PARTICLE_WARMUP_DT_JITTER,
8
+ } from "../ParticleConstants.js";
9
+ import { chunk_particle_header } from "../data/particle_header.js";
10
+ import { chunk_particle_emitter_age } from "../shaders/chunk_particle_emitter_age.js";
11
+ import { chunk_particle_setup_context } from "../shaders/chunk_particle_setup_context.js";
12
+
13
+ /**
14
+ * What a warm-up tick does to one particle: run its emitter's UPDATE program over it, by a tick
15
+ * jittered for it alone, and say whether it lived.
16
+ *
17
+ * Shared by `./shader_particle_warmup_advance.js` and `./shader_particle_warmup_advance_wide.js`
18
+ * the way the main simulate's step is shared by its two register backings.
19
+ *
20
+ * ## Why this is not `particle_simulate_one`
21
+ *
22
+ * It is the same shape — header, record, node, context, program, verdict — and it differs in two
23
+ * things that are each the whole point of a separate pipeline.
24
+ *
25
+ * It decodes the program section **per lane**. The main step reads the section parameters from the
26
+ * wave's first lane, and is correct only because the bucketing passes regrouped the list so every
27
+ * wave holds one program. The warm-up feeds its advance the raw alive list — spawned by emitters that
28
+ * may run different programs, appended in whatever order the atomics landed — and would need the
29
+ * bucketing's six passes per tick to earn the broadcast. Per-lane decode costs the warm-up some of
30
+ * its own occupancy and nothing else, and the warm-up's occupancy is its own business: nothing here
31
+ * is linked into the main passes, and their compiled code is unchanged by this file existing.
32
+ *
33
+ * It **jitters the tick per particle**. Every particle born in one tick would otherwise reach the
34
+ * end of the loop with exactly that tick's age, and a warm-up of N ticks would arrive as N cohorts.
35
+ * A program does not care what `DELTA_TIME` it is handed, so each particle is advanced by
36
+ * `dt * (1 + PARTICLE_WARMUP_DT_JITTER * (u - 0.5))` for a `u` hashed from its slot and the tick —
37
+ * a hash and not a draw from `random()`, so the program's own random stream is exactly what it would
38
+ * have been.
39
+ *
40
+ * There is no padding sentinel to recognise: the list this reads is the alive list, which holds real
41
+ * slots only. The generation test is kept — the host holds the queue for one frame and an emitter
42
+ * cannot leave mid-loop, but the header carries the generation and honouring it is one compare.
43
+ *
44
+ * @type {CodeChunk}
45
+ */
46
+ export const chunk_particle_warmup_step = CodeChunk.from(/* language=wgsl */ `
47
+ const WARMUP_RECORD_WORDS : u32 = ${PARTICLE_RECORD_WORD_COUNT}u;
48
+ const WARMUP_HEADER_EMITTER : u32 = ${PARTICLE_RECORD_HEADER_EMITTER}u;
49
+ const WARMUP_DT_JITTER : f32 = ${PARTICLE_WARMUP_DT_JITTER};
50
+ // A lane of the jitter hash that is neither the slot nor the tick, so the jitter is not the RNG
51
+ // seed's hash of the same two numbers.
52
+ const WARMUP_JITTER_SALT : u32 = 0x9e3779b9u;
53
+
54
+ // Advance one particle by one warm-up tick. Returns whether it is still alive.
55
+ fn particle_warmup_advance_one(
56
+ scene_database : ptr<storage, array<u32>>,
57
+ emitter_database : ptr<storage, array<u32>>,
58
+ program : ptr<storage, array<u32>>,
59
+ pool : ptr<storage, array<u32>, read_write>,
60
+ slot : u32,
61
+ dt : f32,
62
+ time : f32,
63
+ frame : u32,
64
+ ) -> bool {
65
+ let record_base = slot * WARMUP_RECORD_WORDS;
66
+ let header = (*pool)[record_base + WARMUP_HEADER_EMITTER];
67
+ let emitter_index = particle_header_emitter(header);
68
+
69
+ let em = particle_emitter_read(emitter_database, emitter_index);
70
+
71
+ if (particle_header_generation(header) != em.generation) { return false; }
72
+
73
+ let node = scene_read_node(scene_database, em.node);
74
+
75
+ let u = hash_to_float01(hash_lowbias32_vec3u(vec3<u32>(slot, frame, WARMUP_JITTER_SALT)));
76
+ let dt_jittered = dt * (1.0 + WARMUP_DT_JITTER * (u - 0.5));
77
+
78
+ particle_vm_reset();
79
+ particle_setup_context(
80
+ em, node, slot,
81
+ dt_jittered, time,
82
+ particle_emitter_age(emitter_database, emitter_index),
83
+ 0.0, frame,
84
+ );
85
+ particle_vm_execute(
86
+ program,
87
+ em.update_offset * PARTICLE_VM_INSTRUCTION_WORDS,
88
+ em.update_count,
89
+ em.constant_offset,
90
+ pool,
91
+ record_base,
92
+ );
93
+
94
+ return !vm_killed;
95
+ }
96
+ `, [
97
+ chunk_particle_setup_context,
98
+ chunk_particle_emitter_age,
99
+ chunk_particle_header,
100
+ chunk_hash_lowbias32_vec3u,
101
+ chunk_hash_to_float01,
102
+ ]);
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Run a batch of newly added emitters' simulations forward before they are first shown, so that a
3
+ * continuous effect arrives at its steady state instead of growing into it in front of the player.
4
+ *
5
+ * ## What a warm-up is
6
+ *
7
+ * The ordinary loop — spawn, init, advance — run over a population of its own until every emitter
8
+ * in the batch has been running for its `prewarm`. It is not a batch of particles dumped in one
9
+ * tick and aged: an emitter keeps spawning throughout, the ones that die are replaced the way they
10
+ * are in a live scene, and whatever drives the rate (a curve, `EMITTER_AGE`, the program itself)
11
+ * drives it here, because it is the same program being run. What the loop leaves is the population
12
+ * the emitter would have had, moved into the main pool.
13
+ *
14
+ * ## Why it is a pipeline of its own
15
+ *
16
+ * Because the main one is tuned and it must not pay for this. Emit and simulate are the passes whose
17
+ * register pressure sets the system's occupancy, and their waves are kept program-uniform by the
18
+ * bucketing; a warm-up folded into either would spend registers on every frame for work that
19
+ * happens on one, and a loop inside a lane would break the uniform flow across a wave. So this
20
+ * shares code with the main frame and integrates nothing into it: the emit pass is reused unchanged
21
+ * over the warm-up's buffers, the advance is a pass of the warm-up's own (`./chunk_particle_warmup_step.js`
22
+ * says why), and the main passes' compiled code is byte-identical whether this file exists or not.
23
+ *
24
+ * ## The population is transient
25
+ *
26
+ * Pool, alive lists, free list and counters are graph transients that exist for this frame's loop
27
+ * and are then moved — record by record — into the main pool by the migrate pass. That is what keeps
28
+ * the separation clean: the loop's free-list traffic never touches the main free list, the main
29
+ * passes never see a half-warmed particle, and the one point of contact is a pass that pops from the
30
+ * main pool and pushes nothing back.
31
+ *
32
+ * ## Bounded
33
+ *
34
+ * The tick count is at most `PARTICLE_WARMUP_MAX_TICKS`, with the tick length stretched to cover the
35
+ * longest pre-warm in the batch (`./warmup_schedule.js`), so the frame that pays for a warm-up pays
36
+ * for a known number of dispatches whatever was asked. Per tick: reset, tick, the scan, the emit
37
+ * command, emit, advance — six or seven passes, all sized by constants or by the scan.
38
+ *
39
+ * ## Where it sits in the frame
40
+ *
41
+ * After the frame's own emit and simulate, before the bucketing. Migrate appends to the same alive
42
+ * list they did, so the bucketing puts the warmed particles in next frame's simulate list, the bounds
43
+ * pass measures them into their emitter's box this frame, and the draw draws them this frame. Which
44
+ * is also what closes the culling fixed point the bounds passes describe: an emitter that arrives
45
+ * with a warmed population is measured on its first frame, whatever the frustum thinks of its origin.
46
+ *
47
+ * Recorded only on a frame with something queued. The host knows: an emitter is queued when it is
48
+ * registered with a `prewarm`, and the queue is consumed by the frame that records it.
49
+ *
50
+ * @param {object} params
51
+ * @param {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} params.graph
52
+ * @param {number} params.scene_database graph handle
53
+ * @param {number} params.emitter_database graph handle, threaded: the warm-up tick writes ages
54
+ * @param {number} params.program graph handle of the packed program buffer
55
+ * @param {number} params.pool main pool, threaded
56
+ * @param {number} params.alive_out main alive list, threaded
57
+ * @param {number} params.dead main free list, threaded
58
+ * @param {number} params.counters main counters, threaded
59
+ * @param {number} params.vm_registers the wide register file's handle, or -1 when the system is on
60
+ * the fast file
61
+ * @param {GPUBuffer} params.queue the host's queue buffer, `PARTICLE_WARMUP_QUEUE_WORDS` per entry
62
+ * @param {number} params.queue_count entries in the queue
63
+ * @param {number} params.warm_capacity slots in the transient pool
64
+ * @param {number} params.capacity main pool capacity
65
+ * @param {number} params.emitter_capacity element capacity of the emitter table
66
+ * @param {import("./warmup_schedule.js").WarmupSchedule} params.schedule
67
+ * @param {boolean} params.wide_registers
68
+ * @param {object} params.frame
69
+ * @param {number} params.frame.time the frame's clock — the loop counts down to it
70
+ * @param {number} params.frame.index
71
+ * @returns {{pool: number, alive_out: number, dead: number, counters: number, emitter_database: number, vm_registers: number}}
72
+ */
73
+ export function graph_particle_warmup({ graph, scene_database, emitter_database, program, pool, alive_out, dead, counters, vm_registers, queue, queue_count, warm_capacity, capacity, emitter_capacity, schedule, wide_registers, frame, }: {
74
+ graph: import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph;
75
+ scene_database: number;
76
+ emitter_database: number;
77
+ program: number;
78
+ pool: number;
79
+ alive_out: number;
80
+ dead: number;
81
+ counters: number;
82
+ vm_registers: number;
83
+ queue: GPUBuffer;
84
+ queue_count: number;
85
+ warm_capacity: number;
86
+ capacity: number;
87
+ emitter_capacity: number;
88
+ schedule: import("./warmup_schedule.js").WarmupSchedule;
89
+ wide_registers: boolean;
90
+ frame: {
91
+ time: number;
92
+ index: number;
93
+ };
94
+ }): {
95
+ pool: number;
96
+ alive_out: number;
97
+ dead: number;
98
+ counters: number;
99
+ emitter_database: number;
100
+ vm_registers: number;
101
+ };
102
+ //# sourceMappingURL=graph_particle_warmup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph_particle_warmup.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/warmup/graph_particle_warmup.js"],"names":[],"mappings":"AA6BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH;IAtBqG,KAAK,EAA/F,OAAO,8DAA8D,EAAE,UAAU;IAClE,cAAc,EAA7B,MAAM;IACS,gBAAgB,EAA/B,MAAM;IACS,OAAO,EAAtB,MAAM;IACS,IAAI,EAAnB,MAAM;IACS,SAAS,EAAxB,MAAM;IACS,IAAI,EAAnB,MAAM;IACS,QAAQ,EAAvB,MAAM;IACS,YAAY,EAA3B,MAAM;IAEY,KAAK;IACR,WAAW,EAA1B,MAAM;IACS,aAAa,EAA5B,MAAM;IACS,QAAQ,EAAvB,MAAM;IACS,gBAAgB,EAA/B,MAAM;IACgD,QAAQ,EAA9D,OAAO,sBAAsB,EAAE,cAAc;IAC7B,cAAc,EAA9B,OAAO;IACQ,KAAK;QACC,IAAI,EAAzB,MAAM;QACe,KAAK,EAA1B,MAAM;;IACJ;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAC,CAqO7H"}
@@ -0,0 +1,329 @@
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { align_4 } from "../../../../core/binary/align_4.js";
3
+ import { BufferResourceDescriptor } from "../../../device/graph/BufferResourceDescriptor.js";
4
+ import { INDIRECT_COMPUTE_COMMAND_DESCRIPTOR } from "../../gpu_primitive/indirect/IndirectComputeCommandBuildPass.js";
5
+ import { graph_prefix_scan_csdldf } from "../../gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js";
6
+ import { PREFIX_SCAN_CSDLDF_HEADER_WORDS } from "../../gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.js";
7
+ import { shader_prefix_sum_to_command } from "../../rasterize/expand/mesh/shader_prefix_sum_to_command.js";
8
+ import { graph_compute_indirect_pass } from "../../shader/graph/compute/graph_compute_indirect_pass.js";
9
+ import { graph_compute_pass } from "../../shader/graph/compute/graph_compute_pass.js";
10
+ import { graph_create_buffer } from "../../shader/graph/graph_create_buffer.js";
11
+ import { graph_import_buffer } from "../../shader/graph/graph_import_buffer.js";
12
+ import { PARTICLE_RECORD_WORD_COUNT, PARTICLE_WARMUP_WORKGROUP_SIZE } from "../ParticleConstants.js";
13
+ import { PARTICLE_COUNTER_COUNT } from "../data/PARTICLE_COUNTERS.js";
14
+ import { shader_particle_emit } from "../shaders/shader_particle_emit.js";
15
+ import {
16
+ PARTICLE_EMIT_WIDE_WORKGROUP_COUNT,
17
+ shader_particle_emit_wide,
18
+ } from "../shaders/shader_particle_emit_wide.js";
19
+ import {
20
+ PARTICLE_WARMUP_WORKGROUP_COUNT,
21
+ shader_particle_warmup_init,
22
+ shader_particle_warmup_migrate,
23
+ shader_particle_warmup_reset,
24
+ shader_particle_warmup_tick,
25
+ } from "./shader_particle_warmup.js";
26
+ import { shader_particle_warmup_advance } from "./shader_particle_warmup_advance.js";
27
+ import { shader_particle_warmup_advance_wide } from "./shader_particle_warmup_advance_wide.js";
28
+ import { warmup_remaining } from "./warmup_schedule.js";
29
+
30
+ /**
31
+ * Run a batch of newly added emitters' simulations forward before they are first shown, so that a
32
+ * continuous effect arrives at its steady state instead of growing into it in front of the player.
33
+ *
34
+ * ## What a warm-up is
35
+ *
36
+ * The ordinary loop — spawn, init, advance — run over a population of its own until every emitter
37
+ * in the batch has been running for its `prewarm`. It is not a batch of particles dumped in one
38
+ * tick and aged: an emitter keeps spawning throughout, the ones that die are replaced the way they
39
+ * are in a live scene, and whatever drives the rate (a curve, `EMITTER_AGE`, the program itself)
40
+ * drives it here, because it is the same program being run. What the loop leaves is the population
41
+ * the emitter would have had, moved into the main pool.
42
+ *
43
+ * ## Why it is a pipeline of its own
44
+ *
45
+ * Because the main one is tuned and it must not pay for this. Emit and simulate are the passes whose
46
+ * register pressure sets the system's occupancy, and their waves are kept program-uniform by the
47
+ * bucketing; a warm-up folded into either would spend registers on every frame for work that
48
+ * happens on one, and a loop inside a lane would break the uniform flow across a wave. So this
49
+ * shares code with the main frame and integrates nothing into it: the emit pass is reused unchanged
50
+ * over the warm-up's buffers, the advance is a pass of the warm-up's own (`./chunk_particle_warmup_step.js`
51
+ * says why), and the main passes' compiled code is byte-identical whether this file exists or not.
52
+ *
53
+ * ## The population is transient
54
+ *
55
+ * Pool, alive lists, free list and counters are graph transients that exist for this frame's loop
56
+ * and are then moved — record by record — into the main pool by the migrate pass. That is what keeps
57
+ * the separation clean: the loop's free-list traffic never touches the main free list, the main
58
+ * passes never see a half-warmed particle, and the one point of contact is a pass that pops from the
59
+ * main pool and pushes nothing back.
60
+ *
61
+ * ## Bounded
62
+ *
63
+ * The tick count is at most `PARTICLE_WARMUP_MAX_TICKS`, with the tick length stretched to cover the
64
+ * longest pre-warm in the batch (`./warmup_schedule.js`), so the frame that pays for a warm-up pays
65
+ * for a known number of dispatches whatever was asked. Per tick: reset, tick, the scan, the emit
66
+ * command, emit, advance — six or seven passes, all sized by constants or by the scan.
67
+ *
68
+ * ## Where it sits in the frame
69
+ *
70
+ * After the frame's own emit and simulate, before the bucketing. Migrate appends to the same alive
71
+ * list they did, so the bucketing puts the warmed particles in next frame's simulate list, the bounds
72
+ * pass measures them into their emitter's box this frame, and the draw draws them this frame. Which
73
+ * is also what closes the culling fixed point the bounds passes describe: an emitter that arrives
74
+ * with a warmed population is measured on its first frame, whatever the frustum thinks of its origin.
75
+ *
76
+ * Recorded only on a frame with something queued. The host knows: an emitter is queued when it is
77
+ * registered with a `prewarm`, and the queue is consumed by the frame that records it.
78
+ *
79
+ * @param {object} params
80
+ * @param {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} params.graph
81
+ * @param {number} params.scene_database graph handle
82
+ * @param {number} params.emitter_database graph handle, threaded: the warm-up tick writes ages
83
+ * @param {number} params.program graph handle of the packed program buffer
84
+ * @param {number} params.pool main pool, threaded
85
+ * @param {number} params.alive_out main alive list, threaded
86
+ * @param {number} params.dead main free list, threaded
87
+ * @param {number} params.counters main counters, threaded
88
+ * @param {number} params.vm_registers the wide register file's handle, or -1 when the system is on
89
+ * the fast file
90
+ * @param {GPUBuffer} params.queue the host's queue buffer, `PARTICLE_WARMUP_QUEUE_WORDS` per entry
91
+ * @param {number} params.queue_count entries in the queue
92
+ * @param {number} params.warm_capacity slots in the transient pool
93
+ * @param {number} params.capacity main pool capacity
94
+ * @param {number} params.emitter_capacity element capacity of the emitter table
95
+ * @param {import("./warmup_schedule.js").WarmupSchedule} params.schedule
96
+ * @param {boolean} params.wide_registers
97
+ * @param {object} params.frame
98
+ * @param {number} params.frame.time the frame's clock — the loop counts down to it
99
+ * @param {number} params.frame.index
100
+ * @returns {{pool: number, alive_out: number, dead: number, counters: number, emitter_database: number, vm_registers: number}}
101
+ */
102
+ export function graph_particle_warmup({
103
+ graph,
104
+ scene_database,
105
+ emitter_database,
106
+ program,
107
+ pool,
108
+ alive_out,
109
+ dead,
110
+ counters,
111
+ vm_registers,
112
+ queue,
113
+ queue_count,
114
+ warm_capacity,
115
+ capacity,
116
+ emitter_capacity,
117
+ schedule,
118
+ wide_registers,
119
+ frame,
120
+ }) {
121
+ assert.defined(graph, "graph");
122
+ assert.isPositiveInteger(queue_count, "queue_count");
123
+ assert.isPositiveInteger(warm_capacity, "warm_capacity");
124
+ assert.isPositiveInteger(schedule.ticks, "schedule.ticks");
125
+
126
+ const WORD = Uint32Array.BYTES_PER_ELEMENT;
127
+ const STORAGE = GPUBufferUsage.STORAGE;
128
+
129
+ const gr_queue = graph_import_buffer(graph, queue, "particles/warmup/queue");
130
+
131
+ // The transient population. Uncleared where the init pass writes every word that will be read
132
+ // (the free list), cleared where a word could be read before it is written (the counters, and
133
+ // the alive lists' tails are bounded by counts the passes wrote).
134
+ // Threaded like everything a pass writes: emit and advance both rename it, and the next reader
135
+ // must take the renamed handle or the graph's validator rejects the frame as reading a stale
136
+ // version.
137
+ let warm_pool = graph_create_buffer(graph, "particles/warmup/pool", BufferResourceDescriptor.from(
138
+ warm_capacity * PARTICLE_RECORD_WORD_COUNT * WORD, STORAGE,
139
+ ));
140
+ const warm_alive = [
141
+ graph_create_buffer(graph, "particles/warmup/alive_a", BufferResourceDescriptor.from(warm_capacity * WORD, STORAGE)),
142
+ graph_create_buffer(graph, "particles/warmup/alive_b", BufferResourceDescriptor.from(warm_capacity * WORD, STORAGE)),
143
+ ];
144
+ let warm_dead = graph_create_buffer(graph, "particles/warmup/dead", BufferResourceDescriptor.from(warm_capacity * WORD, STORAGE));
145
+ let warm_counters = graph_create_buffer(graph, "particles/warmup/counters", BufferResourceDescriptor.empty(
146
+ PARTICLE_COUNTER_COUNT * WORD, STORAGE | GPUBufferUsage.COPY_DST,
147
+ ));
148
+
149
+ // Every slot onto the free list.
150
+ {
151
+ const out = graph_compute_pass({
152
+ graph,
153
+ shader: shader_particle_warmup_init,
154
+ bindings: { dead: warm_dead, counters: warm_counters, u_capacity: warm_capacity },
155
+ group_count: [Math.ceil(warm_capacity / PARTICLE_WARMUP_WORKGROUP_SIZE), 1, 1],
156
+ });
157
+ warm_dead = out.dead;
158
+ warm_counters = out.counters;
159
+ }
160
+
161
+ const count_words = PREFIX_SCAN_CSDLDF_HEADER_WORDS + align_4(Math.max(1, emitter_capacity));
162
+ const count_bytes = count_words * WORD;
163
+
164
+ let gr_queue_rw = gr_queue;
165
+
166
+ for (let tick = 0; tick < schedule.ticks; tick++) {
167
+ const remaining = warmup_remaining(schedule, tick);
168
+ // The clock at the start of this tick: the frame's, less what is still to run.
169
+ const time = frame.time - remaining;
170
+ // Distinct per tick, and unlike any frame index the main emit will seed with, so a warmed
171
+ // particle's random stream is not a later particle's in the same slot.
172
+ const frame_index = (frame.index ^ Math.imul(tick + 1, 0x9e3779b9)) >>> 0;
173
+
174
+ // Last tick's survivors are this tick's input; this tick appends to the other list.
175
+ const alive_in = warm_alive[(tick + 1) % 2];
176
+ let alive_this = warm_alive[tick % 2];
177
+
178
+ // 1. Roll the counters: alive -> alive_in, alive = 0, budget = dead.
179
+ warm_counters = graph_compute_pass({
180
+ graph,
181
+ shader: shader_particle_warmup_reset,
182
+ bindings: { counters: warm_counters },
183
+ group_count: [1, 1, 1],
184
+ }).counters;
185
+
186
+ // 2. The spawn decision, per queued emitter, into a count list as long as the emitter table.
187
+ // Cleared whole: the tick writes only the queued rows.
188
+ let spawn_counts = graph_create_buffer(graph, "particles/warmup/spawn_counts", BufferResourceDescriptor.from(
189
+ count_bytes, STORAGE, 0, count_bytes,
190
+ ));
191
+
192
+ {
193
+ const out = graph_compute_pass({
194
+ graph,
195
+ shader: shader_particle_warmup_tick,
196
+ bindings: {
197
+ queue: gr_queue_rw,
198
+ emitter_database,
199
+ counters: warm_counters,
200
+ spawn_counts,
201
+ settings: {
202
+ u_dt: schedule.dt,
203
+ u_remaining: remaining,
204
+ u_capacity: warm_capacity,
205
+ u_emitter_capacity: emitter_capacity,
206
+ u_count: queue_count,
207
+ },
208
+ },
209
+ group_count: [Math.ceil(queue_count / PARTICLE_WARMUP_WORKGROUP_SIZE), 1, 1],
210
+ });
211
+ gr_queue_rw = out.queue;
212
+ emitter_database = out.emitter_database;
213
+ warm_counters = out.counters;
214
+ spawn_counts = out.spawn_counts;
215
+ }
216
+
217
+ // 3. Scan the counts; the last sum is the tick's newborn count.
218
+ const spawn_prefix = graph_prefix_scan_csdldf({
219
+ graph,
220
+ data: spawn_counts,
221
+ element_max_count: Math.max(1, emitter_capacity),
222
+ });
223
+
224
+ // 4. That total as the emit dispatch — for the fast emit; the wide one reads the total as a
225
+ // loop bound instead, as it does in the main frame.
226
+ const emit_command = graph_compute_pass({
227
+ graph,
228
+ shader: shader_prefix_sum_to_command,
229
+ bindings: {
230
+ prefix_sums: spawn_prefix,
231
+ command: graph_create_buffer(graph, "particles/warmup/emit_command", INDIRECT_COMPUTE_COMMAND_DESCRIPTOR),
232
+ },
233
+ group_count: [1, 1, 1],
234
+ }).command;
235
+
236
+ // 5. Emit — the main pass, unchanged, over the warm-up's buffers. It finds each newborn's
237
+ // emitter in the scan, reads the record and the age off the main database, pops the
238
+ // transient free list and appends to the transient alive list.
239
+ {
240
+ const bindings = {
241
+ scene_database,
242
+ emitter_database,
243
+ program,
244
+ spawn_prefix,
245
+ pool: warm_pool, alive_out: alive_this, dead: warm_dead, counters: warm_counters,
246
+ settings: { u_dt: schedule.dt, u_time: time, u_frame: frame_index, u_capacity: warm_capacity },
247
+ };
248
+
249
+ const out = wide_registers
250
+ ? graph_compute_pass({
251
+ graph,
252
+ shader: shader_particle_emit_wide,
253
+ bindings: { ...bindings, vm_registers },
254
+ group_count: [PARTICLE_EMIT_WIDE_WORKGROUP_COUNT, 1, 1],
255
+ })
256
+ : graph_compute_indirect_pass({
257
+ graph,
258
+ shader: shader_particle_emit,
259
+ bindings,
260
+ command: emit_command,
261
+ });
262
+
263
+ warm_pool = out.pool;
264
+ alive_this = out.alive_out;
265
+ warm_dead = out.dead;
266
+ warm_counters = out.counters;
267
+
268
+ if (wide_registers) { vm_registers = out.vm_registers; }
269
+ }
270
+
271
+ // 6. Advance last tick's survivors by one tick, into the same list the newborns went to.
272
+ {
273
+ const bindings = {
274
+ scene_database,
275
+ emitter_database,
276
+ program,
277
+ pool: warm_pool, alive_in, alive_out: alive_this, dead: warm_dead, counters: warm_counters,
278
+ settings: { u_dt: schedule.dt, u_time: time, u_frame: frame_index },
279
+ };
280
+
281
+ const out = wide_registers
282
+ ? graph_compute_pass({
283
+ graph,
284
+ shader: shader_particle_warmup_advance_wide,
285
+ bindings: { ...bindings, vm_registers },
286
+ group_count: [PARTICLE_WARMUP_WORKGROUP_COUNT, 1, 1],
287
+ })
288
+ : graph_compute_pass({
289
+ graph,
290
+ shader: shader_particle_warmup_advance,
291
+ bindings,
292
+ group_count: [PARTICLE_WARMUP_WORKGROUP_COUNT, 1, 1],
293
+ });
294
+
295
+ warm_pool = out.pool;
296
+ alive_this = out.alive_out;
297
+ warm_dead = out.dead;
298
+ warm_counters = out.counters;
299
+
300
+ if (wide_registers) { vm_registers = out.vm_registers; }
301
+ }
302
+
303
+ warm_alive[tick % 2] = alive_this;
304
+ }
305
+
306
+ // 7. The population is the scene's: every survivor into a main-pool slot, onto the main alive
307
+ // list.
308
+ {
309
+ const out = graph_compute_pass({
310
+ graph,
311
+ shader: shader_particle_warmup_migrate,
312
+ bindings: {
313
+ warm_pool,
314
+ warm_alive: warm_alive[(schedule.ticks - 1) % 2],
315
+ warm_counters,
316
+ pool, alive_out, dead, counters,
317
+ u_capacity: capacity,
318
+ },
319
+ group_count: [PARTICLE_WARMUP_WORKGROUP_COUNT, 1, 1],
320
+ });
321
+
322
+ pool = out.pool;
323
+ alive_out = out.alive_out;
324
+ dead = out.dead;
325
+ counters = out.counters;
326
+ }
327
+
328
+ return { pool, alive_out, dead, counters, emitter_database, vm_registers };
329
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * The passes that are the warm-up's own. The rest of the loop is the main pipeline's, bound to a
3
+ * population of its own — see `./graph_particle_warmup.js` for the loop and for why it is separate.
4
+ *
5
+ * - {@link shader_particle_warmup_init} — hand the transient pool its free list, once per warm-up.
6
+ * - {@link shader_particle_warmup_reset} — roll the transient counters over, once per tick.
7
+ * - {@link shader_particle_warmup_tick} — one thread per queued emitter: the spawn decision for a
8
+ * tick, over a queue the host wrote rather than over the emitter table.
9
+ * - {@link shader_particle_warmup_migrate} — one thread per warmed particle: move it into the main
10
+ * pool, once the loop is done.
11
+ *
12
+ * Everything the warm-up integrates per emitter lives in the queue entry (its accumulator), not in
13
+ * the emitter's state row — with one exception, deliberately: the emitter's *age*. INIT and UPDATE
14
+ * read `EMITTER_AGE` off the state row through the same chunk whether the main emit pass or the
15
+ * warm-up's runs them, so the warm-up tick writes the age the emitter has reached into that row as it
16
+ * goes. When the loop ends the row says `prewarm`, and the next real tick adds its `dt` to that.
17
+ */
18
+ /**
19
+ * Word offsets within one entry of the warm-up queue the host writes:
20
+ * `[emitter row, pre-warm seconds, spawn accumulator, clock]`.
21
+ *
22
+ * The accumulator is the host's to seed and the GPU's from then on — a fraction in `[0, 1)` hashed
23
+ * from the row, so that two emitters queued together do not put their first whole particle on the
24
+ * same tick. The clock is the emitter's own tick rate, `1 ± PARTICLE_WARMUP_EMITTER_JITTER / 2`, for
25
+ * the same reason a beat further in.
26
+ *
27
+ * Raw words rather than a `WebGPUStruct`, like the spawn-command list: it is a short host-authored
28
+ * list read once a tick, and the floats are `bitcast` on the way in and out.
29
+ */
30
+ export const WARMUP_QUEUE: Readonly<{
31
+ ROW: 0;
32
+ PREWARM: 1;
33
+ ACCUMULATOR: 2;
34
+ CLOCK: 3;
35
+ }>;
36
+ /** Workgroups the bounded per-particle passes launch. */
37
+ export const PARTICLE_WARMUP_WORKGROUP_COUNT: number;
38
+ /**
39
+ * One thread per slot of the transient pool: every slot onto the free list, and the counters to
40
+ * match. What the main system does once on the CPU when it allocates its pool, done on the GPU here
41
+ * because the pool is a graph transient and there is no CPU moment to write it in.
42
+ *
43
+ * @type {ComputeShader}
44
+ */
45
+ export const shader_particle_warmup_init: ComputeShader;
46
+ /**
47
+ * The top of a warm-up tick: last tick's alive list becomes this tick's advance input, the alive
48
+ * count starts over, and the tick's spawn budget is the free list as it stands.
49
+ *
50
+ * The main frame splits this between its reset pass and its build-indirect pass, because its
51
+ * simulate consumes the program-coherent list the bucketing built rather than the alive list
52
+ * itself. The warm-up's advance consumes the alive list directly (see `./chunk_particle_warmup_step.js`
53
+ * for why it can), so the snapshot is just the count.
54
+ *
55
+ * @type {ComputeShader}
56
+ */
57
+ export const shader_particle_warmup_reset: ComputeShader;
58
+ /**
59
+ * Per-dispatch, 20 bytes, read-only.
60
+ * @type {WebGPUStruct}
61
+ */
62
+ export const WARMUP_TICK_SETTINGS: WebGPUStruct;
63
+ /**
64
+ * One thread per queued emitter: how many particles it spawns this tick.
65
+ *
66
+ * The main emitter tick's spawn decision — integrate the rate, take from the budget, write the
67
+ * count by row for the scan — over the host's queue instead of the emitter table, and without the
68
+ * parts that belong to a live frame: no generation test (the host holds the queue for exactly one
69
+ * frame), no culling (a warm-up is what makes an emitter measurable in the first place), no pending
70
+ * bursts (they are the frame's, not the past's).
71
+ *
72
+ * ## When an emitter takes part
73
+ *
74
+ * Once `u_remaining` is within its own pre-warm: the loop's clock counts down to now, and an emitter
75
+ * joins it when the time left is what it asked to have been running for. Two emitters queued with
76
+ * different durations therefore end the same loop having each run for its own — the shorter one
77
+ * simply sat out the start — rather than the shorter one being run for the longer's time and
78
+ * arriving with a population that is all dead of old age.
79
+ *
80
+ * ## The count list is the emitter table's
81
+ *
82
+ * The counts are written by emitter *row*, into a list as long as the table, exactly as the main
83
+ * tick writes them. That is what lets the main emit pass be reused unchanged: it finds a newborn's
84
+ * emitter by searching the scan of that list, and the row it finds is the row its record reads.
85
+ * Rows not in the queue count zero, which the cleared buffer already says.
86
+ *
87
+ * @type {ComputeShader}
88
+ */
89
+ export const shader_particle_warmup_tick: ComputeShader;
90
+ /**
91
+ * One thread per particle the loop left alive: a slot from the main pool, the record copied into
92
+ * it, and the slot onto the main alive list. The moment the warm-up's population becomes the
93
+ * scene's.
94
+ *
95
+ * The pop is the emit pass's, wrap guard and all, and it is the only thing this pass does to the
96
+ * main free list: it never pushes, so it is safe against nothing and needs no ordering beyond
97
+ * running after the main emit and simulate of the frame, which the graph gives it. A particle the
98
+ * main pool has no room for is dropped, as a spawn the pool has no room for is.
99
+ *
100
+ * The record is copied whole, header included. The header names the emitter's main-table row and
101
+ * generation — the warm-up's emit stamped it from the same record the main emit reads — so the
102
+ * copied particle is an ordinary one to every pass that meets it from here on.
103
+ *
104
+ * Bounded launch, grid stride over the transient alive count: the population is small and nothing
105
+ * should size a dispatch from the host to cover it.
106
+ *
107
+ * @type {ComputeShader}
108
+ */
109
+ export const shader_particle_warmup_migrate: ComputeShader;
110
+ import { ComputeShader } from "../../shader/ComputeShader.js";
111
+ import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
112
+ //# sourceMappingURL=shader_particle_warmup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_particle_warmup.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/warmup/shader_particle_warmup.js"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;;;;GAWG;AACH;;;;;GAKG;AAEH,yDAAyD;AACzD,qDAA6G;AAc7G;;;;;;GAMG;AACH,0CAFU,aAAa,CAqBpB;AASH;;;;;;;;;;GAUG;AACH,2CAFU,aAAa,CAapB;AAIH;;;GAGG;AACH,mCAFU,YAAY,CAaW;AAkBjC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,0CAFU,aAAa,CAyDpB;AAiBH;;;;;;;;;;;;;;;;;;GAkBG;AACH,6CAFU,aAAa,CAuCpB;8BAzT2B,+BAA+B;6BAFhC,mCAAmC"}