@woosh/meep-engine 3.11.3 → 3.12.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/README.md +14 -18
- package/editor/SelectionVisualizer.js +127 -127
- package/editor/entity_world_bounds.js +27 -27
- package/editor/particles/rebuildParticleEmitter.js +31 -31
- package/editor/process/SymbolicDisplayProcess.js +1 -1
- package/editor/process/symbolic/CameraSymbolicDisplay.js +146 -146
- package/editor/process/symbolic/LightSymbolicDisplay.js +172 -172
- package/editor/prototypeEditorShell.js +156 -156
- package/editor/selection/editor_pick.js +130 -130
- package/editor/selection/screen_rect_frustum.js +119 -119
- package/editor/tools/v2/TransformControls.js +971 -971
- package/package.json +1 -1
- package/src/engine/Engine.d.ts +3 -3
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +726 -726
- package/src/engine/EngineHarness.d.ts +1 -1
- package/src/engine/EngineHarness.js +590 -590
- package/src/engine/ecs/HIERARCHY_REVIEW.md +717 -717
- package/src/engine/ecs/terrain/ecs/BuildLightTexture.d.ts +1 -1
- package/src/engine/ecs/terrain/ecs/BuildLightTexture.js +27 -27
- package/src/engine/ecs/terrain/ecs/Terrain.d.ts +1 -5
- package/src/engine/ecs/terrain/ecs/Terrain.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/Terrain.js +790 -790
- package/src/engine/ecs/terrain/util/loadVisibleTerrainTiles.js +129 -129
- package/src/engine/graphics/ecs/camera/camera_find_active.d.ts +1 -1
- package/src/engine/graphics/ecs/camera/camera_find_active.js +28 -28
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts +1 -1
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +428 -428
- package/src/engine/graphics/ecs/water/Water.d.ts +1 -1
- package/src/engine/graphics/ecs/water/Water.js +104 -104
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +1 -1
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +1 -1
- package/src/engine/graphics3/AnimationGraphSystem.d.ts +65 -0
- package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -0
- package/src/engine/graphics3/AnimationGraphSystem.js +329 -0
- package/src/engine/graphics3/AnimationGraphSystem3.d.ts +6 -61
- package/src/engine/graphics3/AnimationGraphSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/AnimationGraphSystem3.js +6 -325
- package/src/engine/graphics3/AnimationSystem.d.ts +76 -0
- package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -0
- package/src/engine/graphics3/AnimationSystem.js +352 -0
- package/src/engine/graphics3/AnimationSystem3.d.ts +6 -72
- package/src/engine/graphics3/AnimationSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/AnimationSystem3.js +6 -348
- package/src/engine/graphics3/CameraSystem.d.ts +49 -0
- package/src/engine/graphics3/CameraSystem.d.ts.map +1 -0
- package/src/engine/graphics3/CameraSystem.js +170 -0
- package/src/engine/graphics3/CameraSystem3.d.ts +6 -45
- package/src/engine/graphics3/CameraSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/CameraSystem3.js +6 -166
- package/src/engine/graphics3/DebugDrawSystem.d.ts +72 -0
- package/src/engine/graphics3/DebugDrawSystem.d.ts.map +1 -0
- package/src/engine/graphics3/DebugDrawSystem.js +205 -0
- package/src/engine/graphics3/DebugDrawSystem3.d.ts +6 -68
- package/src/engine/graphics3/DebugDrawSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/DebugDrawSystem3.js +6 -201
- package/src/engine/graphics3/DecalSystem.d.ts +81 -0
- package/src/engine/graphics3/DecalSystem.d.ts.map +1 -0
- package/src/engine/graphics3/DecalSystem.js +441 -0
- package/src/engine/graphics3/DecalSystem3.d.ts +6 -77
- package/src/engine/graphics3/DecalSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/DecalSystem3.js +6 -437
- package/src/engine/graphics3/FogOfWarSystem.d.ts +74 -0
- package/src/engine/graphics3/FogOfWarSystem.d.ts.map +1 -0
- package/src/engine/graphics3/FogOfWarSystem.js +265 -0
- package/src/engine/graphics3/FogOfWarSystem3.d.ts +6 -70
- package/src/engine/graphics3/FogOfWarSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/FogOfWarSystem3.js +6 -261
- package/src/engine/graphics3/GraphicsEngine.d.ts +340 -0
- package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -0
- package/src/engine/graphics3/GraphicsEngine.js +790 -0
- package/src/engine/graphics3/GraphicsEngine3.d.ts +6 -336
- package/src/engine/graphics3/GraphicsEngine3.d.ts.map +1 -1
- package/src/engine/graphics3/GraphicsEngine3.js +6 -786
- package/src/engine/graphics3/HighlightSystem.d.ts +82 -0
- package/src/engine/graphics3/HighlightSystem.d.ts.map +1 -0
- package/src/engine/graphics3/HighlightSystem.js +241 -0
- package/src/engine/graphics3/HighlightSystem3.d.ts +6 -78
- package/src/engine/graphics3/HighlightSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/HighlightSystem3.js +6 -237
- package/src/engine/graphics3/LightSystem.d.ts +40 -0
- package/src/engine/graphics3/LightSystem.d.ts.map +1 -0
- package/src/engine/graphics3/LightSystem.js +211 -0
- package/src/engine/graphics3/LightSystem3.d.ts +6 -36
- package/src/engine/graphics3/LightSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/LightSystem3.js +6 -207
- package/src/engine/graphics3/MeshSystem.d.ts +106 -0
- package/src/engine/graphics3/MeshSystem.d.ts.map +1 -0
- package/src/engine/graphics3/MeshSystem.js +647 -0
- package/src/engine/graphics3/MeshSystem3.d.ts +6 -102
- package/src/engine/graphics3/MeshSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/MeshSystem3.js +6 -642
- package/src/engine/graphics3/ParticipatingMedia.d.ts +2 -2
- package/src/engine/graphics3/ParticipatingMedia.js +203 -203
- package/src/engine/graphics3/ParticipatingMediaSystem.d.ts +87 -0
- package/src/engine/graphics3/ParticipatingMediaSystem.d.ts.map +1 -0
- package/src/engine/graphics3/ParticipatingMediaSystem.js +184 -0
- package/src/engine/graphics3/ParticipatingMediaSystem3.d.ts +6 -83
- package/src/engine/graphics3/ParticipatingMediaSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/ParticipatingMediaSystem3.js +6 -180
- package/src/engine/graphics3/ParticleEmitterSystem.d.ts +76 -0
- package/src/engine/graphics3/ParticleEmitterSystem.d.ts.map +1 -0
- package/src/engine/graphics3/ParticleEmitterSystem.js +289 -0
- package/src/engine/graphics3/ParticleEmitterSystem3.d.ts +6 -72
- package/src/engine/graphics3/ParticleEmitterSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/ParticleEmitterSystem3.js +6 -285
- package/src/engine/graphics3/PathDisplaySystem.d.ts +70 -0
- package/src/engine/graphics3/PathDisplaySystem.d.ts.map +1 -0
- package/src/engine/graphics3/PathDisplaySystem.js +309 -0
- package/src/engine/graphics3/PathDisplaySystem3.d.ts +6 -66
- package/src/engine/graphics3/PathDisplaySystem3.d.ts.map +1 -1
- package/src/engine/graphics3/PathDisplaySystem3.js +6 -305
- package/src/engine/graphics3/Pickable.d.ts +1 -1
- package/src/engine/graphics3/Pickable.js +65 -65
- package/src/engine/graphics3/PickingQuery.d.ts +1 -1
- package/src/engine/graphics3/PickingQuery.js +48 -48
- package/src/engine/graphics3/PickingSystem.d.ts +67 -0
- package/src/engine/graphics3/PickingSystem.d.ts.map +1 -0
- package/src/engine/graphics3/PickingSystem.js +273 -0
- package/src/engine/graphics3/PickingSystem3.d.ts +6 -63
- package/src/engine/graphics3/PickingSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/PickingSystem3.js +6 -269
- package/src/engine/graphics3/ShadedGeometrySystem.d.ts +47 -0
- package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -0
- package/src/engine/graphics3/ShadedGeometrySystem.js +169 -0
- package/src/engine/graphics3/ShadedGeometrySystem3.d.ts +6 -43
- package/src/engine/graphics3/ShadedGeometrySystem3.d.ts.map +1 -1
- package/src/engine/graphics3/ShadedGeometrySystem3.js +6 -165
- package/src/engine/graphics3/TerrainSystem.d.ts +80 -0
- package/src/engine/graphics3/TerrainSystem.d.ts.map +1 -0
- package/src/engine/graphics3/TerrainSystem.js +566 -0
- package/src/engine/graphics3/TerrainSystem3.d.ts +6 -76
- package/src/engine/graphics3/TerrainSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/TerrainSystem3.js +6 -562
- package/src/engine/graphics3/TooltipComponentSystem.d.ts +65 -0
- package/src/engine/graphics3/TooltipComponentSystem.d.ts.map +1 -0
- package/src/engine/graphics3/TooltipComponentSystem.js +328 -0
- package/src/engine/graphics3/TooltipComponentSystem3.d.ts +6 -61
- package/src/engine/graphics3/TooltipComponentSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/TooltipComponentSystem3.js +6 -324
- package/src/engine/graphics3/Trail3DSystem.d.ts +73 -0
- package/src/engine/graphics3/Trail3DSystem.d.ts.map +1 -0
- package/src/engine/graphics3/Trail3DSystem.js +221 -0
- package/src/engine/graphics3/Trail3DSystem3.d.ts +6 -69
- package/src/engine/graphics3/Trail3DSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/Trail3DSystem3.js +6 -217
- package/src/engine/graphics3/VolumetricLightMap.d.ts +2 -2
- package/src/engine/graphics3/VolumetricLightMap.js +2 -2
- package/src/engine/graphics3/VolumetricLightMapSystem.d.ts +98 -0
- package/src/engine/graphics3/VolumetricLightMapSystem.d.ts.map +1 -0
- package/src/engine/graphics3/VolumetricLightMapSystem.js +261 -0
- package/src/engine/graphics3/VolumetricLightMapSystem3.d.ts +6 -94
- package/src/engine/graphics3/VolumetricLightMapSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/VolumetricLightMapSystem3.js +10 -261
- package/src/engine/graphics3/WaterSystem.d.ts +59 -0
- package/src/engine/graphics3/WaterSystem.d.ts.map +1 -0
- package/src/engine/graphics3/WaterSystem.js +293 -0
- package/src/engine/graphics3/WaterSystem3.d.ts +6 -55
- package/src/engine/graphics3/WaterSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/WaterSystem3.js +6 -289
- package/src/engine/graphics3/animation/AnimationGraphController.d.ts +1 -1
- package/src/engine/graphics3/animation/AnimationGraphController.js +518 -518
- package/src/engine/graphics3/animation/ClipListPlayer.d.ts +1 -1
- package/src/engine/graphics3/animation/ClipListPlayer.js +263 -263
- package/src/engine/graphics3/animation/ClipPlayback.d.ts +2 -2
- package/src/engine/graphics3/animation/ClipPlayback.js +84 -84
- package/src/engine/graphics3/decal/graph_build_decal_clusters.d.ts.map +1 -1
- package/src/engine/graphics3/decal/graph_build_decal_clusters.js +6 -8
- package/src/engine/graphics3/decal/shader_cluster_assign_decals.d.ts +0 -7
- package/src/engine/graphics3/decal/shader_cluster_assign_decals.d.ts.map +1 -1
- package/src/engine/graphics3/decal/shader_cluster_assign_decals.js +1 -1
- package/src/engine/graphics3/decal/shader_cull_decals_frustum.d.ts +0 -4
- package/src/engine/graphics3/decal/shader_cull_decals_frustum.d.ts.map +1 -1
- package/src/engine/graphics3/decal/shader_cull_decals_frustum.js +1 -1
- package/src/engine/graphics3/highlight/pack_highlight_table.d.ts +2 -2
- package/src/engine/graphics3/highlight/pack_highlight_table.d.ts.map +1 -1
- package/src/engine/graphics3/highlight/pack_highlight_table.js +74 -74
- package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts +1 -1
- package/src/engine/graphics3/pose/query_entity_node_world_pose.js +101 -101
- package/src/engine/graphics3/preview/make_model_thumbnail.d.ts +3 -3
- package/src/engine/graphics3/preview/make_model_thumbnail.d.ts.map +1 -1
- package/src/engine/graphics3/preview/make_model_thumbnail.js +48 -48
- package/src/engine/graphics3/shade_camera_projection_ray.d.ts +1 -1
- package/src/engine/graphics3/shade_camera_projection_ray.js +77 -77
- package/src/engine/graphics3/shade_node_to_entity_composition.d.ts +1 -1
- package/src/engine/graphics3/shade_node_to_entity_composition.js +84 -84
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_leaf_triangles.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_leaf_triangles.js +0 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_points.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_points.js +0 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_visibility.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_visibility.js +133 -134
- package/src/shade/playground/skinned_blas_refit/verify_leaf_triangles.js +202 -202
- package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.js +249 -249
- package/src/shade/renderer/STATIC_GRAPHICS_ENGINE_ASSETS.js +1 -1
- package/src/shade/renderer/animation/pose/PosePlayback.d.ts +2 -1
- package/src/shade/renderer/animation/pose/PosePlayback.d.ts.map +1 -1
- package/src/shade/renderer/animation/pose/PosePlayback.js +2 -1
- package/src/shade/renderer/animation/shader_animation_apply.d.ts.map +1 -1
- package/src/shade/renderer/animation/shader_animation_apply.js +128 -129
- package/src/shade/renderer/animation/shader_animation_pose_resolve.d.ts.map +1 -1
- package/src/shade/renderer/animation/shader_animation_pose_resolve.js +176 -177
- package/src/shade/renderer/animation/shader_animation_tick.d.ts.map +1 -1
- package/src/shade/renderer/animation/shader_animation_tick.js +125 -126
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_geometry_sphere_derive.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_geometry_sphere_derive.js +98 -99
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_reduce.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_reduce.js +212 -213
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_scatter.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_scatter.js +120 -121
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_skinned_mesh_bounds_refresh.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_skinned_mesh_bounds_refresh.js +75 -76
- package/src/shade/renderer/animation/skinning/shader_meshlet_apply_skinning.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/shader_meshlet_apply_skinning.js +371 -372
- package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.js +104 -105
- package/src/shade/renderer/atmosphere/shader_multiscatter_lut.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/shader_multiscatter_lut.js +0 -1
- package/src/shade/renderer/buffer/graph_inspect_gpu_buffer.js +136 -136
- package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUDatabase.js +2 -3
- package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +319 -319
- package/src/shade/renderer/buffer/util/shader_buffer_copy_storage_to_storage.d.ts.map +1 -1
- package/src/shade/renderer/buffer/util/shader_buffer_copy_storage_to_storage.js +41 -42
- package/src/shade/renderer/buffer/util/shader_buffer_intra_copy_regions.d.ts.map +1 -1
- package/src/shade/renderer/buffer/util/shader_buffer_intra_copy_regions.js +83 -84
- package/src/shade/renderer/dynamic/shader_dynamic_mesh.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/shader_dynamic_mesh.js +177 -170
- package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +918 -918
- package/src/shade/renderer/geometry/bvh/record_blas_refit.js +4 -4
- package/src/shade/renderer/geometry/bvh/shader_blas_refit_leaf_bounds.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/shader_blas_refit_leaf_bounds.js +121 -122
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +774 -774
- package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts +1 -1
- package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.js +69 -70
- package/src/shade/renderer/global_illumination/lpv/placement/graph_generate_probe_locations.js +367 -367
- package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lvp_atlas_to_sh.js +184 -184
- package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +1115 -1115
- package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.js +217 -217
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.js +142 -143
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.js +0 -1
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_refit.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_refit.js +140 -141
- package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram.js +0 -1
- package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter.js +0 -1
- package/src/shade/renderer/light/cluster/cull/graph_cull_lights.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/cull/graph_cull_lights.js +191 -198
- package/src/shade/renderer/light/cluster/cull/shader_cull_lights_frustum.d.ts +0 -6
- package/src/shade/renderer/light/cluster/cull/shader_cull_lights_frustum.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/cull/shader_cull_lights_frustum.js +120 -120
- package/src/shade/renderer/light/cluster/cull/shader_cull_lights_hzb.d.ts +0 -4
- package/src/shade/renderer/light/cluster/cull/shader_cull_lights_hzb.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/cull/shader_cull_lights_hzb.js +112 -112
- package/src/shade/renderer/light/cluster/graph_assign_clsuters.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/graph_assign_clsuters.js +4 -7
- package/src/shade/renderer/light/cluster/shader_cluster_assign_lights.d.ts +0 -6
- package/src/shade/renderer/light/cluster/shader_cluster_assign_lights.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/shader_cluster_assign_lights.js +1 -1
- package/src/shade/renderer/lightmap/bake/raster/shader_lightmap_to_viz_buffer.js +222 -222
- package/src/shade/renderer/lightmap/bake/tile/shader_lightmap_tile_composit.js +81 -81
- package/src/shade/renderer/material/GPUMaterialContext.js +380 -380
- package/src/shade/renderer/material/standard/fragment_gbuffer_vt.js +169 -169
- package/src/shade/renderer/object_property/shader_object_property_process.d.ts.map +1 -1
- package/src/shade/renderer/object_property/shader_object_property_process.js +83 -84
- package/src/shade/renderer/object_property/shader_refresh_all_mesh_bounds.d.ts.map +1 -1
- package/src/shade/renderer/object_property/shader_refresh_all_mesh_bounds.js +57 -58
- package/src/shade/renderer/particles/prototypeParticleSystem.js +2 -3
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.js +117 -118
- package/src/shade/renderer/particles/shaders/shader_particle_finalize.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_finalize.js +77 -79
- package/src/shade/renderer/particles/shaders/shader_particle_render.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_render.js +190 -183
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +99 -100
- package/src/shade/renderer/particles/sort/shader_particle_sort.d.ts.map +1 -1
- package/src/shade/renderer/particles/sort/shader_particle_sort.js +158 -161
- package/src/shade/renderer/path_tracer/graph_path_trace_scene.js +184 -184
- package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.js +119 -119
- package/src/shade/renderer/postprocess/dof/raymarch/graph_postprocess_dof.js +3 -4
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_raymarch_compute.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_raymarch_compute.js +266 -267
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_slice_compute.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_slice_compute.js +270 -271
- package/src/shade/renderer/postprocess/nss/shader_nss_concat.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_concat.js +68 -69
- package/src/shade/renderer/postprocess/nss/shader_nss_conv_layer.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_conv_layer.js +225 -226
- package/src/shade/renderer/postprocess/nss/shader_nss_extract_feedback.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_extract_feedback.js +49 -50
- package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +291 -292
- package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +230 -231
- package/src/shade/renderer/postprocess/ssr/reproject/shader_ffx_denoiser_reflections_reproject.d.ts +16 -2
- package/src/shade/renderer/postprocess/ssr/reproject/shader_ffx_denoiser_reflections_reproject.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/reproject/shader_ffx_denoiser_reflections_reproject.js +12 -12
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +2 -2
- package/src/shade/renderer/rasterize/bucket/shader_count_meshlets_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_count_meshlets_by_material.js +68 -69
- package/src/shade/renderer/rasterize/bucket/shader_make_meshlet_indirect_draw_commands_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_make_meshlet_indirect_draw_commands_by_material.js +59 -60
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +0 -1
- package/src/shade/renderer/rasterize/bucket/shader_sort_meshlets_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_sort_meshlets_by_material.js +64 -65
- package/src/shade/renderer/rasterize/compute/graph_mesh_frustum_cull.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/compute/graph_mesh_frustum_cull.js +168 -169
- package/src/shade/renderer/rasterize/compute/graph_mesh_sphere_cull.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/compute/graph_mesh_sphere_cull.js +160 -161
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +109 -110
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +115 -116
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_classify_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_classify_bucket.js +139 -140
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_count_by_rasterization_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_count_by_rasterization_bucket.js +91 -92
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.js +88 -89
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.js +90 -91
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +65 -66
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js +89 -90
- package/src/shade/renderer/rasterize/expand/graph_mesh_filter_one_way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/graph_mesh_filter_one_way.js +169 -170
- package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.js +89 -90
- package/src/shade/renderer/rasterize/expand/mesh/shader_meshes_to_meshlet_counts.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/mesh/shader_meshes_to_meshlet_counts.js +61 -62
- package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.js +153 -154
- package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.js +144 -144
- package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_pass_descriptor.js +88 -88
- package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.js +217 -217
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.js +179 -179
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.js +178 -178
- package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.js +194 -194
- package/src/shade/renderer/rasterize/native/viz/viz_rasterization_opaque_pass_descriptor.js +76 -76
- package/src/shade/renderer/restir/di/shader_restir_di_denoise.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/shader_restir_di_denoise.js +136 -137
- package/src/shade/renderer/restir/di/shader_restir_di_resample.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/shader_restir_di_resample.js +129 -130
- package/src/shade/renderer/restir/di/shader_restir_di_resolve.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/shader_restir_di_resolve.js +99 -100
- package/src/shade/renderer/restir/di/shader_restir_di_spatial.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/shader_restir_di_spatial.js +116 -117
- package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.js +383 -383
- package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy_naive.js +123 -123
- package/src/shade/renderer/scene/hierarchy/shader_nodes_record_input_positions.d.ts.map +1 -1
- package/src/shade/renderer/scene/hierarchy/shader_nodes_record_input_positions.js +64 -65
- package/src/shade/renderer/scene/hierarchy/shader_nodes_update_transform_hierarchy.d.ts.map +1 -1
- package/src/shade/renderer/scene/hierarchy/shader_nodes_update_transform_hierarchy.js +372 -373
- package/src/shade/renderer/scene/hierarchy/shader_nodes_update_transform_hierarchy_naive.d.ts.map +1 -1
- package/src/shade/renderer/scene/hierarchy/shader_nodes_update_transform_hierarchy_naive.js +111 -112
- package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.d.ts.map +1 -1
- package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.js +0 -1
- package/src/shade/renderer/shader/ComputeShader.d.ts +24 -3
- package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
- package/src/shade/renderer/shader/ComputeShader.js +350 -296
- package/src/shade/renderer/shader/ImageShader.js +217 -217
- package/src/shade/renderer/shader/ShaderDescriptor.d.ts +5 -0
- package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/ShaderDescriptor.js +20 -0
- package/src/shade/renderer/shader/util/compute_infer_workgroup_size_from_source.d.ts +47 -0
- package/src/shade/renderer/shader/util/compute_infer_workgroup_size_from_source.d.ts.map +1 -0
- package/src/shade/renderer/shader/util/compute_infer_workgroup_size_from_source.js +448 -0
- package/src/shade/renderer/shadow/map/csm/graph_csm_setup_cascades.js +3 -3
- package/src/shade/renderer/shadow/ray/staged/gen/graph_gen_rays.js +3 -3
- package/src/shade/renderer/shadow/ray/staged/trace/graph_trace_rays.js +2 -2
- package/src/shade/renderer/shadow/sdf/cascade/CascadedSceneSDF.js +4 -4
- package/src/shade/renderer/texture/virtual/build_shader_vt_feedback.d.ts.map +1 -1
- package/src/shade/renderer/texture/virtual/build_shader_vt_feedback.js +231 -232
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +12 -15
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts +3 -2
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +3 -2
- package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts +0 -2
- package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +17 -6
- package/src/shade/renderer/water/shader_water.js +246 -246
- package/src/shade/vitest.setup.mjs +1 -1
- package/src/shade/wgsl/emulator/ComputeShaderEmulator.js +291 -291
- package/src/view/minimap/Minimap.d.ts +2 -2
- package/src/view/minimap/Minimap.d.ts.map +1 -1
- package/src/view/minimap/Minimap.js +225 -225
- package/src/view/minimap/dom/MinimapCameraView.d.ts +3 -3
- package/src/view/minimap/dom/MinimapCameraView.d.ts.map +1 -1
- package/src/view/minimap/dom/MinimapCameraView.js +206 -206
- package/src/shade/renderer/shadow/map/csm/shader/shader_setup_cascades.d.ts +0 -3
- package/src/shade/renderer/shadow/map/csm/shader/shader_setup_cascades.d.ts.map +0 -1
- package/src/shade/renderer/shadow/map/csm/shader/shader_setup_cascades.js +0 -20
|
@@ -1,183 +1,190 @@
|
|
|
1
|
-
import { RenderPipelineDescriptor } from "../../../descriptor/pipeline/render/RenderPipelineDescriptor.js";
|
|
2
|
-
import { ColorTargetState } from "../../../descriptor/pipeline/render/ColorTargetState.js";
|
|
3
|
-
import { DepthStencilState } from "../../../descriptor/pipeline/render/DepthStencilState.js";
|
|
4
|
-
import { WebGPUArray } from "../../shader/type/WebGPUArray.js";
|
|
5
|
-
import { CAMERA_UNIFORM_STRUCT } from "../../camera/CAMERA_UNIFORM_STRUCT.js";
|
|
6
|
-
import { ShaderDescriptor } from "../../shader/ShaderDescriptor.js";
|
|
7
|
-
import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
|
|
8
|
-
import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
|
|
9
|
-
import {
|
|
10
|
-
PARTICLE_RECORD_HEADER_EMITTER,
|
|
11
|
-
PARTICLE_RECORD_WORD_COUNT,
|
|
12
|
-
} from "../ParticleConstants.js";
|
|
13
|
-
import { EMITTER_ATTRIBUTE_ABSENT, EMITTER_FLAG } from "../data/PARTICLE_EMITTER_LAYOUT.js";
|
|
14
|
-
import { chunk_particle_emitter } from "../data/chunk_particle_emitter.js";
|
|
15
|
-
import { chunk_particle_lighting_unlit } from "./chunk_particle_lighting.js";
|
|
16
|
-
import { chunk_particle_render_math } from "./chunk_particle_render_math.js";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* The billboard renderer.
|
|
20
|
-
*
|
|
21
|
-
* One instanced draw covers every visible particle: `instance_index` indexes the depth-`sorted` slot
|
|
22
|
-
* list, `vertex_index` (0..5) picks a quad corner. The vertex stage reads the particle's render-bound
|
|
23
|
-
* attributes (position / size / colour / rotation / flipbook frame), expands the corner per the
|
|
24
|
-
* emitter's projection mode, and projects with the camera. The fragment stage samples the atlas
|
|
25
|
-
* sub-rect + flipbook cell, applies an optional soft-depth fade against the scene depth, runs the
|
|
26
|
-
* pluggable lighting hook (unlit by default; the feature swaps in the shading-chunk-backed one when
|
|
27
|
-
* an emitter enables lighting), and emits premultiplied colour.
|
|
28
|
-
*
|
|
29
|
-
* A single blend state — `src*1 + dst*(1-srcAlpha)` on both channels — expresses alpha and additive
|
|
30
|
-
* blending; the shader chooses per particle by how it premultiplies (see `particle_premultiply`), so
|
|
31
|
-
* the whole draw stays GPU-driven with no pipeline switches.
|
|
32
|
-
*
|
|
33
|
-
* The math (billboard expansion, atlas/flipbook UV, soft fade, premultiply) is unit-tested in
|
|
34
|
-
* {@link ./chunk_particle_render_math.spec.js}; this module assembles it into a render pipeline.
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
/** Premultiplied blend: additive when a=0 (dst preserved, colour adds), over-blend when a=srcAlpha. */
|
|
38
|
-
export const PARTICLE_BILLBOARD_BLEND = {
|
|
39
|
-
color: { operation: "add", srcFactor: "one", dstFactor: "one-minus-src-alpha" },
|
|
40
|
-
alpha: { operation: "add", srcFactor: "one", dstFactor: "one-minus-src-alpha" },
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const resources = new ShaderResourceSetDescriptor();
|
|
44
|
-
resources.createGroup()
|
|
45
|
-
.addUniform("camera", CAMERA_UNIFORM_STRUCT)
|
|
46
|
-
.addStorageBuffer("pool", WebGPUArray.u32, false)
|
|
47
|
-
.addStorageBuffer("sorted", WebGPUArray.u32, false)
|
|
48
|
-
.addStorageBuffer("emitters", WebGPUArray.u32, false)
|
|
49
|
-
// Sampled with a filtering sampler, so the atlas must be a filterable float texture.
|
|
50
|
-
.addTexture("atlas", "float")
|
|
51
|
-
.addSampler("atlas_sampler", "filtering")
|
|
52
|
-
// Only textureLoad-ed (soft depth), so it can be unfilterable — matches an r32float scene depth.
|
|
53
|
-
.addTexture("scene_depth", "unfilterable-float");
|
|
54
|
-
|
|
55
|
-
const body = CodeChunk.from(/* wgsl */ `
|
|
56
|
-
const PARTICLE_RECORD_WORDS : u32 = ${PARTICLE_RECORD_WORD_COUNT}u;
|
|
57
|
-
const PARTICLE_HEADER_EMITTER : u32 = ${PARTICLE_RECORD_HEADER_EMITTER}u;
|
|
58
|
-
const PARTICLE_ATTRIBUTE_ABSENT : u32 = ${EMITTER_ATTRIBUTE_ABSENT}u;
|
|
59
|
-
const PARTICLE_FLAG_SOFT_DEPTH : u32 = ${EMITTER_FLAG.SOFT_DEPTH}u;
|
|
60
|
-
const PARTICLE_FLAG_LIGHTING : u32 = ${EMITTER_FLAG.LIGHTING}u;
|
|
61
|
-
const PARTICLE_SOFT_FADE_RANGE : f32 = 0.5;
|
|
62
|
-
|
|
63
|
-
struct ParticleVertexOut {
|
|
64
|
-
@builtin(position) clip : vec4<f32>,
|
|
65
|
-
@location(0) uv : vec2<f32>,
|
|
66
|
-
@location(1) color : vec4<f32>,
|
|
67
|
-
@location(2) world_position : vec3<f32>,
|
|
68
|
-
@location(3) normal : vec3<f32>,
|
|
69
|
-
@location(4) view_depth : f32,
|
|
70
|
-
@location(5) @interpolate(flat) flags : u32,
|
|
71
|
-
@location(6) @interpolate(flat) blend : u32,
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
fn particle_read_vec(base : u32, offset : u32, count : u32) -> vec4<f32> {
|
|
75
|
-
var v = vec4<f32>(0.0);
|
|
76
|
-
if (count > 0u) { v.x = bitcast<f32>(pool[base + offset]); }
|
|
77
|
-
if (count > 1u) { v.y = bitcast<f32>(pool[base + offset + 1u]); }
|
|
78
|
-
if (count > 2u) { v.z = bitcast<f32>(pool[base + offset + 2u]); }
|
|
79
|
-
if (count > 3u) { v.w = bitcast<f32>(pool[base + offset + 3u]); }
|
|
80
|
-
return v;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
@vertex
|
|
84
|
-
fn vs_main(@builtin(vertex_index) vi : u32, @builtin(instance_index) ii : u32) -> ParticleVertexOut {
|
|
85
|
-
var corners = array<vec2<f32>, 6>(
|
|
86
|
-
vec2<f32>(-1.0, -1.0), vec2<f32>(1.0, -1.0), vec2<f32>(1.0, 1.0),
|
|
87
|
-
vec2<f32>(-1.0, -1.0), vec2<f32>(1.0, 1.0), vec2<f32>(-1.0, 1.0),
|
|
88
|
-
);
|
|
89
|
-
let corner = corners[vi];
|
|
90
|
-
|
|
91
|
-
let slot = sorted[ii];
|
|
92
|
-
let base = slot * PARTICLE_RECORD_WORDS;
|
|
93
|
-
let emitter_index = pool[base + PARTICLE_HEADER_EMITTER];
|
|
94
|
-
let em = particle_emitter_read(&emitters, emitter_index);
|
|
95
|
-
|
|
96
|
-
var world_center = vec3<f32>(0.0);
|
|
97
|
-
if (em.render_position != PARTICLE_ATTRIBUTE_ABSENT) { world_center = particle_read_vec(base, em.render_position, 3u).xyz; }
|
|
98
|
-
var size = 1.0;
|
|
99
|
-
if (em.render_size != PARTICLE_ATTRIBUTE_ABSENT) { size = bitcast<f32>(pool[base + em.render_size]); }
|
|
100
|
-
var color = vec4<f32>(1.0);
|
|
101
|
-
if (em.render_color != PARTICLE_ATTRIBUTE_ABSENT) { color = particle_read_vec(base, em.render_color, 4u); }
|
|
102
|
-
var rotation = 0.0;
|
|
103
|
-
if (em.render_rotation != PARTICLE_ATTRIBUTE_ABSENT) { rotation = bitcast<f32>(pool[base + em.render_rotation]); }
|
|
104
|
-
var frame = 0.0;
|
|
105
|
-
if (em.render_frame != PARTICLE_ATTRIBUTE_ABSENT) { frame = bitcast<f32>(pool[base + em.render_frame]); }
|
|
106
|
-
var velocity = vec3<f32>(0.0);
|
|
107
|
-
if (em.render_velocity != PARTICLE_ATTRIBUTE_ABSENT) { velocity = particle_read_vec(base, em.render_velocity, 3u).xyz; }
|
|
108
|
-
|
|
109
|
-
let cam_right = camera.transform[0].xyz;
|
|
110
|
-
let cam_up = camera.transform[1].xyz;
|
|
111
|
-
let cam_forward = -camera.transform[2].xyz;
|
|
112
|
-
|
|
113
|
-
let offset = particle_billboard_offset(corner, size, rotation, cam_right, cam_up, cam_forward, velocity, particle_emitter_projection(em.flags));
|
|
114
|
-
let world = world_center + offset;
|
|
115
|
-
|
|
116
|
-
var out : ParticleVertexOut;
|
|
117
|
-
out.clip = camera.view_projection_matrix * vec4<f32>(world, 1.0);
|
|
118
|
-
out.uv = particle_atlas_uv(corner * 0.5 + vec2<f32>(0.5), em.atlas_region, em.flipbook, frame);
|
|
119
|
-
out.color = color;
|
|
120
|
-
out.world_position = world;
|
|
121
|
-
out.normal = -cam_forward;
|
|
122
|
-
out.view_depth = -(camera.view_matrix * vec4<f32>(world, 1.0)).z;
|
|
123
|
-
out.flags = em.flags;
|
|
124
|
-
out.blend = particle_emitter_blend(em.flags);
|
|
125
|
-
return out;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
@fragment
|
|
129
|
-
fn fs_main(in : ParticleVertexOut) -> @location(0) vec4<f32> {
|
|
130
|
-
let sampled = textureSample(atlas, atlas_sampler, in.uv);
|
|
131
|
-
var color = sampled * in.color;
|
|
132
|
-
|
|
133
|
-
if ((in.flags & PARTICLE_FLAG_SOFT_DEPTH) != 0u) {
|
|
134
|
-
let scene_dev = textureLoad(scene_depth, vec2<i32>(in.clip.xy), 0).r;
|
|
135
|
-
// Reverse-Z hyperbolic linearisation: view_depth = A / (device_depth + B).
|
|
136
|
-
let A = camera.device_depth_to_view_space.y;
|
|
137
|
-
let B = camera.device_depth_to_view_space.x;
|
|
138
|
-
let scene_vd = select(A / (scene_dev + B), 1e9, scene_dev <= 0.0);
|
|
139
|
-
color.a = color.a * particle_soft_fade(scene_vd, in.view_depth, PARTICLE_SOFT_FADE_RANGE);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if ((in.flags & PARTICLE_FLAG_LIGHTING) != 0u) {
|
|
143
|
-
color = particle_apply_lighting(color, in.world_position, normalize(in.normal));
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return particle_premultiply(color, in.blend);
|
|
147
|
-
}
|
|
148
|
-
`, [chunk_particle_emitter, chunk_particle_render_math, chunk_particle_lighting_unlit]);
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
* @
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
1
|
+
import { RenderPipelineDescriptor } from "../../../descriptor/pipeline/render/RenderPipelineDescriptor.js";
|
|
2
|
+
import { ColorTargetState } from "../../../descriptor/pipeline/render/ColorTargetState.js";
|
|
3
|
+
import { DepthStencilState } from "../../../descriptor/pipeline/render/DepthStencilState.js";
|
|
4
|
+
import { WebGPUArray } from "../../shader/type/WebGPUArray.js";
|
|
5
|
+
import { CAMERA_UNIFORM_STRUCT } from "../../camera/CAMERA_UNIFORM_STRUCT.js";
|
|
6
|
+
import { ShaderDescriptor } from "../../shader/ShaderDescriptor.js";
|
|
7
|
+
import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
|
|
8
|
+
import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
|
|
9
|
+
import {
|
|
10
|
+
PARTICLE_RECORD_HEADER_EMITTER,
|
|
11
|
+
PARTICLE_RECORD_WORD_COUNT,
|
|
12
|
+
} from "../ParticleConstants.js";
|
|
13
|
+
import { EMITTER_ATTRIBUTE_ABSENT, EMITTER_FLAG } from "../data/PARTICLE_EMITTER_LAYOUT.js";
|
|
14
|
+
import { chunk_particle_emitter } from "../data/chunk_particle_emitter.js";
|
|
15
|
+
import { chunk_particle_lighting_unlit } from "./chunk_particle_lighting.js";
|
|
16
|
+
import { chunk_particle_render_math } from "./chunk_particle_render_math.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The billboard renderer.
|
|
20
|
+
*
|
|
21
|
+
* One instanced draw covers every visible particle: `instance_index` indexes the depth-`sorted` slot
|
|
22
|
+
* list, `vertex_index` (0..5) picks a quad corner. The vertex stage reads the particle's render-bound
|
|
23
|
+
* attributes (position / size / colour / rotation / flipbook frame), expands the corner per the
|
|
24
|
+
* emitter's projection mode, and projects with the camera. The fragment stage samples the atlas
|
|
25
|
+
* sub-rect + flipbook cell, applies an optional soft-depth fade against the scene depth, runs the
|
|
26
|
+
* pluggable lighting hook (unlit by default; the feature swaps in the shading-chunk-backed one when
|
|
27
|
+
* an emitter enables lighting), and emits premultiplied colour.
|
|
28
|
+
*
|
|
29
|
+
* A single blend state — `src*1 + dst*(1-srcAlpha)` on both channels — expresses alpha and additive
|
|
30
|
+
* blending; the shader chooses per particle by how it premultiplies (see `particle_premultiply`), so
|
|
31
|
+
* the whole draw stays GPU-driven with no pipeline switches.
|
|
32
|
+
*
|
|
33
|
+
* The math (billboard expansion, atlas/flipbook UV, soft fade, premultiply) is unit-tested in
|
|
34
|
+
* {@link ./chunk_particle_render_math.spec.js}; this module assembles it into a render pipeline.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/** Premultiplied blend: additive when a=0 (dst preserved, colour adds), over-blend when a=srcAlpha. */
|
|
38
|
+
export const PARTICLE_BILLBOARD_BLEND = {
|
|
39
|
+
color: { operation: "add", srcFactor: "one", dstFactor: "one-minus-src-alpha" },
|
|
40
|
+
alpha: { operation: "add", srcFactor: "one", dstFactor: "one-minus-src-alpha" },
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const resources = new ShaderResourceSetDescriptor();
|
|
44
|
+
resources.createGroup()
|
|
45
|
+
.addUniform("camera", CAMERA_UNIFORM_STRUCT)
|
|
46
|
+
.addStorageBuffer("pool", WebGPUArray.u32, false)
|
|
47
|
+
.addStorageBuffer("sorted", WebGPUArray.u32, false)
|
|
48
|
+
.addStorageBuffer("emitters", WebGPUArray.u32, false)
|
|
49
|
+
// Sampled with a filtering sampler, so the atlas must be a filterable float texture.
|
|
50
|
+
.addTexture("atlas", "float")
|
|
51
|
+
.addSampler("atlas_sampler", "filtering")
|
|
52
|
+
// Only textureLoad-ed (soft depth), so it can be unfilterable — matches an r32float scene depth.
|
|
53
|
+
.addTexture("scene_depth", "unfilterable-float");
|
|
54
|
+
|
|
55
|
+
const body = CodeChunk.from(/* wgsl */ `
|
|
56
|
+
const PARTICLE_RECORD_WORDS : u32 = ${PARTICLE_RECORD_WORD_COUNT}u;
|
|
57
|
+
const PARTICLE_HEADER_EMITTER : u32 = ${PARTICLE_RECORD_HEADER_EMITTER}u;
|
|
58
|
+
const PARTICLE_ATTRIBUTE_ABSENT : u32 = ${EMITTER_ATTRIBUTE_ABSENT}u;
|
|
59
|
+
const PARTICLE_FLAG_SOFT_DEPTH : u32 = ${EMITTER_FLAG.SOFT_DEPTH}u;
|
|
60
|
+
const PARTICLE_FLAG_LIGHTING : u32 = ${EMITTER_FLAG.LIGHTING}u;
|
|
61
|
+
const PARTICLE_SOFT_FADE_RANGE : f32 = 0.5;
|
|
62
|
+
|
|
63
|
+
struct ParticleVertexOut {
|
|
64
|
+
@builtin(position) clip : vec4<f32>,
|
|
65
|
+
@location(0) uv : vec2<f32>,
|
|
66
|
+
@location(1) color : vec4<f32>,
|
|
67
|
+
@location(2) world_position : vec3<f32>,
|
|
68
|
+
@location(3) normal : vec3<f32>,
|
|
69
|
+
@location(4) view_depth : f32,
|
|
70
|
+
@location(5) @interpolate(flat) flags : u32,
|
|
71
|
+
@location(6) @interpolate(flat) blend : u32,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn particle_read_vec(base : u32, offset : u32, count : u32) -> vec4<f32> {
|
|
75
|
+
var v = vec4<f32>(0.0);
|
|
76
|
+
if (count > 0u) { v.x = bitcast<f32>(pool[base + offset]); }
|
|
77
|
+
if (count > 1u) { v.y = bitcast<f32>(pool[base + offset + 1u]); }
|
|
78
|
+
if (count > 2u) { v.z = bitcast<f32>(pool[base + offset + 2u]); }
|
|
79
|
+
if (count > 3u) { v.w = bitcast<f32>(pool[base + offset + 3u]); }
|
|
80
|
+
return v;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@vertex
|
|
84
|
+
fn vs_main(@builtin(vertex_index) vi : u32, @builtin(instance_index) ii : u32) -> ParticleVertexOut {
|
|
85
|
+
var corners = array<vec2<f32>, 6>(
|
|
86
|
+
vec2<f32>(-1.0, -1.0), vec2<f32>(1.0, -1.0), vec2<f32>(1.0, 1.0),
|
|
87
|
+
vec2<f32>(-1.0, -1.0), vec2<f32>(1.0, 1.0), vec2<f32>(-1.0, 1.0),
|
|
88
|
+
);
|
|
89
|
+
let corner = corners[vi];
|
|
90
|
+
|
|
91
|
+
let slot = sorted[ii];
|
|
92
|
+
let base = slot * PARTICLE_RECORD_WORDS;
|
|
93
|
+
let emitter_index = pool[base + PARTICLE_HEADER_EMITTER];
|
|
94
|
+
let em = particle_emitter_read(&emitters, emitter_index);
|
|
95
|
+
|
|
96
|
+
var world_center = vec3<f32>(0.0);
|
|
97
|
+
if (em.render_position != PARTICLE_ATTRIBUTE_ABSENT) { world_center = particle_read_vec(base, em.render_position, 3u).xyz; }
|
|
98
|
+
var size = 1.0;
|
|
99
|
+
if (em.render_size != PARTICLE_ATTRIBUTE_ABSENT) { size = bitcast<f32>(pool[base + em.render_size]); }
|
|
100
|
+
var color = vec4<f32>(1.0);
|
|
101
|
+
if (em.render_color != PARTICLE_ATTRIBUTE_ABSENT) { color = particle_read_vec(base, em.render_color, 4u); }
|
|
102
|
+
var rotation = 0.0;
|
|
103
|
+
if (em.render_rotation != PARTICLE_ATTRIBUTE_ABSENT) { rotation = bitcast<f32>(pool[base + em.render_rotation]); }
|
|
104
|
+
var frame = 0.0;
|
|
105
|
+
if (em.render_frame != PARTICLE_ATTRIBUTE_ABSENT) { frame = bitcast<f32>(pool[base + em.render_frame]); }
|
|
106
|
+
var velocity = vec3<f32>(0.0);
|
|
107
|
+
if (em.render_velocity != PARTICLE_ATTRIBUTE_ABSENT) { velocity = particle_read_vec(base, em.render_velocity, 3u).xyz; }
|
|
108
|
+
|
|
109
|
+
let cam_right = camera.transform[0].xyz;
|
|
110
|
+
let cam_up = camera.transform[1].xyz;
|
|
111
|
+
let cam_forward = -camera.transform[2].xyz;
|
|
112
|
+
|
|
113
|
+
let offset = particle_billboard_offset(corner, size, rotation, cam_right, cam_up, cam_forward, velocity, particle_emitter_projection(em.flags));
|
|
114
|
+
let world = world_center + offset;
|
|
115
|
+
|
|
116
|
+
var out : ParticleVertexOut;
|
|
117
|
+
out.clip = camera.view_projection_matrix * vec4<f32>(world, 1.0);
|
|
118
|
+
out.uv = particle_atlas_uv(corner * 0.5 + vec2<f32>(0.5), em.atlas_region, em.flipbook, frame);
|
|
119
|
+
out.color = color;
|
|
120
|
+
out.world_position = world;
|
|
121
|
+
out.normal = -cam_forward;
|
|
122
|
+
out.view_depth = -(camera.view_matrix * vec4<f32>(world, 1.0)).z;
|
|
123
|
+
out.flags = em.flags;
|
|
124
|
+
out.blend = particle_emitter_blend(em.flags);
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@fragment
|
|
129
|
+
fn fs_main(in : ParticleVertexOut) -> @location(0) vec4<f32> {
|
|
130
|
+
let sampled = textureSample(atlas, atlas_sampler, in.uv);
|
|
131
|
+
var color = sampled * in.color;
|
|
132
|
+
|
|
133
|
+
if ((in.flags & PARTICLE_FLAG_SOFT_DEPTH) != 0u) {
|
|
134
|
+
let scene_dev = textureLoad(scene_depth, vec2<i32>(in.clip.xy), 0).r;
|
|
135
|
+
// Reverse-Z hyperbolic linearisation: view_depth = A / (device_depth + B).
|
|
136
|
+
let A = camera.device_depth_to_view_space.y;
|
|
137
|
+
let B = camera.device_depth_to_view_space.x;
|
|
138
|
+
let scene_vd = select(A / (scene_dev + B), 1e9, scene_dev <= 0.0);
|
|
139
|
+
color.a = color.a * particle_soft_fade(scene_vd, in.view_depth, PARTICLE_SOFT_FADE_RANGE);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if ((in.flags & PARTICLE_FLAG_LIGHTING) != 0u) {
|
|
143
|
+
color = particle_apply_lighting(color, in.world_position, normalize(in.normal));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return particle_premultiply(color, in.blend);
|
|
147
|
+
}
|
|
148
|
+
`, [chunk_particle_emitter, chunk_particle_render_math, chunk_particle_lighting_unlit]);
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The shader itself. One compilation, shared by every pipeline built from it — the options below
|
|
152
|
+
* vary the pipeline state, never the WGSL.
|
|
153
|
+
*
|
|
154
|
+
* @type {ShaderDescriptor}
|
|
155
|
+
*/
|
|
156
|
+
const descriptor = ShaderDescriptor.from({ label: "Particle Billboard", body, resources });
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Build the billboard render pipeline descriptor.
|
|
160
|
+
* @param {object} [options]
|
|
161
|
+
* @param {string} [options.color_format] colour target format
|
|
162
|
+
* @param {string|null} [options.depth_format] scene depth format (test-only, no write); pass null to
|
|
163
|
+
* render without a depth attachment (e.g. an additive-only prototype with no scene geometry)
|
|
164
|
+
* @param {GPUCompareFunction} [options.depth_compare] depth test — "greater"/"greater-equal" for
|
|
165
|
+
* reverse-Z scenes (the engine convention), "less"/"less-equal" for a standard-Z scene
|
|
166
|
+
* @returns {RenderPipelineDescriptor}
|
|
167
|
+
*/
|
|
168
|
+
export function create_particle_billboard_pipeline({ color_format = "rgba16float", depth_format = "depth32float", depth_compare = "greater" } = {}) {
|
|
169
|
+
const code = descriptor.source;
|
|
170
|
+
|
|
171
|
+
return RenderPipelineDescriptor.from({
|
|
172
|
+
label: "Particle Billboard",
|
|
173
|
+
layout: resources.generatePipelineLayout(GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT),
|
|
174
|
+
vertex: { module: { code }, entryPoint: "vs_main" },
|
|
175
|
+
fragment: {
|
|
176
|
+
module: { code },
|
|
177
|
+
entryPoint: "fs_main",
|
|
178
|
+
targets: [ColorTargetState.from({ format: color_format, blend: PARTICLE_BILLBOARD_BLEND })],
|
|
179
|
+
},
|
|
180
|
+
// Depth-test against the scene, but never write (transparent). Omitted entirely when no depth
|
|
181
|
+
// attachment is bound.
|
|
182
|
+
depthStencil: depth_format == null
|
|
183
|
+
? undefined
|
|
184
|
+
: DepthStencilState.from({ format: depth_format, depthWriteEnabled: false, depthCompare: depth_compare }),
|
|
185
|
+
primitive: { topology: "triangle-list", cullMode: "none" },
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** The billboard shader's resource set (for building bind groups + the draw command). */
|
|
190
|
+
export const PARTICLE_BILLBOARD_RESOURCES = resources;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader_particle_simulate.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_simulate.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,+CAHU,aAAa,CAG4B;AA0DnD,
|
|
1
|
+
{"version":3,"file":"shader_particle_simulate.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/shaders/shader_particle_simulate.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,+CAHU,aAAa,CAG4B;AA0DnD,qDAIG;8BAhG2B,+BAA+B"}
|
|
@@ -1,100 +1,99 @@
|
|
|
1
|
-
import { atomic_u32, f32, u32 } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
2
|
-
import { WebGPUArray } from "../../shader/type/WebGPUArray.js";
|
|
3
|
-
import { ComputeShader } from "../../shader/ComputeShader.js";
|
|
4
|
-
import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
|
|
5
|
-
import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
|
|
6
|
-
import {
|
|
7
|
-
PARTICLE_RECORD_HEADER_EMITTER,
|
|
8
|
-
PARTICLE_RECORD_WORD_COUNT,
|
|
9
|
-
PARTICLE_VM_INSTRUCTION_WORDS,
|
|
10
|
-
} from "../ParticleConstants.js";
|
|
11
|
-
import { PARTICLE_COUNTER } from "../data/PARTICLE_COUNTERS.js";
|
|
12
|
-
import { chunk_particle_context, chunk_particle_curve_disabled } from "./chunk_particle_context.js";
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* The particle simulate pass — Destiny-style single execution shader.
|
|
16
|
-
*
|
|
17
|
-
* One dispatch processes the entire alive list across every emitter. Per particle: read its owning
|
|
18
|
-
* emitter, set up the VM context + RNG, run that emitter's compiled UPDATE program over the record,
|
|
19
|
-
* then compact — killed particles are pushed back to the dead (free) list, survivors are appended to
|
|
20
|
-
* the new alive list. There is exactly one pipeline regardless of how many distinct effects exist,
|
|
21
|
-
* because behaviour is data (the bytecode program), not code.
|
|
22
|
-
*
|
|
23
|
-
* The input length is read from `counters[ALIVE_IN]` — the previous frame's final alive count,
|
|
24
|
-
* snapshotted on the GPU by the build-indirect pass — NOT from a CPU uniform. A CPU-provided count
|
|
25
|
-
* is inevitably stale (readback latency) and corrupts the pool: under-counting orphans the tail of
|
|
26
|
-
* the alive list (slots leak into limbo), over-counting re-simulates stale entries and double-frees
|
|
27
|
-
* their slots. Dispatch this shader with `dispatchWorkgroupsIndirect` using the args the
|
|
28
|
-
* build-indirect pass wrote last frame, so thread count and bound agree by construction.
|
|
29
|
-
*
|
|
30
|
-
* All structured reads go through `array<u32>` for emulator-testability. Curve sampling uses the
|
|
31
|
-
* pluggable `particle_vm_sample_curve` — here the no-op provider; the feature swaps in the
|
|
32
|
-
* animation-database-backed one.
|
|
33
|
-
*
|
|
34
|
-
* @type {ComputeShader}
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
export const PARTICLE_SIMULATE_WORKGROUP_SIZE = 64;
|
|
38
|
-
|
|
39
|
-
const resources = new ShaderResourceSetDescriptor();
|
|
40
|
-
resources.createGroup()
|
|
41
|
-
.addStorageBuffer("emitters", WebGPUArray.u32, false)
|
|
42
|
-
.addStorageBuffer("program", WebGPUArray.u32, false)
|
|
43
|
-
.addStorageBuffer("vm_constants", WebGPUArray.u32, false)
|
|
44
|
-
.addStorageBuffer("pool", WebGPUArray.u32, true)
|
|
45
|
-
.addStorageBuffer("alive_in", WebGPUArray.u32, false)
|
|
46
|
-
.addStorageBuffer("alive_out", WebGPUArray.u32, true)
|
|
47
|
-
.addStorageBuffer("dead", WebGPUArray.u32, true)
|
|
48
|
-
.addStorageBuffer("counters", WebGPUArray.from(atomic_u32), true)
|
|
49
|
-
.addUniform("u_dt", f32)
|
|
50
|
-
.addUniform("u_time", f32)
|
|
51
|
-
.addUniform("u_frame", u32);
|
|
52
|
-
|
|
53
|
-
const body = CodeChunk.from(/* wgsl */ `
|
|
54
|
-
const PARTICLE_RECORD_WORDS : u32 = ${PARTICLE_RECORD_WORD_COUNT}u;
|
|
55
|
-
const PARTICLE_HEADER_EMITTER : u32 = ${PARTICLE_RECORD_HEADER_EMITTER}u;
|
|
56
|
-
const PARTICLE_INSTRUCTION_WORDS : u32 = ${PARTICLE_VM_INSTRUCTION_WORDS}u;
|
|
57
|
-
const COUNTER_ALIVE : u32 = ${PARTICLE_COUNTER.ALIVE}u;
|
|
58
|
-
const COUNTER_DEAD : u32 = ${PARTICLE_COUNTER.DEAD}u;
|
|
59
|
-
const COUNTER_ALIVE_IN : u32 = ${PARTICLE_COUNTER.ALIVE_IN}u;
|
|
60
|
-
|
|
61
|
-
@compute @workgroup_size(${PARTICLE_SIMULATE_WORKGROUP_SIZE}, 1, 1)
|
|
62
|
-
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
|
|
63
|
-
let i = gid.x;
|
|
64
|
-
// The exact alive-list length, snapshotted on-GPU last frame — never a stale CPU value.
|
|
65
|
-
if (i >= atomicLoad(&counters[COUNTER_ALIVE_IN])) { return; }
|
|
66
|
-
|
|
67
|
-
let slot = alive_in[i];
|
|
68
|
-
let record_base = slot * PARTICLE_RECORD_WORDS;
|
|
69
|
-
let emitter_index = pool[record_base + PARTICLE_HEADER_EMITTER];
|
|
70
|
-
|
|
71
|
-
let em = particle_emitter_read(&emitters, emitter_index);
|
|
72
|
-
|
|
73
|
-
particle_vm_reset();
|
|
74
|
-
particle_setup_context(em, slot, u_dt, u_time, 0.0, 0.0, u_frame);
|
|
75
|
-
particle_vm_execute(
|
|
76
|
-
&program,
|
|
77
|
-
em.update_offset * PARTICLE_INSTRUCTION_WORDS,
|
|
78
|
-
em.update_count,
|
|
79
|
-
&vm_constants,
|
|
80
|
-
em.constant_offset,
|
|
81
|
-
&pool,
|
|
82
|
-
record_base,
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
if (vm_killed) {
|
|
86
|
-
let d = atomicAdd(&counters[COUNTER_DEAD], 1u);
|
|
87
|
-
dead[d] = slot;
|
|
88
|
-
} else {
|
|
89
|
-
let a = atomicAdd(&counters[COUNTER_ALIVE], 1u);
|
|
90
|
-
alive_out[a] = slot;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
`, [chunk_particle_context, chunk_particle_curve_disabled]);
|
|
94
|
-
|
|
95
|
-
export const shader_particle_simulate = ComputeShader.from({
|
|
96
|
-
label: "Particle Simulate",
|
|
97
|
-
resources,
|
|
98
|
-
body,
|
|
99
|
-
|
|
100
|
-
});
|
|
1
|
+
import { atomic_u32, f32, u32 } from "../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
2
|
+
import { WebGPUArray } from "../../shader/type/WebGPUArray.js";
|
|
3
|
+
import { ComputeShader } from "../../shader/ComputeShader.js";
|
|
4
|
+
import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
|
|
5
|
+
import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
|
|
6
|
+
import {
|
|
7
|
+
PARTICLE_RECORD_HEADER_EMITTER,
|
|
8
|
+
PARTICLE_RECORD_WORD_COUNT,
|
|
9
|
+
PARTICLE_VM_INSTRUCTION_WORDS,
|
|
10
|
+
} from "../ParticleConstants.js";
|
|
11
|
+
import { PARTICLE_COUNTER } from "../data/PARTICLE_COUNTERS.js";
|
|
12
|
+
import { chunk_particle_context, chunk_particle_curve_disabled } from "./chunk_particle_context.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The particle simulate pass — Destiny-style single execution shader.
|
|
16
|
+
*
|
|
17
|
+
* One dispatch processes the entire alive list across every emitter. Per particle: read its owning
|
|
18
|
+
* emitter, set up the VM context + RNG, run that emitter's compiled UPDATE program over the record,
|
|
19
|
+
* then compact — killed particles are pushed back to the dead (free) list, survivors are appended to
|
|
20
|
+
* the new alive list. There is exactly one pipeline regardless of how many distinct effects exist,
|
|
21
|
+
* because behaviour is data (the bytecode program), not code.
|
|
22
|
+
*
|
|
23
|
+
* The input length is read from `counters[ALIVE_IN]` — the previous frame's final alive count,
|
|
24
|
+
* snapshotted on the GPU by the build-indirect pass — NOT from a CPU uniform. A CPU-provided count
|
|
25
|
+
* is inevitably stale (readback latency) and corrupts the pool: under-counting orphans the tail of
|
|
26
|
+
* the alive list (slots leak into limbo), over-counting re-simulates stale entries and double-frees
|
|
27
|
+
* their slots. Dispatch this shader with `dispatchWorkgroupsIndirect` using the args the
|
|
28
|
+
* build-indirect pass wrote last frame, so thread count and bound agree by construction.
|
|
29
|
+
*
|
|
30
|
+
* All structured reads go through `array<u32>` for emulator-testability. Curve sampling uses the
|
|
31
|
+
* pluggable `particle_vm_sample_curve` — here the no-op provider; the feature swaps in the
|
|
32
|
+
* animation-database-backed one.
|
|
33
|
+
*
|
|
34
|
+
* @type {ComputeShader}
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
export const PARTICLE_SIMULATE_WORKGROUP_SIZE = 64;
|
|
38
|
+
|
|
39
|
+
const resources = new ShaderResourceSetDescriptor();
|
|
40
|
+
resources.createGroup()
|
|
41
|
+
.addStorageBuffer("emitters", WebGPUArray.u32, false)
|
|
42
|
+
.addStorageBuffer("program", WebGPUArray.u32, false)
|
|
43
|
+
.addStorageBuffer("vm_constants", WebGPUArray.u32, false)
|
|
44
|
+
.addStorageBuffer("pool", WebGPUArray.u32, true)
|
|
45
|
+
.addStorageBuffer("alive_in", WebGPUArray.u32, false)
|
|
46
|
+
.addStorageBuffer("alive_out", WebGPUArray.u32, true)
|
|
47
|
+
.addStorageBuffer("dead", WebGPUArray.u32, true)
|
|
48
|
+
.addStorageBuffer("counters", WebGPUArray.from(atomic_u32), true)
|
|
49
|
+
.addUniform("u_dt", f32)
|
|
50
|
+
.addUniform("u_time", f32)
|
|
51
|
+
.addUniform("u_frame", u32);
|
|
52
|
+
|
|
53
|
+
const body = CodeChunk.from(/* wgsl */ `
|
|
54
|
+
const PARTICLE_RECORD_WORDS : u32 = ${PARTICLE_RECORD_WORD_COUNT}u;
|
|
55
|
+
const PARTICLE_HEADER_EMITTER : u32 = ${PARTICLE_RECORD_HEADER_EMITTER}u;
|
|
56
|
+
const PARTICLE_INSTRUCTION_WORDS : u32 = ${PARTICLE_VM_INSTRUCTION_WORDS}u;
|
|
57
|
+
const COUNTER_ALIVE : u32 = ${PARTICLE_COUNTER.ALIVE}u;
|
|
58
|
+
const COUNTER_DEAD : u32 = ${PARTICLE_COUNTER.DEAD}u;
|
|
59
|
+
const COUNTER_ALIVE_IN : u32 = ${PARTICLE_COUNTER.ALIVE_IN}u;
|
|
60
|
+
|
|
61
|
+
@compute @workgroup_size(${PARTICLE_SIMULATE_WORKGROUP_SIZE}, 1, 1)
|
|
62
|
+
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
|
|
63
|
+
let i = gid.x;
|
|
64
|
+
// The exact alive-list length, snapshotted on-GPU last frame — never a stale CPU value.
|
|
65
|
+
if (i >= atomicLoad(&counters[COUNTER_ALIVE_IN])) { return; }
|
|
66
|
+
|
|
67
|
+
let slot = alive_in[i];
|
|
68
|
+
let record_base = slot * PARTICLE_RECORD_WORDS;
|
|
69
|
+
let emitter_index = pool[record_base + PARTICLE_HEADER_EMITTER];
|
|
70
|
+
|
|
71
|
+
let em = particle_emitter_read(&emitters, emitter_index);
|
|
72
|
+
|
|
73
|
+
particle_vm_reset();
|
|
74
|
+
particle_setup_context(em, slot, u_dt, u_time, 0.0, 0.0, u_frame);
|
|
75
|
+
particle_vm_execute(
|
|
76
|
+
&program,
|
|
77
|
+
em.update_offset * PARTICLE_INSTRUCTION_WORDS,
|
|
78
|
+
em.update_count,
|
|
79
|
+
&vm_constants,
|
|
80
|
+
em.constant_offset,
|
|
81
|
+
&pool,
|
|
82
|
+
record_base,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
if (vm_killed) {
|
|
86
|
+
let d = atomicAdd(&counters[COUNTER_DEAD], 1u);
|
|
87
|
+
dead[d] = slot;
|
|
88
|
+
} else {
|
|
89
|
+
let a = atomicAdd(&counters[COUNTER_ALIVE], 1u);
|
|
90
|
+
alive_out[a] = slot;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
`, [chunk_particle_context, chunk_particle_curve_disabled]);
|
|
94
|
+
|
|
95
|
+
export const shader_particle_simulate = ComputeShader.from({
|
|
96
|
+
label: "Particle Simulate",
|
|
97
|
+
resources,
|
|
98
|
+
body,
|
|
99
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader_particle_sort.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/sort/shader_particle_sort.js"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,8CAA+C;AAyB/C,
|
|
1
|
+
{"version":3,"file":"shader_particle_sort.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/sort/shader_particle_sort.js"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,8CAA+C;AAyB/C,uDAIG;AA+DH,2DAIG;AA4BH,yDAIG;8BA3J2B,+BAA+B"}
|