@woosh/meep-engine 3.17.2 → 3.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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,187 @@
|
|
|
1
|
+
import { atomic_u32, u32 } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
2
|
+
import { WebGPUArray } from "../../shader/type/WebGPUArray.js";
|
|
3
|
+
import { AABB3_STRUCT } from "../../shader/chunk/geometry/aabb3/AABB3_STRUCT.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_EMITTER_TICK_WORKGROUP_SIZE,
|
|
9
|
+
PARTICLE_RECORD_HEADER_EMITTER,
|
|
10
|
+
PARTICLE_RECORD_WORD_COUNT,
|
|
11
|
+
PARTICLE_SIMULATE_WORKGROUP_SIZE,
|
|
12
|
+
} from "../ParticleConstants.js";
|
|
13
|
+
import { PARTICLE_COUNTER } from "../data/PARTICLE_COUNTERS.js";
|
|
14
|
+
import { PARTICLE_EMITTER_DESCRIPTOR, PARTICLE_EMITTER_STATE_DESCRIPTOR } from "../data/PARTICLE_DATABASE_SPEC.js";
|
|
15
|
+
import { chunk_particle_header } from "../data/particle_header.js";
|
|
16
|
+
import { chunk_particle_bounds_of_record, chunk_particle_bounds_store } from "./chunk_particle_bounds.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The two passes that measure every emitter's bounding box, at the end of the frame that produced
|
|
20
|
+
* the particles.
|
|
21
|
+
*
|
|
22
|
+
* - {@link shader_particle_bounds_accumulate} — one thread per live particle: read where its quad
|
|
23
|
+
* is and merge it into its emitter's accumulator.
|
|
24
|
+
* - {@link shader_particle_bounds_publish} — one thread per emitter row: hand the accumulation to
|
|
25
|
+
* the state row the culling and occupancy passes read, and start the next frame's measurement.
|
|
26
|
+
*
|
|
27
|
+
* ## Why this is not a tail on the simulate pass
|
|
28
|
+
*
|
|
29
|
+
* It was, briefly. Two things are wrong with booking the box from inside emit and simulate. The
|
|
30
|
+
* measurement is not of one population: simulate sees last frame's survivors and emit sees this
|
|
31
|
+
* frame's newborns, so the union spans two frames and is looser than either. And the merge is six
|
|
32
|
+
* atomics in the pass whose register pressure decides the whole system's occupancy — the interpreter
|
|
33
|
+
* — paid to compute something that needs none of the VM, none of the scene, and five words of the
|
|
34
|
+
* record.
|
|
35
|
+
*
|
|
36
|
+
* Run over the alive list instead and the measurement is of exactly the set that is alive and about
|
|
37
|
+
* to be drawn, taken by a pass that reads a header, an emitter row and three attributes.
|
|
38
|
+
*
|
|
39
|
+
* ## Sizing
|
|
40
|
+
*
|
|
41
|
+
* The accumulate pass is dispatched indirectly from `sim_dispatch_args`, which the coherence reset
|
|
42
|
+
* wrote from the GPU's own alive count — the same args the render sort's two per-particle passes
|
|
43
|
+
* take, and the reason its workgroup size must stay {@link PARTICLE_SIMULATE_WORKGROUP_SIZE}, which
|
|
44
|
+
* is what those args were divided by. Its element bound is `counters[ALIVE]`, read in the shader.
|
|
45
|
+
* Nothing here is sized from the host.
|
|
46
|
+
*
|
|
47
|
+
* The publish pass walks the emitter table with the table's page iterator, one page group per
|
|
48
|
+
* workgroup, like the tick.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
export { PARTICLE_SIMULATE_WORKGROUP_SIZE, PARTICLE_EMITTER_TICK_WORKGROUP_SIZE };
|
|
52
|
+
|
|
53
|
+
// --- accumulate -------------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
const accumulate_resources = new ShaderResourceSetDescriptor();
|
|
56
|
+
|
|
57
|
+
accumulate_resources.createGroup()
|
|
58
|
+
.addStorageBuffer("emitter_database", WebGPUArray.u32, false)
|
|
59
|
+
.addStorageBuffer("pool", WebGPUArray.u32, false)
|
|
60
|
+
.addStorageBuffer("alive", WebGPUArray.u32, false)
|
|
61
|
+
.addStorageBuffer("counters", WebGPUArray.from(atomic_u32), true);
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* One thread per live particle: merge its quad into its emitter's accumulator.
|
|
65
|
+
*
|
|
66
|
+
* The alive list holds real slots only — the padding sentinel belongs to the simulation-order list,
|
|
67
|
+
* and an orphan was killed by the simulate pass that built this list — so every entry is a particle
|
|
68
|
+
* whose emitter row is live and whose record has this frame's values in it.
|
|
69
|
+
*
|
|
70
|
+
* It decodes a whole emitter record to reach four of its fields, which the bucketing histogram
|
|
71
|
+
* deliberately does not (`chunk_particle_emitter_program_id`). The difference is what is being paid
|
|
72
|
+
* for: emitters are counted in tens, so the records are a working set that stays resident for the
|
|
73
|
+
* whole dispatch, while the pool reads are a gather over the free list and are what this pass costs.
|
|
74
|
+
* The billboard vertex stage reads a record the same way, per vertex.
|
|
75
|
+
*
|
|
76
|
+
* @type {ComputeShader}
|
|
77
|
+
*/
|
|
78
|
+
export const shader_particle_bounds_accumulate = ComputeShader.from({
|
|
79
|
+
label: "Particle Bounds Accumulate",
|
|
80
|
+
resources: accumulate_resources,
|
|
81
|
+
body: CodeChunk.from(/* language=wgsl */ `
|
|
82
|
+
const PARTICLE_RECORD_WORDS : u32 = ${PARTICLE_RECORD_WORD_COUNT}u;
|
|
83
|
+
const PARTICLE_HEADER_EMITTER : u32 = ${PARTICLE_RECORD_HEADER_EMITTER}u;
|
|
84
|
+
const COUNTER_ALIVE : u32 = ${PARTICLE_COUNTER.ALIVE}u;
|
|
85
|
+
|
|
86
|
+
@compute @workgroup_size(${PARTICLE_SIMULATE_WORKGROUP_SIZE}, 1, 1)
|
|
87
|
+
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
|
|
88
|
+
let i = gid.x;
|
|
89
|
+
|
|
90
|
+
// This frame's alive count, as emit and simulate left it. The indirect dispatch was built from
|
|
91
|
+
// the same number, so the excess is at most a workgroup's tail.
|
|
92
|
+
if (i >= atomicLoad(&counters[COUNTER_ALIVE])) { return; }
|
|
93
|
+
|
|
94
|
+
let slot = alive[i];
|
|
95
|
+
let record_base = slot * PARTICLE_RECORD_WORDS;
|
|
96
|
+
let emitter_row = particle_header_emitter(pool[record_base + PARTICLE_HEADER_EMITTER]);
|
|
97
|
+
|
|
98
|
+
let em = particle_emitter_read(&emitter_database, emitter_row);
|
|
99
|
+
let sample = particle_bounds_of_record(em, &pool, record_base);
|
|
100
|
+
|
|
101
|
+
particle_bounds_contribute(emitter_row, sample.center, sample.radius);
|
|
102
|
+
}
|
|
103
|
+
`, [
|
|
104
|
+
chunk_particle_bounds_of_record,
|
|
105
|
+
chunk_particle_bounds_store,
|
|
106
|
+
chunk_particle_header,
|
|
107
|
+
]),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// --- publish ----------------------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
const PG = PARTICLE_EMITTER_DESCRIPTOR.page_iterator_symbol_prefix(PARTICLE_EMITTER_TICK_WORKGROUP_SIZE, true);
|
|
113
|
+
const STATE = PARTICLE_EMITTER_STATE_DESCRIPTOR;
|
|
114
|
+
|
|
115
|
+
// Generated once and held, because each call builds a fresh chunk declaring the same function: two
|
|
116
|
+
// calls for one field would be two declarations of it in the assembled shader.
|
|
117
|
+
const WRITE_BOUNDS_MIN = STATE.wgsl_gen_write_field_code("bounds_min");
|
|
118
|
+
const WRITE_BOUNDS_MAX = STATE.wgsl_gen_write_field_code("bounds_max");
|
|
119
|
+
|
|
120
|
+
const publish_resources = new ShaderResourceSetDescriptor();
|
|
121
|
+
|
|
122
|
+
publish_resources.createGroup()
|
|
123
|
+
.addStorageBuffer("emitter_database", WebGPUArray.u32, true)
|
|
124
|
+
.addStorageBuffer("counters", WebGPUArray.from(atomic_u32), true);
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* One thread per emitter table row: publish what the accumulate pass measured into
|
|
128
|
+
* `bounds_min` / `bounds_max` of the emitter's state row, and reset the accumulator.
|
|
129
|
+
*
|
|
130
|
+
* The state row rather than the accumulator directly, because the readers — the tick's frustum test
|
|
131
|
+
* next frame, the AVBOIT occupancy later in this one — should not each have to know the
|
|
132
|
+
* accumulator's layout or repeat the empty case below. It is also where the rest of an emitter's
|
|
133
|
+
* GPU-owned state lives, for the reason {@link ../data/PARTICLE_EMITTER_STATE.js} gives.
|
|
134
|
+
*
|
|
135
|
+
* ## The empty case
|
|
136
|
+
*
|
|
137
|
+
* No measured particles means unknown bounds, represented by an infinite box. The tick lets such
|
|
138
|
+
* an emitter spawn until a finite population can be measured; occupancy skips it because there is
|
|
139
|
+
* nothing to splat. This also lets an exhausted effect restart without requiring authored bounds
|
|
140
|
+
* or prewarm. Readers recognize the sentinel before doing geometry arithmetic on infinities.
|
|
141
|
+
*
|
|
142
|
+
* @type {ComputeShader}
|
|
143
|
+
*/
|
|
144
|
+
export const shader_particle_bounds_publish = ComputeShader.from({
|
|
145
|
+
label: "Particle Bounds Publish",
|
|
146
|
+
resources: publish_resources,
|
|
147
|
+
body: CodeChunk.from(/* language=wgsl */ `
|
|
148
|
+
@compute @workgroup_size(${PARTICLE_EMITTER_TICK_WORKGROUP_SIZE}, 1, 1)
|
|
149
|
+
fn main(
|
|
150
|
+
@builtin(workgroup_id) wg_id : vec3<u32>,
|
|
151
|
+
@builtin(local_invocation_index) local_id : u32,
|
|
152
|
+
) {
|
|
153
|
+
// page_address is uniform across the workgroup, so this branch is uniform.
|
|
154
|
+
if (!${PG}_setup(&emitter_database, wg_id.x, local_id)) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let slot_in_page = ${PG}_slot_in_page(local_id);
|
|
159
|
+
|
|
160
|
+
if (slot_in_page >= ${PG}_ELEMENTS_PER_PAGE || !${PG}_is_occupied(slot_in_page)) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let row = ${PG}_slot_to_index(slot_in_page);
|
|
165
|
+
|
|
166
|
+
var box = particle_bounds_read(row);
|
|
167
|
+
|
|
168
|
+
if (particle_bounds_is_empty(box)) {
|
|
169
|
+
// The empty accumulator already holds [+inf, -inf]. Swap the loaded endpoints to
|
|
170
|
+
// publish unknown bounds without constructing forbidden infinite constant expressions.
|
|
171
|
+
box = ${AABB3_STRUCT.make({ min: "box.max", max: "box.min" })};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
particle_bounds_reset(row);
|
|
175
|
+
|
|
176
|
+
// Two field writes rather than a whole-row read-modify-write: the tick wrote this row earlier in
|
|
177
|
+
// the frame, and there is no reason for this pass to carry the rest of it through registers.
|
|
178
|
+
${STATE.marshalling_method_write_field("bounds_min")}(&emitter_database, row, box.min);
|
|
179
|
+
${STATE.marshalling_method_write_field("bounds_max")}(&emitter_database, row, box.max);
|
|
180
|
+
}
|
|
181
|
+
`, [
|
|
182
|
+
PARTICLE_EMITTER_DESCRIPTOR.chunk_iterate(PARTICLE_EMITTER_TICK_WORKGROUP_SIZE, true),
|
|
183
|
+
WRITE_BOUNDS_MIN,
|
|
184
|
+
WRITE_BOUNDS_MAX,
|
|
185
|
+
chunk_particle_bounds_store,
|
|
186
|
+
]),
|
|
187
|
+
});
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {{keys: number, histogram: number, cursor: number, bucket_counts: number, dispatch_args: number}} ParticleBucketScratch
|
|
3
|
+
*/
|
|
1
4
|
/**
|
|
2
5
|
* Frame-graph wiring for the simulation-order bucketing: turns the frame's freshly compacted alive
|
|
3
6
|
* list into the program-coherent, workgroup-padded list NEXT frame's simulate consumes.
|
|
@@ -36,9 +39,10 @@
|
|
|
36
39
|
* GPUBuffer twice makes two resource entries the graph cannot see are the same memory, so the read
|
|
37
40
|
* and the write end up on separate dependency chains
|
|
38
41
|
* @param {number} params.bucket_count number of distinct compiled programs
|
|
39
|
-
* @
|
|
42
|
+
* @param {ParticleBucketScratch} [params.scratch] latest handles when bucketing again in this graph
|
|
43
|
+
* @returns {{counters: number, sim_list: number, dispatch_args: number, scratch: ParticleBucketScratch}} the threaded handles downstream passes must read
|
|
40
44
|
*/
|
|
41
|
-
export function graph_particle_bucket({ graph, gpu, emitter_database, pool, alive, counters, sim_list, bucket_count }: {
|
|
45
|
+
export function graph_particle_bucket({ graph, gpu, emitter_database, pool, alive, counters, sim_list, bucket_count, scratch }: {
|
|
42
46
|
graph: import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph;
|
|
43
47
|
gpu: {
|
|
44
48
|
sim_list: GPUBuffer;
|
|
@@ -54,9 +58,18 @@ export function graph_particle_bucket({ graph, gpu, emitter_database, pool, aliv
|
|
|
54
58
|
counters: number;
|
|
55
59
|
sim_list: number;
|
|
56
60
|
bucket_count: number;
|
|
61
|
+
scratch?: ParticleBucketScratch;
|
|
57
62
|
}): {
|
|
58
63
|
counters: number;
|
|
59
64
|
sim_list: number;
|
|
60
65
|
dispatch_args: number;
|
|
66
|
+
scratch: ParticleBucketScratch;
|
|
67
|
+
};
|
|
68
|
+
export type ParticleBucketScratch = {
|
|
69
|
+
keys: number;
|
|
70
|
+
histogram: number;
|
|
71
|
+
cursor: number;
|
|
72
|
+
bucket_counts: number;
|
|
73
|
+
dispatch_args: number;
|
|
61
74
|
};
|
|
62
75
|
//# sourceMappingURL=graph_particle_bucket.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph_particle_bucket.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/coherence/graph_particle_bucket.js"],"names":[],"mappings":"AAkBA
|
|
1
|
+
{"version":3,"file":"graph_particle_bucket.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/coherence/graph_particle_bucket.js"],"names":[],"mappings":"AAkBA;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH;IApBqG,KAAK,EAA/F,OAAO,8DAA8D,EAAE,UAAU;IAClE,GAAG;QACI,QAAQ;QACR,QAAQ;QACR,aAAa;QACb,iBAAiB;QACjB,UAAU;QACV,iBAAiB;;IACxB,gBAAgB,EAA/B,MAAM;IACS,IAAI,EAAnB,MAAM;IACS,KAAK,EAApB,MAAM;IACS,QAAQ,EAAvB,MAAM;IACS,QAAQ,EAAvB,MAAM;IAIS,YAAY,EAA3B,MAAM;IACyB,OAAO,GAAtC,qBAAqB;;cACR,MAAM;cAAY,MAAM;mBAAiB,MAAM;aAAW,qBAAqB;EAyGtG;oCAnJY;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAC"}
|
|
@@ -16,6 +16,10 @@ import {
|
|
|
16
16
|
shader_particle_bucket_scatter,
|
|
17
17
|
} from "./shader_particle_bucket.js";
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {{keys: number, histogram: number, cursor: number, bucket_counts: number, dispatch_args: number}} ParticleBucketScratch
|
|
21
|
+
*/
|
|
22
|
+
|
|
19
23
|
/**
|
|
20
24
|
* Frame-graph wiring for the simulation-order bucketing: turns the frame's freshly compacted alive
|
|
21
25
|
* list into the program-coherent, workgroup-padded list NEXT frame's simulate consumes.
|
|
@@ -54,9 +58,10 @@ import {
|
|
|
54
58
|
* GPUBuffer twice makes two resource entries the graph cannot see are the same memory, so the read
|
|
55
59
|
* and the write end up on separate dependency chains
|
|
56
60
|
* @param {number} params.bucket_count number of distinct compiled programs
|
|
57
|
-
* @
|
|
61
|
+
* @param {ParticleBucketScratch} [params.scratch] latest handles when bucketing again in this graph
|
|
62
|
+
* @returns {{counters: number, sim_list: number, dispatch_args: number, scratch: ParticleBucketScratch}} the threaded handles downstream passes must read
|
|
58
63
|
*/
|
|
59
|
-
export function graph_particle_bucket({ graph, gpu, emitter_database, pool, alive, counters, sim_list, bucket_count }) {
|
|
64
|
+
export function graph_particle_bucket({ graph, gpu, emitter_database, pool, alive, counters, sim_list, bucket_count, scratch }) {
|
|
60
65
|
assert.defined(graph, "graph");
|
|
61
66
|
assert.isPositiveInteger(bucket_count, "bucket_count");
|
|
62
67
|
assert.isNonNegativeInteger(sim_list, "sim_list");
|
|
@@ -74,11 +79,12 @@ export function graph_particle_bucket({ graph, gpu, emitter_database, pool, aliv
|
|
|
74
79
|
// between the two passes unexpressed — the graph's own validator rejects it, because both
|
|
75
80
|
// versions name one piece of memory and the stale-looking read silently returns the new
|
|
76
81
|
// contents.
|
|
77
|
-
|
|
78
|
-
let
|
|
79
|
-
let
|
|
80
|
-
let
|
|
81
|
-
let
|
|
82
|
+
// An edit frame buckets twice. Reuse the latest handles so both runs share one dependency chain.
|
|
83
|
+
let keys = scratch?.keys ?? graph_import_buffer(graph, gpu.sim_keys, "particles/sim_keys");
|
|
84
|
+
let histogram = scratch?.histogram ?? graph_import_buffer(graph, gpu.sim_histogram, "particles/sim_histogram");
|
|
85
|
+
let cursor = scratch?.cursor ?? graph_import_buffer(graph, gpu.sim_cursor, "particles/sim_cursor");
|
|
86
|
+
let bucket_counts = scratch?.bucket_counts ?? graph_import_buffer(graph, gpu.sim_bucket_counts, "particles/sim_bucket_counts");
|
|
87
|
+
let dispatch_args = scratch?.dispatch_args ?? graph_import_buffer(graph, gpu.sim_dispatch_args, "particles/sim_dispatch_args");
|
|
82
88
|
|
|
83
89
|
// 0. Clear the bins and cursors, write the scan's {count} header, and size the two per-particle
|
|
84
90
|
// passes below from the GPU's own alive count.
|
|
@@ -157,7 +163,7 @@ export function graph_particle_bucket({ graph, gpu, emitter_database, pool, aliv
|
|
|
157
163
|
|
|
158
164
|
// `dispatch_args` goes back too: it holds one workgroup per live particle, written from the
|
|
159
165
|
// GPU's own alive count, which is exactly the shape the depth sort's per-particle passes need.
|
|
160
|
-
return { counters, sim_list, dispatch_args };
|
|
166
|
+
return { counters, sim_list, dispatch_args, scratch: { keys, histogram: scanned, cursor, bucket_counts, dispatch_args } };
|
|
161
167
|
}
|
|
162
168
|
|
|
163
169
|
/**
|
|
@@ -1,7 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* How many words the counters buffer needs to hold the counters plus one accumulator per row of an
|
|
3
|
+
* emitter table of `emitter_capacity` elements.
|
|
4
|
+
*
|
|
5
|
+
* @param {number} emitter_capacity element capacity of the emitter table
|
|
6
|
+
* @returns {number}
|
|
7
|
+
*/
|
|
8
|
+
export function particle_counters_word_count(emitter_capacity: number): number;
|
|
9
|
+
/**
|
|
10
|
+
* `row_count` accumulators, each holding the empty interval — what the publish pass leaves behind,
|
|
11
|
+
* and what a row must hold before anything has measured it.
|
|
12
|
+
*
|
|
13
|
+
* A zero-filled accumulator is NOT that: it reads back as a valid degenerate box at the world
|
|
14
|
+
* origin, which would union the origin into the first box measured for the row. WebGPU zero-fills a
|
|
15
|
+
* new buffer, so the host writes this over a newly grown region rather than relying on the fill.
|
|
16
|
+
*
|
|
17
|
+
* @param {number} row_count
|
|
18
|
+
* @returns {Uint32Array}
|
|
19
|
+
*/
|
|
20
|
+
export function particle_bounds_empty_words(row_count: number): Uint32Array;
|
|
21
|
+
/**
|
|
22
|
+
* Indices into the head of the particle counters buffer (an `array<atomic<u32>>`). The simulate/emit
|
|
23
|
+
* passes use atomics on these slots to append to the alive/dead lists; a finalize pass turns the
|
|
24
|
+
* counts into indirect dispatch/draw arguments.
|
|
25
|
+
*
|
|
26
|
+
* The buffer does not end here: {@link PARTICLE_BOUNDS_BASE} onward is the per-emitter bounds
|
|
27
|
+
* accumulator, described below.
|
|
5
28
|
*/
|
|
6
29
|
export const PARTICLE_COUNTER: Readonly<{
|
|
7
30
|
/** length of the alive list produced this frame */
|
|
@@ -47,6 +70,37 @@ export const PARTICLE_COUNTER: Readonly<{
|
|
|
47
70
|
*/
|
|
48
71
|
SIM_PADDED: 5;
|
|
49
72
|
}>;
|
|
50
|
-
/** Number of `u32` atomic slots
|
|
73
|
+
/** Number of `u32` atomic slots the counters themselves occupy — the head of the buffer. */
|
|
51
74
|
export const PARTICLE_COUNTER_COUNT: 8;
|
|
75
|
+
/**
|
|
76
|
+
* First word of the per-emitter bounds accumulator, which occupies the rest of the counters buffer:
|
|
77
|
+
* {@link PARTICLE_BOUNDS_WORDS} words per emitter table row, indexed by row.
|
|
78
|
+
*
|
|
79
|
+
* ## Why it lives here rather than in a buffer of its own
|
|
80
|
+
*
|
|
81
|
+
* The accumulator is merged into with atomics — one contribution per live particle — which means a
|
|
82
|
+
* binding declared `array<atomic<u32>>`. The emitter database cannot be it: the passes that read a
|
|
83
|
+
* record read it out of an `array<u32>` binding, and one buffer under two access types is aliasing.
|
|
84
|
+
*
|
|
85
|
+
* The counters buffer is already exactly that: bound in both bounds passes, already atomic, already
|
|
86
|
+
* read-write, and already this system's cross-pass GPU-owned scratch. Giving the accumulator a
|
|
87
|
+
* buffer of its own would add a binding and a growth path to say the same thing. So it is a section
|
|
88
|
+
* of this one: the counters keep their slots, the reset pass keeps writing the same fixed indices,
|
|
89
|
+
* and the section is addressed off this base.
|
|
90
|
+
*
|
|
91
|
+
* @type {number}
|
|
92
|
+
*/
|
|
93
|
+
export const PARTICLE_BOUNDS_BASE: number;
|
|
94
|
+
/**
|
|
95
|
+
* Words one emitter's bounds accumulator takes: `min.xyz` then `max.xyz`, each an f32 bit pattern
|
|
96
|
+
* held in a `u32` slot (see `../bounds/chunk_particle_bounds.js` for why the storage is plain f32
|
|
97
|
+
* rather than an order-preserving encoding).
|
|
98
|
+
*
|
|
99
|
+
* @type {number}
|
|
100
|
+
*/
|
|
101
|
+
export const PARTICLE_BOUNDS_WORDS: number;
|
|
102
|
+
/** `bitcast<u32>(f32(+inf))` — the lower corner of the empty interval. */
|
|
103
|
+
export const PARTICLE_BOUNDS_PLUS_INF: 2139095040;
|
|
104
|
+
/** `bitcast<u32>(f32(-inf))` — the upper corner of the empty interval. */
|
|
105
|
+
export const PARTICLE_BOUNDS_MINUS_INF: 4286578688;
|
|
52
106
|
//# sourceMappingURL=PARTICLE_COUNTERS.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PARTICLE_COUNTERS.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/data/PARTICLE_COUNTERS.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PARTICLE_COUNTERS.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/data/PARTICLE_COUNTERS.js"],"names":[],"mappings":"AAqFA;;;;;;GAMG;AACH,+DAHW,MAAM,GACJ,MAAM,CAIlB;AAQD;;;;;;;;;;GAUG;AACH,uDAHW,MAAM,GACJ,WAAW,CAevB;AA9HD;;;;;;;GAOG;AACH;IACI,mDAAmD;;IAEnD,qCAAqC;;IAErC;;;;;OAKG;;IAEH;;;;;;OAMG;;IAEH;;;;;;;;;;;OAWG;;IAEH;;;;;;;;OAQG;;GAEJ;AAEH,4FAA4F;AAC5F,uCAAwC;AAExC;;;;;;;;;;;;;;;;;GAiBG;AACH,mCAFU,MAAM,CAE2C;AAE3D;;;;;;GAMG;AACH,oCAFU,MAAM,CAEuB;AAavC,0EAA0E;AAC1E,kDAAmD;AAEnD,0EAA0E;AAC1E,mDAAoD"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Indices into the particle counters buffer (an `array<atomic<u32>>`). The simulate/emit
|
|
3
|
-
* atomics on these slots to append to the alive/dead lists; a finalize pass turns the
|
|
4
|
-
* indirect dispatch/draw arguments.
|
|
2
|
+
* Indices into the head of the particle counters buffer (an `array<atomic<u32>>`). The simulate/emit
|
|
3
|
+
* passes use atomics on these slots to append to the alive/dead lists; a finalize pass turns the
|
|
4
|
+
* counts into indirect dispatch/draw arguments.
|
|
5
|
+
*
|
|
6
|
+
* The buffer does not end here: {@link PARTICLE_BOUNDS_BASE} onward is the per-emitter bounds
|
|
7
|
+
* accumulator, described below.
|
|
5
8
|
*/
|
|
6
9
|
export const PARTICLE_COUNTER = Object.freeze({
|
|
7
10
|
/** length of the alive list produced this frame */
|
|
@@ -48,5 +51,77 @@ export const PARTICLE_COUNTER = Object.freeze({
|
|
|
48
51
|
SIM_PADDED: 5,
|
|
49
52
|
});
|
|
50
53
|
|
|
51
|
-
/** Number of `u32` atomic slots
|
|
54
|
+
/** Number of `u32` atomic slots the counters themselves occupy — the head of the buffer. */
|
|
52
55
|
export const PARTICLE_COUNTER_COUNT = 8;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* First word of the per-emitter bounds accumulator, which occupies the rest of the counters buffer:
|
|
59
|
+
* {@link PARTICLE_BOUNDS_WORDS} words per emitter table row, indexed by row.
|
|
60
|
+
*
|
|
61
|
+
* ## Why it lives here rather than in a buffer of its own
|
|
62
|
+
*
|
|
63
|
+
* The accumulator is merged into with atomics — one contribution per live particle — which means a
|
|
64
|
+
* binding declared `array<atomic<u32>>`. The emitter database cannot be it: the passes that read a
|
|
65
|
+
* record read it out of an `array<u32>` binding, and one buffer under two access types is aliasing.
|
|
66
|
+
*
|
|
67
|
+
* The counters buffer is already exactly that: bound in both bounds passes, already atomic, already
|
|
68
|
+
* read-write, and already this system's cross-pass GPU-owned scratch. Giving the accumulator a
|
|
69
|
+
* buffer of its own would add a binding and a growth path to say the same thing. So it is a section
|
|
70
|
+
* of this one: the counters keep their slots, the reset pass keeps writing the same fixed indices,
|
|
71
|
+
* and the section is addressed off this base.
|
|
72
|
+
*
|
|
73
|
+
* @type {number}
|
|
74
|
+
*/
|
|
75
|
+
export const PARTICLE_BOUNDS_BASE = PARTICLE_COUNTER_COUNT;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Words one emitter's bounds accumulator takes: `min.xyz` then `max.xyz`, each an f32 bit pattern
|
|
79
|
+
* held in a `u32` slot (see `../bounds/chunk_particle_bounds.js` for why the storage is plain f32
|
|
80
|
+
* rather than an order-preserving encoding).
|
|
81
|
+
*
|
|
82
|
+
* @type {number}
|
|
83
|
+
*/
|
|
84
|
+
export const PARTICLE_BOUNDS_WORDS = 6;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* How many words the counters buffer needs to hold the counters plus one accumulator per row of an
|
|
88
|
+
* emitter table of `emitter_capacity` elements.
|
|
89
|
+
*
|
|
90
|
+
* @param {number} emitter_capacity element capacity of the emitter table
|
|
91
|
+
* @returns {number}
|
|
92
|
+
*/
|
|
93
|
+
export function particle_counters_word_count(emitter_capacity) {
|
|
94
|
+
return PARTICLE_BOUNDS_BASE + emitter_capacity * PARTICLE_BOUNDS_WORDS;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** `bitcast<u32>(f32(+inf))` — the lower corner of the empty interval. */
|
|
98
|
+
export const PARTICLE_BOUNDS_PLUS_INF = 0x7F800000;
|
|
99
|
+
|
|
100
|
+
/** `bitcast<u32>(f32(-inf))` — the upper corner of the empty interval. */
|
|
101
|
+
export const PARTICLE_BOUNDS_MINUS_INF = 0xFF800000;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* `row_count` accumulators, each holding the empty interval — what the publish pass leaves behind,
|
|
105
|
+
* and what a row must hold before anything has measured it.
|
|
106
|
+
*
|
|
107
|
+
* A zero-filled accumulator is NOT that: it reads back as a valid degenerate box at the world
|
|
108
|
+
* origin, which would union the origin into the first box measured for the row. WebGPU zero-fills a
|
|
109
|
+
* new buffer, so the host writes this over a newly grown region rather than relying on the fill.
|
|
110
|
+
*
|
|
111
|
+
* @param {number} row_count
|
|
112
|
+
* @returns {Uint32Array}
|
|
113
|
+
*/
|
|
114
|
+
export function particle_bounds_empty_words(row_count) {
|
|
115
|
+
const words = new Uint32Array(row_count * PARTICLE_BOUNDS_WORDS);
|
|
116
|
+
|
|
117
|
+
for (let word = 0; word < words.length; word += PARTICLE_BOUNDS_WORDS) {
|
|
118
|
+
words[word] = PARTICLE_BOUNDS_PLUS_INF;
|
|
119
|
+
words[word + 1] = PARTICLE_BOUNDS_PLUS_INF;
|
|
120
|
+
words[word + 2] = PARTICLE_BOUNDS_PLUS_INF;
|
|
121
|
+
words[word + 3] = PARTICLE_BOUNDS_MINUS_INF;
|
|
122
|
+
words[word + 4] = PARTICLE_BOUNDS_MINUS_INF;
|
|
123
|
+
words[word + 5] = PARTICLE_BOUNDS_MINUS_INF;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return words;
|
|
127
|
+
}
|
|
@@ -21,12 +21,32 @@
|
|
|
21
21
|
* against the record's and starts the row over on a mismatch. A freshly allocated page and a reused
|
|
22
22
|
* row both fall out of that one rule.
|
|
23
23
|
*
|
|
24
|
+
* ## The bounds are here for the same reason everything else here is
|
|
25
|
+
*
|
|
26
|
+
* An emitter has no bounds an author could state. Its particles are simulated in world space by
|
|
27
|
+
* arbitrary bytecode and go where that bytecode sends them, at whatever size it gives them; the only
|
|
28
|
+
* honest answer written down in advance is "an infinite sphere", which culls nothing. So the box is
|
|
29
|
+
* measured instead of declared: at the end of each frame a pass over the alive list reduces the live
|
|
30
|
+
* particles' world-space quads into a per-row accumulator, and a second pass publishes that into
|
|
31
|
+
* {@link bounds_min} / {@link bounds_max} here. Both are `../bounds/`.
|
|
32
|
+
*
|
|
33
|
+
* Measured state is GPU-owned state, and this is the table GPU-owned state lives in. On the emitter
|
|
34
|
+
* record it would be overwritten by the next restage — the same hazard the accumulator has, one
|
|
35
|
+
* paragraph up.
|
|
36
|
+
*
|
|
24
37
|
* @type {WebGPUStruct}
|
|
25
38
|
*/
|
|
26
39
|
export const PARTICLE_EMITTER_STATE_STRUCT: WebGPUStruct;
|
|
27
40
|
/**
|
|
28
41
|
* A state row as the CPU stages it when an emitter claims a row: nothing yet. Generation zero is
|
|
29
|
-
* never a live emitter's, so the first tick starts the row over whatever it held before
|
|
42
|
+
* never a live emitter's, so the first tick starts the row over whatever it held before, and the
|
|
43
|
+
* first publish replaces the bounds with a measurement.
|
|
44
|
+
*
|
|
45
|
+
* The infinite box means unknown until the bounds passes have a live population to measure.
|
|
46
|
+
*
|
|
47
|
+
* Every field is present even though the first tick overwrites all of them, because the serializer
|
|
48
|
+
* skips absent fields and table pages are recycled buffers: a skipped field would keep the previous
|
|
49
|
+
* tenant's bytes rather than being zeroed.
|
|
30
50
|
*/
|
|
31
51
|
export const PARTICLE_EMITTER_STATE_EMPTY: Readonly<{
|
|
32
52
|
generation: 0;
|
|
@@ -34,6 +54,8 @@ export const PARTICLE_EMITTER_STATE_EMPTY: Readonly<{
|
|
|
34
54
|
age: 0;
|
|
35
55
|
sleep: 0;
|
|
36
56
|
pending: 0;
|
|
57
|
+
bounds_min: readonly number[];
|
|
58
|
+
bounds_max: readonly number[];
|
|
37
59
|
}>;
|
|
38
60
|
import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
|
|
39
61
|
//# sourceMappingURL=PARTICLE_EMITTER_STATE.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PARTICLE_EMITTER_STATE.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/data/PARTICLE_EMITTER_STATE.js"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"PARTICLE_EMITTER_STATE.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/data/PARTICLE_EMITTER_STATE.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,4CAFU,YAAY,CAwBY;AAElC;;;;;;;;;;GAUG;AACH;;;;;;;;GAQG;6BAnF0B,mCAAmC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f32, u32 } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
1
|
+
import { f32, u32, vec3f } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
2
2
|
import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -24,6 +24,19 @@ import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
|
|
|
24
24
|
* against the record's and starts the row over on a mismatch. A freshly allocated page and a reused
|
|
25
25
|
* row both fall out of that one rule.
|
|
26
26
|
*
|
|
27
|
+
* ## The bounds are here for the same reason everything else here is
|
|
28
|
+
*
|
|
29
|
+
* An emitter has no bounds an author could state. Its particles are simulated in world space by
|
|
30
|
+
* arbitrary bytecode and go where that bytecode sends them, at whatever size it gives them; the only
|
|
31
|
+
* honest answer written down in advance is "an infinite sphere", which culls nothing. So the box is
|
|
32
|
+
* measured instead of declared: at the end of each frame a pass over the alive list reduces the live
|
|
33
|
+
* particles' world-space quads into a per-row accumulator, and a second pass publishes that into
|
|
34
|
+
* {@link bounds_min} / {@link bounds_max} here. Both are `../bounds/`.
|
|
35
|
+
*
|
|
36
|
+
* Measured state is GPU-owned state, and this is the table GPU-owned state lives in. On the emitter
|
|
37
|
+
* record it would be overwritten by the next restage — the same hazard the accumulator has, one
|
|
38
|
+
* paragraph up.
|
|
39
|
+
*
|
|
27
40
|
* @type {WebGPUStruct}
|
|
28
41
|
*/
|
|
29
42
|
export const PARTICLE_EMITTER_STATE_STRUCT = WebGPUStruct.from({
|
|
@@ -37,11 +50,29 @@ export const PARTICLE_EMITTER_STATE_STRUCT = WebGPUStruct.from({
|
|
|
37
50
|
sleep: f32,
|
|
38
51
|
/** particles requested by the spawn-command pass since the last tick, consumed by the tick */
|
|
39
52
|
pending: u32,
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* World-space lower corner of the box holding this emitter's live particles, as the bounds
|
|
56
|
+
* passes left it at the end of the previous frame.
|
|
57
|
+
*
|
|
58
|
+
* Infinite while no live particles have supplied a measurement. The tick treats this as
|
|
59
|
+
* visible; AVBOIT occupancy skips it. Readers test the sentinel before arithmetic on infinity.
|
|
60
|
+
*/
|
|
61
|
+
bounds_min: vec3f,
|
|
62
|
+
/** world-space upper corner; see {@link bounds_min} */
|
|
63
|
+
bounds_max: vec3f,
|
|
40
64
|
}, "ParticleEmitterState").pack();
|
|
41
65
|
|
|
42
66
|
/**
|
|
43
67
|
* A state row as the CPU stages it when an emitter claims a row: nothing yet. Generation zero is
|
|
44
|
-
* never a live emitter's, so the first tick starts the row over whatever it held before
|
|
68
|
+
* never a live emitter's, so the first tick starts the row over whatever it held before, and the
|
|
69
|
+
* first publish replaces the bounds with a measurement.
|
|
70
|
+
*
|
|
71
|
+
* The infinite box means unknown until the bounds passes have a live population to measure.
|
|
72
|
+
*
|
|
73
|
+
* Every field is present even though the first tick overwrites all of them, because the serializer
|
|
74
|
+
* skips absent fields and table pages are recycled buffers: a skipped field would keep the previous
|
|
75
|
+
* tenant's bytes rather than being zeroed.
|
|
45
76
|
*/
|
|
46
77
|
export const PARTICLE_EMITTER_STATE_EMPTY = Object.freeze({
|
|
47
78
|
generation: 0,
|
|
@@ -49,4 +80,6 @@ export const PARTICLE_EMITTER_STATE_EMPTY = Object.freeze({
|
|
|
49
80
|
age: 0,
|
|
50
81
|
sleep: 0,
|
|
51
82
|
pending: 0,
|
|
83
|
+
bounds_min: Object.freeze([-Infinity, -Infinity, -Infinity]),
|
|
84
|
+
bounds_max: Object.freeze([Infinity, Infinity, Infinity]),
|
|
52
85
|
});
|
|
@@ -25,7 +25,7 @@ export function emitter_flags_projection(flags: number): number;
|
|
|
25
25
|
* One emitter's GPU record: which compiled program it runs and where that program's code and
|
|
26
26
|
* constants sit in the {@link ../runtime/ProgramArena.js} buffers, plus the instance parameters the
|
|
27
27
|
* tick / emit / simulate / sort / render passes read — the scene node it hangs off, spawn rate,
|
|
28
|
-
* feature flags,
|
|
28
|
+
* feature flags, render-attribute bindings, atlas region and flipbook grid.
|
|
29
29
|
*
|
|
30
30
|
* There is no transform here. An emitter is a scene node, and its world matrix is the `global` of
|
|
31
31
|
* its row in the scene database's `transforms` table, composed on the GPU by the hierarchy pass
|
|
@@ -33,7 +33,9 @@ export function emitter_flags_projection(flags: number): number;
|
|
|
33
33
|
*
|
|
34
34
|
* Nor is there any per-frame state: what the GPU integrates for an emitter (spawn accumulator, age,
|
|
35
35
|
* sleep) lives in {@link ./PARTICLE_EMITTER_STATE.js}, keyed by the same row, for the reason given
|
|
36
|
-
* there.
|
|
36
|
+
* there. The bounding box the culling and occupancy passes test is there too, and for a second
|
|
37
|
+
* reason: it is measured from the particles rather than declared by an author, so it is the GPU's
|
|
38
|
+
* value and not the CPU's.
|
|
37
39
|
*
|
|
38
40
|
* It lives in a `GPUDatabase` table (see {@link ./PARTICLE_DATABASE_SPEC.js}), so the layout below
|
|
39
41
|
* is the *only* description of it that exists: the JS writer is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PARTICLE_EMITTER_STRUCT.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PARTICLE_EMITTER_STRUCT.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js"],"names":[],"mappings":"AAgIA;;;;;;;;;;GAUG;AACH;IAR6B,QAAQ,GAA1B,OAAO;IACW,UAAU,GAA5B,OAAO;IACW,IAAI,GAAtB,OAAO;IACW,IAAI,GAAtB,OAAO;IACU,KAAK,GAAtB,MAAM;IACW,UAAU,GAA3B,MAAM;IACJ,MAAM,CAWlB;AAED,6DAA6D;AAC7D,2CADY,MAAM,GAAkB,MAAM,CAGzC;AAED,kEAAkE;AAClE,gDADY,MAAM,GAAkB,MAAM,CAGzC;AA3JD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,sCAFU,YAAY,CA+DO;AAE7B,uDAAuD;AACvD,kDAAmD;AAEnD;;GAEG;AACH;;;;;GAKG;AAEH,kGAAkG;AAClG;;;;GAIG;AAKH,kEAAkE;AAClE;;;;;;GAMG;AAqCH,uEAAuE;AACvE;;;;;GAEG;6BAlK0B,mCAAmC"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { f32, u32, vec2f,
|
|
1
|
+
import { f32, u32, vec2f, vec4f } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
2
2
|
import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* One emitter's GPU record: which compiled program it runs and where that program's code and
|
|
6
6
|
* constants sit in the {@link ../runtime/ProgramArena.js} buffers, plus the instance parameters the
|
|
7
7
|
* tick / emit / simulate / sort / render passes read — the scene node it hangs off, spawn rate,
|
|
8
|
-
* feature flags,
|
|
8
|
+
* feature flags, render-attribute bindings, atlas region and flipbook grid.
|
|
9
9
|
*
|
|
10
10
|
* There is no transform here. An emitter is a scene node, and its world matrix is the `global` of
|
|
11
11
|
* its row in the scene database's `transforms` table, composed on the GPU by the hierarchy pass
|
|
@@ -13,7 +13,9 @@ import { WebGPUStruct } from "../../shader/type/WebGPUStruct.js";
|
|
|
13
13
|
*
|
|
14
14
|
* Nor is there any per-frame state: what the GPU integrates for an emitter (spawn accumulator, age,
|
|
15
15
|
* sleep) lives in {@link ./PARTICLE_EMITTER_STATE.js}, keyed by the same row, for the reason given
|
|
16
|
-
* there.
|
|
16
|
+
* there. The bounding box the culling and occupancy passes test is there too, and for a second
|
|
17
|
+
* reason: it is measured from the particles rather than declared by an author, so it is the GPU's
|
|
18
|
+
* value and not the CPU's.
|
|
17
19
|
*
|
|
18
20
|
* It lives in a `GPUDatabase` table (see {@link ./PARTICLE_DATABASE_SPEC.js}), so the layout below
|
|
19
21
|
* is the *only* description of it that exists: the JS writer is
|
|
@@ -58,11 +60,6 @@ export const PARTICLE_EMITTER_STRUCT = WebGPUStruct.from({
|
|
|
58
60
|
*/
|
|
59
61
|
generation: u32,
|
|
60
62
|
|
|
61
|
-
/** local-space bounding sphere centre */
|
|
62
|
-
bounds_center: vec3f,
|
|
63
|
-
/** bounding sphere radius */
|
|
64
|
-
bounds_radius: f32,
|
|
65
|
-
|
|
66
63
|
/** attribute word offset of world position (or {@link EMITTER_ATTRIBUTE_ABSENT}) */
|
|
67
64
|
render_position: u32,
|
|
68
65
|
/** attribute word offset of size */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"particle_emitter_record.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/data/particle_emitter_record.js"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,6CANW,MAAM,WACN,OAAO,+BAA+B,EAAE,eAAe,WACvD,OAAO,yCAAyC,EAAE,yBAAyB,GAEzE,MAAM,
|
|
1
|
+
{"version":3,"file":"particle_emitter_record.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/data/particle_emitter_record.js"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,6CANW,MAAM,WACN,OAAO,+BAA+B,EAAE,eAAe,WACvD,OAAO,yCAAyC,EAAE,yBAAyB,GAEzE,MAAM,CAwClB;AAED;;;;;GAKG;AACH,yCAFa,MAAM,CA2BlB"}
|