@woosh/meep-engine 3.58.0 → 3.59.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/particles/effect/ParticleEffectDocument.d.ts +162 -43
- package/editor/particles/effect/ParticleEffectDocument.d.ts.map +1 -1
- package/editor/particles/effect/ParticleEffectDocument.js +450 -43
- package/editor/particles/effect/ParticleReferenceSimulation.d.ts +12 -3
- package/editor/particles/effect/ParticleReferenceSimulation.d.ts.map +1 -1
- package/editor/particles/effect/ParticleReferenceSimulation.js +78 -23
- package/editor/particles/effect/make_starter_particle_effect.js +17 -17
- package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts +3 -3
- package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleEmitterInspectorView.js +224 -67
- package/editor/view/particles/effect/ParticleGraphEditorView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleGraphEditorView.js +44 -11
- package/editor/view/particles/effect/ParticleNodeParametersView.d.ts +2 -1
- package/editor/view/particles/effect/ParticleNodeParametersView.d.ts.map +1 -1
- package/editor/view/particles/effect/ParticleNodeParametersView.js +46 -16
- package/editor/view/particles/effect/ParticlePreviewView.js +2 -2
- package/editor/view/particles/effect/particle-editor.css +77 -68
- package/package.json +1 -1
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +2 -2
- package/src/engine/ecs/EntityManager.d.ts +29 -5
- package/src/engine/ecs/EntityManager.d.ts.map +1 -1
- package/src/engine/ecs/EntityManager.js +37 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +4 -0
- package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts +74 -17
- package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts.map +1 -1
- package/src/engine/graphics/ecs/particles/ParticleEffect.js +156 -25
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.d.ts +13 -3
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.js +59 -13
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_1_2.d.ts +3 -3
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_1_2.js +9 -9
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_2_3.d.ts +15 -0
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_2_3.d.ts.map +1 -0
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_2_3.js +78 -0
- package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts +2 -0
- package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts.map +1 -1
- package/src/engine/graphics/ecs/trail3d/Trail3D.js +2 -0
- package/src/engine/graphics/ecs/trail3d/seed_trail_stroke.js +1 -1
- package/src/engine/graphics/ecs/trail3d/seed_trail_tube.js +1 -1
- package/src/engine/graphics/trail/tube/TubeX.d.ts +5 -3
- package/src/engine/graphics/trail/tube/TubeX.d.ts.map +1 -1
- package/src/engine/graphics/trail/tube/TubeX.js +5 -3
- package/src/engine/graphics/trail/tube/tube_attributes_spec.d.ts +3 -2
- package/src/engine/graphics/trail/tube/tube_attributes_spec.d.ts.map +1 -1
- package/src/engine/graphics/trail/tube/tube_attributes_spec.js +9 -8
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +65 -4
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/GPUParticleEmitterSystem.js +1351 -904
- package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts +1 -1
- package/src/engine/graphics3/trail/trail_tube_write_geometry.js +13 -13
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/generation/foliage/FOLIAGE_DESIGN.md +26 -5
- package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +35 -0
- package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +2 -1
- package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +552 -0
- package/src/generation/foliage/analysis/tree_crown_opacity.d.ts.map +1 -1
- package/src/generation/foliage/analysis/tree_crown_opacity.js +2 -1
- package/src/generation/foliage/analysis/tree_render_cost.d.ts +5 -3
- package/src/generation/foliage/analysis/tree_render_cost.d.ts.map +1 -1
- package/src/generation/foliage/analysis/tree_render_cost.js +8 -7
- package/src/generation/foliage/asset/TreeAsset.d.ts +17 -0
- package/src/generation/foliage/asset/TreeAsset.d.ts.map +1 -1
- package/src/generation/foliage/asset/TreeAsset.js +20 -0
- package/src/generation/foliage/asset/TreeSpeciesCache.d.ts +69 -0
- package/src/generation/foliage/asset/TreeSpeciesCache.d.ts.map +1 -0
- package/src/generation/foliage/asset/TreeSpeciesCache.js +147 -0
- package/src/generation/foliage/asset/generate_tree.d.ts +10 -0
- package/src/generation/foliage/asset/generate_tree.d.ts.map +1 -1
- package/src/generation/foliage/asset/generate_tree.js +57 -29
- package/src/generation/foliage/asset/place_tree.d.ts +2 -1
- package/src/generation/foliage/asset/place_tree.d.ts.map +1 -1
- package/src/generation/foliage/asset/place_tree.js +2 -1
- package/src/generation/foliage/asset/tree_lod_plan.d.ts +4 -2
- package/src/generation/foliage/asset/tree_lod_plan.d.ts.map +1 -1
- package/src/generation/foliage/asset/tree_lod_plan.js +12 -14
- package/src/generation/foliage/asset/tree_shoot_instances.d.ts +119 -0
- package/src/generation/foliage/asset/tree_shoot_instances.d.ts.map +1 -0
- package/src/generation/foliage/asset/tree_shoot_instances.js +410 -0
- package/src/generation/foliage/asset/tree_shoot_prototypes.d.ts +155 -0
- package/src/generation/foliage/asset/tree_shoot_prototypes.d.ts.map +1 -0
- package/src/generation/foliage/asset/tree_shoot_prototypes.js +251 -0
- package/src/generation/foliage/config/TreeGrowth.d.ts +10 -0
- package/src/generation/foliage/config/TreeGrowth.d.ts.map +1 -0
- package/src/generation/foliage/config/TreeGrowth.js +18 -0
- package/src/generation/foliage/config/TreeLODConfig.d.ts +6 -0
- package/src/generation/foliage/config/TreeLODConfig.d.ts.map +1 -1
- package/src/generation/foliage/config/TreeLODConfig.js +7 -0
- package/src/generation/foliage/index.d.ts +3 -0
- package/src/generation/foliage/index.js +3 -0
- package/src/generation/foliage/material/foliage_tile.d.ts +6 -6
- package/src/generation/foliage/material/foliage_tile.js +3 -3
- package/src/generation/foliage/material/tree_cluster_atlas.d.ts +44 -0
- package/src/generation/foliage/material/tree_cluster_atlas.d.ts.map +1 -0
- package/src/generation/foliage/material/tree_cluster_atlas.js +37 -0
- package/src/generation/foliage/mesh/foliage_collect_attachments.js +2 -2
- package/src/generation/foliage/mesh/foliage_scale_spread.d.ts +14 -0
- package/src/generation/foliage/mesh/foliage_scale_spread.d.ts.map +1 -0
- package/src/generation/foliage/mesh/foliage_scale_spread.js +15 -0
- package/src/generation/foliage/mesh/tree_cluster_representatives.d.ts +8 -7
- package/src/generation/foliage/mesh/tree_cluster_representatives.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_cluster_representatives.js +85 -40
- package/src/generation/foliage/mesh/tree_clusters.d.ts +26 -5
- package/src/generation/foliage/mesh/tree_clusters.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_clusters.js +52 -39
- package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_mesh_build_bark.js +32 -54
- package/src/generation/foliage/presets/make_tree_species_preset.d.ts +6 -1
- package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
- package/src/generation/foliage/presets/make_tree_species_preset.js +157 -3
- package/src/generation/foliage/skeleton/TreeSkeleton.d.ts +19 -0
- package/src/generation/foliage/skeleton/TreeSkeleton.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/TreeSkeleton.js +41 -0
- package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts +5 -0
- package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js +8 -1
- package/src/generation/foliage/skeleton/tree_skeleton_copy_branches.d.ts +70 -0
- package/src/generation/foliage/skeleton/tree_skeleton_copy_branches.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/tree_skeleton_copy_branches.js +171 -0
- package/src/generation/foliage/skeleton/tree_skeleton_extend_branch.d.ts +17 -0
- package/src/generation/foliage/skeleton/tree_skeleton_extend_branch.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/tree_skeleton_extend_branch.js +79 -0
- package/src/generation/foliage/skeleton/tree_skeleton_fit_crown_frame.d.ts +12 -0
- package/src/generation/foliage/skeleton/tree_skeleton_fit_crown_frame.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/tree_skeleton_fit_crown_frame.js +56 -0
- package/src/generation/foliage/skeleton/tree_skeleton_floor_girth.d.ts +11 -0
- package/src/generation/foliage/skeleton/tree_skeleton_floor_girth.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/tree_skeleton_floor_girth.js +38 -0
- package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts +4 -11
- package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/tree_skeleton_grow.js +8 -2034
- package/src/generation/foliage/skeleton/tree_skeleton_grow_framework.d.ts +22 -0
- package/src/generation/foliage/skeleton/tree_skeleton_grow_framework.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/tree_skeleton_grow_framework.js +2050 -0
- package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts +10 -0
- package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.js +27 -56
- package/src/shade/descriptor/pipeline/render/DepthStencilState.d.ts +4 -0
- package/src/shade/descriptor/pipeline/render/DepthStencilState.d.ts.map +1 -1
- package/src/shade/descriptor/pipeline/render/DepthStencilState.js +170 -144
- package/src/shade/descriptor/pipeline/render/MultisampleState.d.ts +4 -0
- package/src/shade/descriptor/pipeline/render/MultisampleState.d.ts.map +1 -1
- package/src/shade/descriptor/pipeline/render/MultisampleState.js +78 -65
- package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.d.ts.map +1 -1
- package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.js +176 -172
- package/src/shade/descriptor/pipeline/render/StencilFaceState.d.ts +4 -0
- package/src/shade/descriptor/pipeline/render/StencilFaceState.d.ts.map +1 -1
- package/src/shade/descriptor/pipeline/render/StencilFaceState.js +107 -88
- package/src/shade/playground/particle_ecs/README.md +9 -8
- package/src/shade/playground/particle_ecs/bonfire_editor.js +3 -3
- package/src/shade/playground/particle_ecs/bonfire_effects.d.ts +6 -6
- package/src/shade/playground/particle_ecs/bonfire_effects.js +6 -6
- package/src/shade/playground/particle_editor/README.md +14 -11
- package/src/shade/playground/particle_system/particle_prototype.js +18 -18
- package/src/shade/playground/particle_system/particle_scene.js +13 -13
- package/src/shade/playground/probe_clipmap/README.md +42 -0
- package/src/shade/playground/probe_clipmap/index.html +178 -0
- package/src/shade/playground/probe_clipmap/main.d.ts +8 -0
- package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -0
- package/src/shade/playground/probe_clipmap/main.js +360 -0
- package/src/shade/renderer/Renderer.d.ts +3 -1
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +94 -38
- package/src/shade/renderer/extension/ViewTextures.d.ts +2 -1
- package/src/shade/renderer/extension/ViewTextures.d.ts.map +1 -1
- package/src/shade/renderer/extension/ViewTextures.js +2 -1
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
- package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +34 -12
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +56 -15
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +2 -2
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +13 -26
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +25 -2
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +54 -32
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_VERDICT.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_VERDICT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_VERDICT.js +37 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.js +16 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.js +2 -6
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_descent.d.ts +131 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_descent.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_descent.js +467 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_instance.d.ts +24 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_instance.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_instance.js +111 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_rule.d.ts +42 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_rule.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_rule.js +404 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_stat.d.ts +16 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_stat.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_stat.js +23 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_want.d.ts +17 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_want.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_want.js +65 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +14 -70
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +13 -773
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_cut_descent.d.ts +55 -0
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_cut_descent.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_cut_descent.js +248 -0
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +15 -174
- package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_probe_meta_pick2.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_probe_meta_pick2.js +8 -24
- package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_sample_forward_indirect.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_sample_forward_indirect.js +1 -25
- package/src/shade/renderer/global_illumination/lpv/deprecated/chunk_lpv_get_visibility_mask.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/lpv/deprecated/chunk_lpv_get_visibility_mask.js +5 -23
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +25 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +126 -8
- package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +832 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.d.ts +7 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.js +8 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts +16 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.js +9 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/{mesh/chunk_mesh_brick_object.d.ts → chunk_brick_object.d.ts} +8 -8
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_object.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_object.js +42 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_provider.d.ts +45 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_provider.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_provider.js +93 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK_INSTANCE_STRUCT.d.ts +0 -7
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK_INSTANCE_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK_INSTANCE_STRUCT.js +0 -8
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +2 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +5 -8
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_provider.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_provider.js +13 -22
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGEO_BRICK.d.ts +99 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGEO_BRICK.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGEO_BRICK.js +139 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGeoBrickProvider.d.ts +65 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGeoBrickProvider.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGeoBrickProvider.js +393 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_box.d.ts +17 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_box.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_box.js +36 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_pair.d.ts +29 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_pair.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_pair.js +108 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_texel.d.ts +31 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_texel.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_texel.js +113 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_triangle.d.ts +36 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_triangle.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_triangle.js +85 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_distance.d.ts +23 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_distance.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_distance.js +273 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_gather.d.ts +13 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_gather.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_gather.js +151 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_traverse.d.ts +13 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_traverse.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_traverse.js +133 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_wait.d.ts +22 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_wait.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_wait.js +135 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +20 -6
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +152 -10
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +7 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +8 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +14 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +50 -5
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_cage.d.ts +19 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_cage.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_cage.js +40 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts +72 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.js +343 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts +29 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +188 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts +26 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.js +132 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +4 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js +26 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.d.ts +3 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.js +8 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_diffuse.d.ts +12 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_diffuse.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_diffuse.js +101 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.js +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.d.ts +15 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.js +175 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.d.ts +26 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.js +210 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.d.ts +3 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.js +3 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts +2 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +5 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +3 -10
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts +5 -9
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.js +9 -110
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.d.ts +27 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.js +110 -0
- package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.d.ts +13 -0
- package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.d.ts.map +1 -1
- package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.js +40 -0
- package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.d.ts +11 -6
- package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.d.ts.map +1 -1
- package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.js +15 -8
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.d.ts +9 -2
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.d.ts.map +1 -1
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.js +25 -11
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/particles/DESIGN.md +151 -42
- package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +283 -0
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts +10 -2
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +46 -8
- package/src/shade/renderer/particles/ParticleConstants.d.ts +23 -6
- package/src/shade/renderer/particles/ParticleConstants.d.ts.map +1 -1
- package/src/shade/renderer/particles/ParticleConstants.js +25 -6
- package/src/shade/renderer/particles/bounds/chunk_particle_bounds.js +5 -5
- package/src/shade/renderer/particles/bounds/shader_particle_bounds.js +187 -187
- package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.d.ts +20 -9
- package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.js +36 -10
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts +8 -7
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js +25 -16
- package/src/shade/renderer/particles/data/PARTICLE_FIELD_BINDING.d.ts +51 -0
- package/src/shade/renderer/particles/data/PARTICLE_FIELD_BINDING.d.ts.map +1 -0
- package/src/shade/renderer/particles/data/PARTICLE_FIELD_BINDING.js +56 -0
- package/src/shade/renderer/particles/data/particle_emitter_record.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/particle_emitter_record.js +2 -0
- package/src/shade/renderer/particles/graph/ParticleGroupBuilder.d.ts +1 -1
- package/src/shade/renderer/particles/graph/ParticleGroupBuilder.js +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts +22 -11
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeDescription.js +14 -11
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts +4 -4
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +59 -24
- package/src/shade/renderer/particles/graph/ParticleValueType.d.ts +3 -3
- package/src/shade/renderer/particles/graph/ParticleValueType.js +287 -287
- package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts +13 -6
- package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/compile_particle_graph.js +46 -27
- package/src/shade/renderer/particles/graph/infer_particle_graph_types.d.ts +8 -2
- package/src/shade/renderer/particles/graph/infer_particle_graph_types.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/infer_particle_graph_types.js +240 -234
- package/src/shade/renderer/particles/graph/make_particle_group.d.ts +1 -1
- package/src/shade/renderer/particles/graph/make_particle_group.js +1 -1
- package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts +3 -2
- package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_graph_authoring.js +3 -2
- package/src/shade/renderer/particles/graph/particle_graph_distributions.js +170 -170
- package/src/shade/renderer/particles/graph/particle_graph_json.d.ts +25 -16
- package/src/shade/renderer/particles/graph/particle_graph_json.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_graph_json.js +16 -2
- package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts +29 -15
- package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_node_parameters.js +54 -22
- package/src/shade/renderer/particles/graph/particle_node_presentation.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/particle_node_presentation.js +18 -8
- package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts +9 -2
- package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/validate_particle_graph.js +70 -32
- package/src/shade/renderer/particles/graph_particles.d.ts +9 -4
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +27 -4
- package/src/shade/renderer/particles/isa/InstructionStream.d.ts +7 -6
- package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/InstructionStream.js +17 -16
- package/src/shade/renderer/particles/isa/ParticleAssembler.d.ts +17 -0
- package/src/shade/renderer/particles/isa/ParticleAssembler.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/ParticleAssembler.js +35 -0
- package/src/shade/renderer/particles/isa/ParticleProgram.d.ts +26 -6
- package/src/shade/renderer/particles/isa/ParticleProgram.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/ParticleProgram.js +61 -9
- package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +55 -4
- package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/ParticleVMISA.js +79 -10
- package/src/shade/renderer/particles/isa/particle_assembly.d.ts +20 -6
- package/src/shade/renderer/particles/isa/particle_assembly.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/particle_assembly.js +136 -25
- package/src/shade/renderer/particles/isa/particle_link_global_fields.d.ts +20 -0
- package/src/shade/renderer/particles/isa/particle_link_global_fields.d.ts.map +1 -0
- package/src/shade/renderer/particles/isa/particle_link_global_fields.js +46 -0
- package/src/shade/renderer/particles/isa/validate_particle_program.js +8 -8
- package/src/shade/renderer/particles/layout/ParticleLayout.d.ts +62 -28
- package/src/shade/renderer/particles/layout/ParticleLayout.d.ts.map +1 -1
- package/src/shade/renderer/particles/layout/ParticleLayout.js +102 -62
- package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.js +2 -0
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.js +1 -1
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.js +4 -3
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.js +2 -2
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts +3 -3
- package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.js +11 -11
- package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts +4 -4
- package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/optimize_particle_program.js +5 -4
- package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts +1 -1
- package/src/shade/renderer/particles/optimizer/particle_integer_bounds.js +1 -1
- package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts +4 -4
- package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_program_equivalence.js +13 -11
- package/src/shade/renderer/particles/optimizer/particle_program_fuzz.js +7 -7
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts +3 -2
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +5 -4
- package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_eliminate_dead_code.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_eliminate_dead_code.js +51 -51
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +5 -5
- package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_narrow_widths.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_pack_registers.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_peephole.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_propagate_copies.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_schedule.js +2 -2
- package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.js +5 -4
- package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +93 -22
- package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/EmitterRegistry.js +336 -29
- package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts +43 -3
- package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.js +43 -3
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +56 -26
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/ParticleEmitter.js +89 -33
- package/src/shade/renderer/particles/runtime/ParticleGlobalFields.d.ts +85 -0
- package/src/shade/renderer/particles/runtime/ParticleGlobalFields.d.ts.map +1 -0
- package/src/shade/renderer/particles/runtime/ParticleGlobalFields.js +221 -0
- package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts +143 -18
- package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/ProgramHeap.js +378 -28
- package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts +19 -7
- package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/create_particle_effect.js +22 -9
- package/src/shade/renderer/particles/shaders/chunk_particle_billboard_vertex.js +8 -8
- package/src/shade/renderer/particles/shaders/chunk_particle_render_math.js +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_setup_context.d.ts +3 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_setup_context.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_setup_context.js +4 -0
- package/src/shade/renderer/particles/shaders/shader_particle_field_bind.d.ts +30 -0
- package/src/shade/renderer/particles/shaders/shader_particle_field_bind.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/shader_particle_field_bind.js +121 -0
- package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.js +3 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +12 -4
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.js +48 -11
- package/src/shade/renderer/particles/vm/chunk_particle_vm.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/chunk_particle_vm.js +36 -14
- 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/gtao/GTAO.d.ts +31 -19
- package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/GTAO.js +44 -30
- package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +16 -2
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/postprocess/nss/NSS.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/NSS.js +4 -3
- package/src/shade/renderer/postprocess/ssr/SSR.d.ts +7 -1
- package/src/shade/renderer/postprocess/ssr/SSR.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/SSR.js +16 -0
- package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_add_hit_irradiance.d.ts +20 -2
- package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_add_hit_irradiance.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_add_hit_irradiance.js +53 -3
- package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_sample_radiance.d.ts +10 -2
- package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_sample_radiance.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_sample_radiance.js +31 -3
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.js +17 -11
- package/src/shade/renderer/postprocess/taa/TAA.d.ts +4 -2
- package/src/shade/renderer/postprocess/taa/TAA.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/taa/TAA.js +6 -1
- package/src/shade/renderer/postprocess/taa/chunk_fsr2_compute_depth_clip.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/taa/chunk_fsr2_compute_depth_clip.js +10 -5
- package/src/shade/renderer/postprocess/taa/shader_taa.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/taa/shader_taa.js +15 -12
- package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.js +26 -17
- package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect.d.ts +4 -3
- package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect.js +6 -4
- package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.d.ts +12 -0
- package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.js +57 -0
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +4 -2
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +4 -2
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts +8 -2
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +28 -15
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw.d.ts +2 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw.js +19 -3
- package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.js +4 -2
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts +3 -1
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +27 -14
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.d.ts +2 -1
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.js +19 -3
- package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_bounds.d.ts +2 -8
- package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_bounds.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_bounds.js +25 -52
- package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_positions.d.ts +15 -0
- package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_positions.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_positions.js +52 -0
- package/src/shade/renderer/shader/chunk/geometry/triangle/TRIANGLE_POSITIONS_STRUCT.d.ts +7 -0
- package/src/shade/renderer/shader/chunk/geometry/triangle/TRIANGLE_POSITIONS_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/triangle/TRIANGLE_POSITIONS_STRUCT.js +12 -0
- package/src/shade/renderer/shader/chunk/grid/chunk_index_to_grid2d_reciprocal.d.ts +22 -0
- package/src/shade/renderer/shader/chunk/grid/chunk_index_to_grid2d_reciprocal.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/grid/chunk_index_to_grid2d_reciprocal.js +37 -0
- package/src/shade/renderer/shader/chunk/light/lpv/depth/chunk_lpv_mask_weights_by_visibility.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/light/lpv/depth/chunk_lpv_mask_weights_by_visibility.js +26 -60
- package/src/shade/renderer/shader/chunk/light/probe/chunk_probe_visibility_weight.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/light/probe/chunk_probe_visibility_weight.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/light/probe/chunk_probe_visibility_weight.js +54 -0
- package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.d.ts +25 -0
- package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.js +43 -0
- package/src/shade/renderer/shader/chunk/random/chunk_jitter_from_vectors.d.ts +14 -0
- package/src/shade/renderer/shader/chunk/random/chunk_jitter_from_vectors.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/random/chunk_jitter_from_vectors.js +37 -0
- package/src/shade/renderer/shader/chunk/random/reservoir/chunk_pick2_wrs_mat2x4.d.ts +27 -0
- package/src/shade/renderer/shader/chunk/random/reservoir/chunk_pick2_wrs_mat2x4.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/random/reservoir/chunk_pick2_wrs_mat2x4.js +61 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/chunk_resolve_irradiance_sh_to_specular.d.ts +21 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/chunk_resolve_irradiance_sh_to_specular.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/chunk_resolve_irradiance_sh_to_specular.js +41 -0
- package/src/shade/renderer/texture/util/texture_fill_rectangle.d.ts.map +1 -1
- package/src/shade/renderer/texture/util/texture_fill_rectangle.js +282 -267
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +8 -4
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +36 -36
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts +6 -1
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.js +498 -484
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts +15 -2
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.js +57 -3
- package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.js +197 -191
- package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +4 -4
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts +2 -1
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
- package/src/shade/renderer/water/GPUWaterRenderer.js +5 -1
- package/src/shade/renderer/water/chunk_water_gi.d.ts +13 -3
- package/src/shade/renderer/water/chunk_water_gi.d.ts.map +1 -1
- package/src/shade/renderer/water/chunk_water_gi.js +47 -5
- package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
- package/src/shade/renderer/water/shader_water.d.ts +3 -2
- package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
- package/src/shade/renderer/water/shader_water.js +9 -3
- package/src/shade/renderer/geometry/sdf/SDF_BUILD_SETTINGS_STRUCT.d.ts +0 -3
- package/src/shade/renderer/geometry/sdf/SDF_BUILD_SETTINGS_STRUCT.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/SFD_BUILD_WORKGROUP_SIZE.d.ts +0 -2
- package/src/shade/renderer/geometry/sdf/SFD_BUILD_WORKGROUP_SIZE.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/chunk_blas_query_sdf.d.ts +0 -8
- package/src/shade/renderer/geometry/sdf/chunk_blas_query_sdf.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/chunk_blas_query_volume_sign.d.ts +0 -3
- package/src/shade/renderer/geometry/sdf/chunk_blas_query_volume_sign.d.ts.map +0 -1
- package/src/shade/renderer/geometry/sdf/shader_build_sdf.d.ts +0 -3
- package/src/shade/renderer/geometry/sdf/shader_build_sdf.d.ts.map +0 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_object.d.ts.map +0 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_object.js +0 -42
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts +0 -31
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/VSMMoverTracker.d.ts +0 -42
- package/src/shade/renderer/shadow/vsm/VSMMoverTracker.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.d.ts +0 -54
- package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.d.ts +0 -14
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.d.ts +0 -30
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.d.ts +0 -23
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.d.ts.map +0 -1
|
@@ -36,12 +36,13 @@ authoring: NodeGraph (nodes+ports) ──compile──▶ Program (bytec
|
|
|
36
36
|
standard node library │
|
|
37
37
|
▼
|
|
38
38
|
runtime CPU: ParticleEmitter (at an entity) ── Scene ──▶ GPUSceneContext (transforms table)
|
|
39
|
-
EmitterRegistry ── GPUDatabase(emitters + emitter_state) ─┤ ProgramHeap ([header][constants][code])
|
|
39
|
+
EmitterRegistry ── GPUDatabase(emitters + emitter_state + field_bindings) ─┤ ProgramHeap ([header][constants][code][fields])
|
|
40
40
|
GPUParticleSystem (owns every buffer, records the frame)
|
|
41
41
|
▼
|
|
42
42
|
runtime GPU: particle pool (array<u32>, uniform stride) + alive/dead lists + counters
|
|
43
43
|
emitter state table (GPU-owned: generation, accumulator, age, sleep, pending)
|
|
44
|
-
┌─
|
|
44
|
+
┌─ field bind (per binding row: a bound transform → its field; only while rows exist)
|
|
45
|
+
├─ spawn commands (CPU bursts → pending)
|
|
45
46
|
├─ emitter tick (per row: cull on the published box, integrate rate, take budget → count)
|
|
46
47
|
├─ scan (csdldf) → emit dispatch
|
|
47
48
|
├─ emit (VM INIT program) ── per newborn: find emitter in scan, pop dead → init → append alive_new
|
|
@@ -56,13 +57,113 @@ runtime GPU: particle pool (array<u32>, uniform stride) + alive/dead lists + cou
|
|
|
56
57
|
└─ draw (instanced billboard quads → the four accumulators)
|
|
57
58
|
```
|
|
58
59
|
|
|
60
|
+
### Vocabulary: fields
|
|
61
|
+
|
|
62
|
+
State is a set of **fields**, named and laid out by a `ParticleLayout`, one kind per scope:
|
|
63
|
+
`particle_field`s live in a particle's pool record, `emitter_field`s in its emitter's block and
|
|
64
|
+
`global_field`s in the system's shared section. Particle fields were once called attributes, and
|
|
65
|
+
saves under that name still load: graph node types `attribute` and `setAttribute`
|
|
66
|
+
(`PARTICLE_NODE_TYPE_RENAMES`), a document's `attributes` key, and the assembly mnemonics `LOAD_ATTR`
|
|
67
|
+
and `STORE_ATTR`. The binary effect format never wrote the word.
|
|
68
|
+
|
|
69
|
+
### Emitter fields
|
|
70
|
+
|
|
71
|
+
The program is a class and an emitter an instance of it. An effect declares **emitter fields** — an
|
|
72
|
+
`emitter_layout`, a `ParticleLayout.emitter` packed from word zero with no fixed size — and every
|
|
73
|
+
emitter of it carries its own values for them (`emitter_fields`, f32 bit patterns). Two emitters of
|
|
74
|
+
one effect that differ only there share one program, one heap placement and one simulation bucket.
|
|
75
|
+
|
|
76
|
+
- **Storage.** The packed program buffer's fourth section, after the code:
|
|
77
|
+
`[header][constants][code][fields]`, header word `PARTICLE_PROGRAM_FIELD_BASE_WORD` saying where it
|
|
78
|
+
starts. The section opens with `PARTICLE_GLOBAL_FIELD_WORDS` reserved for global fields; each
|
|
79
|
+
emitter's block is an allocation of the same `OffsetAllocator` kind the other sections use, held
|
|
80
|
+
by its context as a `FieldBlock` and moved in place by a repack, which moves `placement_version`
|
|
81
|
+
because the record carries the block's offset (`field_offset`). The fields share the program
|
|
82
|
+
buffer's binding.
|
|
83
|
+
- **Reading.** The engine's builtins are the emitter's members as the engine declares them, and an
|
|
84
|
+
effect's emitter fields are the members it declares, so they are read through the same
|
|
85
|
+
instruction: a `LOAD_BUILTIN` id from `VM_BUILTIN_EMITTER_FIELD_BASE` up reads the
|
|
86
|
+
instruction's width in words from the emitter's block, as `LOAD_CONST` reads the pool.
|
|
87
|
+
`vm_ctx.emitter_field_offset` is set beside `emitter_position` by `particle_setup_context`,
|
|
88
|
+
so emit, simulate and the warm-up all have it. The offset is per lane, as the emitter's position
|
|
89
|
+
is: a simulate wave is one program, not one emitter, so the read is a vector load where
|
|
90
|
+
`LOAD_CONST`'s is scalar. The plan's Outcome has what that costs.
|
|
91
|
+
- **Writing.** The CPU's: gameplay writes the component's values in place, `apply_particle_effect`
|
|
92
|
+
finds the change by comparison and copies it to the emitter, and the registry writes the block
|
|
93
|
+
when it restages the row. The heap tracks the changed span, and `GPUParticleSystem` writes that
|
|
94
|
+
span into the existing buffer rather than rebuilding it.
|
|
95
|
+
- **Authoring.** `ParticleEffectDocument.emitter_fields` declares them with the value an emitter
|
|
96
|
+
starts from; the `emitterField` node reads one. `ParticleEffect` serializes them at version 3.
|
|
97
|
+
|
|
98
|
+
### Global fields
|
|
99
|
+
|
|
100
|
+
The system's static members, read by every effect by name — `TIME` and `DELTA_TIME` are the
|
|
101
|
+
engine's, a gust strength or the player's position a game's.
|
|
102
|
+
|
|
103
|
+
- **Layout.** `ParticleGlobalFields`, owned by the heap: the union of what is loaded, append-only,
|
|
104
|
+
in the `PARTICLE_GLOBAL_FIELD_WORDS` reserved at the start of the field section, so a global field
|
|
105
|
+
is addressed from zero and never moves. A program placing a name the system does not have
|
|
106
|
+
declares it, zero-filled; a game may declare names first. A name is one field: a later reader may
|
|
107
|
+
not want more components than it was declared with.
|
|
108
|
+
- **Refusal.** A program whose imports the layout cannot take is refused before anything is claimed
|
|
109
|
+
for it (`ParticleGlobalFields.check`): no id, range or declaration is left behind. The registry's
|
|
110
|
+
flush keeps the emitter on the program it had, with that program's emitter layout — its block,
|
|
111
|
+
values and bindings, even when the emitter's layout changed along with the refused program — and
|
|
112
|
+
does not offer the refused one again until it changes; `GPUParticleEmitterSystem` does the same for an effect it cannot register, and for a
|
|
113
|
+
global value set at a width the layout refuses, so one bad effect never stops the others.
|
|
114
|
+
- **Linking.** A compiled program cannot know a scene's offsets, so it carries `global_imports`
|
|
115
|
+
(name and width, in the order it first reads them) and its global `LOAD_BUILTIN` ids are import
|
|
116
|
+
indices. `ProgramHeap` rewrites them to offsets as it copies the code into place
|
|
117
|
+
(`particle_link_global_fields`); the program it is keyed by stays unlinked, so deduplication
|
|
118
|
+
holds. Assembly carries imports as `.global name n`; the optimizers carry them through.
|
|
119
|
+
- **Values.** The CPU's: `GPUParticleSystem.global_fields.set(name, values)` writes words and marks
|
|
120
|
+
the span, which goes out as one `writeBuffer`; nothing is restaged and no program changes. For a
|
|
121
|
+
game, `GPUParticleEmitterSystem.set_global_field(name, values)` holds the value until a particle
|
|
122
|
+
system exists and hands it over again to a replacement one. A global nobody has set reads 0.
|
|
123
|
+
- **Authoring.** `ParticleEffectDocument.global_fields` declares the imports with the value the
|
|
124
|
+
preview gives them; the `globalField` node reads one; the preview links its own copy of the
|
|
125
|
+
program to its own layout.
|
|
126
|
+
|
|
127
|
+
### Transform bindings
|
|
128
|
+
|
|
129
|
+
A field — an emitter's or a global one — can be bound to a row of the scene's `transforms` table,
|
|
130
|
+
and the GPU writes that row's composed `global` into it every frame: a beam's far end, a homing
|
|
131
|
+
target, a joint the CPU never sees.
|
|
132
|
+
|
|
133
|
+
- **Table.** `field_bindings`, the particle database's third table (CPU-staged): `source` (a
|
|
134
|
+
non-owning link to `transforms`, as the emitter's `node` is), `word` (from the field section's
|
|
135
|
+
base) and `channel` — `POSITION`, `DIRECTION`, `UP` (three words, computed as the emitter's
|
|
136
|
+
builtins of the same names are) or `ORIENTATION` (a quaternion, scale divided out). A field is
|
|
137
|
+
bound only to a channel exactly as wide as it.
|
|
138
|
+
- **Pass.** `shader_particle_field_bind`: one thread per binding row, a page group per workgroup,
|
|
139
|
+
after the counter reset and before the emitter tick, so every VM pass reads this frame's
|
|
140
|
+
transforms. The program buffer is bound read-write in this pass only. Recorded only while the
|
|
141
|
+
table has rows.
|
|
142
|
+
- **Authority.** A bound word is rewritten from scratch every frame, so a span upload or a buffer
|
|
143
|
+
rebuild landing on it is overwritten before anything reads it. Unbinding hands the word
|
|
144
|
+
back to its own value — the emitter's, or the global's last set value or zero — which goes out
|
|
145
|
+
with the next upload.
|
|
146
|
+
- **Mirrors.** A mirrored transform is a reflection, which no quaternion is: `ORIENTATION` takes the
|
|
147
|
+
mirror out of the x axis and writes the rotation that is left.
|
|
148
|
+
- **Bookkeeping.** `EmitterRegistry.bind_emitter_field` / `bind_global_field` and their unbinds. An
|
|
149
|
+
emitter's bindings are restaged with it, because the word they write is its block's offset plus
|
|
150
|
+
the field's, and the block moves; one whose field the layout no longer has is dropped, and they
|
|
151
|
+
go with the emitter.
|
|
152
|
+
- **ECS.** `ParticleEffect.bindings` (`{field, entity, channel}`) and
|
|
153
|
+
`GPUParticleEmitterSystem.bind_global_field`: entity references, resolved with `row_of_entity`,
|
|
154
|
+
the row held through the scene's rows while bound. Runtime data and not saved: nothing in the
|
|
155
|
+
engine's saves carries an entity reference across a load. A target is let go on its own
|
|
156
|
+
`EntityRemoved`, before the entity is gone; a request the registry refuses — or that names an
|
|
157
|
+
entity with no `Transform64` — is remembered and not retried until it, or the emitter's layout,
|
|
158
|
+
changes; one field asked for twice is bound to the first request.
|
|
159
|
+
|
|
59
160
|
### Particle storage — single shared pool, uniform stride
|
|
60
161
|
|
|
61
162
|
All particles live in one `array<u32>` pool with a fixed `RECORD_WORDS` stride (config, default 32
|
|
62
163
|
words = 128 B). Word 0 is a reserved header holding the owning **emitter row** and that row's
|
|
63
|
-
**generation** (`data/particle_header.js`);
|
|
64
|
-
pool + single alive/dead lists means **one** emit dispatch and **one** simulate dispatch
|
|
65
|
-
emitter — the Destiny single-shader property.
|
|
164
|
+
**generation** (`data/particle_header.js`); particle fields occupy words `1..RECORD_WORDS`. A
|
|
165
|
+
single pool + single alive/dead lists means **one** emit dispatch and **one** simulate dispatch
|
|
166
|
+
cover every emitter — the Destiny single-shader property.
|
|
66
167
|
|
|
67
168
|
Lifecycle uses the canonical GPU dead-list / alive-list pair:
|
|
68
169
|
- `dead_list`: stack of free slot indices (+ atomic count). Filled `dead[i] = i` at construction by
|
|
@@ -148,10 +249,10 @@ writes, as it runs an emitter's clock forward (see **Pre-warm**).
|
|
|
148
249
|
### Eight storage buffers
|
|
149
250
|
|
|
150
251
|
A compute stage gets eight storage buffers by default, and the design does not ask for more. Two
|
|
151
|
-
things keep every pass under it: the emitter record
|
|
152
|
-
database buffer, read through one binding; and the VM's constants
|
|
153
|
-
`[header][constants][code]`, the header's first
|
|
154
|
-
(`ParticleConstants.PARTICLE_PROGRAM_HEADER_WORDS`). Emit and simulate bind exactly eight; their
|
|
252
|
+
things keep every pass under it: the emitter record, the GPU-owned state and the transform bindings
|
|
253
|
+
are three tables of one database buffer, read through one binding; and the VM's constants, code and
|
|
254
|
+
fields are one packed buffer — `[header][constants][code][fields]`, the header's first two words
|
|
255
|
+
saying where the code and the fields start (`ParticleConstants.PARTICLE_PROGRAM_HEADER_WORDS`). Emit and simulate bind exactly eight; their
|
|
155
256
|
wide-register variants bind nine, which is the one place the system spends past the default and is
|
|
156
257
|
still inside the ten the engine demands of an adapter. `particle_shaders_wgsl_validity.spec` pins
|
|
157
258
|
the count for every pass.
|
|
@@ -180,7 +281,7 @@ recursion, no data-dependent jumps — conditionals are predicated via CMP/SELEC
|
|
|
180
281
|
Word 0 packs the opcode (bits 0..7), the lane count (8..10), each source's `VM_KIND` (two bits per
|
|
181
282
|
slot at 16..21) and the destination slot (24..31). A source word means what its kind says: `REG`
|
|
182
283
|
is a base slot plus a swizzle, `IMM` is an `f32` bit pattern read in every lane, and `NONE` is a
|
|
183
|
-
raw field the opcode reads for itself (
|
|
284
|
+
raw field the opcode reads for itself (particle field word-offset+comp / builtin id /
|
|
184
285
|
pool index).
|
|
185
286
|
- Constant pool: `array<vec4f>` per program, referenced by `LOAD_CONST`.
|
|
186
287
|
- Two entry sections per program: **INIT** and **UPDATE** (offsets in the emitter record). INIT
|
|
@@ -237,14 +338,14 @@ A core `NodeGraph` holds particle nodes (ports + parameters) for INIT and UPDATE
|
|
|
237
338
|
2. lowers each node to VM ops (nodes emit via a small builder that allocates result registers),
|
|
238
339
|
3. linear-scan register allocation with liveness,
|
|
239
340
|
4. interns constants into the pool,
|
|
240
|
-
5. resolves
|
|
241
|
-
6. emits `
|
|
341
|
+
5. resolves particle, emitter and global field references,
|
|
342
|
+
6. emits `ParticleProgram { init, update, constants, register_count, global_imports }`.
|
|
242
343
|
|
|
243
|
-
Standard node library: constants,
|
|
244
|
-
disk/cone), authored curves and RGB/RGBA gradients,
|
|
245
|
-
compare/select, kill-if, and `wind` (a world position
|
|
246
|
-
Curves and gradients expand into graph nodes that
|
|
247
|
-
binding or sampling opcode is needed.
|
|
344
|
+
Standard node library: constants, particle field get/set, emitter and global field get,
|
|
345
|
+
arithmetic/vector/math, random (uniform/sphere/disk/cone), authored curves and RGB/RGBA gradients,
|
|
346
|
+
noise (curl), integrate, gravity, emit-shapes, compare/select, kill-if, and `wind` (a world position
|
|
347
|
+
in, the scene's wind there out: `SAMPLE_WIND`). Curves and gradients expand into graph nodes that
|
|
348
|
+
emit ordinary VM arithmetic; no animation-table binding or sampling opcode is needed.
|
|
248
349
|
|
|
249
350
|
### Emitters run at entities' rows
|
|
250
351
|
|
|
@@ -258,8 +359,9 @@ matrix could not do, since the CPU never sees the matrix of a row the GPU owns.
|
|
|
258
359
|
scene: an emitter is where its owner says it is, and per-frame upkeep is proportional to what
|
|
259
360
|
changed rather than to how many emitters there are.
|
|
260
361
|
|
|
261
|
-
**The emitter knows nothing about the GPU, and nothing about where.** A `ParticleEmitter` is
|
|
262
|
-
|
|
362
|
+
**The emitter knows nothing about the GPU, and nothing about where.** A `ParticleEmitter` is a
|
|
363
|
+
particle field `layout`, a compiled `program`, an `emitter_layout` with this emitter's
|
|
364
|
+
`emitter_fields`, a `texture` URL, and the emission parameters — all of
|
|
263
365
|
it the author's, all of it meaning the same thing with no device present, all of it what a saved
|
|
264
366
|
effect is made of. Everything the system assigns is a `GPUParticleEmitterContext`, held by the
|
|
265
367
|
`EmitterRegistry` against the emitter and reached through `registry.context(emitter)`: the table
|
|
@@ -541,11 +643,11 @@ premultiplied inputs; straight-alpha and additive inputs have alpha scaled befor
|
|
|
541
643
|
|
|
542
644
|
offset = F(mode, camera, velocity) · Q · (corner.x · size, corner.y · size · stretch, 0)
|
|
543
645
|
|
|
544
|
-
- **`Q` is the `orientation` render channel**, a 4-word
|
|
545
|
-
— the only rotation a particle has. It is normalised at the draw, because a program
|
|
546
|
-
spin drifts off unit length and an unnormalised quaternion scales what it turns by
|
|
547
|
-
length. The zero quaternion, which is what
|
|
548
|
-
no branch, and so does an unbound channel.
|
|
646
|
+
- **`Q` is the `orientation` render channel**, a 4-word particle field holding a quaternion (x, y,
|
|
647
|
+
z, w) — the only rotation a particle has. It is normalised at the draw, because a program
|
|
648
|
+
integrating a spin drifts off unit length and an unnormalised quaternion scales what it turns by
|
|
649
|
+
its squared length. The zero quaternion, which is what a particle field nobody wrote holds, reads
|
|
650
|
+
as no turn with no branch, and so does an unbound channel.
|
|
549
651
|
- **`F` is the mode's frame**, a proper rotation whose x and y are the sprite's right and up and whose
|
|
550
652
|
z is the side the mode shows: BILLBOARD the camera's axes; STRETCHED the screen velocity as its up
|
|
551
653
|
and the camera's axes at rest; VERTICAL world +Y as up and a horizontal face toward the eye;
|
|
@@ -566,14 +668,14 @@ written into it could face all of them.
|
|
|
566
668
|
cannot disagree about which way a mode faces. **Bounds do not change**: the basis is a rotation, so no
|
|
567
669
|
corner reaches past `sqrt(2) · size · stretch`, which is what `particle_billboard_radius` already
|
|
568
670
|
states; the bounds pass never reads the channel. **The VM does not change** either: a program writes
|
|
569
|
-
a vec4
|
|
671
|
+
a vec4 particle field like any other, and the node library has what it takes to build one —
|
|
570
672
|
`quatFromAxisAngle`, `quatLookRotation`, `quatRotate`, `quatMultiply`, `quatIntegrate` (exact for a
|
|
571
673
|
constant angular velocity at any step, which the warm-up's stretched ticks need), `sampleRotation`
|
|
572
674
|
(uniform) and `emitterRotation` (the node's own rotation; `EMITTER_DIRECTION` is its -Z).
|
|
573
675
|
|
|
574
|
-
There
|
|
575
|
-
|
|
576
|
-
|
|
676
|
+
There is no scalar roll channel beside it. A version-1 `ParticleEffect`, whose bytecode wrote a roll
|
|
677
|
+
angle there, loads with its orientation unbound. `ORIENTATION_PLAN_2026_10_15.md` has the
|
|
678
|
+
alternatives and why each lost.
|
|
577
679
|
|
|
578
680
|
Additive vs. alpha is never a pipeline switch: the shader emits premultiplied RGB with alpha 0
|
|
579
681
|
(additive) or alpha a (normal), so one setup covers both and the choice stays per particle and
|
|
@@ -645,21 +747,23 @@ new Entity()
|
|
|
645
747
|
```
|
|
646
748
|
|
|
647
749
|
`engine/graphics/ecs/particles/ParticleEffect.js` carries everything a `ParticleEmitter` node carries
|
|
648
|
-
except the placement: the layout and compiled program, the
|
|
649
|
-
|
|
650
|
-
|
|
750
|
+
except the placement: the layout and compiled program, the emitter layout and this entity's emitter
|
|
751
|
+
field values, the texture URL, the rate, `emitting`, the pre-warm, the flags, the render bindings,
|
|
752
|
+
the flipbook grid and the transform `bindings`. Nothing on it depends on a device, which is what
|
|
753
|
+
makes it the unit an editor inspects and a prefab holds.
|
|
651
754
|
|
|
652
|
-
**All of it serializes, the compiled program included** —
|
|
653
|
-
registered in `populateEngineSerializationRegistry`. The instruction set was designed to be a durable
|
|
755
|
+
**All of it serializes, the compiled program included; the transform bindings do not** —
|
|
756
|
+
`ParticleEffectSerializationAdapter`, version 3, registered in `populateEngineSerializationRegistry`. The instruction set was designed to be a durable
|
|
654
757
|
format, so a level carries bytecode the way it carries a mesh's indices and a shipped build needs no
|
|
655
758
|
compiler: authoring is an editor's job and it is not in the runtime. Two things are consequently wire
|
|
656
759
|
format and cannot be renumbered without a version bump and an upgrader — the **opcode numbers** in
|
|
657
|
-
`isa/ParticleVMISA.js`, and the **order of the
|
|
658
|
-
word offsets from that order
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
760
|
+
`isa/ParticleVMISA.js`, and the **order of the fields** in a layout, because a layout assigns its
|
|
761
|
+
word offsets from that order: the record's render bindings are particle field offsets, and saved
|
|
762
|
+
emitter field values are words in emitter layout order. The
|
|
763
|
+
constant pool goes out as `Uint32` bit patterns rather than floats, because that is the form the
|
|
764
|
+
pool is already compared and hashed in (`ParticleProgram#constant_words`): `-0` and `+0` are the
|
|
765
|
+
same number and different constants, and whether a NaN's payload survives a round trip through a JS
|
|
766
|
+
`number` is implementation-defined even though V8 happens to preserve it.
|
|
663
767
|
|
|
664
768
|
The system builds one `ParticleEmitter` per linked entity and owns it — registered with the
|
|
665
769
|
scene's particle system at the entity's row (`row_of_entity`, held through the scene context's
|
|
@@ -672,7 +776,8 @@ the old one. `emitter_of(entity)` hands the emitter out for what an entity refer
|
|
|
672
776
|
queued and drained inside the frame so it works before the first frame has run.
|
|
673
777
|
|
|
674
778
|
Component changes are found by **comparison** rather than announced: once a frame each entity's
|
|
675
|
-
|
|
779
|
+
component values, emitter field values included, are compared against what was last written to its
|
|
780
|
+
emitter, and the emitter is marked dirty
|
|
676
781
|
only where they differ, so a component nobody touched costs a run of integer comparisons and no
|
|
677
782
|
upload. That is what lets gameplay write `effect.spawn_rate = 0` from code that has never heard of
|
|
678
783
|
this system.
|
|
@@ -739,6 +844,7 @@ src/shade/renderer/particles/
|
|
|
739
844
|
isa/ParticleVMISA.js opcode table (single source of truth)
|
|
740
845
|
isa/ParticleProgram.js Program value type + (de)serialization to u32
|
|
741
846
|
isa/ParticleAssembler.js tiny assembler (build programs in tests/library)
|
|
847
|
+
isa/particle_link_global_fields.js global field import indices → section offsets, at placement
|
|
742
848
|
vm/ParticleVMReference.js JS reference executor
|
|
743
849
|
vm/chunk_particle_vm.js WGSL interpreter CodeChunk (parity target)
|
|
744
850
|
vm/chunk_particle_vm_registers_fast.js register file in var<private> — the interpreter that runs
|
|
@@ -750,17 +856,19 @@ src/shade/renderer/particles/
|
|
|
750
856
|
graph/ParticleNodeRegistry.js standard node library (a NodeRegistry)
|
|
751
857
|
graph/particle_graph_authoring.js authoring sugar over core/model/node-graph
|
|
752
858
|
graph/compile_particle_graph.js graph → Program (register alloc, const intern)
|
|
753
|
-
layout/ParticleLayout.js
|
|
859
|
+
layout/ParticleLayout.js particle field schema ↔ record word offsets
|
|
754
860
|
data/PARTICLE_EMITTER_STRUCT.js the emitter row + flag/blend/projection encoding
|
|
755
861
|
data/particle_emitter_record.js emitter + context -> one row of that struct
|
|
756
862
|
data/PARTICLE_EMITTER_STATE.js the GPU-owned per-emitter state row (second table of the database)
|
|
757
863
|
data/PARTICLE_DATABASE_SPEC.js the GPUDatabase schema, and the emitter table's descriptor
|
|
864
|
+
data/PARTICLE_FIELD_BINDING.js a transform binding row (third table of the database) + channels
|
|
758
865
|
data/PARTICLE_COUNTERS.js counter slot indices
|
|
759
866
|
data/particle_header.js record header encoding (row + generation), JS + WGSL
|
|
760
867
|
coherence/particle_program_buckets.js CPU reference for the simulation-order bucketing
|
|
761
868
|
coherence/shader_particle_bucket.js reset / histogram / pad / scatter / fill
|
|
762
869
|
coherence/graph_particle_bucket.js frame-graph wiring, around graph_prefix_scan_csdldf
|
|
763
|
-
runtime/ProgramHeap.js the one packed [header][constants][code] buffer, allocator-backed
|
|
870
|
+
runtime/ProgramHeap.js the one packed [header][constants][code][fields] buffer, allocator-backed
|
|
871
|
+
runtime/ParticleGlobalFields.js the global field layout: append-only, addressed from zero
|
|
764
872
|
runtime/ProgramPlacement.js where one program sits in it — what an emitter record carries
|
|
765
873
|
runtime/ParticleEmitter.js one emitter — authoring data for an effect, with no GPU in it
|
|
766
874
|
runtime/GPUParticleEmitterContext.js what a registry assigns one: row, generation, placement, patch
|
|
@@ -771,6 +879,7 @@ src/shade/renderer/particles/
|
|
|
771
879
|
shaders/shader_particle_emit.js per-newborn INIT, sized by the scan
|
|
772
880
|
shaders/shader_particle_simulate.js per-particle UPDATE + compaction + orphan kill
|
|
773
881
|
shaders/shader_particle_finalize.js reset counters (+ budget) / build indirect args
|
|
882
|
+
shaders/shader_particle_field_bind.js bound transforms → their fields, before the tick
|
|
774
883
|
shaders/chunk_particle_setup_context.js VM builtins from the emitter's node, + the RNG seed
|
|
775
884
|
shaders/chunk_particle_emitter_age.js the tick pass's running age, off the emitter_state table
|
|
776
885
|
shaders/chunk_particle_spawn_budget.js take from the frame's spawn budget; both ticks spend it
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# Particle, emitter and global fields — scope (2026-10-29, revision 4)
|
|
2
|
+
|
|
3
|
+
**Status: landed.** `DESIGN.md` (*Vocabulary: fields*, *Emitter fields*, *Global fields*, *Transform
|
|
4
|
+
bindings*) describes what was built. This is the scope as proposed. The **Outcome** section at the
|
|
5
|
+
end lists where the build departs from it, and the measurements.
|
|
6
|
+
|
|
7
|
+
**The model.** The program is the class and the emitter is an instance.
|
|
8
|
+
- The class declares the fields every instance carries, and the global fields it reads.
|
|
9
|
+
- The instance holds the values.
|
|
10
|
+
- The class's own data — code, the constant pool, its bucket — is never touched by an instance.
|
|
11
|
+
|
|
12
|
+
**Rejected alternatives:**
|
|
13
|
+
- fixed 32-word emitter rows, in favour of general allocation;
|
|
14
|
+
- GPU-integrated emitter state: values are static or set by gameplay, which the GPU cannot see;
|
|
15
|
+
- a copy of the class for every set of instance values.
|
|
16
|
+
|
|
17
|
+
## Vocabulary
|
|
18
|
+
|
|
19
|
+
| scope | term | engine's own members | read by |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| particle | `particle_field` (was "attribute") | none (by design) | `LOAD_PARTICLE_FIELD` / `STORE_PARTICLE_FIELD` |
|
|
22
|
+
| emitter | `emitter_field` | `EMITTER_POSITION`, `_DIRECTION`, `_UP`, `EMITTER_AGE` | `LOAD_BUILTIN` |
|
|
23
|
+
| system | `global_field` | `TIME`, `DELTA_TIME` | `LOAD_BUILTIN` |
|
|
24
|
+
|
|
25
|
+
**What the rename covers.**
|
|
26
|
+
- **Renamed:** `ParticleLayout`'s entries, the `ParticleEffect` / `ParticleEmitter` API, the editor,
|
|
27
|
+
the graph node types (`particleField` / `setParticleField`), and the documentation.
|
|
28
|
+
- **What keeps loading:** the graph JSON keys node types by name, and those names are wire format,
|
|
29
|
+
so `attribute` and `setAttribute` still load as aliases.
|
|
30
|
+
- **Unchanged:** the binary effect format writes a layout's field names, widths and tags, and no
|
|
31
|
+
vocabulary words, so it does not change.
|
|
32
|
+
- **The mnemonics** become `LOAD_PARTICLE_FIELD` / `STORE_PARTICLE_FIELD`, on the opcode numbers they
|
|
33
|
+
already have. `LOAD_ATTR` / `STORE_ATTR` text still parses, the precedent being legacy `SWIZZLE`
|
|
34
|
+
text.
|
|
35
|
+
|
|
36
|
+
## Format
|
|
37
|
+
|
|
38
|
+
- **The class declares its `emitter_field`s as a `ParticleLayout`**: name, width, an optional `type`
|
|
39
|
+
tag, and a default each. It sits on `ParticleProgram` beside the particle layout.
|
|
40
|
+
- Declaration order is wire format, the same rule as for particle fields.
|
|
41
|
+
- **The class declares the `global_field`s it imports**: a name and a width each.
|
|
42
|
+
- **The system's global layout is the union of what it holds.**
|
|
43
|
+
- It is append-only, and capacity only rises.
|
|
44
|
+
- Game code may declare names up front.
|
|
45
|
+
- A global field nobody has set reads 0.
|
|
46
|
+
|
|
47
|
+
## Storage: a third region of `ProgramHeap`'s buffer
|
|
48
|
+
|
|
49
|
+
**`ProgramHeap` already is this.**
|
|
50
|
+
- Its sections are `ProgramRegion`s over flat word arrays, each managed by an `OffsetAllocator`.
|
|
51
|
+
- It packs them into one buffer, `[header][constants][code]`, which every pass running the VM already
|
|
52
|
+
binds.
|
|
53
|
+
- It repacks when a section has no run long enough, and capacities only rise.
|
|
54
|
+
- A repack moves `placement_version`, and that restages every emitter row.
|
|
55
|
+
|
|
56
|
+
The fields are a third region:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
[header][fields: global (reserved) | emitter blocks][constants][code]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- **Global fields are always addressed from 0.** They take the region's top, reserved at 16 KiB
|
|
63
|
+
(4,096 words), so they never move.
|
|
64
|
+
- **Each instance's `emitter_field` block is one allocation**, sized to its class's layout.
|
|
65
|
+
- The emitter record carries `field_offset`, the block's start within the region. The record writer
|
|
66
|
+
fills it from the instance's context, beside the program placement.
|
|
67
|
+
- An instance whose class declares no emitter fields allocates nothing.
|
|
68
|
+
- **The header gains a word for the field base**, beside the code base it already holds.
|
|
69
|
+
- **No storage binding is added.**
|
|
70
|
+
- Emit and simulate stay at eight, and their wide twins at nine, inside the device floor of ten.
|
|
71
|
+
- A buffer of its own would put the wide twins at ten, the floor itself.
|
|
72
|
+
- This was the deciding cost.
|
|
73
|
+
- **Upload goes by span.**
|
|
74
|
+
- Today a placement re-uploads the whole buffer, which is right for code, because code changes
|
|
75
|
+
rarely.
|
|
76
|
+
- Field values change with gameplay, so the fields region uploads its changed spans through the
|
|
77
|
+
engine's existing small-write upload path (small writes batched in blocks, mapped from 32 KiB up).
|
|
78
|
+
- A repack or growth still rebuilds the whole buffer, as today.
|
|
79
|
+
- **Authority.** The VM reads the buffer and never writes it. The CPU writes values. The binding pass
|
|
80
|
+
(below) writes the words that are bound.
|
|
81
|
+
|
|
82
|
+
## Reading
|
|
83
|
+
|
|
84
|
+
- **`LOAD_BUILTIN` gets two convention ranges above the engine's ids:**
|
|
85
|
+
- `VM_BUILTIN_EMITTER_FIELD_BASE + word offset`;
|
|
86
|
+
- `VM_BUILTIN_GLOBAL_FIELD_BASE + import index`.
|
|
87
|
+
The component count rides in `s1`, as `LOAD_PARTICLE_FIELD` carries it, and lanes past it read 0.
|
|
88
|
+
- **`vm_load_builtin`'s default case calls two host functions.** They follow the external-symbol
|
|
89
|
+
pattern `particle_vm_sample_wind` already uses: `particle_vm_load_emitter_field` and
|
|
90
|
+
`particle_vm_load_global_field`. Every host defines them: emit, simulate, their wide twins, and the
|
|
91
|
+
warm-up advance.
|
|
92
|
+
- **An `emitter_field` is read per lane.**
|
|
93
|
+
- The emitter row comes from the record header, then `field_offset` from the row, then the words.
|
|
94
|
+
- Nothing new is held across the interpreter loop, so `vm_ctx` does not grow.
|
|
95
|
+
- A field read is two dependent reads. Whether to hold `field_offset` in `vm_ctx` instead is decided
|
|
96
|
+
by the measurement below, not by argument.
|
|
97
|
+
- **A `global_field`'s address is the same in every lane**, so it is a scalar read.
|
|
98
|
+
- **Buckets, the constant pool and wave-uniform decode are untouched.**
|
|
99
|
+
|
|
100
|
+
### Linking global fields
|
|
101
|
+
|
|
102
|
+
- Programs are durable content, compiled with no scene present, so a global field's offset cannot be
|
|
103
|
+
baked in.
|
|
104
|
+
- The operand is an index into the program's import table.
|
|
105
|
+
- `ProgramHeap` rewrites it to the global field's offset when it copies the code into place, which
|
|
106
|
+
it already does.
|
|
107
|
+
- The heap stays keyed on the unpatched bytecode.
|
|
108
|
+
- Appending a global field moves nothing.
|
|
109
|
+
|
|
110
|
+
## Transform bindings
|
|
111
|
+
|
|
112
|
+
- **What they are.** A binding names a `transforms` row, a field and a channel. The GPU writes that
|
|
113
|
+
row's composed `global` into the field every frame.
|
|
114
|
+
- **What that gives.** A beam's far end, a homing target, a second bone: any transform can drive a
|
|
115
|
+
field with nothing copied through the CPU. That is what the emitter's own `node` already does for
|
|
116
|
+
`EMITTER_POSITION`, and it works for a row only the GPU composes, such as an animated joint.
|
|
117
|
+
|
|
118
|
+
**Storage: a `field_bindings` table** in the particle database. It is CPU-staged and low-churn, which
|
|
119
|
+
is what `GPUDatabase` is for.
|
|
120
|
+
- `source` is a link to the scene's `transforms` table, non-owning, exactly like the emitter record's
|
|
121
|
+
`node` (`PARTICLE_DATABASE_SPEC.add_link`).
|
|
122
|
+
- `target` is a word address in the fields region. It may be a global field or a word of an emitter
|
|
123
|
+
block, which is one rule for both scopes.
|
|
124
|
+
- `channel` says what is written:
|
|
125
|
+
|
|
126
|
+
| channel | width | from `global` |
|
|
127
|
+
|---|---|---|
|
|
128
|
+
| `POSITION` | 3 | the origin, as `EMITTER_POSITION` |
|
|
129
|
+
| `DIRECTION` | 3 | normalised −Z, as `EMITTER_DIRECTION` |
|
|
130
|
+
| `UP` | 3 | normalised +Y, as `EMITTER_UP` |
|
|
131
|
+
| `ORIENTATION` | 4 | a quaternion, as the `orientation` channel takes it |
|
|
132
|
+
|
|
133
|
+
The channel width must equal the field's width, and the system refuses the binding otherwise.
|
|
134
|
+
- Targets are restaged when `placement_version` moves, the rule every row already follows.
|
|
135
|
+
|
|
136
|
+
**The pass: `shader_particle_field_bind`.**
|
|
137
|
+
- One thread per binding row, walked with the table's page iterator, as the tick walks emitters.
|
|
138
|
+
- It reads `scene_read_node(source).global`, the same read `chunk_particle_setup_context` makes, and
|
|
139
|
+
writes the channel's words into the fields region. The program buffer is bound read-write here and
|
|
140
|
+
only here.
|
|
141
|
+
- It runs once a frame, after the hierarchy pass has composed the rows and before the tick.
|
|
142
|
+
- The host skips the dispatch while the table is empty.
|
|
143
|
+
|
|
144
|
+
**Authority.** A bound word is recomputed from scratch every frame.
|
|
145
|
+
- That is the argument that lets the scene's `transforms` table mix CPU fields with a GPU-written
|
|
146
|
+
`global` (DESIGN.md, *The emitter state*), and it holds here.
|
|
147
|
+
- The CPU's value for a bound field is its default until the first bind.
|
|
148
|
+
- A span upload or a buffer rebuild that lands on a bound word is overwritten before any VM pass
|
|
149
|
+
reads it.
|
|
150
|
+
|
|
151
|
+
**ECS.**
|
|
152
|
+
- `ParticleEffect.bindings`: `[{ field, entity, channel }]`, an entity reference, never a row. The
|
|
153
|
+
system resolves it with `row_of_entity` and holds the row through the scene context's rows, as it
|
|
154
|
+
does for the emitter's own placement.
|
|
155
|
+
- `GPUParticleSystem.global_fields.bind(name, entity, channel)` does the same for global fields.
|
|
156
|
+
|
|
157
|
+
## Everything else it touches
|
|
158
|
+
|
|
159
|
+
- **Optimizers.** `LOAD_BUILTIN` is already a pure read. Width inference has to take a field's width
|
|
160
|
+
from `s1` rather than from `VM_BUILTIN_COMPONENTS`, and the fuzzer must generate both ranges.
|
|
161
|
+
- **Reference VM.** The host passes `emitter_field` and `global_field` words as it passes the builtins
|
|
162
|
+
today.
|
|
163
|
+
- **Graph.** New node types, appended at the end of `ParticleNodeRegistry.js`:
|
|
164
|
+
- `emitterField` (name, type, default);
|
|
165
|
+
- `globalField` (name, type).
|
|
166
|
+
Widths are validated per name.
|
|
167
|
+
- **ECS values.**
|
|
168
|
+
- `ParticleEffect.emitter_fields`: values by name, as `Uint32` bit patterns. Compare-to-last covers
|
|
169
|
+
them, and a change marks the span dirty. It is not a restage, since a block does not move.
|
|
170
|
+
- `GPUParticleSystem.global_fields.set(name, value)` does the same for global fields.
|
|
171
|
+
- **Serialization.** The emitter-field layout and the imports ride in the program; values and bindings
|
|
172
|
+
ride on the effect. `ParticleEffect` goes to v3, with an upgrader that gives old saves none.
|
|
173
|
+
|
|
174
|
+
## Cost
|
|
175
|
+
|
|
176
|
+
- **A static value:** written once, when the block is allocated. Nothing per frame.
|
|
177
|
+
- **A changed value:** one span upload. No restage, no rebucket, no program change.
|
|
178
|
+
- **A binding:** one thread a frame, plus one dispatch (a tiny pass measures 5–8 µs here)
|
|
179
|
+
while any binding exists.
|
|
180
|
+
- **On the GPU:**
|
|
181
|
+
- an `emitter_field` read is a header reload, a row read and up to four loads;
|
|
182
|
+
- a `global_field` read is one scalar read;
|
|
183
|
+
- an effect that reads neither pays nothing that executes.
|
|
184
|
+
|
|
185
|
+
## What gets measured
|
|
186
|
+
|
|
187
|
+
- **The interpreter's register footprint.** Simulate and emit compiled through Dawn, before and after,
|
|
188
|
+
on RDNA2 offline. The default case grows the static code. The gate is no VGPR change.
|
|
189
|
+
- **The cost of an `emitter_field` read.** At 200k alive, on the 4090 and the iGPU, paired in one
|
|
190
|
+
page:
|
|
191
|
+
- the effect reading one field per particle, against the same effect reading a constant;
|
|
192
|
+
- the same pair with `field_offset` held in `vm_ctx`.
|
|
193
|
+
The cheaper of the two read paths is kept.
|
|
194
|
+
- **The bind pass**, at 1 and 1,000 bindings.
|
|
195
|
+
|
|
196
|
+
## Stages
|
|
197
|
+
|
|
198
|
+
Each stage lands red-then-green.
|
|
199
|
+
|
|
200
|
+
| stage | what lands | pinned by |
|
|
201
|
+
|---|---|---|
|
|
202
|
+
| V0 | the vocabulary rename; old graph node names and mnemonics load as aliases | every existing graph and assembly spec green, plus a saved graph using `attribute` loading |
|
|
203
|
+
| E1 | fields region, `field_offset`, emitter-field layout, `LOAD_BUILTIN` emitter range in both executors, graph node, `ParticleEffect.emitter_fields`, span upload, v3 | two bonfires differing only in flame tint: one program, one bucket, two blocks; a value change uploads one span and moves no program id |
|
|
204
|
+
| G1 | global reservation, imports, link at placement, global range, `global_fields.set` | a global field changes a running effect without restaging an emitter row |
|
|
205
|
+
| B1 | `field_bindings`, the bind pass, the ECS and global bind API | a beam whose far end follows an animated joint the CPU never sees |
|
|
206
|
+
|
|
207
|
+
## Outcome (2026-10-29)
|
|
208
|
+
|
|
209
|
+
Landed as revision 4 describes, in four commits — V0 `b8d14148e`, E1 `66031919d`, G1 `f93d1d2e0` and
|
|
210
|
+
B1 `3dd4b7ce7` — and the adversarial review's fixes, `a14459252`, with these departures:
|
|
211
|
+
|
|
212
|
+
- **Emitter fields are declared by the effect's document, as particle fields are**, and the
|
|
213
|
+
`emitterField` node reads one by name; the node does not declare. The same for global imports.
|
|
214
|
+
The emitter layout sits on the effect and the emitter (`emitter_layout`), not on `ParticleProgram`.
|
|
215
|
+
Values are `Uint32` words in layout order (`emitter_fields`), not a map by name.
|
|
216
|
+
- **The fields are the buffer's fourth section**, `[header][constants][code][fields]`, not a region
|
|
217
|
+
between the header and the constants.
|
|
218
|
+
- **The VM reads fields inline** in `LOAD_BUILTIN`'s field branch. There are no host functions
|
|
219
|
+
`particle_vm_load_emitter_field` / `particle_vm_load_global_field`.
|
|
220
|
+
- **Global bindings go through the registry and the ECS system**: `EmitterRegistry.bind_global_field`
|
|
221
|
+
and `GPUParticleEmitterSystem.bind_global_field`. There is no `GPUParticleSystem.global_fields.bind`.
|
|
222
|
+
- **The bind pass runs after the counter reset**, before the spawn commands and the tick.
|
|
223
|
+
- **A field read takes the instruction's width in words**, as `LOAD_CONST` does, rather than a
|
|
224
|
+
component count in `s1`: the compiler emits a field at its own width, and `LOAD_BUILTIN`'s operand
|
|
225
|
+
list — and so every saved assembly text — stays as it was.
|
|
226
|
+
- **`field_offset` is held in `vm_ctx`**, beside `emitter_position`, rather than re-read from the
|
|
227
|
+
emitter row inside the opcode. The re-read form was not built: the measured cost below is the
|
|
228
|
+
address being per-lane, and a row found through the particle's own header is per-lane too.
|
|
229
|
+
- **A value change restages the emitter's row** as well as writing its span — the registry's existing
|
|
230
|
+
path — rather than the span alone.
|
|
231
|
+
- **v3 of `ParticleEffect` carries the program's global imports**, written in E1 so the format bumped
|
|
232
|
+
once.
|
|
233
|
+
- **Transform bindings on the component are runtime data and not saved**: nothing in the engine's
|
|
234
|
+
saves carries an entity reference across a load.
|
|
235
|
+
|
|
236
|
+
**Measured (2026-10-29, at `a14459252`'s code).** Headless Chrome, one device per run. The two arms are two
|
|
237
|
+
particle systems in one page, frames interleaved and the order alternating. Times are GPU timestamps,
|
|
238
|
+
p10, over 1,200 frames on the 4090 and 300 on the iGPU. The emitter tick is the control and reads the
|
|
239
|
+
same in both arms throughout.
|
|
240
|
+
|
|
241
|
+
- **An `emitter_field` read at 200k alive.** The effect is `position += drift * dt`: six
|
|
242
|
+
instructions, where `drift` is a 3-wide emitter field in one arm and a 3-wide constant in the
|
|
243
|
+
other. Simulate:
|
|
244
|
+
|
|
245
|
+
| | constant | field | field / constant |
|
|
246
|
+
|---|---|---|---|
|
|
247
|
+
| RTX 4090, 2 runs | 132–134 µs | 135–137 µs | 1.008, 1.039 |
|
|
248
|
+
| Radeon iGPU (RDNA2), 7 runs | 1,893–1,952 µs | 2,111–2,204 µs | 1.111–1.131 |
|
|
249
|
+
|
|
250
|
+
On the iGPU that is about 1.1 ns per particle per read: an eighth of a program this short. **The
|
|
251
|
+
cause is that the address is per-lane.** Simulate's waves are one program, not one emitter, so
|
|
252
|
+
`vm_ctx.emitter_field_offset` reaches the read per-lane while the constant pool's base arrives
|
|
253
|
+
wave-uniform. Two experiments show it:
|
|
254
|
+
- broadcasting the offset from the first lane, valid only in this one-emitter page, brings the ratio
|
|
255
|
+
to 0.996 and 0.997;
|
|
256
|
+
- hoisting the header word out of the loop changes nothing (1.117, 1.096).
|
|
257
|
+
- **A guarded broadcast was measured and not kept.** It reads at the first lane's offset when
|
|
258
|
+
`subgroupAll` says every lane agrees, and per-lane otherwise. Field-reading programs ran 0.985–0.996
|
|
259
|
+
of the constant arm. But every program without a field read slowed by 2.6–3.6%: 2,001–2,021 µs
|
|
260
|
+
against 1,949–1,952 µs, in three HEAD/fix pairs run back to back. The cost is there even though such
|
|
261
|
+
a program never takes the branch. Most effects read no field, so the common case would pay.
|
|
262
|
+
- **The bind pass**, POSITION bindings:
|
|
263
|
+
|
|
264
|
+
| | 1 binding | 1,000 bindings |
|
|
265
|
+
|---|---|---|
|
|
266
|
+
| RTX 4090, 2 runs | 2.05 µs | 2.05 µs |
|
|
267
|
+
| Radeon iGPU, 2 runs | 2.20–2.24 µs | 5.44 µs |
|
|
268
|
+
|
|
269
|
+
On the 4090 both arms read the same as the emitter-tick control. On the iGPU, 999 more bindings add
|
|
270
|
+
3.2 µs.
|
|
271
|
+
|
|
272
|
+
**Not measured:** the interpreter's register footprint. amdspv and spirv-as are not installed on this
|
|
273
|
+
machine. Every VM pass and the bind pass compile and build pipelines under Tint on both GPUs.
|
|
274
|
+
|
|
275
|
+
## Sources
|
|
276
|
+
|
|
277
|
+
- UE 5.4 source on disk: `Plugins/FX/Niagara/Source/Niagara/Public/NiagaraTypes.h`
|
|
278
|
+
(`FNiagaraEmitterParameters` and `FNiagaraSystemParameters` are the engine's members of each scope,
|
|
279
|
+
with User values beside them), `Classes/NiagaraGPUSystemTick.h`,
|
|
280
|
+
`Classes/NiagaraParameterCollection.h` (globals bound by name).
|
|
281
|
+
- [Niagara key concepts (namespace read/write table)](https://dev.epicgames.com/documentation/unreal-engine/key-concepts-in-niagara-effects-for-unreal-engine)
|
|
282
|
+
- [VFX Graph instancing](https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@17.2/manual/Instancing.html)
|
|
283
|
+
— instances share code and load their properties per instance.
|
|
@@ -22,8 +22,9 @@
|
|
|
22
22
|
* Persistent GPU state, and only that: a buffer is reserved here if and only if its contents have
|
|
23
23
|
* to survive to the next frame. That is the particle pool, the alive list, the dead
|
|
24
24
|
* free-list, the counters, the simulation-order (coherence) list, simulate's indirect dispatch args
|
|
25
|
-
* (written at the end of one frame, read by the next), the emitter database (the emitter table
|
|
26
|
-
*
|
|
25
|
+
* (written at the end of one frame, read by the next), the emitter database (the emitter table, the
|
|
26
|
+
* GPU-owned state table and the transform binding table, one buffer), the packed program buffer
|
|
27
|
+
* (code, constants and field values), and the two CPU-uploaded
|
|
27
28
|
* queues — the spawn-command ring and the warm-up queue. Buffers that depend on the emitter set —
|
|
28
29
|
* the coherence list on the number of distinct programs, the program buffer on the heap, the
|
|
29
30
|
* database on its own pages, the counters on the emitter table's element capacity (they carry the
|
|
@@ -184,6 +185,13 @@ export class GPUParticleSystem {
|
|
|
184
185
|
* @returns {import("./runtime/ParticleEmitter.js").ParticleEmitter[]}
|
|
185
186
|
*/
|
|
186
187
|
get emitters(): import("./runtime/ParticleEmitter.js").ParticleEmitter[];
|
|
188
|
+
/**
|
|
189
|
+
* The system's global fields — the static members every effect may read by name. Setting one is
|
|
190
|
+
* a word write and a span upload on the next frame; nothing is restaged and no program changes.
|
|
191
|
+
*
|
|
192
|
+
* @returns {import("./runtime/ParticleGlobalFields.js").ParticleGlobalFields}
|
|
193
|
+
*/
|
|
194
|
+
get global_fields(): import("./runtime/ParticleGlobalFields.js").ParticleGlobalFields;
|
|
187
195
|
/**
|
|
188
196
|
* Number of simulation-order buckets — one per program id the registry can hand out, which is
|
|
189
197
|
* its peak number of distinct compiled programs rather than its current one.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GPUParticleSystem.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/GPUParticleSystem.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GPUParticleSystem.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/GPUParticleSystem.js"],"names":[],"mappings":"AA6DA;;;;;;;;;;;;;GAaG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8FG;AACH;IAsLI;;;;;;OAMG;IACH,sBANW,MAAM,iBACN,OAAO,6BAA6B,EAAE,eAAe;QAEpC,QAAQ,GAAzB,MAAM;QACW,sBAAsB,GAAvC,MAAM;OAoBhB;IA7MD;;;OAGG;IACH,UAFU,MAAM,CAEP;IAET;;;;OAIG;IACH,eAFU,OAAO,6BAA6B,EAAE,eAAe,CAEjD;IAEd;;;OAGG;IACH,UAFU,MAAM,CAEP;IAET;;OAEG;IACH,UAFU,eAAe,CAEhB;IAET;;;OAGG;IACH,OAFU,MAAM,CAEN;IAEV;;;OAGG;IACH,MAFU,MAAM,CAEP;IAET;;;OAGG;IACH,qBAFU,MAAM,CAEQ;IAExB;;;;OAIG;IACH,sBAAM;IAEN,yBAAyB;IACzB,0BAAc;IAEd;;;;;;;;;;;OAWG;IACH,SAFU,MAAM,CAEH;IA+Ib;;;OAGG;IACH,kCAEC;IAED;;;OAGG;IACH,yEAEC;IAED;;;;;OAKG;IACH,sFAEC;IAED;;;;;;;;;;;;OAYG;IACH,eAFa,MAAM,CAIlB;IAED;;;;;;;OAOG;IACH,eAHW,OAAO,8BAA8B,EAAE,eAAe,SACtD,MAAM,QAwBhB;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH;QAPkG,KAAK,EAA5F,OAAO,2DAA2D,EAAE,UAAU;QAC/D,MAAM,EAArB,MAAM;QACS,cAAc,EAA7B,MAAM;QAES,EAAE,EAAjB,MAAM;QACJ,OAAO,sBAAsB,EAAE,yBAAyB,CAuEpE;IAiBD;;;;;;;;;OASG;IACH;QANgG,KAAK,EAA1F,OAAO,2DAA2D,EAAE,UAAU;QACjE,MAAM,EAAnB,MAAM;QACkB,kBAAkB,EAA1C,UAAU,MAAM,CAAC;QACJ,SAAS,EAAtB,MAAM;QACJ,MAAM,CAalB;IAED;;;;;;;;;;OAUG;IACH;QAPgG,KAAK,EAA1F,OAAO,2DAA2D,EAAE,UAAU;QACjE,MAAM,EAAnB,MAAM;QACO,IAAI,EAAjB,MAAM;QACO,aAAa,EAA1B,MAAM;QACsD,MAAM,EAAlE;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAC;QACnD;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAkBjE;IAED;;;;;;;;;;;;;;;;OAgBG;IACH;QAbgG,KAAK,EAA1F,OAAO,2DAA2D,EAAE,UAAU;QACrB,QAAQ,EAAjE,OAAO,2BAA2B,EAAE,cAAc;QACrC,MAAM,EAAnB,MAAM;QACO,aAAa,EAA1B,MAAM;QACO,IAAI,EAAjB,MAAM;QACO,QAAQ,EAArB,MAAM;QACO,eAAe,EAA5B,MAAM;QACO,oBAAoB,EAAjC,MAAM;QAC2C,sBAAsB,EAAvE;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAC;QAEgC,YAAY,EAAtF;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAC;QACjE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAwB/E;IAED;;;;;;;;;OASG;IACH,qBAHW,OAAO,8BAA8B,EAAE,eAAe,iBACtD,MAAM,QAehB;IAED;;;;OAIG;IACH,wBAFW,OAAO,8BAA8B,EAAE,eAAe,QAMhE;IAED;;;;;OAKG;IACH,2BAHW,OAAO,8BAA8B,EAAE,eAAe,iBACtD,MAAM,QAMhB;IA6cD;;;;;;;OAOG;IACH;YAFoB,MAAM,GAAE,MAAM;MAgBjC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,cAFa,QAAQ,mBAAmB,CAAC,CA8BxC;IAED,gBA2BC;;CACJ;;;;;;;;WAprCa,MAAM;;;;UACN,MAAM;;;;kBACN,MAAM;;;;;cACN,MAAM;;;;;gBAEN,MAAM;;;;;oBAEN,MAAM;;gCAxCY,8BAA8B"}
|