@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
|
@@ -1,425 +1,424 @@
|
|
|
1
|
-
import { assert } from "../../../../core/assert.js";
|
|
2
|
-
import { is_typed_array_equals } from "../../../../core/collection/array/typed/is_typed_array_equals.js";
|
|
3
|
-
import { float32_array_hash } from "../../../../core/collection/array/typed/float32_array_hash.js";
|
|
4
|
-
import { hash_mix2 } from "../../../../core/math/hash/hash_mix2.js";
|
|
5
|
-
import { hash_mix3 } from "../../../../core/math/hash/hash_mix3.js";
|
|
6
|
-
import { computeHashFloat } from "../../../../core/primitives/numbers/computeHashFloat.js";
|
|
7
|
-
import { computeStringHash } from "../../../../core/primitives/strings/computeStringHash.js";
|
|
8
|
-
import { Node3D } from "../../scene/Node3D.js";
|
|
9
|
-
import { EMITTER_ATTRIBUTE_ABSENT, make_emitter_flags } from "../data/PARTICLE_EMITTER_STRUCT.js";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Render channels an emitter can bind to one of its effect's per-particle attributes. The names
|
|
13
|
-
* match the `render_*` fields of {@link ../data/PARTICLE_EMITTER_STRUCT.js}.
|
|
14
|
-
*
|
|
15
|
-
* @type {string[]}
|
|
16
|
-
*/
|
|
17
|
-
export const EMITTER_RENDER_CHANNELS = Object.freeze([
|
|
18
|
-
"position", "size", "color", "rotation", "frame", "velocity",
|
|
19
|
-
]);
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* How many record words the render pass reads for each channel.
|
|
23
|
-
*
|
|
24
|
-
* A channel is read at a fixed width — `chunk_particle_billboard_vertex.js` takes four words for
|
|
25
|
-
* colour and three for position, whatever the attribute behind the offset happens to be. Binding one
|
|
26
|
-
* to a narrower attribute is therefore not a smaller read but a read into whatever the layout put
|
|
27
|
-
* next, and nothing downstream objects: the particles simply come out wrong.
|
|
28
|
-
*
|
|
29
|
-
* Binding is deliberately not made to enforce this — the offsets are the record's, and an author who
|
|
30
|
-
* knows what is packed where may mean it — but an editor has this table so it can say so.
|
|
31
|
-
*
|
|
32
|
-
* @type {Object<string, number>}
|
|
33
|
-
*/
|
|
34
|
-
export const EMITTER_RENDER_CHANNEL_COMPONENTS = Object.freeze({
|
|
35
|
-
position: 3,
|
|
36
|
-
size: 1,
|
|
37
|
-
color: 4,
|
|
38
|
-
rotation: 1,
|
|
39
|
-
frame: 1,
|
|
40
|
-
velocity: 3,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* One particle emitter: a scene node that runs a compiled effect.
|
|
45
|
-
*
|
|
46
|
-
* Being a {@link Node3D} is what places it. Add it to a scene and it gets a row in the scene
|
|
47
|
-
* database's `transforms` table like any other node; parent it to a joint and the GPU hierarchy
|
|
48
|
-
* pass composes its world matrix from the joint's every frame, animation included, with nothing
|
|
49
|
-
* copied through the CPU. Remove it from the scene and the row goes with it — and so do its
|
|
50
|
-
* particles, within a frame, because the emitter's table row is retired with it and its particles
|
|
51
|
-
* carry that row's generation. There is no transform of its own to keep in step with anything.
|
|
52
|
-
*
|
|
53
|
-
* The rest is a description of an effect and nothing else: the attribute {@link layout} and the
|
|
54
|
-
* compiled {@link program}, the {@link texture} to draw with, spawn rate,
|
|
55
|
-
* feature flags,
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
*
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
/** @type {number} record word offset of
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
*
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
*
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
&& this.
|
|
243
|
-
&&
|
|
244
|
-
&&
|
|
245
|
-
&& this.
|
|
246
|
-
&& this.
|
|
247
|
-
&& this.
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
this.
|
|
307
|
-
this.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
this.
|
|
311
|
-
this.
|
|
312
|
-
|
|
313
|
-
this.
|
|
314
|
-
|
|
315
|
-
this.
|
|
316
|
-
|
|
317
|
-
this.
|
|
318
|
-
this.
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
*
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
* @
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
* @param {
|
|
357
|
-
*
|
|
358
|
-
* @param {
|
|
359
|
-
*
|
|
360
|
-
* @param {
|
|
361
|
-
* @param {
|
|
362
|
-
* @param {
|
|
363
|
-
* @param {
|
|
364
|
-
* @param {
|
|
365
|
-
* @
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
if (config.
|
|
382
|
-
emitter.
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (config.
|
|
386
|
-
emitter.
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
emitter.
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
if (config.
|
|
395
|
-
emitter.
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
* @
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
ParticleEmitter.prototype.isParticleEmitter = true;
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { is_typed_array_equals } from "../../../../core/collection/array/typed/is_typed_array_equals.js";
|
|
3
|
+
import { float32_array_hash } from "../../../../core/collection/array/typed/float32_array_hash.js";
|
|
4
|
+
import { hash_mix2 } from "../../../../core/math/hash/hash_mix2.js";
|
|
5
|
+
import { hash_mix3 } from "../../../../core/math/hash/hash_mix3.js";
|
|
6
|
+
import { computeHashFloat } from "../../../../core/primitives/numbers/computeHashFloat.js";
|
|
7
|
+
import { computeStringHash } from "../../../../core/primitives/strings/computeStringHash.js";
|
|
8
|
+
import { Node3D } from "../../scene/Node3D.js";
|
|
9
|
+
import { EMITTER_ATTRIBUTE_ABSENT, make_emitter_flags } from "../data/PARTICLE_EMITTER_STRUCT.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Render channels an emitter can bind to one of its effect's per-particle attributes. The names
|
|
13
|
+
* match the `render_*` fields of {@link ../data/PARTICLE_EMITTER_STRUCT.js}.
|
|
14
|
+
*
|
|
15
|
+
* @type {string[]}
|
|
16
|
+
*/
|
|
17
|
+
export const EMITTER_RENDER_CHANNELS = Object.freeze([
|
|
18
|
+
"position", "size", "color", "rotation", "frame", "velocity",
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* How many record words the render pass reads for each channel.
|
|
23
|
+
*
|
|
24
|
+
* A channel is read at a fixed width — `chunk_particle_billboard_vertex.js` takes four words for
|
|
25
|
+
* colour and three for position, whatever the attribute behind the offset happens to be. Binding one
|
|
26
|
+
* to a narrower attribute is therefore not a smaller read but a read into whatever the layout put
|
|
27
|
+
* next, and nothing downstream objects: the particles simply come out wrong.
|
|
28
|
+
*
|
|
29
|
+
* Binding is deliberately not made to enforce this — the offsets are the record's, and an author who
|
|
30
|
+
* knows what is packed where may mean it — but an editor has this table so it can say so.
|
|
31
|
+
*
|
|
32
|
+
* @type {Object<string, number>}
|
|
33
|
+
*/
|
|
34
|
+
export const EMITTER_RENDER_CHANNEL_COMPONENTS = Object.freeze({
|
|
35
|
+
position: 3,
|
|
36
|
+
size: 1,
|
|
37
|
+
color: 4,
|
|
38
|
+
rotation: 1,
|
|
39
|
+
frame: 1,
|
|
40
|
+
velocity: 3,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* One particle emitter: a scene node that runs a compiled effect.
|
|
45
|
+
*
|
|
46
|
+
* Being a {@link Node3D} is what places it. Add it to a scene and it gets a row in the scene
|
|
47
|
+
* database's `transforms` table like any other node; parent it to a joint and the GPU hierarchy
|
|
48
|
+
* pass composes its world matrix from the joint's every frame, animation included, with nothing
|
|
49
|
+
* copied through the CPU. Remove it from the scene and the row goes with it — and so do its
|
|
50
|
+
* particles, within a frame, because the emitter's table row is retired with it and its particles
|
|
51
|
+
* carry that row's generation. There is no transform of its own to keep in step with anything.
|
|
52
|
+
*
|
|
53
|
+
* The rest is a description of an effect and nothing else: the attribute {@link layout} and the
|
|
54
|
+
* compiled {@link program}, the {@link texture} to draw with, spawn rate, pre-warm duration, blend /
|
|
55
|
+
* projection / feature flags, render-attribute bindings and flipbook grid. Every one of those is the author's,
|
|
56
|
+
* means the same thing with no device present, and is what a saved effect is made of.
|
|
57
|
+
*
|
|
58
|
+
* There are no bounds among them, and there is nowhere here they could go. An emitter's particles
|
|
59
|
+
* are simulated in world space by arbitrary bytecode: they go where the program sends them, at
|
|
60
|
+
* whatever size it gives them, for as long as it keeps them alive. Nothing an author could write
|
|
61
|
+
* down would bound that except "infinite", which culls nothing and marks every depth slice. So the
|
|
62
|
+
* box is measured instead — from the live particles, by a pass of its own at the end of every frame
|
|
63
|
+
* (`../bounds/`) — and it lives with the rest of the measured state in
|
|
64
|
+
* {@link ../data/PARTICLE_EMITTER_STATE.js}. The one thing that IS the author's is whether the
|
|
65
|
+
* emitter opts into culling at all: `EMITTER_FLAG.CULL` in {@link flags}.
|
|
66
|
+
*
|
|
67
|
+
* **Nothing here is the GPU's.** Which table row the emitter was given, which tenancy of it, where
|
|
68
|
+
* its program was placed in the program heap, which `transforms` row its node ended up in, where
|
|
69
|
+
* its texture was packed into the atlas — all of that is
|
|
70
|
+
* {@link ./GPUParticleEmitterContext.js GPUParticleEmitterContext}, held by the
|
|
71
|
+
* {@link ./EmitterRegistry.js} that registered the emitter and reachable through
|
|
72
|
+
* {@link ./EmitterRegistry.js#context}. An emitter no registry holds has none, which is also how
|
|
73
|
+
* "is this emitter live?" is asked. Nor is anything the GPU integrates per frame here — spawn
|
|
74
|
+
* accumulator, age, sleep are {@link ../data/PARTICLE_EMITTER_STATE.js}, and they stay on the GPU.
|
|
75
|
+
*
|
|
76
|
+
* Fields are plain data with no setters. After changing any of them, set `needsUpdate = true` — the
|
|
77
|
+
* node's own change counter, the same one the renderer reads to decide whether a transform needs
|
|
78
|
+
* re-uploading — and {@link ./EmitterRegistry.js#flush} restages the row on its next flush. One
|
|
79
|
+
* counter rather than a setter per field because a row is restaged whole either way: one changed
|
|
80
|
+
* field and ten cost the same upload.
|
|
81
|
+
*/
|
|
82
|
+
export class ParticleEmitter extends Node3D {
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The per-particle attribute schema: which named attributes a particle of this emitter has, how
|
|
86
|
+
* wide each is, and what word of the record it sits at.
|
|
87
|
+
*
|
|
88
|
+
* @type {import("../layout/ParticleLayout.js").ParticleLayout}
|
|
89
|
+
*/
|
|
90
|
+
layout;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The compiled INIT/UPDATE bytecode run for every particle of this emitter.
|
|
94
|
+
* Replace the immutable program to edit it; do not mutate its bytecode in place.
|
|
95
|
+
*
|
|
96
|
+
* @type {import("../isa/ParticleProgram.js").ParticleProgram}
|
|
97
|
+
*/
|
|
98
|
+
program;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Image to draw the particles with, by URL, or `null` to draw against the default atlas — a
|
|
102
|
+
* single white texel, so an untextured emitter is a flat quad of its colour.
|
|
103
|
+
*
|
|
104
|
+
* The ECS GPUParticleEmitterSystem loads this URL through AssetManager and packs the image
|
|
105
|
+
* into a shared sheet. Standalone callers provide their own atlas and regions. Where
|
|
106
|
+
* a given image lands in that sheet is the system's answer, not the author's — it changes on
|
|
107
|
+
* every repack, without the emitter changing. The resolved patch is
|
|
108
|
+
* {@link ./GPUParticleEmitterContext.js#atlas_region}.
|
|
109
|
+
*
|
|
110
|
+
* @type {string|null}
|
|
111
|
+
*/
|
|
112
|
+
texture = null;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Base RNG seed.
|
|
116
|
+
*
|
|
117
|
+
* Two emitters running one program produce identical particles from identical seeds. `0` reads
|
|
118
|
+
* as "unset", and the row written for such an emitter takes its registration's generation
|
|
119
|
+
* instead, which no other emitter of that registry shares.
|
|
120
|
+
*
|
|
121
|
+
* @type {number}
|
|
122
|
+
*/
|
|
123
|
+
seed = 0;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Continuous emission rate, particles per second. Integrated on the GPU by the emitter tick
|
|
127
|
+
* pass; the CPU never counts particles.
|
|
128
|
+
* @type {number}
|
|
129
|
+
*/
|
|
130
|
+
spawn_rate = 0;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Seconds this emitter is run forward before it is first shown, `0` for none.
|
|
134
|
+
*
|
|
135
|
+
* A continuous effect — a smoke column, a dust field — starts empty and grows into its steady
|
|
136
|
+
* state over one particle lifetime, in front of whoever is watching. Setting this to about the
|
|
137
|
+
* effect's particle lifetime means the population that arrives on the first visible frame is the
|
|
138
|
+
* one the emitter would have had by then: spawned, aged, and thinned by its own program over
|
|
139
|
+
* that long, rather than a crowd of newborns.
|
|
140
|
+
*
|
|
141
|
+
* The author's number, and the only thing about a warm-up that is authored. It is not written to
|
|
142
|
+
* the GPU record: the system queues an emitter that has one at the moment it is registered, and
|
|
143
|
+
* the warm-up pipeline (`../warmup/`) runs its simulation forward on that frame, over a
|
|
144
|
+
* population of its own, before moving the result into the scene. Longer costs a longer loop on
|
|
145
|
+
* that one frame and nothing after it.
|
|
146
|
+
*
|
|
147
|
+
* Prewarm controls the initial population's age distribution. It is not needed to bootstrap
|
|
148
|
+
* culling: emitters without a measured population have unknown bounds and remain eligible to spawn.
|
|
149
|
+
*
|
|
150
|
+
* @type {number}
|
|
151
|
+
*/
|
|
152
|
+
prewarm = 0;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Packed feature / blend / projection bits — see {@link make_emitter_flags}.
|
|
156
|
+
* @type {number}
|
|
157
|
+
*/
|
|
158
|
+
flags = 0;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Flipbook grid: columns, rows, over whatever region {@link texture} was packed into. `[1, 1]`
|
|
162
|
+
* is a single frame.
|
|
163
|
+
* @type {Float32Array}
|
|
164
|
+
*/
|
|
165
|
+
flipbook = new Float32Array([1, 1]);
|
|
166
|
+
|
|
167
|
+
/** @type {number} record word offset of world position, or {@link EMITTER_ATTRIBUTE_ABSENT} */
|
|
168
|
+
render_position = EMITTER_ATTRIBUTE_ABSENT;
|
|
169
|
+
/** @type {number} record word offset of size */
|
|
170
|
+
render_size = EMITTER_ATTRIBUTE_ABSENT;
|
|
171
|
+
/** @type {number} record word offset of rgba colour */
|
|
172
|
+
render_color = EMITTER_ATTRIBUTE_ABSENT;
|
|
173
|
+
/** @type {number} record word offset of roll angle, radians */
|
|
174
|
+
render_rotation = EMITTER_ATTRIBUTE_ABSENT;
|
|
175
|
+
/** @type {number} record word offset of flipbook frame index */
|
|
176
|
+
render_frame = EMITTER_ATTRIBUTE_ABSENT;
|
|
177
|
+
/** @type {number} record word offset of velocity, read by the STRETCHED projection */
|
|
178
|
+
render_velocity = EMITTER_ATTRIBUTE_ABSENT;
|
|
179
|
+
|
|
180
|
+
get type() {
|
|
181
|
+
return "ParticleEmitter";
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Bind render channels to per-particle attributes of this emitter's effect, by attribute name.
|
|
186
|
+
* Channels left out of `channels` keep whatever they had; a channel that was never bound stays
|
|
187
|
+
* at {@link EMITTER_ATTRIBUTE_ABSENT}, which the passes read as "this emitter has no such
|
|
188
|
+
* attribute" — the render pass substitutes a default, the sort pass treats the particle as
|
|
189
|
+
* being at the origin.
|
|
190
|
+
*
|
|
191
|
+
* The record stores word offsets rather than names because that is what the render and sort
|
|
192
|
+
* passes index a particle record with; resolving here is the only place a name is involved.
|
|
193
|
+
*
|
|
194
|
+
* @param {Object<string,string>} channels channel name (see {@link EMITTER_RENDER_CHANNELS}) ->
|
|
195
|
+
* attribute name in the effect's layout
|
|
196
|
+
*/
|
|
197
|
+
bind_render(channels) {
|
|
198
|
+
assert.isObject(channels, 'channels');
|
|
199
|
+
assert.defined(this.layout, 'layout');
|
|
200
|
+
|
|
201
|
+
const layout = this.layout;
|
|
202
|
+
|
|
203
|
+
for (const channel of Object.keys(channels)) {
|
|
204
|
+
const offset = layout.offsetOf(channels[channel]);
|
|
205
|
+
|
|
206
|
+
switch (channel) {
|
|
207
|
+
case "position": this.render_position = offset; break;
|
|
208
|
+
case "size": this.render_size = offset; break;
|
|
209
|
+
case "color": this.render_color = offset; break;
|
|
210
|
+
case "rotation": this.render_rotation = offset; break;
|
|
211
|
+
case "frame": this.render_frame = offset; break;
|
|
212
|
+
case "velocity": this.render_velocity = offset; break;
|
|
213
|
+
default:
|
|
214
|
+
throw new Error(
|
|
215
|
+
`Unknown render channel '${channel}', expected one of ${EMITTER_RENDER_CHANNELS.join(', ')}`
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
this.needsUpdate = true;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Structural equality over everything an emitter *is*: where it sits, what it runs, what it
|
|
225
|
+
* draws with, and how it is bound to the renderer. Two emitters that compare equal describe one
|
|
226
|
+
* effect in one place, and one row would serve both.
|
|
227
|
+
*
|
|
228
|
+
* The node's identity is not part of it — `id`, parent and children say where an emitter is in
|
|
229
|
+
* a scene, not what it is — and neither is anything the GPU assigned it, which is not here to
|
|
230
|
+
* be compared. {@link transform_global} is left out too, being derived from
|
|
231
|
+
* {@link transform_local} and the parent chain.
|
|
232
|
+
*
|
|
233
|
+
* @param {ParticleEmitter} other
|
|
234
|
+
* @returns {boolean}
|
|
235
|
+
*/
|
|
236
|
+
equals(other) {
|
|
237
|
+
if (this === other) {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return this.name === other.name
|
|
242
|
+
&& this.texture === other.texture
|
|
243
|
+
&& this.seed === other.seed
|
|
244
|
+
&& this.spawn_rate === other.spawn_rate
|
|
245
|
+
&& this.prewarm === other.prewarm
|
|
246
|
+
&& this.flags === other.flags
|
|
247
|
+
&& this.render_position === other.render_position
|
|
248
|
+
&& this.render_size === other.render_size
|
|
249
|
+
&& this.render_color === other.render_color
|
|
250
|
+
&& this.render_rotation === other.render_rotation
|
|
251
|
+
&& this.render_frame === other.render_frame
|
|
252
|
+
&& this.render_velocity === other.render_velocity
|
|
253
|
+
&& is_typed_array_equals(this.flipbook, other.flipbook)
|
|
254
|
+
&& this.transform_local.equals(other.transform_local)
|
|
255
|
+
&& this.layout.equals(other.layout)
|
|
256
|
+
&& this.program.equals(other.program);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Hash over everything {@link equals} compares, in the same terms — the compiled program hashes
|
|
261
|
+
* by its own bytecode rather than by object identity, so two emitters separately compiled from
|
|
262
|
+
* one graph hash equally, as they compare equally.
|
|
263
|
+
*
|
|
264
|
+
* @returns {number} int32
|
|
265
|
+
*/
|
|
266
|
+
hash() {
|
|
267
|
+
const bindings = hash_mix3(
|
|
268
|
+
hash_mix3(this.render_position, this.render_size, this.render_color),
|
|
269
|
+
hash_mix3(this.render_rotation, this.render_frame, this.render_velocity),
|
|
270
|
+
this.flags
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
const flipbook = float32_array_hash(this.flipbook, 0, this.flipbook.length);
|
|
274
|
+
|
|
275
|
+
const appearance = hash_mix3(
|
|
276
|
+
computeStringHash(this.name),
|
|
277
|
+
computeStringHash(this.texture),
|
|
278
|
+
hash_mix3(this.seed, computeHashFloat(this.spawn_rate), computeHashFloat(this.prewarm))
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
return hash_mix3(
|
|
282
|
+
hash_mix2(bindings, flipbook),
|
|
283
|
+
hash_mix2(appearance, this.transform_local.hash()),
|
|
284
|
+
hash_mix2(this.layout.hash(), this.program.hash())
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Make this emitter a copy of `other`: same effect, same settings, same placement.
|
|
290
|
+
*
|
|
291
|
+
* The layout and the compiled program are shared rather than duplicated — both are immutable
|
|
292
|
+
* once compiled, and sharing them is what puts two emitters of one effect on one program id in
|
|
293
|
+
* the program heap, hence in one simulation bucket.
|
|
294
|
+
*
|
|
295
|
+
* What is not copied is the node's identity and its place in a scene ({@link Node3D#id},
|
|
296
|
+
* parent, children), and anything a registry gave the original: a copy is a second emitter, not
|
|
297
|
+
* a second reference to the first one's table row.
|
|
298
|
+
*
|
|
299
|
+
* @param {ParticleEmitter} other
|
|
300
|
+
*/
|
|
301
|
+
copy(other) {
|
|
302
|
+
super.copy(other);
|
|
303
|
+
|
|
304
|
+
this.name = other.name;
|
|
305
|
+
|
|
306
|
+
this.layout = other.layout;
|
|
307
|
+
this.program = other.program;
|
|
308
|
+
this.texture = other.texture;
|
|
309
|
+
|
|
310
|
+
this.seed = other.seed;
|
|
311
|
+
this.spawn_rate = other.spawn_rate;
|
|
312
|
+
this.prewarm = other.prewarm;
|
|
313
|
+
this.flags = other.flags;
|
|
314
|
+
|
|
315
|
+
this.flipbook.set(other.flipbook);
|
|
316
|
+
|
|
317
|
+
this.render_position = other.render_position;
|
|
318
|
+
this.render_size = other.render_size;
|
|
319
|
+
this.render_color = other.render_color;
|
|
320
|
+
this.render_rotation = other.render_rotation;
|
|
321
|
+
this.render_frame = other.render_frame;
|
|
322
|
+
this.render_velocity = other.render_velocity;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* A second emitter equal to this one, and registered with nothing. Its subtree is cloned the
|
|
327
|
+
* way {@link Node3D#clone} clones one — overridden only because the base builds a plain
|
|
328
|
+
* `Node3D`, which would keep the transform and drop the effect.
|
|
329
|
+
*
|
|
330
|
+
* @returns {ParticleEmitter}
|
|
331
|
+
*/
|
|
332
|
+
clone() {
|
|
333
|
+
const r = new ParticleEmitter();
|
|
334
|
+
|
|
335
|
+
r.copy(this);
|
|
336
|
+
|
|
337
|
+
for (const child of this.children) {
|
|
338
|
+
const clone = child.clone();
|
|
339
|
+
|
|
340
|
+
clone.parent = r;
|
|
341
|
+
|
|
342
|
+
r.children.push(clone);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return r;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Build an emitter from a plain description. Every parameter is optional except the compiled
|
|
350
|
+
* effect — an emitter with no program has nothing to run.
|
|
351
|
+
*
|
|
352
|
+
* `layout` and `program` are the two halves of what {@link ./create_particle_effect.js} returns,
|
|
353
|
+
* so an effect goes in by spreading it: `ParticleEmitter.from({ ...effect, spawn_rate: 100 })`.
|
|
354
|
+
*
|
|
355
|
+
* @param {object} config
|
|
356
|
+
* @param {import("../layout/ParticleLayout.js").ParticleLayout} config.layout per-particle
|
|
357
|
+
* attribute schema
|
|
358
|
+
* @param {import("../isa/ParticleProgram.js").ParticleProgram} config.program compiled INIT /
|
|
359
|
+
* UPDATE bytecode
|
|
360
|
+
* @param {ArrayLike<number>} [config.position] local translation, `[x, y, z]`
|
|
361
|
+
* @param {string|null} [config.texture] image URL to draw with
|
|
362
|
+
* @param {number} [config.seed]
|
|
363
|
+
* @param {number} [config.spawn_rate] particles/second
|
|
364
|
+
* @param {number} [config.prewarm] seconds of emission to run forward before the first frame
|
|
365
|
+
* @param {object} [config.flags] passed to {@link make_emitter_flags}
|
|
366
|
+
* @param {Object<string,string>} [config.render] render channel -> attribute name
|
|
367
|
+
* @param {ArrayLike<number>} [config.flipbook] [cols, rows]
|
|
368
|
+
* @param {string} [config.name]
|
|
369
|
+
* @returns {ParticleEmitter}
|
|
370
|
+
*/
|
|
371
|
+
static from(config) {
|
|
372
|
+
assert.isObject(config, 'config');
|
|
373
|
+
assert.defined(config.layout, 'config.layout');
|
|
374
|
+
assert.defined(config.program, 'config.program');
|
|
375
|
+
|
|
376
|
+
const emitter = new ParticleEmitter();
|
|
377
|
+
|
|
378
|
+
emitter.layout = config.layout;
|
|
379
|
+
emitter.program = config.program;
|
|
380
|
+
|
|
381
|
+
if (config.name !== undefined) {
|
|
382
|
+
emitter.name = config.name;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (config.texture !== undefined) {
|
|
386
|
+
emitter.texture = config.texture;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (config.position !== undefined) {
|
|
390
|
+
emitter.transform_local.setTranslation(config.position[0], config.position[1], config.position[2]);
|
|
391
|
+
emitter.updateMatrices();
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (config.seed !== undefined) {
|
|
395
|
+
emitter.seed = config.seed;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (config.spawn_rate !== undefined) {
|
|
399
|
+
emitter.spawn_rate = config.spawn_rate;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (config.prewarm !== undefined) {
|
|
403
|
+
emitter.prewarm = config.prewarm;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
emitter.flags = make_emitter_flags(config.flags ?? {});
|
|
407
|
+
|
|
408
|
+
if (config.flipbook !== undefined) {
|
|
409
|
+
emitter.flipbook.set(config.flipbook);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (config.render !== undefined) {
|
|
413
|
+
emitter.bind_render(config.render);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return emitter;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* @readonly
|
|
422
|
+
* @type {boolean}
|
|
423
|
+
*/
|
|
424
|
+
ParticleEmitter.prototype.isParticleEmitter = true;
|