@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,318 @@
|
|
|
1
|
+
import { atomic_u32, f32, u32 } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
2
|
+
import { WebGPUArray } from "../../shader/type/WebGPUArray.js";
|
|
3
|
+
import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
|
|
4
|
+
import { COLLECTION_U32_STRUCT_READ } from "../../gpu_primitive/COLLECTION_U32_STRUCT_READ.js";
|
|
5
|
+
import { ComputeShader } from "../../shader/ComputeShader.js";
|
|
6
|
+
import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
|
|
7
|
+
import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
|
|
8
|
+
import {
|
|
9
|
+
PARTICLE_RECORD_WORD_COUNT,
|
|
10
|
+
PARTICLE_WARMUP_LAUNCH_LANES,
|
|
11
|
+
PARTICLE_WARMUP_QUEUE_WORDS,
|
|
12
|
+
PARTICLE_WARMUP_WORKGROUP_SIZE,
|
|
13
|
+
} from "../ParticleConstants.js";
|
|
14
|
+
import { PARTICLE_COUNTER } from "../data/PARTICLE_COUNTERS.js";
|
|
15
|
+
import { PARTICLE_EMITTER_DESCRIPTOR, PARTICLE_EMITTER_STATE_DESCRIPTOR } from "../data/PARTICLE_DATABASE_SPEC.js";
|
|
16
|
+
import { chunk_particle_spawn_budget } from "../shaders/chunk_particle_spawn_budget.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The passes that are the warm-up's own. The rest of the loop is the main pipeline's, bound to a
|
|
20
|
+
* population of its own — see `./graph_particle_warmup.js` for the loop and for why it is separate.
|
|
21
|
+
*
|
|
22
|
+
* - {@link shader_particle_warmup_init} — hand the transient pool its free list, once per warm-up.
|
|
23
|
+
* - {@link shader_particle_warmup_reset} — roll the transient counters over, once per tick.
|
|
24
|
+
* - {@link shader_particle_warmup_tick} — one thread per queued emitter: the spawn decision for a
|
|
25
|
+
* tick, over a queue the host wrote rather than over the emitter table.
|
|
26
|
+
* - {@link shader_particle_warmup_migrate} — one thread per warmed particle: move it into the main
|
|
27
|
+
* pool, once the loop is done.
|
|
28
|
+
*
|
|
29
|
+
* Everything the warm-up integrates per emitter lives in the queue entry (its accumulator), not in
|
|
30
|
+
* the emitter's state row — with one exception, deliberately: the emitter's *age*. INIT and UPDATE
|
|
31
|
+
* read `EMITTER_AGE` off the state row through the same chunk whether the main emit pass or the
|
|
32
|
+
* warm-up's runs them, so the warm-up tick writes the age the emitter has reached into that row as it
|
|
33
|
+
* goes. When the loop ends the row says `prewarm`, and the next real tick adds its `dt` to that.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Word offsets within one entry of the warm-up queue the host writes:
|
|
38
|
+
* `[emitter row, pre-warm seconds, spawn accumulator, clock]`.
|
|
39
|
+
*
|
|
40
|
+
* The accumulator is the host's to seed and the GPU's from then on — a fraction in `[0, 1)` hashed
|
|
41
|
+
* from the row, so that two emitters queued together do not put their first whole particle on the
|
|
42
|
+
* same tick. The clock is the emitter's own tick rate, `1 ± PARTICLE_WARMUP_EMITTER_JITTER / 2`, for
|
|
43
|
+
* the same reason a beat further in.
|
|
44
|
+
*
|
|
45
|
+
* Raw words rather than a `WebGPUStruct`, like the spawn-command list: it is a short host-authored
|
|
46
|
+
* list read once a tick, and the floats are `bitcast` on the way in and out.
|
|
47
|
+
*/
|
|
48
|
+
export const WARMUP_QUEUE = Object.freeze({
|
|
49
|
+
ROW: 0,
|
|
50
|
+
PREWARM: 1,
|
|
51
|
+
ACCUMULATOR: 2,
|
|
52
|
+
CLOCK: 3,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
/** Workgroups the bounded per-particle passes launch. */
|
|
56
|
+
export const PARTICLE_WARMUP_WORKGROUP_COUNT = PARTICLE_WARMUP_LAUNCH_LANES / PARTICLE_WARMUP_WORKGROUP_SIZE;
|
|
57
|
+
|
|
58
|
+
const WG = PARTICLE_WARMUP_WORKGROUP_SIZE;
|
|
59
|
+
|
|
60
|
+
// --- init -------------------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
const init_resources = new ShaderResourceSetDescriptor();
|
|
63
|
+
|
|
64
|
+
init_resources.setImmediate("u_capacity", u32);
|
|
65
|
+
|
|
66
|
+
init_resources.createGroup()
|
|
67
|
+
.addStorageBuffer("dead", WebGPUArray.u32, true)
|
|
68
|
+
.addStorageBuffer("counters", WebGPUArray.from(atomic_u32), true);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* One thread per slot of the transient pool: every slot onto the free list, and the counters to
|
|
72
|
+
* match. What the main system does once on the CPU when it allocates its pool, done on the GPU here
|
|
73
|
+
* because the pool is a graph transient and there is no CPU moment to write it in.
|
|
74
|
+
*
|
|
75
|
+
* @type {ComputeShader}
|
|
76
|
+
*/
|
|
77
|
+
export const shader_particle_warmup_init = ComputeShader.from({
|
|
78
|
+
label: "Particle Warm-up Init",
|
|
79
|
+
resources: init_resources,
|
|
80
|
+
body: CodeChunk.from(/* language=wgsl */ `
|
|
81
|
+
@compute @workgroup_size(${WG}, 1, 1)
|
|
82
|
+
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
|
|
83
|
+
let i = gid.x;
|
|
84
|
+
|
|
85
|
+
if (i == 0u) {
|
|
86
|
+
atomicStore(&counters[${PARTICLE_COUNTER.DEAD}u], u_capacity);
|
|
87
|
+
atomicStore(&counters[${PARTICLE_COUNTER.ALIVE}u], 0u);
|
|
88
|
+
atomicStore(&counters[${PARTICLE_COUNTER.ALIVE_IN}u], 0u);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (i >= u_capacity) { return; }
|
|
92
|
+
|
|
93
|
+
dead[i] = i;
|
|
94
|
+
}
|
|
95
|
+
`),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// --- reset ------------------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
const reset_resources = new ShaderResourceSetDescriptor();
|
|
101
|
+
|
|
102
|
+
reset_resources.createGroup()
|
|
103
|
+
.addStorageBuffer("counters", WebGPUArray.from(atomic_u32), true);
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The top of a warm-up tick: last tick's alive list becomes this tick's advance input, the alive
|
|
107
|
+
* count starts over, and the tick's spawn budget is the free list as it stands.
|
|
108
|
+
*
|
|
109
|
+
* The main frame splits this between its reset pass and its build-indirect pass, because its
|
|
110
|
+
* simulate consumes the program-coherent list the bucketing built rather than the alive list
|
|
111
|
+
* itself. The warm-up's advance consumes the alive list directly (see `./chunk_particle_warmup_step.js`
|
|
112
|
+
* for why it can), so the snapshot is just the count.
|
|
113
|
+
*
|
|
114
|
+
* @type {ComputeShader}
|
|
115
|
+
*/
|
|
116
|
+
export const shader_particle_warmup_reset = ComputeShader.from({
|
|
117
|
+
label: "Particle Warm-up Reset",
|
|
118
|
+
resources: reset_resources,
|
|
119
|
+
body: CodeChunk.from(/* language=wgsl */ `
|
|
120
|
+
@compute @workgroup_size(1, 1, 1)
|
|
121
|
+
fn main() {
|
|
122
|
+
atomicStore(&counters[${PARTICLE_COUNTER.ALIVE_IN}u], atomicLoad(&counters[${PARTICLE_COUNTER.ALIVE}u]));
|
|
123
|
+
atomicStore(&counters[${PARTICLE_COUNTER.ALIVE}u], 0u);
|
|
124
|
+
atomicStore(&counters[${PARTICLE_COUNTER.SPAWN_BUDGET}u], atomicLoad(&counters[${PARTICLE_COUNTER.DEAD}u]));
|
|
125
|
+
}
|
|
126
|
+
`),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// --- tick -------------------------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Per-dispatch, 20 bytes, read-only.
|
|
133
|
+
* @type {WebGPUStruct}
|
|
134
|
+
*/
|
|
135
|
+
export const WARMUP_TICK_SETTINGS = WebGPUStruct.from({
|
|
136
|
+
/** seconds this tick advances the population by */
|
|
137
|
+
u_dt: f32,
|
|
138
|
+
/** seconds from the start of this tick to "now" — the end of the loop */
|
|
139
|
+
u_remaining: f32,
|
|
140
|
+
/** transient pool capacity — the accumulator's ceiling and the budget's wrap guard */
|
|
141
|
+
u_capacity: u32,
|
|
142
|
+
/** element capacity of the emitter table — the length of the counts list the scan consumes */
|
|
143
|
+
u_emitter_capacity: u32,
|
|
144
|
+
/** entries in the queue */
|
|
145
|
+
u_count: u32,
|
|
146
|
+
}, "ParticleWarmupTickSettings");
|
|
147
|
+
|
|
148
|
+
const EMITTER = PARTICLE_EMITTER_DESCRIPTOR;
|
|
149
|
+
const STATE = PARTICLE_EMITTER_STATE_DESCRIPTOR;
|
|
150
|
+
|
|
151
|
+
// Generated once and held: each call builds a fresh chunk declaring the same function.
|
|
152
|
+
const WRITE_AGE = STATE.wgsl_gen_write_field_code("age");
|
|
153
|
+
|
|
154
|
+
const tick_resources = new ShaderResourceSetDescriptor();
|
|
155
|
+
|
|
156
|
+
tick_resources.setImmediate("settings", WARMUP_TICK_SETTINGS);
|
|
157
|
+
|
|
158
|
+
tick_resources.createGroup()
|
|
159
|
+
.addStorageBuffer("queue", WebGPUArray.u32, true)
|
|
160
|
+
.addStorageBuffer("emitter_database", WebGPUArray.u32, true)
|
|
161
|
+
.addStorageBuffer("counters", WebGPUArray.from(atomic_u32), true)
|
|
162
|
+
.addStorageBuffer("spawn_counts", COLLECTION_U32_STRUCT_READ, true);
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* One thread per queued emitter: how many particles it spawns this tick.
|
|
166
|
+
*
|
|
167
|
+
* The main emitter tick's spawn decision — integrate the rate, take from the budget, write the
|
|
168
|
+
* count by row for the scan — over the host's queue instead of the emitter table, and without the
|
|
169
|
+
* parts that belong to a live frame: no generation test (the host holds the queue for exactly one
|
|
170
|
+
* frame), no culling (a warm-up is what makes an emitter measurable in the first place), no pending
|
|
171
|
+
* bursts (they are the frame's, not the past's).
|
|
172
|
+
*
|
|
173
|
+
* ## When an emitter takes part
|
|
174
|
+
*
|
|
175
|
+
* Once `u_remaining` is within its own pre-warm: the loop's clock counts down to now, and an emitter
|
|
176
|
+
* joins it when the time left is what it asked to have been running for. Two emitters queued with
|
|
177
|
+
* different durations therefore end the same loop having each run for its own — the shorter one
|
|
178
|
+
* simply sat out the start — rather than the shorter one being run for the longer's time and
|
|
179
|
+
* arriving with a population that is all dead of old age.
|
|
180
|
+
*
|
|
181
|
+
* ## The count list is the emitter table's
|
|
182
|
+
*
|
|
183
|
+
* The counts are written by emitter *row*, into a list as long as the table, exactly as the main
|
|
184
|
+
* tick writes them. That is what lets the main emit pass be reused unchanged: it finds a newborn's
|
|
185
|
+
* emitter by searching the scan of that list, and the row it finds is the row its record reads.
|
|
186
|
+
* Rows not in the queue count zero, which the cleared buffer already says.
|
|
187
|
+
*
|
|
188
|
+
* @type {ComputeShader}
|
|
189
|
+
*/
|
|
190
|
+
export const shader_particle_warmup_tick = ComputeShader.from({
|
|
191
|
+
label: "Particle Warm-up Tick",
|
|
192
|
+
resources: tick_resources,
|
|
193
|
+
body: CodeChunk.from(/* language=wgsl */ `
|
|
194
|
+
const WARMUP_QUEUE_WORDS : u32 = ${PARTICLE_WARMUP_QUEUE_WORDS}u;
|
|
195
|
+
const WARMUP_Q_ROW : u32 = ${WARMUP_QUEUE.ROW}u;
|
|
196
|
+
const WARMUP_Q_PREWARM : u32 = ${WARMUP_QUEUE.PREWARM}u;
|
|
197
|
+
const WARMUP_Q_ACCUMULATOR : u32 = ${WARMUP_QUEUE.ACCUMULATOR}u;
|
|
198
|
+
const WARMUP_Q_CLOCK : u32 = ${WARMUP_QUEUE.CLOCK}u;
|
|
199
|
+
|
|
200
|
+
@compute @workgroup_size(${WG}, 1, 1)
|
|
201
|
+
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
|
|
202
|
+
let i = gid.x;
|
|
203
|
+
|
|
204
|
+
// The scan reads exactly this many counts, queued or not.
|
|
205
|
+
if (i == 0u) {
|
|
206
|
+
spawn_counts.count = settings.u_emitter_capacity;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (i >= settings.u_count) { return; }
|
|
210
|
+
|
|
211
|
+
let base = i * WARMUP_QUEUE_WORDS;
|
|
212
|
+
let row = queue[base + WARMUP_Q_ROW];
|
|
213
|
+
let prewarm = bitcast<f32>(queue[base + WARMUP_Q_PREWARM]);
|
|
214
|
+
var accumulator = bitcast<f32>(queue[base + WARMUP_Q_ACCUMULATOR]);
|
|
215
|
+
let clock = bitcast<f32>(queue[base + WARMUP_Q_CLOCK]);
|
|
216
|
+
|
|
217
|
+
var count = 0u;
|
|
218
|
+
|
|
219
|
+
if (settings.u_remaining <= prewarm) {
|
|
220
|
+
let em = ${EMITTER.marshalling_method_read_rw}(&emitter_database, row);
|
|
221
|
+
|
|
222
|
+
// This emitter's own beat: the tick, at its own clock.
|
|
223
|
+
accumulator = min(accumulator + em.spawn_rate * settings.u_dt * clock, f32(settings.u_capacity));
|
|
224
|
+
|
|
225
|
+
let wanted = u32(floor(accumulator));
|
|
226
|
+
|
|
227
|
+
if (wanted > 0u) {
|
|
228
|
+
count = particle_take_spawn_budget(wanted, settings.u_capacity);
|
|
229
|
+
accumulator = accumulator - f32(count);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// How long the emitter has been running once this tick is done — what this tick's newborns
|
|
233
|
+
// and advances read as EMITTER_AGE, on the row the main passes read it from too.
|
|
234
|
+
${STATE.marshalling_method_write_field("age")}(&emitter_database, row, prewarm - settings.u_remaining + settings.u_dt);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
spawn_counts.elements[row] = count;
|
|
238
|
+
queue[base + WARMUP_Q_ACCUMULATOR] = bitcast<u32>(accumulator);
|
|
239
|
+
}
|
|
240
|
+
`, [
|
|
241
|
+
EMITTER.chunk_read_rw,
|
|
242
|
+
WRITE_AGE,
|
|
243
|
+
chunk_particle_spawn_budget,
|
|
244
|
+
]),
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// --- migrate ----------------------------------------------------------------------------------
|
|
248
|
+
|
|
249
|
+
const migrate_resources = new ShaderResourceSetDescriptor();
|
|
250
|
+
|
|
251
|
+
migrate_resources.setImmediate("u_capacity", u32);
|
|
252
|
+
|
|
253
|
+
migrate_resources.createGroup()
|
|
254
|
+
.addStorageBuffer("warm_pool", WebGPUArray.u32, false)
|
|
255
|
+
.addStorageBuffer("warm_alive", WebGPUArray.u32, false)
|
|
256
|
+
.addStorageBuffer("warm_counters", WebGPUArray.from(atomic_u32), true)
|
|
257
|
+
.addStorageBuffer("pool", WebGPUArray.u32, true)
|
|
258
|
+
.addStorageBuffer("alive_out", WebGPUArray.u32, true)
|
|
259
|
+
.addStorageBuffer("dead", WebGPUArray.u32, true)
|
|
260
|
+
.addStorageBuffer("counters", WebGPUArray.from(atomic_u32), true);
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* One thread per particle the loop left alive: a slot from the main pool, the record copied into
|
|
264
|
+
* it, and the slot onto the main alive list. The moment the warm-up's population becomes the
|
|
265
|
+
* scene's.
|
|
266
|
+
*
|
|
267
|
+
* The pop is the emit pass's, wrap guard and all, and it is the only thing this pass does to the
|
|
268
|
+
* main free list: it never pushes, so it is safe against nothing and needs no ordering beyond
|
|
269
|
+
* running after the main emit and simulate of the frame, which the graph gives it. A particle the
|
|
270
|
+
* main pool has no room for is dropped, as a spawn the pool has no room for is.
|
|
271
|
+
*
|
|
272
|
+
* The record is copied whole, header included. The header names the emitter's main-table row and
|
|
273
|
+
* generation — the warm-up's emit stamped it from the same record the main emit reads — so the
|
|
274
|
+
* copied particle is an ordinary one to every pass that meets it from here on.
|
|
275
|
+
*
|
|
276
|
+
* Bounded launch, grid stride over the transient alive count: the population is small and nothing
|
|
277
|
+
* should size a dispatch from the host to cover it.
|
|
278
|
+
*
|
|
279
|
+
* @type {ComputeShader}
|
|
280
|
+
*/
|
|
281
|
+
export const shader_particle_warmup_migrate = ComputeShader.from({
|
|
282
|
+
label: "Particle Warm-up Migrate",
|
|
283
|
+
resources: migrate_resources,
|
|
284
|
+
body: CodeChunk.from(/* language=wgsl */ `
|
|
285
|
+
const COUNTER_ALIVE : u32 = ${PARTICLE_COUNTER.ALIVE}u;
|
|
286
|
+
const COUNTER_DEAD : u32 = ${PARTICLE_COUNTER.DEAD}u;
|
|
287
|
+
const WARMUP_LAUNCH_LANES : u32 = ${PARTICLE_WARMUP_LAUNCH_LANES}u;
|
|
288
|
+
const WARMUP_RECORD_WORDS : u32 = ${PARTICLE_RECORD_WORD_COUNT}u;
|
|
289
|
+
|
|
290
|
+
@compute @workgroup_size(${WG}, 1, 1)
|
|
291
|
+
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
|
|
292
|
+
let total = atomicLoad(&warm_counters[COUNTER_ALIVE]);
|
|
293
|
+
|
|
294
|
+
for (var i = gid.x; i < total; i = i + WARMUP_LAUNCH_LANES) {
|
|
295
|
+
let src = warm_alive[i];
|
|
296
|
+
|
|
297
|
+
// Pop a free slot off the main dead-list stack; drop the particle if the pool is exhausted.
|
|
298
|
+
// The guard catches WRAPPED values, not just 0 — see chunk_particle_emit_step for why.
|
|
299
|
+
let old_dead = atomicSub(&counters[COUNTER_DEAD], 1u);
|
|
300
|
+
if (old_dead == 0u || old_dead > u_capacity) {
|
|
301
|
+
atomicAdd(&counters[COUNTER_DEAD], 1u); // undo the over-pop
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
let dst = dead[old_dead - 1u];
|
|
305
|
+
|
|
306
|
+
let src_base = src * WARMUP_RECORD_WORDS;
|
|
307
|
+
let dst_base = dst * WARMUP_RECORD_WORDS;
|
|
308
|
+
|
|
309
|
+
for (var w = 0u; w < WARMUP_RECORD_WORDS; w = w + 1u) {
|
|
310
|
+
pool[dst_base + w] = warm_pool[src_base + w];
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
let a = atomicAdd(&counters[COUNTER_ALIVE], 1u);
|
|
314
|
+
alive_out[a] = dst;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
`),
|
|
318
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The warm-up's advance pass over the fast register file: one warm-up tick of UPDATE over every
|
|
3
|
+
* particle the previous tick left alive, compacting survivors into the next alive list and the dead
|
|
4
|
+
* onto the transient free list.
|
|
5
|
+
*
|
|
6
|
+
* What the main simulate pass is to a frame, this is to a warm-up tick, and it is a shader of its
|
|
7
|
+
* own rather than that pass bound to other buffers for the reasons `./chunk_particle_warmup_step.js`
|
|
8
|
+
* gives: it reads the alive list directly, so it decodes per lane, and it jitters the tick per
|
|
9
|
+
* particle. Nothing about it is linked into the main passes.
|
|
10
|
+
*
|
|
11
|
+
* A bounded launch with a grid-stride loop over the transient alive count — the wide interpreter's
|
|
12
|
+
* shape — so no indirect-args pass is needed per tick and the loop's passes are all sized by
|
|
13
|
+
* constants. `alive_in` is the list the previous tick built (or the emit pass of this one appended
|
|
14
|
+
* to, on the pass before); `alive_out` is the other of the pair.
|
|
15
|
+
*
|
|
16
|
+
* @type {ComputeShader}
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Per-dispatch, 12 bytes, read-only. The same three numbers the main simulate takes, as a struct of
|
|
20
|
+
* this pass's own rather than that pass's export: the two must be free to diverge.
|
|
21
|
+
* @type {WebGPUStruct}
|
|
22
|
+
*/
|
|
23
|
+
export const WARMUP_ADVANCE_SETTINGS: WebGPUStruct;
|
|
24
|
+
/**
|
|
25
|
+
* The entry point both register backings share, as WGSL text: the wide variant prepends its
|
|
26
|
+
* register bind and is otherwise this.
|
|
27
|
+
* @type {string}
|
|
28
|
+
*/
|
|
29
|
+
export const WARMUP_ADVANCE_BODY: string;
|
|
30
|
+
export const shader_particle_warmup_advance: ComputeShader;
|
|
31
|
+
export { PARTICLE_WARMUP_WORKGROUP_COUNT };
|
|
32
|
+
import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
|
|
33
|
+
import { ComputeShader } from "../../shader/ComputeShader.js";
|
|
34
|
+
import { PARTICLE_WARMUP_WORKGROUP_COUNT } from "./shader_particle_warmup.js";
|
|
35
|
+
//# sourceMappingURL=shader_particle_warmup_advance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shader_particle_warmup_advance.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/warmup/shader_particle_warmup_advance.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;GAIG;AACH,sCAFU,YAAY,CAMc;AAgBpC;;;;GAIG;AACH,kCAFU,MAAM,CA6Bd;AAEF,2DAeG;;6BAvG0B,mCAAmC;8BAClC,+BAA+B;gDAQb,6BAA6B"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { atomic_u32, f32, u32 } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
2
|
+
import { WebGPUArray } from "../../shader/type/WebGPUArray.js";
|
|
3
|
+
import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
|
|
4
|
+
import { ComputeShader } from "../../shader/ComputeShader.js";
|
|
5
|
+
import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
|
|
6
|
+
import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
|
|
7
|
+
import { PARTICLE_WARMUP_LAUNCH_LANES, PARTICLE_WARMUP_WORKGROUP_SIZE } from "../ParticleConstants.js";
|
|
8
|
+
import { PARTICLE_COUNTER } from "../data/PARTICLE_COUNTERS.js";
|
|
9
|
+
import { chunk_particle_curve_disabled } from "../shaders/chunk_particle_curve_disabled.js";
|
|
10
|
+
import { chunk_particle_vm_registers_fast } from "../vm/chunk_particle_vm_registers_fast.js";
|
|
11
|
+
import { chunk_particle_warmup_step } from "./chunk_particle_warmup_step.js";
|
|
12
|
+
import { PARTICLE_WARMUP_WORKGROUP_COUNT } from "./shader_particle_warmup.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The warm-up's advance pass over the fast register file: one warm-up tick of UPDATE over every
|
|
16
|
+
* particle the previous tick left alive, compacting survivors into the next alive list and the dead
|
|
17
|
+
* onto the transient free list.
|
|
18
|
+
*
|
|
19
|
+
* What the main simulate pass is to a frame, this is to a warm-up tick, and it is a shader of its
|
|
20
|
+
* own rather than that pass bound to other buffers for the reasons `./chunk_particle_warmup_step.js`
|
|
21
|
+
* gives: it reads the alive list directly, so it decodes per lane, and it jitters the tick per
|
|
22
|
+
* particle. Nothing about it is linked into the main passes.
|
|
23
|
+
*
|
|
24
|
+
* A bounded launch with a grid-stride loop over the transient alive count — the wide interpreter's
|
|
25
|
+
* shape — so no indirect-args pass is needed per tick and the loop's passes are all sized by
|
|
26
|
+
* constants. `alive_in` is the list the previous tick built (or the emit pass of this one appended
|
|
27
|
+
* to, on the pass before); `alive_out` is the other of the pair.
|
|
28
|
+
*
|
|
29
|
+
* @type {ComputeShader}
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Per-dispatch, 12 bytes, read-only. The same three numbers the main simulate takes, as a struct of
|
|
34
|
+
* this pass's own rather than that pass's export: the two must be free to diverge.
|
|
35
|
+
* @type {WebGPUStruct}
|
|
36
|
+
*/
|
|
37
|
+
export const WARMUP_ADVANCE_SETTINGS = WebGPUStruct.from({
|
|
38
|
+
u_dt: f32,
|
|
39
|
+
u_time: f32,
|
|
40
|
+
u_frame: u32,
|
|
41
|
+
}, "ParticleWarmupAdvanceSettings");
|
|
42
|
+
|
|
43
|
+
const resources = new ShaderResourceSetDescriptor();
|
|
44
|
+
|
|
45
|
+
resources.setImmediate("settings", WARMUP_ADVANCE_SETTINGS);
|
|
46
|
+
|
|
47
|
+
resources.createGroup()
|
|
48
|
+
.addStorageBuffer("scene_database", WebGPUArray.u32, false)
|
|
49
|
+
.addStorageBuffer("emitter_database", WebGPUArray.u32, false)
|
|
50
|
+
.addStorageBuffer("program", WebGPUArray.u32, false)
|
|
51
|
+
.addStorageBuffer("pool", WebGPUArray.u32, true)
|
|
52
|
+
.addStorageBuffer("alive_in", WebGPUArray.u32, false)
|
|
53
|
+
.addStorageBuffer("alive_out", WebGPUArray.u32, true)
|
|
54
|
+
.addStorageBuffer("dead", WebGPUArray.u32, true)
|
|
55
|
+
.addStorageBuffer("counters", WebGPUArray.from(atomic_u32), true);
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The entry point both register backings share, as WGSL text: the wide variant prepends its
|
|
59
|
+
* register bind and is otherwise this.
|
|
60
|
+
* @type {string}
|
|
61
|
+
*/
|
|
62
|
+
export const WARMUP_ADVANCE_BODY = /* language=wgsl */ `
|
|
63
|
+
const COUNTER_ALIVE : u32 = ${PARTICLE_COUNTER.ALIVE}u;
|
|
64
|
+
const COUNTER_DEAD : u32 = ${PARTICLE_COUNTER.DEAD}u;
|
|
65
|
+
const COUNTER_ALIVE_IN : u32 = ${PARTICLE_COUNTER.ALIVE_IN}u;
|
|
66
|
+
const WARMUP_LAUNCH_LANES : u32 = ${PARTICLE_WARMUP_LAUNCH_LANES}u;
|
|
67
|
+
|
|
68
|
+
fn particle_warmup_advance_all(lane : u32) {
|
|
69
|
+
let total = atomicLoad(&counters[COUNTER_ALIVE_IN]);
|
|
70
|
+
|
|
71
|
+
for (var i = lane; i < total; i = i + WARMUP_LAUNCH_LANES) {
|
|
72
|
+
let slot = alive_in[i];
|
|
73
|
+
|
|
74
|
+
let survived = particle_warmup_advance_one(
|
|
75
|
+
&scene_database, &emitter_database, &program, &pool,
|
|
76
|
+
slot,
|
|
77
|
+
settings.u_dt, settings.u_time, settings.u_frame,
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (survived) {
|
|
81
|
+
let a = atomicAdd(&counters[COUNTER_ALIVE], 1u);
|
|
82
|
+
alive_out[a] = slot;
|
|
83
|
+
} else {
|
|
84
|
+
let d = atomicAdd(&counters[COUNTER_DEAD], 1u);
|
|
85
|
+
dead[d] = slot;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
export const shader_particle_warmup_advance = ComputeShader.from({
|
|
92
|
+
label: "Particle Warm-up Advance",
|
|
93
|
+
resources,
|
|
94
|
+
body: CodeChunk.from(/* language=wgsl */ `
|
|
95
|
+
${WARMUP_ADVANCE_BODY}
|
|
96
|
+
|
|
97
|
+
@compute @workgroup_size(${PARTICLE_WARMUP_WORKGROUP_SIZE}, 1, 1)
|
|
98
|
+
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
|
|
99
|
+
particle_warmup_advance_all(gid.x);
|
|
100
|
+
}
|
|
101
|
+
`, [
|
|
102
|
+
chunk_particle_warmup_step,
|
|
103
|
+
chunk_particle_vm_registers_fast,
|
|
104
|
+
chunk_particle_curve_disabled,
|
|
105
|
+
]),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
export { PARTICLE_WARMUP_WORKGROUP_COUNT };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shader_particle_warmup_advance_wide.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.js"],"names":[],"mappings":"AAkDA,gEAmBG;8BAlE2B,+BAA+B"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { atomic_u32, f32 } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
3
|
+
import { WebGPUArray } from "../../shader/type/WebGPUArray.js";
|
|
4
|
+
import { ComputeShader } from "../../shader/ComputeShader.js";
|
|
5
|
+
import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
|
|
6
|
+
import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
|
|
7
|
+
import {
|
|
8
|
+
PARTICLE_VM_WIDE_LAUNCH_LANES,
|
|
9
|
+
PARTICLE_WARMUP_LAUNCH_LANES,
|
|
10
|
+
PARTICLE_WARMUP_WORKGROUP_SIZE,
|
|
11
|
+
} from "../ParticleConstants.js";
|
|
12
|
+
import { chunk_particle_curve_disabled } from "../shaders/chunk_particle_curve_disabled.js";
|
|
13
|
+
import { chunk_particle_vm_registers_wide } from "../vm/chunk_particle_vm_registers_wide.js";
|
|
14
|
+
import { chunk_particle_warmup_step } from "./chunk_particle_warmup_step.js";
|
|
15
|
+
import { WARMUP_ADVANCE_BODY, WARMUP_ADVANCE_SETTINGS } from "./shader_particle_warmup_advance.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The warm-up's advance pass over the WIDE register file — for a system whose hungriest effect has
|
|
19
|
+
* put the interpreter on the storage-backed file. Same pass as
|
|
20
|
+
* {@link ./shader_particle_warmup_advance.js}, same entry point text, plus the register bind and the
|
|
21
|
+
* ninth binding, exactly as the main simulate's wide variant relates to its fast one.
|
|
22
|
+
*
|
|
23
|
+
* The register file is indexed by launch lane and reused across the grid-stride loop's iterations,
|
|
24
|
+
* which is sound for the reason `../vm/chunk_particle_vm_registers_wide.js` gives: a program writes
|
|
25
|
+
* a register before it reads it. It is the same buffer the main wide passes use, sized by
|
|
26
|
+
* {@link PARTICLE_VM_WIDE_LAUNCH_LANES}, which is why the warm-up's launch must be exactly that wide.
|
|
27
|
+
*
|
|
28
|
+
* @type {ComputeShader}
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
assert.equal(
|
|
32
|
+
PARTICLE_WARMUP_LAUNCH_LANES, PARTICLE_VM_WIDE_LAUNCH_LANES,
|
|
33
|
+
"the warm-up's launch must match the wide register file's lane count, which sizes the file",
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const resources = new ShaderResourceSetDescriptor();
|
|
37
|
+
|
|
38
|
+
resources.setImmediate("settings", WARMUP_ADVANCE_SETTINGS);
|
|
39
|
+
|
|
40
|
+
resources.createGroup()
|
|
41
|
+
.addStorageBuffer("scene_database", WebGPUArray.u32, false)
|
|
42
|
+
.addStorageBuffer("emitter_database", WebGPUArray.u32, false)
|
|
43
|
+
.addStorageBuffer("program", WebGPUArray.u32, false)
|
|
44
|
+
.addStorageBuffer("pool", WebGPUArray.u32, true)
|
|
45
|
+
.addStorageBuffer("alive_in", WebGPUArray.u32, false)
|
|
46
|
+
.addStorageBuffer("alive_out", WebGPUArray.u32, true)
|
|
47
|
+
.addStorageBuffer("dead", WebGPUArray.u32, true)
|
|
48
|
+
.addStorageBuffer("counters", WebGPUArray.from(atomic_u32), true)
|
|
49
|
+
.addStorageBuffer("vm_registers", WebGPUArray.from(f32), true);
|
|
50
|
+
|
|
51
|
+
export const shader_particle_warmup_advance_wide = ComputeShader.from({
|
|
52
|
+
label: "Particle Warm-up Advance (wide registers)",
|
|
53
|
+
resources,
|
|
54
|
+
body: CodeChunk.from(/* language=wgsl */ `
|
|
55
|
+
${WARMUP_ADVANCE_BODY}
|
|
56
|
+
|
|
57
|
+
@compute @workgroup_size(${PARTICLE_WARMUP_WORKGROUP_SIZE}, 1, 1)
|
|
58
|
+
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
|
|
59
|
+
// This invocation's column of the register file. The launch is exactly
|
|
60
|
+
// PARTICLE_WARMUP_LAUNCH_LANES wide, so gid.x is in range by construction.
|
|
61
|
+
particle_vm_bind_registers(gid.x);
|
|
62
|
+
|
|
63
|
+
particle_warmup_advance_all(gid.x);
|
|
64
|
+
}
|
|
65
|
+
`, [
|
|
66
|
+
chunk_particle_warmup_step,
|
|
67
|
+
chunk_particle_vm_registers_wide,
|
|
68
|
+
chunk_particle_curve_disabled,
|
|
69
|
+
]),
|
|
70
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a batch of pre-warms is paid off: in how many ticks, and how long each is.
|
|
3
|
+
*
|
|
4
|
+
* Shared by the GPU loop (`./graph_particle_warmup.js`) and the editor's CPU preview
|
|
5
|
+
* (`editor/particles/effect/ParticleReferenceSimulation.js`), so the two integrate the same debt in
|
|
6
|
+
* the same steps and an author sees in the preview what the scene will show.
|
|
7
|
+
*
|
|
8
|
+
* The tick count is bounded and the tick length stretches to cover the debt — not the other way
|
|
9
|
+
* round — because the count is what the frame pays for: every tick is a handful of dispatches. A
|
|
10
|
+
* two-hundred-millisecond warm-up at a ten-millisecond floor is twenty ticks of ten; a three-second
|
|
11
|
+
* one is {@link PARTICLE_WARMUP_MAX_TICKS} ticks of ninety-odd.
|
|
12
|
+
*
|
|
13
|
+
* @typedef {object} WarmupSchedule
|
|
14
|
+
* @property {number} ticks how many times the loop runs; zero for nothing owed
|
|
15
|
+
* @property {number} dt seconds each tick advances the population by
|
|
16
|
+
* @property {number} duration `ticks * dt` — the loop's whole span, never less than the longest
|
|
17
|
+
* pre-warm in the batch and less than one tick more
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* @param {number} max_prewarm the longest pre-warm in the batch, seconds
|
|
21
|
+
* @returns {WarmupSchedule}
|
|
22
|
+
*/
|
|
23
|
+
export function warmup_schedule(max_prewarm: number): WarmupSchedule;
|
|
24
|
+
/**
|
|
25
|
+
* Seconds between the start of tick `tick` and "now" — the moment the loop ends and the population
|
|
26
|
+
* joins the scene. An emitter takes part in a tick once this is within its own pre-warm, so that
|
|
27
|
+
* whatever the longest pre-warm in the batch was, every emitter has run for exactly its own by the
|
|
28
|
+
* end.
|
|
29
|
+
*
|
|
30
|
+
* @param {WarmupSchedule} schedule
|
|
31
|
+
* @param {number} tick
|
|
32
|
+
* @returns {number}
|
|
33
|
+
*/
|
|
34
|
+
export function warmup_remaining(schedule: WarmupSchedule, tick: number): number;
|
|
35
|
+
/**
|
|
36
|
+
* How a batch of pre-warms is paid off: in how many ticks, and how long each is.
|
|
37
|
+
*
|
|
38
|
+
* Shared by the GPU loop (`./graph_particle_warmup.js`) and the editor's CPU preview
|
|
39
|
+
* (`editor/particles/effect/ParticleReferenceSimulation.js`), so the two integrate the same debt in
|
|
40
|
+
* the same steps and an author sees in the preview what the scene will show.
|
|
41
|
+
*
|
|
42
|
+
* The tick count is bounded and the tick length stretches to cover the debt — not the other way
|
|
43
|
+
* round — because the count is what the frame pays for: every tick is a handful of dispatches. A
|
|
44
|
+
* two-hundred-millisecond warm-up at a ten-millisecond floor is twenty ticks of ten; a three-second
|
|
45
|
+
* one is {@link PARTICLE_WARMUP_MAX_TICKS } ticks of ninety-odd.
|
|
46
|
+
*/
|
|
47
|
+
export type WarmupSchedule = {
|
|
48
|
+
/**
|
|
49
|
+
* how many times the loop runs; zero for nothing owed
|
|
50
|
+
*/
|
|
51
|
+
ticks: number;
|
|
52
|
+
/**
|
|
53
|
+
* seconds each tick advances the population by
|
|
54
|
+
*/
|
|
55
|
+
dt: number;
|
|
56
|
+
/**
|
|
57
|
+
* `ticks * dt` — the loop's whole span, never less than the longest
|
|
58
|
+
* pre-warm in the batch and less than one tick more
|
|
59
|
+
*/
|
|
60
|
+
duration: number;
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=warmup_schedule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warmup_schedule.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/warmup/warmup_schedule.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;GAGG;AACH,6CAHW,MAAM,GACJ,cAAc,CAgB1B;AAED;;;;;;;;;GASG;AACH,2CAJW,cAAc,QACd,MAAM,GACJ,MAAM,CAIlB;;;;;;;;;;;;;;;;;WAtCa,MAAM;;;;QACN,MAAM;;;;;cACN,MAAM"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { PARTICLE_WARMUP_MAX_TICKS, PARTICLE_WARMUP_TICK_SECONDS } from "../ParticleConstants.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* How a batch of pre-warms is paid off: in how many ticks, and how long each is.
|
|
6
|
+
*
|
|
7
|
+
* Shared by the GPU loop (`./graph_particle_warmup.js`) and the editor's CPU preview
|
|
8
|
+
* (`editor/particles/effect/ParticleReferenceSimulation.js`), so the two integrate the same debt in
|
|
9
|
+
* the same steps and an author sees in the preview what the scene will show.
|
|
10
|
+
*
|
|
11
|
+
* The tick count is bounded and the tick length stretches to cover the debt — not the other way
|
|
12
|
+
* round — because the count is what the frame pays for: every tick is a handful of dispatches. A
|
|
13
|
+
* two-hundred-millisecond warm-up at a ten-millisecond floor is twenty ticks of ten; a three-second
|
|
14
|
+
* one is {@link PARTICLE_WARMUP_MAX_TICKS} ticks of ninety-odd.
|
|
15
|
+
*
|
|
16
|
+
* @typedef {object} WarmupSchedule
|
|
17
|
+
* @property {number} ticks how many times the loop runs; zero for nothing owed
|
|
18
|
+
* @property {number} dt seconds each tick advances the population by
|
|
19
|
+
* @property {number} duration `ticks * dt` — the loop's whole span, never less than the longest
|
|
20
|
+
* pre-warm in the batch and less than one tick more
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {number} max_prewarm the longest pre-warm in the batch, seconds
|
|
25
|
+
* @returns {WarmupSchedule}
|
|
26
|
+
*/
|
|
27
|
+
export function warmup_schedule(max_prewarm) {
|
|
28
|
+
assert.isNumber(max_prewarm, "max_prewarm");
|
|
29
|
+
assert.greaterThanOrEqual(max_prewarm, 0, "max_prewarm");
|
|
30
|
+
|
|
31
|
+
if (max_prewarm <= 0) {
|
|
32
|
+
return { ticks: 0, dt: 0, duration: 0 };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const dt = Math.max(PARTICLE_WARMUP_TICK_SECONDS, max_prewarm / PARTICLE_WARMUP_MAX_TICKS);
|
|
36
|
+
|
|
37
|
+
// `max / (max / MAX)` is MAX up to rounding, and a rounding error's `ceil` is MAX + 1.
|
|
38
|
+
const ticks = Math.min(PARTICLE_WARMUP_MAX_TICKS, Math.ceil(max_prewarm / dt));
|
|
39
|
+
|
|
40
|
+
return { ticks, dt, duration: ticks * dt };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Seconds between the start of tick `tick` and "now" — the moment the loop ends and the population
|
|
45
|
+
* joins the scene. An emitter takes part in a tick once this is within its own pre-warm, so that
|
|
46
|
+
* whatever the longest pre-warm in the batch was, every emitter has run for exactly its own by the
|
|
47
|
+
* end.
|
|
48
|
+
*
|
|
49
|
+
* @param {WarmupSchedule} schedule
|
|
50
|
+
* @param {number} tick
|
|
51
|
+
* @returns {number}
|
|
52
|
+
*/
|
|
53
|
+
export function warmup_remaining(schedule, tick) {
|
|
54
|
+
return schedule.duration - tick * schedule.dt;
|
|
55
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostProcess.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/postprocess/PostProcess.js"],"names":[],"mappings":"AAGA;IAYI;;;OAGG;IACH,uCAIC;IAnBD;;OAEG;IACH,MAFU,IAAI,CAEV;IAGJ;;OAEG;IACH,KAFU,GAAG,CAEV;IAYH;;;OAGG;IACH,oBAFW,MAAM,QAIhB;IAED,
|
|
1
|
+
{"version":3,"file":"PostProcess.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/postprocess/PostProcess.js"],"names":[],"mappings":"AAGA;IAYI;;;OAGG;IACH,uCAIC;IAnBD;;OAEG;IACH,MAFU,IAAI,CAEV;IAGJ;;OAEG;IACH,KAFU,GAAG,CAEV;IAYH;;;OAGG;IACH,oBAFW,MAAM,QAIhB;IAED,sBAEC;CACJ;qBApCoB,gBAAgB;oBACjB,cAAc"}
|