@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.
- package/editor/actions/concrete/ComponentAddAction.d.ts +1 -0
- package/editor/actions/concrete/ComponentAddAction.d.ts.map +1 -1
- package/editor/actions/concrete/ComponentAddAction.js +4 -0
- package/editor/actions/concrete/ComponentRemoveAction.d.ts +1 -0
- package/editor/actions/concrete/ComponentRemoveAction.d.ts.map +1 -1
- package/editor/actions/concrete/ComponentRemoveAction.js +4 -0
- package/editor/actions/concrete/EntityCreateAction.d.ts +1 -0
- package/editor/actions/concrete/EntityCreateAction.d.ts.map +1 -1
- package/editor/actions/concrete/EntityCreateAction.js +7 -0
- package/editor/actions/concrete/EntityRemoveAction.d.ts +1 -0
- package/editor/actions/concrete/EntityRemoveAction.d.ts.map +1 -1
- package/editor/actions/concrete/EntityRemoveAction.js +4 -0
- package/editor/actions/concrete/PatchTerrainHeightAction.d.ts +10 -0
- package/editor/actions/concrete/PatchTerrainHeightAction.d.ts.map +1 -1
- package/editor/actions/concrete/PatchTerrainHeightAction.js +107 -85
- package/editor/actions/concrete/TransformModifyAction.d.ts +1 -0
- package/editor/actions/concrete/TransformModifyAction.d.ts.map +1 -1
- package/editor/actions/concrete/TransformModifyAction.js +4 -0
- package/editor/particles/effect/ParticleEffectDocument.d.ts.map +1 -1
- package/editor/particles/effect/ParticleEffectDocument.js +10 -6
- package/editor/particles/effect/ParticleReferenceSimulation.d.ts.map +1 -1
- package/editor/particles/effect/ParticleReferenceSimulation.js +98 -4
- package/editor/particles/effect/make_starter_particle_effect.d.ts.map +1 -1
- package/editor/particles/effect/make_starter_particle_effect.js +0 -2
- package/editor/tools/engine/ToolEngine.d.ts +30 -0
- package/editor/tools/engine/ToolEngine.d.ts.map +1 -1
- package/editor/tools/engine/ToolEngine.js +257 -188
- package/editor/view/ecs/EntityList.d.ts.map +1 -1
- package/editor/view/ecs/EntityList.js +6 -5
- package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleEmitterInspectorView.js +17 -9
- package/package.json +1 -1
- package/src/CODEC_LAYOUT_VERIFICATION.md +1 -2
- package/src/core/binary/meshopt/MESHOPT_VERTEX_BLOCK.d.ts +56 -0
- package/src/core/binary/meshopt/MESHOPT_VERTEX_BLOCK.d.ts.map +1 -0
- package/src/core/binary/meshopt/MESHOPT_VERTEX_BLOCK.js +73 -0
- package/src/core/binary/meshopt/meshopt_decode_vertex_buffer.d.ts.map +1 -1
- package/src/core/binary/meshopt/meshopt_decode_vertex_buffer.js +18 -63
- package/src/core/binary/meshopt/meshopt_encode_byte_group.d.ts +53 -0
- package/src/core/binary/meshopt/meshopt_encode_byte_group.d.ts.map +1 -0
- package/src/core/binary/meshopt/meshopt_encode_byte_group.js +140 -0
- package/src/core/binary/meshopt/meshopt_encode_data_block.d.ts +32 -0
- package/src/core/binary/meshopt/meshopt_encode_data_block.d.ts.map +1 -0
- package/src/core/binary/meshopt/meshopt_encode_data_block.js +77 -0
- package/src/core/binary/meshopt/meshopt_encode_index_sequence.d.ts +46 -0
- package/src/core/binary/meshopt/meshopt_encode_index_sequence.d.ts.map +1 -0
- package/src/core/binary/meshopt/meshopt_encode_index_sequence.js +146 -0
- package/src/core/binary/meshopt/meshopt_encode_vertex_buffer.d.ts +40 -0
- package/src/core/binary/meshopt/meshopt_encode_vertex_buffer.d.ts.map +1 -0
- package/src/core/binary/meshopt/meshopt_encode_vertex_buffer.js +700 -0
- package/src/core/binary/meshopt/meshopt_write_uint_var.d.ts +24 -0
- package/src/core/binary/meshopt/meshopt_write_uint_var.d.ts.map +1 -0
- package/src/core/binary/meshopt/meshopt_write_uint_var.js +39 -0
- package/src/core/math/random/seededRandom_Mulberry32.d.ts.map +1 -1
- package/src/core/math/random/seededRandom_Mulberry32.js +4 -2
- package/src/core/process/undo/Action.d.ts +19 -0
- package/src/core/process/undo/Action.d.ts.map +1 -1
- package/src/core/process/undo/Action.js +17 -0
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +78 -0
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -0
- package/src/engine/graphics3/GPUParticleEmitterSystem.js +310 -0
- package/src/engine/graphics3/GraphicsEngine.d.ts +17 -0
- package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -1
- package/src/engine/graphics3/GraphicsEngine.js +30 -10
- package/src/engine/graphics3/particles/particle_gpu_records.d.ts.map +1 -1
- package/src/engine/graphics3/particles/particle_gpu_records.js +0 -2
- package/src/engine/interpolation/InterpolationSystem.d.ts +7 -0
- package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
- package/src/engine/interpolation/InterpolationSystem.js +10 -0
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +14 -34
- package/src/engine/network/time/RenderPlayout.d.ts +76 -0
- package/src/engine/network/time/RenderPlayout.d.ts.map +1 -0
- package/src/engine/network/time/RenderPlayout.js +163 -0
- package/src/engine/network/transport/adapters/WebSocketTransport.d.ts.map +1 -1
- package/src/engine/network/transport/adapters/WebSocketTransport.js +11 -4
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +4 -12
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +39 -13
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/sound/simulation/core/VolumeField.d.ts.map +1 -1
- package/src/engine/sound/simulation/core/VolumeField.js +4 -1
- package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +23 -2
- package/src/shade/playground/particle_system/README.md +139 -139
- package/src/shade/playground/particle_system/particle_prototype.d.ts.map +1 -1
- package/src/shade/playground/particle_system/particle_prototype.js +0 -2
- package/src/shade/playground/particle_system/particle_scene.d.ts +6 -9
- package/src/shade/playground/particle_system/particle_scene.d.ts.map +1 -1
- package/src/shade/playground/particle_system/particle_scene.js +6 -13
- package/src/shade/playground/ssr_reprojection/README.md +103 -0
- package/src/shade/playground/ssr_reprojection/SpatialFilterProbe.d.ts +17 -0
- package/src/shade/playground/ssr_reprojection/SpatialFilterProbe.d.ts.map +1 -0
- package/src/shade/playground/ssr_reprojection/SpatialFilterProbe.js +68 -0
- package/src/shade/playground/ssr_reprojection/index.html +79 -0
- package/src/shade/playground/ssr_reprojection/main.d.ts +2 -0
- package/src/shade/playground/ssr_reprojection/main.d.ts.map +1 -0
- package/src/shade/playground/ssr_reprojection/main.js +245 -0
- package/src/shade/playground/ssr_reprojection/scene.d.ts +18 -0
- package/src/shade/playground/ssr_reprojection/scene.d.ts.map +1 -0
- package/src/shade/playground/ssr_reprojection/scene.js +51 -0
- package/src/shade/renderer/Renderer.d.ts +2 -23
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +185 -218
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts +5 -8
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.js +12 -12
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTable.js +6 -0
- package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +7 -0
- package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_sample_specular.d.ts +4 -0
- package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_sample_specular.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_sample_specular.js +51 -0
- package/src/shade/renderer/global_illumination/brick4/gpu/draw/shader_brick4_specular.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/draw/shader_brick4_specular.js +5 -35
- package/src/shade/renderer/particles/DESIGN.md +703 -514
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts +16 -4
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +1189 -991
- package/src/shade/renderer/particles/ParticleConstants.d.ts +64 -0
- package/src/shade/renderer/particles/ParticleConstants.d.ts.map +1 -1
- package/src/shade/renderer/particles/ParticleConstants.js +71 -0
- package/src/shade/renderer/particles/bounds/chunk_particle_bounds.d.ts +57 -0
- package/src/shade/renderer/particles/bounds/chunk_particle_bounds.d.ts.map +1 -0
- package/src/shade/renderer/particles/bounds/chunk_particle_bounds.js +181 -0
- package/src/shade/renderer/particles/bounds/chunk_particle_bounds_unknown.d.ts +7 -0
- package/src/shade/renderer/particles/bounds/chunk_particle_bounds_unknown.d.ts.map +1 -0
- package/src/shade/renderer/particles/bounds/chunk_particle_bounds_unknown.js +12 -0
- package/src/shade/renderer/particles/bounds/graph_particle_bounds.d.ts +33 -0
- package/src/shade/renderer/particles/bounds/graph_particle_bounds.d.ts.map +1 -0
- package/src/shade/renderer/particles/bounds/graph_particle_bounds.js +67 -0
- package/src/shade/renderer/particles/bounds/shader_particle_bounds.d.ts +40 -0
- package/src/shade/renderer/particles/bounds/shader_particle_bounds.d.ts.map +1 -0
- package/src/shade/renderer/particles/bounds/shader_particle_bounds.js +187 -0
- package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts +15 -2
- package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts.map +1 -1
- package/src/shade/renderer/particles/coherence/graph_particle_bucket.js +14 -8
- package/src/shade/renderer/particles/data/PARTICLE_COUNTERS.d.ts +58 -4
- package/src/shade/renderer/particles/data/PARTICLE_COUNTERS.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/PARTICLE_COUNTERS.js +79 -4
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STATE.d.ts +23 -1
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STATE.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STATE.js +35 -2
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts +4 -2
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js +5 -8
- package/src/shade/renderer/particles/data/particle_emitter_record.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/particle_emitter_record.js +0 -6
- package/src/shade/renderer/particles/graph_particles.d.ts +25 -3
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +108 -31
- package/src/shade/renderer/particles/graph_particles_avboit.d.ts +6 -4
- package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles_avboit.js +5 -5
- package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +5 -0
- package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/EmitterRegistry.js +27 -6
- package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts +4 -0
- package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.js +6 -1
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +35 -27
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/ParticleEmitter.js +424 -425
- package/src/shade/renderer/particles/shaders/chunk_particle_emitter_warmup.d.ts +20 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_emitter_warmup.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts +4 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_render_math.js +38 -2
- package/src/shade/renderer/particles/shaders/chunk_particle_spawn_budget.d.ts +22 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_spawn_budget.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_spawn_budget.js +42 -0
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.js +53 -22
- package/src/shade/renderer/particles/shaders/shader_particle_emitter_tick.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emitter_tick.js +213 -216
- package/src/shade/renderer/particles/shaders/shader_particle_reclaim.d.ts +50 -0
- package/src/shade/renderer/particles/shaders/shader_particle_reclaim.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/shader_particle_render.js +1 -1
- package/src/shade/renderer/particles/warmup/chunk_particle_warmup_step.d.ts +36 -0
- package/src/shade/renderer/particles/warmup/chunk_particle_warmup_step.d.ts.map +1 -0
- package/src/shade/renderer/particles/warmup/chunk_particle_warmup_step.js +102 -0
- package/src/shade/renderer/particles/warmup/graph_particle_warmup.d.ts +102 -0
- package/src/shade/renderer/particles/warmup/graph_particle_warmup.d.ts.map +1 -0
- package/src/shade/renderer/particles/warmup/graph_particle_warmup.js +329 -0
- package/src/shade/renderer/particles/warmup/shader_particle_warmup.d.ts +112 -0
- package/src/shade/renderer/particles/warmup/shader_particle_warmup.d.ts.map +1 -0
- package/src/shade/renderer/particles/warmup/shader_particle_warmup.js +318 -0
- package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance.d.ts +35 -0
- package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance.d.ts.map +1 -0
- package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance.js +108 -0
- package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.d.ts +3 -0
- package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.d.ts.map +1 -0
- package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.js +70 -0
- package/src/shade/renderer/particles/warmup/warmup_schedule.d.ts +62 -0
- package/src/shade/renderer/particles/warmup/warmup_schedule.d.ts.map +1 -0
- package/src/shade/renderer/particles/warmup/warmup_schedule.js +55 -0
- package/src/shade/renderer/postprocess/PostProcess.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/PostProcess.js +2 -1
- package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +286 -0
- package/src/shade/renderer/postprocess/ssr/SSR.d.ts +57 -21
- package/src/shade/renderer/postprocess/ssr/SSR.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/SSR.js +230 -129
- package/src/shade/renderer/postprocess/ssr/SSRReprojectionMode.d.ts +11 -0
- package/src/shade/renderer/postprocess/ssr/SSRReprojectionMode.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/SSRReprojectionMode.js +6 -0
- package/src/shade/renderer/postprocess/ssr/chunk_ssr_metadata.d.ts +4 -0
- package/src/shade/renderer/postprocess/ssr/chunk_ssr_metadata.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/chunk_ssr_metadata.js +32 -0
- package/src/shade/renderer/postprocess/ssr/chunk_ssr_spatial_variance.d.ts +4 -0
- package/src/shade/renderer/postprocess/ssr/chunk_ssr_spatial_variance.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/chunk_ssr_spatial_variance.js +41 -0
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.d.ts +3 -0
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_reprojection.js +30 -0
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_sample_history.d.ts +4 -0
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_sample_history.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_sample_history.js +70 -0
- package/src/shade/renderer/postprocess/ssr/resolve/build_ssr_resolve_shader.d.ts +21 -0
- package/src/shade/renderer/postprocess/ssr/resolve/build_ssr_resolve_shader.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/resolve/build_ssr_resolve_shader.js +363 -0
- package/src/shade/renderer/postprocess/ssr/resolve/chunk_get_neighbour_weight.js +1 -1
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_Brick4.d.ts +2 -0
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_Brick4.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_Brick4.js +24 -0
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_IBL.d.ts +1 -6
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_IBL.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_IBL.js +16 -332
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_LPV.d.ts +1 -6
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_LPV.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_LPV.js +25 -358
- package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts +0 -5
- package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.js +201 -276
- package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts +1 -0
- package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +167 -143
- package/src/shade/renderer/shader/graph/graph_create_buffer.d.ts +15 -0
- package/src/shade/renderer/shader/graph/graph_create_buffer.d.ts.map +1 -0
- package/src/shade/renderer/shader/graph/graph_create_buffer.js +20 -0
- package/src/shade/renderer/view/GPUViewContext.d.ts +3 -4
- package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
- package/src/shade/renderer/view/GPUViewContext.js +5 -5
- package/src/core/binary/meshopt/__meshopt_test_streams.d.ts +0 -24
- package/src/core/binary/meshopt/__meshopt_test_streams.d.ts.map +0 -1
- package/src/core/binary/meshopt/__meshopt_test_streams.js +0 -237
- package/src/core/geom/3d/atlas/atlas_test_fixtures.d.ts +0 -84
- package/src/core/geom/3d/atlas/atlas_test_fixtures.d.ts.map +0 -1
- package/src/core/geom/3d/atlas/atlas_test_fixtures.js +0 -266
- package/src/engine/asset/loaders/gltf_test_fixtures.d.ts +0 -97
- package/src/engine/asset/loaders/gltf_test_fixtures.d.ts.map +0 -1
- package/src/engine/asset/loaders/gltf_test_fixtures.js +0 -359
- package/src/engine/sound/simulation/core/OcclusionSolver.d.ts +0 -29
- package/src/engine/sound/simulation/core/OcclusionSolver.d.ts.map +0 -1
- package/src/shade/renderer/animation/skin_test_fixtures.d.ts +0 -86
- package/src/shade/renderer/animation/skin_test_fixtures.d.ts.map +0 -1
- package/src/shade/renderer/animation/skin_test_fixtures.js +0 -250
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_test_fixtures.d.ts +0 -16
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_test_fixtures.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_test_fixtures.js +0 -27
- package/src/shade/renderer/particles/particle_test_fixtures.d.ts +0 -151
- package/src/shade/renderer/particles/particle_test_fixtures.d.ts.map +0 -1
- package/src/shade/renderer/particles/particle_test_fixtures.js +0 -229
- package/src/shade/renderer/particles/shaders/chunk_particle_emitter_world_sphere.js +0 -23
- 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"}
|