@woosh/meep-engine 3.53.0 → 3.55.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/package.json +1 -1
- package/src/core/math/noise/worley_noise_2d.d.ts +14 -0
- package/src/core/math/noise/worley_noise_2d.d.ts.map +1 -0
- package/src/core/math/noise/worley_noise_2d.js +74 -0
- package/src/engine/graphics/texture/atlas/CachingTextureAtlas.d.ts +6 -1
- package/src/engine/graphics/texture/atlas/CachingTextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/CachingTextureAtlas.js +363 -325
- package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.d.ts +93 -14
- package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.js +322 -183
- package/src/engine/graphics/texture/atlas/ReferencedTextureAtlas.d.ts +9 -0
- package/src/engine/graphics/texture/atlas/ReferencedTextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +110 -83
- package/src/engine/graphics/texture/atlas/SpriteAtlas.d.ts +42 -0
- package/src/engine/graphics/texture/atlas/SpriteAtlas.d.ts.map +1 -0
- package/src/engine/{graphics3/decal/DecalAtlas.js → graphics/texture/atlas/SpriteAtlas.js} +202 -194
- package/src/engine/{graphics3/decal/DecalAtlasFill.d.ts → graphics/texture/atlas/SpriteAtlasFill.d.ts} +4 -4
- package/src/engine/graphics/texture/atlas/SpriteAtlasFill.d.ts.map +1 -0
- package/src/engine/graphics/texture/atlas/SpriteAtlasFill.js +30 -0
- package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts +7 -0
- package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/TextureAtlas.js +11 -1
- package/src/engine/{graphics3/decal/decal_atlas_border.d.ts → graphics/texture/atlas/sprite_atlas_border.d.ts} +12 -12
- package/src/engine/graphics/texture/atlas/sprite_atlas_border.d.ts.map +1 -0
- package/src/engine/{graphics3/decal/decal_atlas_border.js → graphics/texture/atlas/sprite_atlas_border.js} +69 -69
- package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
- package/src/engine/graphics3/DecalSystem.js +447 -450
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +9 -22
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/GPUParticleEmitterSystem.js +892 -951
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/generation/foliage/FOLIAGE_DESIGN.md +2 -1
- package/src/generation/foliage/config/BarkMaterialConfig.d.ts +4 -3
- package/src/generation/foliage/config/BarkMaterialConfig.d.ts.map +1 -1
- package/src/generation/foliage/config/BarkMaterialConfig.js +6 -6
- package/src/generation/foliage/config/FoliageBarkType.d.ts +11 -0
- package/src/generation/foliage/config/FoliageBarkType.d.ts.map +1 -0
- package/src/generation/foliage/config/FoliageBarkType.js +16 -0
- package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +58 -5
- package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -1
- package/src/generation/foliage/config/FoliageMaterialConfig.js +279 -181
- package/src/generation/foliage/index.d.ts +2 -1
- package/src/generation/foliage/index.js +44 -43
- package/src/generation/foliage/material/make_bark_material.d.ts.map +1 -1
- package/src/generation/foliage/material/make_bark_material.js +23 -95
- package/src/generation/foliage/material/make_foliage_material.d.ts +29 -3
- package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -1
- package/src/generation/foliage/material/make_foliage_material.js +605 -359
- package/src/generation/foliage/mesh/branch_collar_project.d.ts.map +1 -1
- package/src/generation/foliage/mesh/branch_collar_project.js +205 -203
- package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +15 -0
- package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -1
- package/src/generation/foliage/mesh/foliage_collect_attachments.js +569 -502
- package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1049 -1047
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +2 -1
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +454 -415
- package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
- package/src/generation/foliage/presets/make_tree_species_preset.js +870 -837
- package/src/generation/foliage/skeleton/crown_envelope_evaluate.js +121 -121
- package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts +10 -7
- package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js +206 -179
- package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/tree_skeleton_grow.js +1871 -1104
- package/src/shade/RENDERER_CONTRACT.md +5 -2
- package/src/shade/device/SHADE_DEVICE_FLOOR.d.ts.map +1 -1
- package/src/shade/device/SHADE_DEVICE_FLOOR.js +2 -0
- package/src/shade/playground/foliage_wind/foliage_world.d.ts +6 -0
- package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
- package/src/shade/playground/foliage_wind/foliage_world.js +602 -593
- package/src/shade/playground/foliage_wind/index.html +260 -254
- package/src/shade/playground/foliage_wind/main.js +275 -263
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +1 -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/sdf/GPUGeometrySDFManager.js +1 -1
- package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +3 -3
- package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
- package/src/shade/renderer/hiz/HierarchicalZBuffer.js +350 -294
- package/src/shade/renderer/hiz/generate_downsampler_code.d.ts +0 -2
- package/src/shade/renderer/hiz/generate_downsampler_code.d.ts.map +1 -1
- package/src/shade/renderer/hiz/generate_downsampler_code.js +99 -100
- package/src/shade/renderer/hiz/hzb_pick_alignment.d.ts +15 -0
- package/src/shade/renderer/hiz/hzb_pick_alignment.d.ts.map +1 -0
- package/src/shade/renderer/hiz/hzb_pick_alignment.js +148 -0
- package/src/shade/renderer/hiz/hzb_plan_reduction_steps.d.ts +28 -0
- package/src/shade/renderer/hiz/hzb_plan_reduction_steps.d.ts.map +1 -0
- package/src/shade/renderer/hiz/hzb_plan_reduction_steps.js +58 -0
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +5 -5
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +57 -67
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +3 -3
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +1 -1
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.js +111 -112
- package/src/shade/renderer/hiz/shader_hzb_spd.d.ts +5 -0
- package/src/shade/renderer/hiz/shader_hzb_spd.d.ts.map +1 -0
- package/src/shade/renderer/hiz/shader_hzb_spd.js +160 -0
- package/src/shade/renderer/light/GPULightCollection.d.ts +8 -0
- package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
- package/src/shade/renderer/light/GPULightCollection.js +67 -0
- package/src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.d.ts +7 -0
- package/src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.js +13 -0
- package/src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.d.ts +10 -0
- package/src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.js +72 -0
- package/src/shade/renderer/light/world_cluster/WORLD_LIGHT_CLUSTER.d.ts +39 -0
- package/src/shade/renderer/light/world_cluster/WORLD_LIGHT_CLUSTER.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/WORLD_LIGHT_CLUSTER.js +90 -0
- package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.d.ts +12 -0
- package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.js +56 -0
- package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.d.ts +31 -0
- package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.js +196 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.d.ts +10 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.js +163 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_cull_lights.d.ts +4 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_cull_lights.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_cull_lights.js +137 -0
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +4 -3
- package/src/shade/renderer/particles/graph_particles_avboit.d.ts +4 -3
- package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles_avboit.js +28 -11
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +9 -13
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +25 -20
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +21 -38
- package/src/shade/renderer/postprocess/denoise/fragment_shader_denoise_ao.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/denoise/fragment_shader_denoise_ao.js +154 -147
- package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +2 -1
- package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/GTAO.js +5 -1
- package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.d.ts +8 -0
- package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.js +10 -1
- package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +5 -0
- package/src/shade/renderer/postprocess/gtao/chunk_gtao_compute_mip_level.d.ts +22 -0
- package/src/shade/renderer/postprocess/gtao/chunk_gtao_compute_mip_level.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/gtao/chunk_gtao_compute_mip_level.js +33 -0
- package/src/shade/renderer/postprocess/gtao/chunk_gtao_resolve_hzb_depth.d.ts +22 -0
- package/src/shade/renderer/postprocess/gtao/chunk_gtao_resolve_hzb_depth.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/gtao/chunk_gtao_resolve_hzb_depth.js +56 -0
- package/src/shade/renderer/postprocess/gtao/chunk_gtao_sample_depth.d.ts +13 -0
- package/src/shade/renderer/postprocess/gtao/chunk_gtao_sample_depth.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/gtao/chunk_gtao_sample_depth.js +42 -0
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts +2 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +382 -357
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +414 -410
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -7
- package/src/shade/renderer/shader/chunk/depth/chunk_query_depth_from_screen_space_bb.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/depth/chunk_query_depth_from_screen_space_bb.js +62 -62
- package/src/shade/renderer/shader/chunk/random/lowbias/chunk_hash_lowbias32_vec2u.d.ts +6 -0
- package/src/shade/renderer/shader/chunk/random/lowbias/chunk_hash_lowbias32_vec2u.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/random/lowbias/chunk_hash_lowbias32_vec2u.js +19 -0
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_get_mip_resolution.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_get_mip_resolution.js +16 -10
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_hierarchical_raymarch.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_hierarchical_raymarch.js +118 -117
- package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts +41 -7
- package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts.map +1 -1
- package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.js +162 -58
- package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.js +1 -1
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +10 -12
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +583 -606
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +640 -640
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts +113 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.js +484 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.d.ts +50 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.js +60 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP_STRUCT.d.ts +25 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP_STRUCT.js +47 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IrradianceCascadePlacement.d.ts +74 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IrradianceCascadePlacement.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IrradianceCascadePlacement.js +173 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts +26 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.js +83 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_local_light.d.ts +36 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_local_light.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_local_light.js +129 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_sample.d.ts +121 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_sample.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_sample.js +370 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.d.ts +16 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.js +191 -0
- package/src/shade/renderer/wind/GPUSceneWind.d.ts +1 -1
- package/src/shade/renderer/wind/GPUSceneWind.js +1 -1
- package/src/engine/graphics3/decal/DecalAtlas.d.ts +0 -43
- package/src/engine/graphics3/decal/DecalAtlas.d.ts.map +0 -1
- package/src/engine/graphics3/decal/DecalAtlasFill.d.ts.map +0 -1
- package/src/engine/graphics3/decal/DecalAtlasFill.js +0 -32
- package/src/engine/graphics3/decal/decal_atlas_border.d.ts.map +0 -1
- package/src/shade/renderer/postprocess/gtao/graph_build_depth_mipmap.d.ts +0 -26
- package/src/shade/renderer/postprocess/gtao/graph_build_depth_mipmap.d.ts.map +0 -1
- package/src/shade/renderer/postprocess/gtao/graph_build_depth_mipmap.js +0 -268
- package/src/shade/renderer/postprocess/ssr/copy_shader_f32.d.ts +0 -3
- package/src/shade/renderer/postprocess/ssr/copy_shader_f32.d.ts.map +0 -1
- package/src/shade/renderer/postprocess/ssr/copy_shader_f32.js +0 -32
- package/src/shade/renderer/postprocess/ssr/depth_max_shader.d.ts +0 -17
- package/src/shade/renderer/postprocess/ssr/depth_max_shader.d.ts.map +0 -1
- package/src/shade/renderer/postprocess/ssr/depth_max_shader.js +0 -98
- package/src/shade/renderer/postprocess/ssr/graph_build_depth_max_pyramid.d.ts +0 -23
- package/src/shade/renderer/postprocess/ssr/graph_build_depth_max_pyramid.d.ts.map +0 -1
- package/src/shade/renderer/postprocess/ssr/graph_build_depth_max_pyramid.js +0 -118
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_froxel_centre_ws.d.ts +0 -15
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_froxel_centre_ws.d.ts.map +0 -1
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_froxel_centre_ws.js +0 -49
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.d.ts +0 -17
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.d.ts.map +0 -1
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.js +0 -50
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi_sample.d.ts +0 -35
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi_sample.d.ts.map +0 -1
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi_sample.js +0 -105
- package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.d.ts +0 -35
- package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.d.ts.map +0 -1
- package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.js +0 -80
- package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi.d.ts +0 -10
- package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi.d.ts.map +0 -1
- package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi.js +0 -51
- package/src/shade/renderer/volumetrics/gi/volumetrics_gi_resources.d.ts +0 -28
- package/src/shade/renderer/volumetrics/gi/volumetrics_gi_resources.d.ts.map +0 -1
- package/src/shade/renderer/volumetrics/gi/volumetrics_gi_resources.js +0 -39
- package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts +0 -48
- package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts.map +0 -1
- package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.js +0 -121
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.d.ts +0 -28
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.d.ts.map +0 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.js +0 -237
|
@@ -1,640 +1,640 @@
|
|
|
1
|
-
import { assert } from "../../../core/assert.js";
|
|
2
|
-
import { SamplerDescriptor } from "../../descriptor/texture/SamplerDescriptor.js";
|
|
3
|
-
import { BufferResourceDescriptor } from "../../device/graph/BufferResourceDescriptor.js";
|
|
4
|
-
import { TextureResourceDescriptor } from "../../device/graph/TextureResourceDescriptor.js";
|
|
5
|
-
import { ShaderSwitchSet } from "../shader/compiler/ShaderSwitchSet.js";
|
|
6
|
-
import { graph_compute_pass } from "../shader/graph/compute/graph_compute_pass.js";
|
|
7
|
-
import { graph_import_buffer } from "../shader/graph/graph_import_buffer.js";
|
|
8
|
-
import { graph_import_texture } from "../shader/graph/graph_import_texture.js";
|
|
9
|
-
import { SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR } from "../shadow/map/SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR.js";
|
|
10
|
-
import { STATIC_GRAPHICS_ENGINE_ASSETS } from "../STATIC_GRAPHICS_ENGINE_ASSETS.js";
|
|
11
|
-
import { DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR } from "../texture/DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR.js";
|
|
12
|
-
import { WIND_FIELD_UNIFORM } from "../wind/WIND_FIELD_UNIFORM.js";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { shader_volumetrics_bin_participating_media } from "./shader_volumetrics_bin_participating_media.js";
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
} from "./
|
|
28
|
-
import { shader_volumetrics_taa } from "./taa/shader_volumetrics_taa.js";
|
|
29
|
-
import {
|
|
30
|
-
VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT,
|
|
31
|
-
VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION,
|
|
32
|
-
volumetrics_sun_shadow_sub_steps
|
|
33
|
-
} from "./VOLUMETRICS_SUN_SHADOW_RESOLUTION.js";
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
*
|
|
37
|
-
* @param {Object} options
|
|
38
|
-
* @param {FrameGraph} options.graph
|
|
39
|
-
* @param {GPUCameraContext} options.camera
|
|
40
|
-
* @param {GPUSceneContext} options.scene
|
|
41
|
-
* @param {GPUViewContext} options.view
|
|
42
|
-
* @param {number} options.volumetrics_metadata
|
|
43
|
-
* @param {number[]} options.resolution output resolution
|
|
44
|
-
* @param {ShaderSwitchSet} options.shader_switches the renderer's; the build adds the wind field's shape
|
|
45
|
-
*/
|
|
46
|
-
function graph_integrate_participating_media({
|
|
47
|
-
graph,
|
|
48
|
-
camera,
|
|
49
|
-
scene,
|
|
50
|
-
view,
|
|
51
|
-
volumetrics_metadata,
|
|
52
|
-
resolution,
|
|
53
|
-
shader_switches,
|
|
54
|
-
}) {
|
|
55
|
-
|
|
56
|
-
const data = {};
|
|
57
|
-
|
|
58
|
-
// the media build's workgroups, each of which the bin gives a list of the volumes it may see
|
|
59
|
-
const groups = [
|
|
60
|
-
Math.ceil(resolution[0] / VOLUMETRICS_MEDIA_WORKGROUP_RESOLUTION[0]),
|
|
61
|
-
Math.ceil(resolution[1] / VOLUMETRICS_MEDIA_WORKGROUP_RESOLUTION[1]),
|
|
62
|
-
resolution[2],
|
|
63
|
-
];
|
|
64
|
-
|
|
65
|
-
// A bit a volume. Sized from the scene's volumes, which the table's rows never outnumber; the
|
|
66
|
-
// shaders take the volume count off the table and the words a list gets off this buffer.
|
|
67
|
-
const volume_count = scene.volumetrics.source.volumes.length;
|
|
68
|
-
const list_words = Math.ceil(volume_count / 32);
|
|
69
|
-
const group_lists_bytes = 4 * Math.max(4, groups[0] * groups[1] * groups[2] * list_words);
|
|
70
|
-
|
|
71
|
-
// the near and the far field: a count, then a row for every volume either may hold
|
|
72
|
-
const field_bytes = 4 * Math.max(4, 1 + volume_count);
|
|
73
|
-
|
|
74
|
-
const pass = graph.add(
|
|
75
|
-
"aerial lut",
|
|
76
|
-
data,
|
|
77
|
-
/**
|
|
78
|
-
*
|
|
79
|
-
* @param {} data
|
|
80
|
-
* @param {FramePassResources} resources
|
|
81
|
-
* @param {GraphicsExecutionContext} context
|
|
82
|
-
*/
|
|
83
|
-
(data, resources, context) => {
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* @type {GPUTextureContext}
|
|
87
|
-
*/
|
|
88
|
-
const output0 = resources.get(data.output0);
|
|
89
|
-
/**
|
|
90
|
-
* @type {GPUTextureContext}
|
|
91
|
-
*/
|
|
92
|
-
const output1 = resources.get(data.output1);
|
|
93
|
-
|
|
94
|
-
const group_lists = resources.get(data.group_lists);
|
|
95
|
-
const near_field = resources.get(data.near_field);
|
|
96
|
-
const far_field = resources.get(data.far_field);
|
|
97
|
-
|
|
98
|
-
const encoder = context.encoder;
|
|
99
|
-
|
|
100
|
-
const volumetrics_metadata = resources.get(data.volumetrics_metadata);
|
|
101
|
-
|
|
102
|
-
shader_volumetrics_split_participating_media.dispatch({
|
|
103
|
-
encoder,
|
|
104
|
-
bindings: {
|
|
105
|
-
camera: camera.buffer.buffer,
|
|
106
|
-
volumetrics_metadata,
|
|
107
|
-
scene_database: scene.scene_database_buffer,
|
|
108
|
-
near_field,
|
|
109
|
-
far_field,
|
|
110
|
-
},
|
|
111
|
-
group_count_x: Math.max(1, Math.ceil(volume_count / VOLUMETRICS_MEDIA_SPLIT_LANES)),
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
shader_volumetrics_bin_participating_media.dispatch({
|
|
115
|
-
encoder,
|
|
116
|
-
bindings: {
|
|
117
|
-
camera: camera.buffer.buffer,
|
|
118
|
-
volumetrics_metadata,
|
|
119
|
-
scene_database: scene.scene_database_buffer,
|
|
120
|
-
near_field,
|
|
121
|
-
group_lists,
|
|
122
|
-
},
|
|
123
|
-
group_count_x: groups[0],
|
|
124
|
-
group_count_y: groups[1],
|
|
125
|
-
group_count_z: groups[2],
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* The scene's noise atlas, imported this frame so a grow between frames is seen.
|
|
130
|
-
* @type {GPUTextureContext}
|
|
131
|
-
*/
|
|
132
|
-
const noise_atlas = resources.get(data.noise_atlas);
|
|
133
|
-
|
|
134
|
-
// the per-froxel point the noise is read at moves by this volume every frame
|
|
135
|
-
const tSTBN_vec3 = context.graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
|
|
136
|
-
|
|
137
|
-
const bindings = {
|
|
138
|
-
camera: camera.buffer.buffer,
|
|
139
|
-
view: view.uniform_buffer.buffer,
|
|
140
|
-
volumetrics_metadata,
|
|
141
|
-
scene_database: scene.scene_database_buffer,
|
|
142
|
-
tSTBN_vec3: tSTBN_vec3.obtainView(),
|
|
143
|
-
tParticipatingMediaNoise: noise_atlas.obtainView(),
|
|
144
|
-
sParticipatingMediaNoise: context.graphics.samplers.obtain(PARTICIPATING_MEDIA_NOISE_SAMPLER_DESCRIPTOR),
|
|
145
|
-
tOutput0: output0.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
|
|
146
|
-
tOutput1: output1.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
|
|
147
|
-
group_lists,
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
// taken this frame rather than held: a producer that grows the field replaces its atlas
|
|
151
|
-
scene.wind.bind(bindings);
|
|
152
|
-
|
|
153
|
-
// and read in the shape it has this frame: with no cascades the wind is the far field
|
|
154
|
-
// everywhere, and that variant links neither the cascades' read nor the noise's flow map
|
|
155
|
-
const switches = shader_switches.with(WIND_FIELD_UNIFORM, scene.wind.cascade_count === 0);
|
|
156
|
-
|
|
157
|
-
shader_volumetrics_build_participating_media.variant(switches).dispatchThreads({
|
|
158
|
-
encoder,
|
|
159
|
-
thread_count_x: output0.width,
|
|
160
|
-
thread_count_y: output0.height,
|
|
161
|
-
thread_count_z: output0.depth,
|
|
162
|
-
bindings,
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
data.volumetrics_metadata = pass.read(volumetrics_metadata);
|
|
169
|
-
// the split appends to lists counted from zero
|
|
170
|
-
data.near_field = pass.create("participating media near field", BufferResourceDescriptor.from(
|
|
171
|
-
field_bytes,
|
|
172
|
-
GPUBufferUsage.STORAGE,
|
|
173
|
-
0, 4,
|
|
174
|
-
));
|
|
175
|
-
data.far_field = pass.create("participating media far field", BufferResourceDescriptor.from(
|
|
176
|
-
field_bytes,
|
|
177
|
-
GPUBufferUsage.STORAGE,
|
|
178
|
-
0, 4,
|
|
179
|
-
));
|
|
180
|
-
// the bin ORs bits into zeroed lists
|
|
181
|
-
data.group_lists = pass.create("participating media group lists", BufferResourceDescriptor.from(
|
|
182
|
-
group_lists_bytes,
|
|
183
|
-
GPUBufferUsage.STORAGE,
|
|
184
|
-
0, group_lists_bytes,
|
|
185
|
-
));
|
|
186
|
-
data.noise_atlas = pass.read(graph_import_texture(graph, scene.volumetrics.noise_atlas.texture, "volumetrics noise atlas"));
|
|
187
|
-
|
|
188
|
-
data.output0 = pass.create("Participating Media 0", TextureResourceDescriptor.from({
|
|
189
|
-
resolution,
|
|
190
|
-
dimension: "3d",
|
|
191
|
-
format: "rgba16float",
|
|
192
|
-
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
|
|
193
|
-
}));
|
|
194
|
-
data.output1 = pass.create("Participating Media 1", TextureResourceDescriptor.from({
|
|
195
|
-
resolution,
|
|
196
|
-
dimension: "3d",
|
|
197
|
-
format: "rgba16float",
|
|
198
|
-
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
|
|
199
|
-
}));
|
|
200
|
-
|
|
201
|
-
return {
|
|
202
|
-
participating_media0: data.output0,
|
|
203
|
-
participating_media1: data.output1,
|
|
204
|
-
volumetrics_metadata: data.volumetrics_metadata,
|
|
205
|
-
far_field: data.far_field,
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Q-04. The sun's optical depth, integrated once per frame into cascaded light-aligned volumes so
|
|
211
|
-
* the lighting pass can read it in a single fetch instead of marching toward the sun from every
|
|
212
|
-
* froxel.
|
|
213
|
-
*
|
|
214
|
-
* Sits between the participating-media build and the lighting pass because it reads the former and
|
|
215
|
-
* is read by the latter; the frame graph derives that ordering from the handles alone. The cascades
|
|
216
|
-
* are ordered among themselves for the same reason: each one is seeded from the value the cascade
|
|
217
|
-
* outside it already computed at its entry face, so the outermost is built first and the handle it
|
|
218
|
-
* returns is what makes the next pass wait for it.
|
|
219
|
-
*
|
|
220
|
-
* A texture per cascade rather than one texture with the cascades stacked along w. Stacking would
|
|
221
|
-
* put a pass's own output and its input in the same texture, which WebGPU rejects — a subresource
|
|
222
|
-
* cannot be bound as writable storage and as a sampled texture at once — and there is no
|
|
223
|
-
* subresource finer than the whole 3D texture to split it on.
|
|
224
|
-
*
|
|
225
|
-
* Always present, even with the mode off — the volumes are then dispatched at 1x1x1 (see
|
|
226
|
-
* `GPUViewVolumetrics`), which keeps the graph's topology identical on both sides of the A/B. A
|
|
227
|
-
* pass appearing and disappearing would change resource aliasing and pass scheduling along with the
|
|
228
|
-
* thing being measured, and this subsystem has already produced one confident wrong answer from a
|
|
229
|
-
* measurement where the two sides did not pay the same fixed costs.
|
|
230
|
-
*
|
|
231
|
-
* @param {Object} options
|
|
232
|
-
* @param {FrameGraph} options.graph
|
|
233
|
-
* @param {GPUCameraContext} options.camera
|
|
234
|
-
* @param {number} options.participating_media1
|
|
235
|
-
* @param {number} options.volumetrics_metadata
|
|
236
|
-
* @param {number[]} options.resolution voxel counts of one cascade
|
|
237
|
-
* @returns {number[]} handles of the cascades, innermost first
|
|
238
|
-
*/
|
|
239
|
-
function graph_build_sun_shadow_volume({
|
|
240
|
-
graph,
|
|
241
|
-
camera,
|
|
242
|
-
participating_media1,
|
|
243
|
-
volumetrics_metadata,
|
|
244
|
-
resolution,
|
|
245
|
-
}) {
|
|
246
|
-
|
|
247
|
-
const camera_buffer = graph_import_buffer(graph, camera.buffer.buffer, "volumetrics sun shadow camera");
|
|
248
|
-
|
|
249
|
-
const group_count = [
|
|
250
|
-
// one invocation per COLUMN along the sun axis, so only x and y are dispatched
|
|
251
|
-
Math.ceil(resolution[0] / VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION[0]),
|
|
252
|
-
Math.ceil(resolution[1] / VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION[1]),
|
|
253
|
-
1,
|
|
254
|
-
];
|
|
255
|
-
|
|
256
|
-
const cascades = [];
|
|
257
|
-
|
|
258
|
-
for (let cascade = VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT - 1; cascade >= 0; cascade--) {
|
|
259
|
-
|
|
260
|
-
// Every cascade but the outermost starts its scan from the one outside it — which the
|
|
261
|
-
// descending loop has already added, and which is the one difference the two build shaders
|
|
262
|
-
// exist for.
|
|
263
|
-
const seeded = cascade < VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT - 1;
|
|
264
|
-
|
|
265
|
-
const bindings = {
|
|
266
|
-
// which cascade this dispatch is building; the shader is shared across all of them
|
|
267
|
-
settings: {
|
|
268
|
-
cascade,
|
|
269
|
-
sub_steps: volumetrics_sun_shadow_sub_steps(cascade),
|
|
270
|
-
},
|
|
271
|
-
camera: camera_buffer,
|
|
272
|
-
volumetrics_metadata,
|
|
273
|
-
tParticipatingMedia1: participating_media1,
|
|
274
|
-
tSunShadowVolume: TextureResourceDescriptor.from({
|
|
275
|
-
resolution,
|
|
276
|
-
dimension: "3d",
|
|
277
|
-
format: "rgba16float",
|
|
278
|
-
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
|
|
279
|
-
}),
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
if (seeded) {
|
|
283
|
-
bindings.tSunShadowOuter = cascades[cascade + 1];
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
const outputs = graph_compute_pass({
|
|
287
|
-
graph,
|
|
288
|
-
shader: seeded
|
|
289
|
-
? shader_volumetrics_build_sun_shadow_volume_seeded
|
|
290
|
-
: shader_volumetrics_build_sun_shadow_volume_outermost,
|
|
291
|
-
group_count,
|
|
292
|
-
bindings,
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
cascades[cascade] = outputs.tSunShadowVolume;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
return cascades;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
*
|
|
303
|
-
* @param {FrameGraph} graph
|
|
304
|
-
* @param participating_media0
|
|
305
|
-
* @param participating_media1
|
|
306
|
-
* @param volumetrics_metadata
|
|
307
|
-
* @param light_cluster_data
|
|
308
|
-
* @param light_cluster_lookup
|
|
309
|
-
* @param light_cluster_parameters
|
|
310
|
-
* @param shadowmap_atlas
|
|
311
|
-
* @param sun_transmittance_lut
|
|
312
|
-
* @param sun_multiple_scattering_lut
|
|
313
|
-
* @param {number[]} sun_shadow_cascades handles of the Q-04 optical-depth cascades, innermost first
|
|
314
|
-
* @param lights
|
|
315
|
-
* @param view
|
|
316
|
-
* @param camera
|
|
317
|
-
* @param resolution
|
|
318
|
-
* @param {ShaderSwitchSet} shader_switches the renderer's; the lighting pass is built for them
|
|
319
|
-
* @returns {number} the lit scattering volume
|
|
320
|
-
*/
|
|
321
|
-
function graph_integrate_light_scattering({
|
|
322
|
-
graph,
|
|
323
|
-
participating_media0,
|
|
324
|
-
participating_media1,
|
|
325
|
-
volumetrics_metadata,
|
|
326
|
-
light_cluster_data,
|
|
327
|
-
light_cluster_lookup,
|
|
328
|
-
light_cluster_parameters,
|
|
329
|
-
shadowmap_atlas,
|
|
330
|
-
sun_transmittance_lut,
|
|
331
|
-
sun_multiple_scattering_lut,
|
|
332
|
-
sun_shadow_cascades,
|
|
333
|
-
lights,
|
|
334
|
-
view,
|
|
335
|
-
camera,
|
|
336
|
-
resolution,
|
|
337
|
-
shader_switches,
|
|
338
|
-
}) {
|
|
339
|
-
|
|
340
|
-
const data = {};
|
|
341
|
-
|
|
342
|
-
const pass = graph.add("scattering lut", data, (data, resources, context) => {
|
|
343
|
-
const output = resources.get(data.output);
|
|
344
|
-
|
|
345
|
-
const volumetrics_metadata = resources.get(data.volumetrics_metadata);
|
|
346
|
-
|
|
347
|
-
const participating_media0 = resources.get(data.participating_media0);
|
|
348
|
-
const participating_media1 = resources.get(data.participating_media1);
|
|
349
|
-
|
|
350
|
-
const light_cluster_data = resources.get(data.light_cluster_data);
|
|
351
|
-
const light_cluster_lookup = resources.get(data.light_cluster_lookup);
|
|
352
|
-
const light_cluster_parameters = resources.get(data.light_cluster_parameters);
|
|
353
|
-
const shadowmap_atlas = resources.get(data.shadowmap_atlas);
|
|
354
|
-
|
|
355
|
-
const sun_transmittance_lut = resources.get(data.sun_transmittance_lut);
|
|
356
|
-
const sun_multiple_scattering_lut = resources.get(data.sun_multiple_scattering_lut);
|
|
357
|
-
const sun_shadow_cascades = data.sun_shadow_cascades.map(handle => resources.get(handle));
|
|
358
|
-
|
|
359
|
-
const sampler_shadowmap = context.graphics.samplers.obtain(SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR);
|
|
360
|
-
const sLinear = context.graphics.samplers.obtain(SamplerDescriptor.from({
|
|
361
|
-
magFilter: "linear",
|
|
362
|
-
}));
|
|
363
|
-
|
|
364
|
-
// Spatiotemporal blue noise for the per-froxel sample offset. The pass takes one sample and
|
|
365
|
-
// leans on the volumetric TAA to integrate, which only works if each froxel's sequence over
|
|
366
|
-
// frames is well distributed — the property a per-froxel hash does not have.
|
|
367
|
-
const tSTBN_vec3 = context.graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
|
|
368
|
-
|
|
369
|
-
const encoder = context.encoder;
|
|
370
|
-
|
|
371
|
-
const bindings = {
|
|
372
|
-
camera: camera.buffer.buffer,
|
|
373
|
-
view: view.uniform_buffer.buffer,
|
|
374
|
-
volumetrics_metadata,
|
|
375
|
-
sLinear,
|
|
376
|
-
tSunTransmittance: sun_transmittance_lut.obtainView(),
|
|
377
|
-
tMultiScattering: sun_multiple_scattering_lut.obtainView(),
|
|
378
|
-
tSTBN_vec3: tSTBN_vec3.obtainView(),
|
|
379
|
-
tParticipatingMedia0: participating_media0.obtainView(),
|
|
380
|
-
tParticipatingMedia1: participating_media1.obtainView(),
|
|
381
|
-
tLighting: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
|
|
382
|
-
//
|
|
383
|
-
light_data: lights.buffer_data,
|
|
384
|
-
|
|
385
|
-
cluster_data: light_cluster_data,
|
|
386
|
-
cluster_lookup: light_cluster_lookup,
|
|
387
|
-
cluster_parameters: light_cluster_parameters,
|
|
388
|
-
|
|
389
|
-
shadowmapAtlas: shadowmap_atlas.obtainView(),
|
|
390
|
-
sCompareLinear: sampler_shadowmap,
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
// One texture per cascade, under the names the read side declares. Bound here rather than
|
|
394
|
-
// above because the count is a constant of the structure, not of this pass.
|
|
395
|
-
for (let cascade = 0; cascade < sun_shadow_cascades.length; cascade++) {
|
|
396
|
-
bindings[volumetrics_sun_shadow_texture_name(cascade)] = sun_shadow_cascades[cascade].obtainView();
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
shader_volumetrics_build_lighting.variant(shader_switches).dispatchThreads({
|
|
400
|
-
encoder,
|
|
401
|
-
thread_count_x: output.width,
|
|
402
|
-
thread_count_y: output.height,
|
|
403
|
-
thread_count_z: output.depth,
|
|
404
|
-
bindings
|
|
405
|
-
})
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
data.participating_media0 = pass.read(participating_media0);
|
|
409
|
-
data.participating_media1 = pass.read(participating_media1);
|
|
410
|
-
data.volumetrics_metadata = pass.read(volumetrics_metadata);
|
|
411
|
-
|
|
412
|
-
data.shadowmap_atlas = pass.read(shadowmap_atlas);
|
|
413
|
-
data.light_cluster_data = pass.read(light_cluster_data);
|
|
414
|
-
data.light_cluster_lookup = pass.read(light_cluster_lookup);
|
|
415
|
-
data.light_cluster_parameters = pass.read(light_cluster_parameters);
|
|
416
|
-
|
|
417
|
-
data.sun_transmittance_lut = pass.read(sun_transmittance_lut);
|
|
418
|
-
data.sun_multiple_scattering_lut = pass.read(sun_multiple_scattering_lut);
|
|
419
|
-
data.sun_shadow_cascades = sun_shadow_cascades.map(handle => pass.read(handle));
|
|
420
|
-
|
|
421
|
-
data.output = pass.create("Light Scattering LUT", TextureResourceDescriptor.from({
|
|
422
|
-
resolution,
|
|
423
|
-
dimension: "3d",
|
|
424
|
-
format: "rgba16float",
|
|
425
|
-
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
|
|
426
|
-
}));
|
|
427
|
-
|
|
428
|
-
return data.output;
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* The fog: participating media -> per-froxel lighting -> ray-marched integration into the aerial LUT
|
|
434
|
-
* every surface behind it is seen through. Particle lighting is not here — it needs no medium, and
|
|
435
|
-
* `
|
|
436
|
-
*
|
|
437
|
-
* @param {Object} options
|
|
438
|
-
* @param {FrameGraph} options.graph
|
|
439
|
-
* @param {GPUCameraContext} options.camera
|
|
440
|
-
* @param {GPULightCollection} options.lights
|
|
441
|
-
* @param {GPUViewContext} options.view
|
|
442
|
-
* @param {GPUSky} options.sky the scene's sky, already {@link GPUSky#update updated}: its two
|
|
443
|
-
* persistent LUTs are imported and read, not rebuilt. The sun's transmittance and the multiple
|
|
444
|
-
* scattering depend on nothing but the atmosphere's constants, so building them again per frame
|
|
445
|
-
* bought the same texels at a cost that was paid whether or not the scene had any fog.
|
|
446
|
-
* @param {number} options.light_cluster_data
|
|
447
|
-
* @param {number} options.light_cluster_lookup
|
|
448
|
-
* @param {number} options.light_cluster_parameters
|
|
449
|
-
* @param {number} options.shadowmap_atlas
|
|
450
|
-
* @param {number[]} options.volumetric_resolution
|
|
451
|
-
* @param {number[]} options.sun_shadow_resolution voxel counts of one Q-04 sun optical-depth cascade;
|
|
452
|
-
* `[1, 1, 1]` when the froxels are marching instead, which keeps the passes in the graph without
|
|
453
|
-
* doing any work
|
|
454
|
-
* @param {number} options.volumetrics_metadata
|
|
455
|
-
* @param {number} [options.taa_history] imported previous-frame accumulated scattering volume
|
|
456
|
-
* @param {number} [options.taa_output] imported destination for this frame's accumulated scattering volume
|
|
457
|
-
* @param {GPUCameraContext} [options.camera_previous] previous-frame camera, for temporal reprojection
|
|
458
|
-
* @param {ShaderSwitchSet} [options.shader_switches] the renderer's; the lighting pass is built for them
|
|
459
|
-
*/
|
|
460
|
-
export function graph_build_volumetrics({
|
|
461
|
-
graph,
|
|
462
|
-
camera,
|
|
463
|
-
lights,
|
|
464
|
-
view,
|
|
465
|
-
sky,
|
|
466
|
-
light_cluster_data,
|
|
467
|
-
light_cluster_lookup,
|
|
468
|
-
light_cluster_parameters,
|
|
469
|
-
shadowmap_atlas,
|
|
470
|
-
volumetric_resolution,
|
|
471
|
-
sun_shadow_resolution,
|
|
472
|
-
volumetrics_metadata,
|
|
473
|
-
taa_history,
|
|
474
|
-
taa_output,
|
|
475
|
-
camera_previous,
|
|
476
|
-
shader_switches = ShaderSwitchSet.EMPTY,
|
|
477
|
-
}) {
|
|
478
|
-
|
|
479
|
-
assert.defined(view, 'view');
|
|
480
|
-
assert.defined(sky, 'sky');
|
|
481
|
-
assert.equal(sky.needs_update, false, 'sky has not been updated, its LUTs hold nothing yet');
|
|
482
|
-
assert.defined(volumetric_resolution, 'volumetric_resolution');
|
|
483
|
-
assert.defined(sun_shadow_resolution, 'sun_shadow_resolution');
|
|
484
|
-
|
|
485
|
-
graph.push_scope("build volumetrics");
|
|
486
|
-
|
|
487
|
-
// Read-only here, so nothing in this graph orders against a write to either; the sky wrote
|
|
488
|
-
// them in commands of its own, submitted before this frame's.
|
|
489
|
-
const transmittance_lut = graph_import_texture(graph, sky.lut_transmittance);
|
|
490
|
-
const multiscatted_lut = graph_import_texture(graph, sky.lut_multiple_scattering);
|
|
491
|
-
|
|
492
|
-
const {
|
|
493
|
-
participating_media0,
|
|
494
|
-
participating_media1,
|
|
495
|
-
far_field,
|
|
496
|
-
} = graph_integrate_participating_media({
|
|
497
|
-
graph,
|
|
498
|
-
scene: view.scene,
|
|
499
|
-
view,
|
|
500
|
-
resolution: volumetric_resolution,
|
|
501
|
-
volumetrics_metadata,
|
|
502
|
-
camera,
|
|
503
|
-
shader_switches,
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
const sun_shadow_cascades = graph_build_sun_shadow_volume({
|
|
507
|
-
graph,
|
|
508
|
-
camera,
|
|
509
|
-
participating_media1,
|
|
510
|
-
volumetrics_metadata,
|
|
511
|
-
resolution: sun_shadow_resolution,
|
|
512
|
-
});
|
|
513
|
-
|
|
514
|
-
const light_scattering_lut = graph_integrate_light_scattering({
|
|
515
|
-
graph,
|
|
516
|
-
resolution: volumetric_resolution,
|
|
517
|
-
camera,
|
|
518
|
-
view,
|
|
519
|
-
sun_transmittance_lut: transmittance_lut,
|
|
520
|
-
sun_multiple_scattering_lut: multiscatted_lut,
|
|
521
|
-
sun_shadow_cascades,
|
|
522
|
-
participating_media0,
|
|
523
|
-
participating_media1,
|
|
524
|
-
volumetrics_metadata,
|
|
525
|
-
light_cluster_data,
|
|
526
|
-
light_cluster_lookup,
|
|
527
|
-
light_cluster_parameters,
|
|
528
|
-
shadowmap_atlas,
|
|
529
|
-
lights,
|
|
530
|
-
shader_switches,
|
|
531
|
-
})
|
|
532
|
-
|
|
533
|
-
// Temporal reprojection of the per-froxel lit scattering volume, applied BEFORE aerial
|
|
534
|
-
// integration — reprojecting the already-integrated aerial LUT would double-integrate along the
|
|
535
|
-
// view ray. Optional: skipped when no history ping-pong is supplied (TAA disabled), in which
|
|
536
|
-
// case the aerial pass consumes the raw (noisier) scattering LUT directly.
|
|
537
|
-
let volume_lighting_resolved = light_scattering_lut;
|
|
538
|
-
|
|
539
|
-
if (taa_history !== undefined && taa_output !== undefined) {
|
|
540
|
-
const taa_outputs = graph_compute_pass({
|
|
541
|
-
graph,
|
|
542
|
-
shader: shader_volumetrics_taa,
|
|
543
|
-
group_count: [
|
|
544
|
-
Math.ceil(volumetric_resolution[0] / 8),
|
|
545
|
-
Math.ceil(volumetric_resolution[1] / 8),
|
|
546
|
-
Math.ceil(volumetric_resolution[2] / 4),
|
|
547
|
-
],
|
|
548
|
-
bindings: {
|
|
549
|
-
t_current: light_scattering_lut,
|
|
550
|
-
t_history: taa_history,
|
|
551
|
-
t_output: taa_output,
|
|
552
|
-
volumetrics_metadata,
|
|
553
|
-
camera_current: graph_import_buffer(graph, camera.buffer.buffer, "volumetrics taa camera"),
|
|
554
|
-
camera_previous: graph_import_buffer(graph, camera_previous.buffer.buffer, "volumetrics taa camera previous"),
|
|
555
|
-
},
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
volume_lighting_resolved = taa_outputs.t_output;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
const a_data = {};
|
|
562
|
-
|
|
563
|
-
const a_pass = graph.add("aerial lut", a_data, (data, resources, context) => {
|
|
564
|
-
const output = resources.get(data.output);
|
|
565
|
-
|
|
566
|
-
const participating_media0 = resources.get(data.participating_media0);
|
|
567
|
-
const participating_media1 = resources.get(data.participating_media1);
|
|
568
|
-
const volumetrics_metadata = resources.get(data.volumetrics_metadata);
|
|
569
|
-
|
|
570
|
-
const light_scattering_lut = resources.get(data.light_scattering_lut);
|
|
571
|
-
const sun_transmittance_lut = resources.get(data.sun_transmittance_lut);
|
|
572
|
-
const far_field = resources.get(data.far_field);
|
|
573
|
-
|
|
574
|
-
const encoder = context.encoder;
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
const graphics = context.graphics;
|
|
578
|
-
|
|
579
|
-
const sLinear = graphics.samplers.obtain(SamplerDescriptor.from({
|
|
580
|
-
magFilter: "linear",
|
|
581
|
-
}));
|
|
582
|
-
|
|
583
|
-
const tSTBN_vec3 = graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
|
|
584
|
-
|
|
585
|
-
shader_volumetrics_build_scattering_lut.dispatchThreads({
|
|
586
|
-
encoder,
|
|
587
|
-
thread_count_x: output.width,
|
|
588
|
-
thread_count_y: output.height,
|
|
589
|
-
bindings: {
|
|
590
|
-
camera: camera.buffer.buffer,
|
|
591
|
-
view: view.uniform_buffer.buffer,
|
|
592
|
-
volumetrics_metadata,
|
|
593
|
-
tSTBN_vec3: tSTBN_vec3.obtainView(),
|
|
594
|
-
sLinear,
|
|
595
|
-
|
|
596
|
-
tVolumeLighting: light_scattering_lut.obtainView(),
|
|
597
|
-
tParticipatingMedia0: participating_media0.obtainView(),
|
|
598
|
-
tParticipatingMedia1: participating_media1.obtainView(),
|
|
599
|
-
|
|
600
|
-
// RDR2-style far-field march inputs (used beyond froxel_far)
|
|
601
|
-
scene_database: view.scene.scene_database_buffer,
|
|
602
|
-
far_field,
|
|
603
|
-
light_data: lights.buffer_data,
|
|
604
|
-
tSunTransmittance: sun_transmittance_lut.obtainView(),
|
|
605
|
-
|
|
606
|
-
tOutput: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
|
|
607
|
-
}
|
|
608
|
-
});
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
});
|
|
612
|
-
|
|
613
|
-
a_data.participating_media0 = a_pass.read(participating_media0);
|
|
614
|
-
a_data.participating_media1 = a_pass.read(participating_media1);
|
|
615
|
-
a_data.volumetrics_metadata = a_pass.read(volumetrics_metadata);
|
|
616
|
-
a_data.sun_transmittance_lut = a_pass.read(transmittance_lut);
|
|
617
|
-
a_data.far_field = a_pass.read(far_field);
|
|
618
|
-
|
|
619
|
-
a_data.output = a_pass.create("Integrated Volumetrics", TextureResourceDescriptor.from({
|
|
620
|
-
resolution: volumetric_resolution,
|
|
621
|
-
dimension: "3d",
|
|
622
|
-
format: "rgba16float",
|
|
623
|
-
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
|
|
624
|
-
}))
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
a_data.light_scattering_lut = a_pass.read(volume_lighting_resolved);
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
// TODO add temporal reprojection
|
|
631
|
-
|
|
632
|
-
graph.pop_scope();
|
|
633
|
-
|
|
634
|
-
return {
|
|
635
|
-
lut_transmittance: transmittance_lut,
|
|
636
|
-
lut_multiple_scattering: multiscatted_lut,
|
|
637
|
-
lut_aerial: a_data.output,
|
|
638
|
-
volumetrics_metadata,
|
|
639
|
-
};
|
|
640
|
-
}
|
|
1
|
+
import { assert } from "../../../core/assert.js";
|
|
2
|
+
import { SamplerDescriptor } from "../../descriptor/texture/SamplerDescriptor.js";
|
|
3
|
+
import { BufferResourceDescriptor } from "../../device/graph/BufferResourceDescriptor.js";
|
|
4
|
+
import { TextureResourceDescriptor } from "../../device/graph/TextureResourceDescriptor.js";
|
|
5
|
+
import { ShaderSwitchSet } from "../shader/compiler/ShaderSwitchSet.js";
|
|
6
|
+
import { graph_compute_pass } from "../shader/graph/compute/graph_compute_pass.js";
|
|
7
|
+
import { graph_import_buffer } from "../shader/graph/graph_import_buffer.js";
|
|
8
|
+
import { graph_import_texture } from "../shader/graph/graph_import_texture.js";
|
|
9
|
+
import { SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR } from "../shadow/map/SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR.js";
|
|
10
|
+
import { STATIC_GRAPHICS_ENGINE_ASSETS } from "../STATIC_GRAPHICS_ENGINE_ASSETS.js";
|
|
11
|
+
import { DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR } from "../texture/DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR.js";
|
|
12
|
+
import { WIND_FIELD_UNIFORM } from "../wind/WIND_FIELD_UNIFORM.js";
|
|
13
|
+
import { VOLUMETRICS_MEDIA_WORKGROUP_RESOLUTION } from "./chunk_volumetrics_media_group_list.js";
|
|
14
|
+
import { volumetrics_sun_shadow_texture_name } from "./chunk_volumetrics_sun_optical_depth.js";
|
|
15
|
+
import { PARTICIPATING_MEDIA_NOISE_SAMPLER_DESCRIPTOR } from "./noise/PARTICIPATING_MEDIA_NOISE.js";
|
|
16
|
+
import { shader_volumetrics_bin_participating_media } from "./shader_volumetrics_bin_participating_media.js";
|
|
17
|
+
import { shader_volumetrics_build_lighting } from "./shader_volumetrics_build_lighting.js";
|
|
18
|
+
import { shader_volumetrics_build_participating_media } from "./shader_volumetrics_build_participating_media.js";
|
|
19
|
+
import { shader_volumetrics_build_scattering_lut } from "./shader_volumetrics_build_scattering_lut.js";
|
|
20
|
+
import {
|
|
21
|
+
shader_volumetrics_build_sun_shadow_volume_outermost,
|
|
22
|
+
shader_volumetrics_build_sun_shadow_volume_seeded
|
|
23
|
+
} from "./shader_volumetrics_build_sun_shadow_volume.js";
|
|
24
|
+
import {
|
|
25
|
+
shader_volumetrics_split_participating_media,
|
|
26
|
+
VOLUMETRICS_MEDIA_SPLIT_LANES
|
|
27
|
+
} from "./shader_volumetrics_split_participating_media.js";
|
|
28
|
+
import { shader_volumetrics_taa } from "./taa/shader_volumetrics_taa.js";
|
|
29
|
+
import {
|
|
30
|
+
VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT,
|
|
31
|
+
VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION,
|
|
32
|
+
volumetrics_sun_shadow_sub_steps
|
|
33
|
+
} from "./VOLUMETRICS_SUN_SHADOW_RESOLUTION.js";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
* @param {Object} options
|
|
38
|
+
* @param {FrameGraph} options.graph
|
|
39
|
+
* @param {GPUCameraContext} options.camera
|
|
40
|
+
* @param {GPUSceneContext} options.scene
|
|
41
|
+
* @param {GPUViewContext} options.view
|
|
42
|
+
* @param {number} options.volumetrics_metadata
|
|
43
|
+
* @param {number[]} options.resolution output resolution
|
|
44
|
+
* @param {ShaderSwitchSet} options.shader_switches the renderer's; the build adds the wind field's shape
|
|
45
|
+
*/
|
|
46
|
+
function graph_integrate_participating_media({
|
|
47
|
+
graph,
|
|
48
|
+
camera,
|
|
49
|
+
scene,
|
|
50
|
+
view,
|
|
51
|
+
volumetrics_metadata,
|
|
52
|
+
resolution,
|
|
53
|
+
shader_switches,
|
|
54
|
+
}) {
|
|
55
|
+
|
|
56
|
+
const data = {};
|
|
57
|
+
|
|
58
|
+
// the media build's workgroups, each of which the bin gives a list of the volumes it may see
|
|
59
|
+
const groups = [
|
|
60
|
+
Math.ceil(resolution[0] / VOLUMETRICS_MEDIA_WORKGROUP_RESOLUTION[0]),
|
|
61
|
+
Math.ceil(resolution[1] / VOLUMETRICS_MEDIA_WORKGROUP_RESOLUTION[1]),
|
|
62
|
+
resolution[2],
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
// A bit a volume. Sized from the scene's volumes, which the table's rows never outnumber; the
|
|
66
|
+
// shaders take the volume count off the table and the words a list gets off this buffer.
|
|
67
|
+
const volume_count = scene.volumetrics.source.volumes.length;
|
|
68
|
+
const list_words = Math.ceil(volume_count / 32);
|
|
69
|
+
const group_lists_bytes = 4 * Math.max(4, groups[0] * groups[1] * groups[2] * list_words);
|
|
70
|
+
|
|
71
|
+
// the near and the far field: a count, then a row for every volume either may hold
|
|
72
|
+
const field_bytes = 4 * Math.max(4, 1 + volume_count);
|
|
73
|
+
|
|
74
|
+
const pass = graph.add(
|
|
75
|
+
"aerial lut",
|
|
76
|
+
data,
|
|
77
|
+
/**
|
|
78
|
+
*
|
|
79
|
+
* @param {} data
|
|
80
|
+
* @param {FramePassResources} resources
|
|
81
|
+
* @param {GraphicsExecutionContext} context
|
|
82
|
+
*/
|
|
83
|
+
(data, resources, context) => {
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @type {GPUTextureContext}
|
|
87
|
+
*/
|
|
88
|
+
const output0 = resources.get(data.output0);
|
|
89
|
+
/**
|
|
90
|
+
* @type {GPUTextureContext}
|
|
91
|
+
*/
|
|
92
|
+
const output1 = resources.get(data.output1);
|
|
93
|
+
|
|
94
|
+
const group_lists = resources.get(data.group_lists);
|
|
95
|
+
const near_field = resources.get(data.near_field);
|
|
96
|
+
const far_field = resources.get(data.far_field);
|
|
97
|
+
|
|
98
|
+
const encoder = context.encoder;
|
|
99
|
+
|
|
100
|
+
const volumetrics_metadata = resources.get(data.volumetrics_metadata);
|
|
101
|
+
|
|
102
|
+
shader_volumetrics_split_participating_media.dispatch({
|
|
103
|
+
encoder,
|
|
104
|
+
bindings: {
|
|
105
|
+
camera: camera.buffer.buffer,
|
|
106
|
+
volumetrics_metadata,
|
|
107
|
+
scene_database: scene.scene_database_buffer,
|
|
108
|
+
near_field,
|
|
109
|
+
far_field,
|
|
110
|
+
},
|
|
111
|
+
group_count_x: Math.max(1, Math.ceil(volume_count / VOLUMETRICS_MEDIA_SPLIT_LANES)),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
shader_volumetrics_bin_participating_media.dispatch({
|
|
115
|
+
encoder,
|
|
116
|
+
bindings: {
|
|
117
|
+
camera: camera.buffer.buffer,
|
|
118
|
+
volumetrics_metadata,
|
|
119
|
+
scene_database: scene.scene_database_buffer,
|
|
120
|
+
near_field,
|
|
121
|
+
group_lists,
|
|
122
|
+
},
|
|
123
|
+
group_count_x: groups[0],
|
|
124
|
+
group_count_y: groups[1],
|
|
125
|
+
group_count_z: groups[2],
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The scene's noise atlas, imported this frame so a grow between frames is seen.
|
|
130
|
+
* @type {GPUTextureContext}
|
|
131
|
+
*/
|
|
132
|
+
const noise_atlas = resources.get(data.noise_atlas);
|
|
133
|
+
|
|
134
|
+
// the per-froxel point the noise is read at moves by this volume every frame
|
|
135
|
+
const tSTBN_vec3 = context.graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
|
|
136
|
+
|
|
137
|
+
const bindings = {
|
|
138
|
+
camera: camera.buffer.buffer,
|
|
139
|
+
view: view.uniform_buffer.buffer,
|
|
140
|
+
volumetrics_metadata,
|
|
141
|
+
scene_database: scene.scene_database_buffer,
|
|
142
|
+
tSTBN_vec3: tSTBN_vec3.obtainView(),
|
|
143
|
+
tParticipatingMediaNoise: noise_atlas.obtainView(),
|
|
144
|
+
sParticipatingMediaNoise: context.graphics.samplers.obtain(PARTICIPATING_MEDIA_NOISE_SAMPLER_DESCRIPTOR),
|
|
145
|
+
tOutput0: output0.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
|
|
146
|
+
tOutput1: output1.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
|
|
147
|
+
group_lists,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// taken this frame rather than held: a producer that grows the field replaces its atlas
|
|
151
|
+
scene.wind.bind(bindings);
|
|
152
|
+
|
|
153
|
+
// and read in the shape it has this frame: with no cascades the wind is the far field
|
|
154
|
+
// everywhere, and that variant links neither the cascades' read nor the noise's flow map
|
|
155
|
+
const switches = shader_switches.with(WIND_FIELD_UNIFORM, scene.wind.cascade_count === 0);
|
|
156
|
+
|
|
157
|
+
shader_volumetrics_build_participating_media.variant(switches).dispatchThreads({
|
|
158
|
+
encoder,
|
|
159
|
+
thread_count_x: output0.width,
|
|
160
|
+
thread_count_y: output0.height,
|
|
161
|
+
thread_count_z: output0.depth,
|
|
162
|
+
bindings,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
data.volumetrics_metadata = pass.read(volumetrics_metadata);
|
|
169
|
+
// the split appends to lists counted from zero
|
|
170
|
+
data.near_field = pass.create("participating media near field", BufferResourceDescriptor.from(
|
|
171
|
+
field_bytes,
|
|
172
|
+
GPUBufferUsage.STORAGE,
|
|
173
|
+
0, 4,
|
|
174
|
+
));
|
|
175
|
+
data.far_field = pass.create("participating media far field", BufferResourceDescriptor.from(
|
|
176
|
+
field_bytes,
|
|
177
|
+
GPUBufferUsage.STORAGE,
|
|
178
|
+
0, 4,
|
|
179
|
+
));
|
|
180
|
+
// the bin ORs bits into zeroed lists
|
|
181
|
+
data.group_lists = pass.create("participating media group lists", BufferResourceDescriptor.from(
|
|
182
|
+
group_lists_bytes,
|
|
183
|
+
GPUBufferUsage.STORAGE,
|
|
184
|
+
0, group_lists_bytes,
|
|
185
|
+
));
|
|
186
|
+
data.noise_atlas = pass.read(graph_import_texture(graph, scene.volumetrics.noise_atlas.texture, "volumetrics noise atlas"));
|
|
187
|
+
|
|
188
|
+
data.output0 = pass.create("Participating Media 0", TextureResourceDescriptor.from({
|
|
189
|
+
resolution,
|
|
190
|
+
dimension: "3d",
|
|
191
|
+
format: "rgba16float",
|
|
192
|
+
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
|
|
193
|
+
}));
|
|
194
|
+
data.output1 = pass.create("Participating Media 1", TextureResourceDescriptor.from({
|
|
195
|
+
resolution,
|
|
196
|
+
dimension: "3d",
|
|
197
|
+
format: "rgba16float",
|
|
198
|
+
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
|
|
199
|
+
}));
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
participating_media0: data.output0,
|
|
203
|
+
participating_media1: data.output1,
|
|
204
|
+
volumetrics_metadata: data.volumetrics_metadata,
|
|
205
|
+
far_field: data.far_field,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Q-04. The sun's optical depth, integrated once per frame into cascaded light-aligned volumes so
|
|
211
|
+
* the lighting pass can read it in a single fetch instead of marching toward the sun from every
|
|
212
|
+
* froxel.
|
|
213
|
+
*
|
|
214
|
+
* Sits between the participating-media build and the lighting pass because it reads the former and
|
|
215
|
+
* is read by the latter; the frame graph derives that ordering from the handles alone. The cascades
|
|
216
|
+
* are ordered among themselves for the same reason: each one is seeded from the value the cascade
|
|
217
|
+
* outside it already computed at its entry face, so the outermost is built first and the handle it
|
|
218
|
+
* returns is what makes the next pass wait for it.
|
|
219
|
+
*
|
|
220
|
+
* A texture per cascade rather than one texture with the cascades stacked along w. Stacking would
|
|
221
|
+
* put a pass's own output and its input in the same texture, which WebGPU rejects — a subresource
|
|
222
|
+
* cannot be bound as writable storage and as a sampled texture at once — and there is no
|
|
223
|
+
* subresource finer than the whole 3D texture to split it on.
|
|
224
|
+
*
|
|
225
|
+
* Always present, even with the mode off — the volumes are then dispatched at 1x1x1 (see
|
|
226
|
+
* `GPUViewVolumetrics`), which keeps the graph's topology identical on both sides of the A/B. A
|
|
227
|
+
* pass appearing and disappearing would change resource aliasing and pass scheduling along with the
|
|
228
|
+
* thing being measured, and this subsystem has already produced one confident wrong answer from a
|
|
229
|
+
* measurement where the two sides did not pay the same fixed costs.
|
|
230
|
+
*
|
|
231
|
+
* @param {Object} options
|
|
232
|
+
* @param {FrameGraph} options.graph
|
|
233
|
+
* @param {GPUCameraContext} options.camera
|
|
234
|
+
* @param {number} options.participating_media1
|
|
235
|
+
* @param {number} options.volumetrics_metadata
|
|
236
|
+
* @param {number[]} options.resolution voxel counts of one cascade
|
|
237
|
+
* @returns {number[]} handles of the cascades, innermost first
|
|
238
|
+
*/
|
|
239
|
+
function graph_build_sun_shadow_volume({
|
|
240
|
+
graph,
|
|
241
|
+
camera,
|
|
242
|
+
participating_media1,
|
|
243
|
+
volumetrics_metadata,
|
|
244
|
+
resolution,
|
|
245
|
+
}) {
|
|
246
|
+
|
|
247
|
+
const camera_buffer = graph_import_buffer(graph, camera.buffer.buffer, "volumetrics sun shadow camera");
|
|
248
|
+
|
|
249
|
+
const group_count = [
|
|
250
|
+
// one invocation per COLUMN along the sun axis, so only x and y are dispatched
|
|
251
|
+
Math.ceil(resolution[0] / VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION[0]),
|
|
252
|
+
Math.ceil(resolution[1] / VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION[1]),
|
|
253
|
+
1,
|
|
254
|
+
];
|
|
255
|
+
|
|
256
|
+
const cascades = [];
|
|
257
|
+
|
|
258
|
+
for (let cascade = VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT - 1; cascade >= 0; cascade--) {
|
|
259
|
+
|
|
260
|
+
// Every cascade but the outermost starts its scan from the one outside it — which the
|
|
261
|
+
// descending loop has already added, and which is the one difference the two build shaders
|
|
262
|
+
// exist for.
|
|
263
|
+
const seeded = cascade < VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT - 1;
|
|
264
|
+
|
|
265
|
+
const bindings = {
|
|
266
|
+
// which cascade this dispatch is building; the shader is shared across all of them
|
|
267
|
+
settings: {
|
|
268
|
+
cascade,
|
|
269
|
+
sub_steps: volumetrics_sun_shadow_sub_steps(cascade),
|
|
270
|
+
},
|
|
271
|
+
camera: camera_buffer,
|
|
272
|
+
volumetrics_metadata,
|
|
273
|
+
tParticipatingMedia1: participating_media1,
|
|
274
|
+
tSunShadowVolume: TextureResourceDescriptor.from({
|
|
275
|
+
resolution,
|
|
276
|
+
dimension: "3d",
|
|
277
|
+
format: "rgba16float",
|
|
278
|
+
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
|
|
279
|
+
}),
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
if (seeded) {
|
|
283
|
+
bindings.tSunShadowOuter = cascades[cascade + 1];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const outputs = graph_compute_pass({
|
|
287
|
+
graph,
|
|
288
|
+
shader: seeded
|
|
289
|
+
? shader_volumetrics_build_sun_shadow_volume_seeded
|
|
290
|
+
: shader_volumetrics_build_sun_shadow_volume_outermost,
|
|
291
|
+
group_count,
|
|
292
|
+
bindings,
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
cascades[cascade] = outputs.tSunShadowVolume;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return cascades;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
*
|
|
303
|
+
* @param {FrameGraph} graph
|
|
304
|
+
* @param participating_media0
|
|
305
|
+
* @param participating_media1
|
|
306
|
+
* @param volumetrics_metadata
|
|
307
|
+
* @param light_cluster_data
|
|
308
|
+
* @param light_cluster_lookup
|
|
309
|
+
* @param light_cluster_parameters
|
|
310
|
+
* @param shadowmap_atlas
|
|
311
|
+
* @param sun_transmittance_lut
|
|
312
|
+
* @param sun_multiple_scattering_lut
|
|
313
|
+
* @param {number[]} sun_shadow_cascades handles of the Q-04 optical-depth cascades, innermost first
|
|
314
|
+
* @param lights
|
|
315
|
+
* @param view
|
|
316
|
+
* @param camera
|
|
317
|
+
* @param resolution
|
|
318
|
+
* @param {ShaderSwitchSet} shader_switches the renderer's; the lighting pass is built for them
|
|
319
|
+
* @returns {number} the lit scattering volume
|
|
320
|
+
*/
|
|
321
|
+
function graph_integrate_light_scattering({
|
|
322
|
+
graph,
|
|
323
|
+
participating_media0,
|
|
324
|
+
participating_media1,
|
|
325
|
+
volumetrics_metadata,
|
|
326
|
+
light_cluster_data,
|
|
327
|
+
light_cluster_lookup,
|
|
328
|
+
light_cluster_parameters,
|
|
329
|
+
shadowmap_atlas,
|
|
330
|
+
sun_transmittance_lut,
|
|
331
|
+
sun_multiple_scattering_lut,
|
|
332
|
+
sun_shadow_cascades,
|
|
333
|
+
lights,
|
|
334
|
+
view,
|
|
335
|
+
camera,
|
|
336
|
+
resolution,
|
|
337
|
+
shader_switches,
|
|
338
|
+
}) {
|
|
339
|
+
|
|
340
|
+
const data = {};
|
|
341
|
+
|
|
342
|
+
const pass = graph.add("scattering lut", data, (data, resources, context) => {
|
|
343
|
+
const output = resources.get(data.output);
|
|
344
|
+
|
|
345
|
+
const volumetrics_metadata = resources.get(data.volumetrics_metadata);
|
|
346
|
+
|
|
347
|
+
const participating_media0 = resources.get(data.participating_media0);
|
|
348
|
+
const participating_media1 = resources.get(data.participating_media1);
|
|
349
|
+
|
|
350
|
+
const light_cluster_data = resources.get(data.light_cluster_data);
|
|
351
|
+
const light_cluster_lookup = resources.get(data.light_cluster_lookup);
|
|
352
|
+
const light_cluster_parameters = resources.get(data.light_cluster_parameters);
|
|
353
|
+
const shadowmap_atlas = resources.get(data.shadowmap_atlas);
|
|
354
|
+
|
|
355
|
+
const sun_transmittance_lut = resources.get(data.sun_transmittance_lut);
|
|
356
|
+
const sun_multiple_scattering_lut = resources.get(data.sun_multiple_scattering_lut);
|
|
357
|
+
const sun_shadow_cascades = data.sun_shadow_cascades.map(handle => resources.get(handle));
|
|
358
|
+
|
|
359
|
+
const sampler_shadowmap = context.graphics.samplers.obtain(SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR);
|
|
360
|
+
const sLinear = context.graphics.samplers.obtain(SamplerDescriptor.from({
|
|
361
|
+
magFilter: "linear",
|
|
362
|
+
}));
|
|
363
|
+
|
|
364
|
+
// Spatiotemporal blue noise for the per-froxel sample offset. The pass takes one sample and
|
|
365
|
+
// leans on the volumetric TAA to integrate, which only works if each froxel's sequence over
|
|
366
|
+
// frames is well distributed — the property a per-froxel hash does not have.
|
|
367
|
+
const tSTBN_vec3 = context.graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
|
|
368
|
+
|
|
369
|
+
const encoder = context.encoder;
|
|
370
|
+
|
|
371
|
+
const bindings = {
|
|
372
|
+
camera: camera.buffer.buffer,
|
|
373
|
+
view: view.uniform_buffer.buffer,
|
|
374
|
+
volumetrics_metadata,
|
|
375
|
+
sLinear,
|
|
376
|
+
tSunTransmittance: sun_transmittance_lut.obtainView(),
|
|
377
|
+
tMultiScattering: sun_multiple_scattering_lut.obtainView(),
|
|
378
|
+
tSTBN_vec3: tSTBN_vec3.obtainView(),
|
|
379
|
+
tParticipatingMedia0: participating_media0.obtainView(),
|
|
380
|
+
tParticipatingMedia1: participating_media1.obtainView(),
|
|
381
|
+
tLighting: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
|
|
382
|
+
//
|
|
383
|
+
light_data: lights.buffer_data,
|
|
384
|
+
|
|
385
|
+
cluster_data: light_cluster_data,
|
|
386
|
+
cluster_lookup: light_cluster_lookup,
|
|
387
|
+
cluster_parameters: light_cluster_parameters,
|
|
388
|
+
|
|
389
|
+
shadowmapAtlas: shadowmap_atlas.obtainView(),
|
|
390
|
+
sCompareLinear: sampler_shadowmap,
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
// One texture per cascade, under the names the read side declares. Bound here rather than
|
|
394
|
+
// above because the count is a constant of the structure, not of this pass.
|
|
395
|
+
for (let cascade = 0; cascade < sun_shadow_cascades.length; cascade++) {
|
|
396
|
+
bindings[volumetrics_sun_shadow_texture_name(cascade)] = sun_shadow_cascades[cascade].obtainView();
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
shader_volumetrics_build_lighting.variant(shader_switches).dispatchThreads({
|
|
400
|
+
encoder,
|
|
401
|
+
thread_count_x: output.width,
|
|
402
|
+
thread_count_y: output.height,
|
|
403
|
+
thread_count_z: output.depth,
|
|
404
|
+
bindings
|
|
405
|
+
})
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
data.participating_media0 = pass.read(participating_media0);
|
|
409
|
+
data.participating_media1 = pass.read(participating_media1);
|
|
410
|
+
data.volumetrics_metadata = pass.read(volumetrics_metadata);
|
|
411
|
+
|
|
412
|
+
data.shadowmap_atlas = pass.read(shadowmap_atlas);
|
|
413
|
+
data.light_cluster_data = pass.read(light_cluster_data);
|
|
414
|
+
data.light_cluster_lookup = pass.read(light_cluster_lookup);
|
|
415
|
+
data.light_cluster_parameters = pass.read(light_cluster_parameters);
|
|
416
|
+
|
|
417
|
+
data.sun_transmittance_lut = pass.read(sun_transmittance_lut);
|
|
418
|
+
data.sun_multiple_scattering_lut = pass.read(sun_multiple_scattering_lut);
|
|
419
|
+
data.sun_shadow_cascades = sun_shadow_cascades.map(handle => pass.read(handle));
|
|
420
|
+
|
|
421
|
+
data.output = pass.create("Light Scattering LUT", TextureResourceDescriptor.from({
|
|
422
|
+
resolution,
|
|
423
|
+
dimension: "3d",
|
|
424
|
+
format: "rgba16float",
|
|
425
|
+
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
|
|
426
|
+
}));
|
|
427
|
+
|
|
428
|
+
return data.output;
|
|
429
|
+
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* The fog: participating media -> per-froxel lighting -> ray-marched integration into the aerial LUT
|
|
434
|
+
* every surface behind it is seen through. Particle lighting is not here — it needs no medium, and
|
|
435
|
+
* `GPUIrradianceClipmap` builds it on its own.
|
|
436
|
+
*
|
|
437
|
+
* @param {Object} options
|
|
438
|
+
* @param {FrameGraph} options.graph
|
|
439
|
+
* @param {GPUCameraContext} options.camera
|
|
440
|
+
* @param {GPULightCollection} options.lights
|
|
441
|
+
* @param {GPUViewContext} options.view
|
|
442
|
+
* @param {GPUSky} options.sky the scene's sky, already {@link GPUSky#update updated}: its two
|
|
443
|
+
* persistent LUTs are imported and read, not rebuilt. The sun's transmittance and the multiple
|
|
444
|
+
* scattering depend on nothing but the atmosphere's constants, so building them again per frame
|
|
445
|
+
* bought the same texels at a cost that was paid whether or not the scene had any fog.
|
|
446
|
+
* @param {number} options.light_cluster_data
|
|
447
|
+
* @param {number} options.light_cluster_lookup
|
|
448
|
+
* @param {number} options.light_cluster_parameters
|
|
449
|
+
* @param {number} options.shadowmap_atlas
|
|
450
|
+
* @param {number[]} options.volumetric_resolution
|
|
451
|
+
* @param {number[]} options.sun_shadow_resolution voxel counts of one Q-04 sun optical-depth cascade;
|
|
452
|
+
* `[1, 1, 1]` when the froxels are marching instead, which keeps the passes in the graph without
|
|
453
|
+
* doing any work
|
|
454
|
+
* @param {number} options.volumetrics_metadata
|
|
455
|
+
* @param {number} [options.taa_history] imported previous-frame accumulated scattering volume
|
|
456
|
+
* @param {number} [options.taa_output] imported destination for this frame's accumulated scattering volume
|
|
457
|
+
* @param {GPUCameraContext} [options.camera_previous] previous-frame camera, for temporal reprojection
|
|
458
|
+
* @param {ShaderSwitchSet} [options.shader_switches] the renderer's; the lighting pass is built for them
|
|
459
|
+
*/
|
|
460
|
+
export function graph_build_volumetrics({
|
|
461
|
+
graph,
|
|
462
|
+
camera,
|
|
463
|
+
lights,
|
|
464
|
+
view,
|
|
465
|
+
sky,
|
|
466
|
+
light_cluster_data,
|
|
467
|
+
light_cluster_lookup,
|
|
468
|
+
light_cluster_parameters,
|
|
469
|
+
shadowmap_atlas,
|
|
470
|
+
volumetric_resolution,
|
|
471
|
+
sun_shadow_resolution,
|
|
472
|
+
volumetrics_metadata,
|
|
473
|
+
taa_history,
|
|
474
|
+
taa_output,
|
|
475
|
+
camera_previous,
|
|
476
|
+
shader_switches = ShaderSwitchSet.EMPTY,
|
|
477
|
+
}) {
|
|
478
|
+
|
|
479
|
+
assert.defined(view, 'view');
|
|
480
|
+
assert.defined(sky, 'sky');
|
|
481
|
+
assert.equal(sky.needs_update, false, 'sky has not been updated, its LUTs hold nothing yet');
|
|
482
|
+
assert.defined(volumetric_resolution, 'volumetric_resolution');
|
|
483
|
+
assert.defined(sun_shadow_resolution, 'sun_shadow_resolution');
|
|
484
|
+
|
|
485
|
+
graph.push_scope("build volumetrics");
|
|
486
|
+
|
|
487
|
+
// Read-only here, so nothing in this graph orders against a write to either; the sky wrote
|
|
488
|
+
// them in commands of its own, submitted before this frame's.
|
|
489
|
+
const transmittance_lut = graph_import_texture(graph, sky.lut_transmittance);
|
|
490
|
+
const multiscatted_lut = graph_import_texture(graph, sky.lut_multiple_scattering);
|
|
491
|
+
|
|
492
|
+
const {
|
|
493
|
+
participating_media0,
|
|
494
|
+
participating_media1,
|
|
495
|
+
far_field,
|
|
496
|
+
} = graph_integrate_participating_media({
|
|
497
|
+
graph,
|
|
498
|
+
scene: view.scene,
|
|
499
|
+
view,
|
|
500
|
+
resolution: volumetric_resolution,
|
|
501
|
+
volumetrics_metadata,
|
|
502
|
+
camera,
|
|
503
|
+
shader_switches,
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
const sun_shadow_cascades = graph_build_sun_shadow_volume({
|
|
507
|
+
graph,
|
|
508
|
+
camera,
|
|
509
|
+
participating_media1,
|
|
510
|
+
volumetrics_metadata,
|
|
511
|
+
resolution: sun_shadow_resolution,
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
const light_scattering_lut = graph_integrate_light_scattering({
|
|
515
|
+
graph,
|
|
516
|
+
resolution: volumetric_resolution,
|
|
517
|
+
camera,
|
|
518
|
+
view,
|
|
519
|
+
sun_transmittance_lut: transmittance_lut,
|
|
520
|
+
sun_multiple_scattering_lut: multiscatted_lut,
|
|
521
|
+
sun_shadow_cascades,
|
|
522
|
+
participating_media0,
|
|
523
|
+
participating_media1,
|
|
524
|
+
volumetrics_metadata,
|
|
525
|
+
light_cluster_data,
|
|
526
|
+
light_cluster_lookup,
|
|
527
|
+
light_cluster_parameters,
|
|
528
|
+
shadowmap_atlas,
|
|
529
|
+
lights,
|
|
530
|
+
shader_switches,
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
// Temporal reprojection of the per-froxel lit scattering volume, applied BEFORE aerial
|
|
534
|
+
// integration — reprojecting the already-integrated aerial LUT would double-integrate along the
|
|
535
|
+
// view ray. Optional: skipped when no history ping-pong is supplied (TAA disabled), in which
|
|
536
|
+
// case the aerial pass consumes the raw (noisier) scattering LUT directly.
|
|
537
|
+
let volume_lighting_resolved = light_scattering_lut;
|
|
538
|
+
|
|
539
|
+
if (taa_history !== undefined && taa_output !== undefined) {
|
|
540
|
+
const taa_outputs = graph_compute_pass({
|
|
541
|
+
graph,
|
|
542
|
+
shader: shader_volumetrics_taa,
|
|
543
|
+
group_count: [
|
|
544
|
+
Math.ceil(volumetric_resolution[0] / 8),
|
|
545
|
+
Math.ceil(volumetric_resolution[1] / 8),
|
|
546
|
+
Math.ceil(volumetric_resolution[2] / 4),
|
|
547
|
+
],
|
|
548
|
+
bindings: {
|
|
549
|
+
t_current: light_scattering_lut,
|
|
550
|
+
t_history: taa_history,
|
|
551
|
+
t_output: taa_output,
|
|
552
|
+
volumetrics_metadata,
|
|
553
|
+
camera_current: graph_import_buffer(graph, camera.buffer.buffer, "volumetrics taa camera"),
|
|
554
|
+
camera_previous: graph_import_buffer(graph, camera_previous.buffer.buffer, "volumetrics taa camera previous"),
|
|
555
|
+
},
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
volume_lighting_resolved = taa_outputs.t_output;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const a_data = {};
|
|
562
|
+
|
|
563
|
+
const a_pass = graph.add("aerial lut", a_data, (data, resources, context) => {
|
|
564
|
+
const output = resources.get(data.output);
|
|
565
|
+
|
|
566
|
+
const participating_media0 = resources.get(data.participating_media0);
|
|
567
|
+
const participating_media1 = resources.get(data.participating_media1);
|
|
568
|
+
const volumetrics_metadata = resources.get(data.volumetrics_metadata);
|
|
569
|
+
|
|
570
|
+
const light_scattering_lut = resources.get(data.light_scattering_lut);
|
|
571
|
+
const sun_transmittance_lut = resources.get(data.sun_transmittance_lut);
|
|
572
|
+
const far_field = resources.get(data.far_field);
|
|
573
|
+
|
|
574
|
+
const encoder = context.encoder;
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
const graphics = context.graphics;
|
|
578
|
+
|
|
579
|
+
const sLinear = graphics.samplers.obtain(SamplerDescriptor.from({
|
|
580
|
+
magFilter: "linear",
|
|
581
|
+
}));
|
|
582
|
+
|
|
583
|
+
const tSTBN_vec3 = graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
|
|
584
|
+
|
|
585
|
+
shader_volumetrics_build_scattering_lut.dispatchThreads({
|
|
586
|
+
encoder,
|
|
587
|
+
thread_count_x: output.width,
|
|
588
|
+
thread_count_y: output.height,
|
|
589
|
+
bindings: {
|
|
590
|
+
camera: camera.buffer.buffer,
|
|
591
|
+
view: view.uniform_buffer.buffer,
|
|
592
|
+
volumetrics_metadata,
|
|
593
|
+
tSTBN_vec3: tSTBN_vec3.obtainView(),
|
|
594
|
+
sLinear,
|
|
595
|
+
|
|
596
|
+
tVolumeLighting: light_scattering_lut.obtainView(),
|
|
597
|
+
tParticipatingMedia0: participating_media0.obtainView(),
|
|
598
|
+
tParticipatingMedia1: participating_media1.obtainView(),
|
|
599
|
+
|
|
600
|
+
// RDR2-style far-field march inputs (used beyond froxel_far)
|
|
601
|
+
scene_database: view.scene.scene_database_buffer,
|
|
602
|
+
far_field,
|
|
603
|
+
light_data: lights.buffer_data,
|
|
604
|
+
tSunTransmittance: sun_transmittance_lut.obtainView(),
|
|
605
|
+
|
|
606
|
+
tOutput: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
a_data.participating_media0 = a_pass.read(participating_media0);
|
|
614
|
+
a_data.participating_media1 = a_pass.read(participating_media1);
|
|
615
|
+
a_data.volumetrics_metadata = a_pass.read(volumetrics_metadata);
|
|
616
|
+
a_data.sun_transmittance_lut = a_pass.read(transmittance_lut);
|
|
617
|
+
a_data.far_field = a_pass.read(far_field);
|
|
618
|
+
|
|
619
|
+
a_data.output = a_pass.create("Integrated Volumetrics", TextureResourceDescriptor.from({
|
|
620
|
+
resolution: volumetric_resolution,
|
|
621
|
+
dimension: "3d",
|
|
622
|
+
format: "rgba16float",
|
|
623
|
+
usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
|
|
624
|
+
}))
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
a_data.light_scattering_lut = a_pass.read(volume_lighting_resolved);
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
// TODO add temporal reprojection
|
|
631
|
+
|
|
632
|
+
graph.pop_scope();
|
|
633
|
+
|
|
634
|
+
return {
|
|
635
|
+
lut_transmittance: transmittance_lut,
|
|
636
|
+
lut_multiple_scattering: multiscatted_lut,
|
|
637
|
+
lut_aerial: a_data.output,
|
|
638
|
+
volumetrics_metadata,
|
|
639
|
+
};
|
|
640
|
+
}
|