@woosh/meep-engine 3.11.1 → 3.11.3
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/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +294 -290
- package/src/engine/graphics3/ParticipatingMedia.d.ts +111 -0
- package/src/engine/graphics3/ParticipatingMedia.d.ts.map +1 -0
- package/src/engine/graphics3/ParticipatingMedia.js +203 -0
- package/src/engine/graphics3/ParticipatingMediaSerializationAdapter.d.ts +34 -0
- package/src/engine/graphics3/ParticipatingMediaSerializationAdapter.d.ts.map +1 -0
- package/src/engine/graphics3/ParticipatingMediaSerializationAdapter.js +73 -0
- package/src/engine/graphics3/ParticipatingMediaSystem3.d.ts +87 -0
- package/src/engine/graphics3/ParticipatingMediaSystem3.d.ts.map +1 -0
- package/src/engine/graphics3/ParticipatingMediaSystem3.js +184 -0
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.d.ts +16 -2
- package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.d.ts.map +1 -1
- package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.js +28 -4
- package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.d.ts +1 -1
- package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.d.ts.map +1 -1
- package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.js +5 -2
- package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +564 -451
- package/src/shade/device/ShadeGPUCommandContext.d.ts +18 -2
- package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
- package/src/shade/device/ShadeGPUCommandContext.js +994 -940
- package/src/shade/device/immediate_data_supported.d.ts +33 -0
- package/src/shade/device/immediate_data_supported.d.ts.map +1 -0
- package/src/shade/device/immediate_data_supported.js +53 -0
- package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts +18 -0
- package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUCommandEncoder.js +24 -0
- package/src/shade/device/mock/SoftwareGPUComputePassEncoder.d.ts +7 -0
- package/src/shade/device/mock/SoftwareGPUComputePassEncoder.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUComputePassEncoder.js +49 -1
- package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUDevice.js +20 -2
- package/src/shade/device/mock/SoftwareGPUImmediateData.d.ts +65 -0
- package/src/shade/device/mock/SoftwareGPUImmediateData.d.ts.map +1 -0
- package/src/shade/device/mock/SoftwareGPUImmediateData.js +160 -0
- package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts +7 -0
- package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPURenderPassEncoder.js +50 -0
- package/src/shade/device/mock/pipeline_immediate_size.d.ts +11 -0
- package/src/shade/device/mock/pipeline_immediate_size.d.ts.map +1 -0
- package/src/shade/device/mock/pipeline_immediate_size.js +18 -0
- package/src/shade/device/pipeline/PipelineLayoutManager.d.ts.map +1 -1
- package/src/shade/device/pipeline/PipelineLayoutManager.js +1 -0
- package/src/shade/playground/volumetrics_froxel/README.md +104 -1
- package/src/shade/playground/volumetrics_froxel/index.html +20 -1
- package/src/shade/playground/volumetrics_froxel/main.d.ts.map +1 -1
- package/src/shade/playground/volumetrics_froxel/main.js +298 -0
- package/src/shade/playground/volumetrics_froxel/measure.d.ts +119 -0
- package/src/shade/playground/volumetrics_froxel/measure.d.ts.map +1 -0
- package/src/shade/playground/volumetrics_froxel/measure.js +559 -0
- package/src/shade/renderer/GraphicsContext.d.ts +9 -2
- package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
- package/src/shade/renderer/GraphicsContext.js +13 -1
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +22 -18
- package/src/shade/renderer/atmosphere/GPUSky.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/GPUSky.js +145 -142
- package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.d.ts +34 -0
- package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.d.ts.map +1 -0
- package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.js +36 -0
- package/src/shade/renderer/atmosphere/SAMPLER_SKY_LUT.d.ts +20 -0
- package/src/shade/renderer/atmosphere/SAMPLER_SKY_LUT.d.ts.map +1 -0
- package/src/shade/renderer/atmosphere/SAMPLER_SKY_LUT.js +25 -0
- package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts +14 -1
- package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.js +163 -177
- package/src/shade/renderer/atmosphere/chunk_multiscatter_sample_direction.d.ts +20 -0
- package/src/shade/renderer/atmosphere/chunk_multiscatter_sample_direction.d.ts.map +1 -0
- package/src/shade/renderer/atmosphere/chunk_multiscatter_sample_direction.js +46 -0
- package/src/shade/renderer/atmosphere/chunk_sample_multiscatter_lut.d.ts +11 -1
- package/src/shade/renderer/atmosphere/chunk_sample_multiscatter_lut.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/chunk_sample_multiscatter_lut.js +57 -27
- package/src/shade/renderer/atmosphere/chunk_sample_transmittance_lut.d.ts +19 -1
- package/src/shade/renderer/atmosphere/chunk_sample_transmittance_lut.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/chunk_sample_transmittance_lut.js +69 -33
- package/src/shade/renderer/atmosphere/chunk_sky_lut_compute_uv.d.ts +13 -0
- package/src/shade/renderer/atmosphere/chunk_sky_lut_compute_uv.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/chunk_sky_lut_compute_uv.js +35 -35
- package/src/shade/renderer/atmosphere/chunk_sky_lut_params.d.ts +13 -0
- package/src/shade/renderer/atmosphere/chunk_sky_lut_params.d.ts.map +1 -0
- package/src/shade/renderer/atmosphere/chunk_sky_lut_params.js +38 -0
- package/src/shade/renderer/atmosphere/chunk_sky_lut_texel_to_unit.d.ts +17 -0
- package/src/shade/renderer/atmosphere/chunk_sky_lut_texel_to_unit.d.ts.map +1 -0
- package/src/shade/renderer/atmosphere/chunk_sky_lut_texel_to_unit.js +29 -0
- package/src/shade/renderer/atmosphere/chunk_sky_lut_uv.d.ts +21 -0
- package/src/shade/renderer/atmosphere/chunk_sky_lut_uv.d.ts.map +1 -0
- package/src/shade/renderer/atmosphere/chunk_sky_lut_uv.js +42 -0
- package/src/shade/renderer/atmosphere/shader_multiscatter_lut.d.ts +2 -2
- package/src/shade/renderer/atmosphere/shader_multiscatter_lut.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/shader_multiscatter_lut.js +165 -84
- package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.js +215 -204
- package/src/shade/renderer/atmosphere/shader_transmittance_lut.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/shader_transmittance_lut.js +79 -67
- package/src/shade/renderer/light/cluster/graph_assign_clsuters.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/graph_assign_clsuters.js +6 -2
- package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/GTAO.js +4 -0
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +341 -345
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +0 -2
- 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 +58 -57
- package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +7 -3
- package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +77 -81
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +5 -1
- package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
- package/src/shade/renderer/shader/ComputeShader.js +6 -2
- package/src/shade/renderer/shader/ImageShader.d.ts.map +1 -1
- package/src/shade/renderer/shader/ImageShader.js +4 -1
- package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/ShaderDescriptor.js +26 -0
- package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_RADII_DECLARATION.d.ts +18 -0
- package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_RADII_DECLARATION.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_RADII_DECLARATION.js +32 -0
- package/src/shade/renderer/shader/chunk/atmosphere/PLANET_CENTER_DECLARATION.d.ts +7 -0
- package/src/shade/renderer/shader/chunk/atmosphere/PLANET_CENTER_DECLARATION.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/atmosphere/PLANET_CENTER_DECLARATION.js +17 -6
- package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_ray_bounds.d.ts +21 -0
- package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_ray_bounds.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_ray_bounds.js +69 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_contains_aabb3.d.ts +9 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_contains_aabb3.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_contains_aabb3.js +22 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_from_transformed_corners.d.ts +16 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_from_transformed_corners.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_from_transformed_corners.js +41 -0
- package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_m4.d.ts +11 -0
- package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_m4.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_m4.js +15 -19
- package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_plane_matrix.d.ts +23 -0
- package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_plane_matrix.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_plane_matrix.js +44 -0
- package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_uv_octahedral_unit_decode.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_uv_octahedral_unit_decode.js +1 -4
- package/src/shade/renderer/shader/compiler/CodeChunk.d.ts +7 -1
- package/src/shade/renderer/shader/compiler/CodeChunk.d.ts.map +1 -1
- package/src/shade/renderer/shader/compiler/CodeChunk.js +37 -2
- package/src/shade/renderer/shader/graph/compute/compute_binding_read_names.d.ts.map +1 -1
- package/src/shade/renderer/shader/graph/compute/compute_binding_read_names.js +6 -0
- package/src/shade/renderer/shader/graph/compute/graph_compute_indirect_pass.js +1 -1
- package/src/shade/renderer/shader/graph/compute/graph_compute_pass.js +1 -1
- package/src/shade/renderer/shader/graph/graph_image_pass.js +1 -1
- package/src/shade/renderer/shader/graph/graph_prepare_bindings.d.ts.map +1 -1
- package/src/shade/renderer/shader/graph/graph_prepare_bindings.js +7 -0
- package/src/shade/renderer/shader/graph/graph_prepare_pass_input_data.d.ts +3 -1
- package/src/shade/renderer/shader/graph/graph_prepare_pass_input_data.d.ts.map +1 -1
- package/src/shade/renderer/shader/graph/graph_prepare_pass_input_data.js +12 -1
- package/src/shade/renderer/shader/pass/RenderPassDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/pass/RenderPassDescriptor.js +1 -0
- package/src/shade/renderer/shader/resource/IMMEDIATE_DATA.d.ts +21 -0
- package/src/shade/renderer/shader/resource/IMMEDIATE_DATA.d.ts.map +1 -0
- package/src/shade/renderer/shader/resource/IMMEDIATE_DATA.js +21 -0
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts +59 -1
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +195 -2
- package/src/shade/renderer/shader/type/type_has_arrays.d.ts +14 -0
- package/src/shade/renderer/shader/type/type_has_arrays.d.ts.map +1 -0
- package/src/shade/renderer/shader/type/type_has_arrays.js +33 -0
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_point2.d.ts +14 -13
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_point2.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_point2.js +133 -129
- package/src/shade/renderer/view/GPUViewSkyContext.d.ts.map +1 -1
- package/src/shade/renderer/view/GPUViewSkyContext.js +169 -173
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +480 -315
- package/src/shade/renderer/volumetrics/NOTES.md +887 -8
- package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.d.ts +5 -0
- package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.js +21 -2
- package/src/shade/renderer/volumetrics/SceneVolumetrics.d.ts +26 -0
- package/src/shade/renderer/volumetrics/SceneVolumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/SceneVolumetrics.js +64 -21
- package/src/shade/renderer/volumetrics/VOLUMETRICS_METADATA_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/VOLUMETRICS_METADATA_STRUCT.js +84 -28
- package/src/shade/renderer/volumetrics/VOLUMETRICS_SUN_SHADOW_RESOLUTION.d.ts +98 -0
- package/src/shade/renderer/volumetrics/VOLUMETRICS_SUN_SHADOW_RESOLUTION.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/VOLUMETRICS_SUN_SHADOW_RESOLUTION.js +111 -0
- package/src/shade/renderer/volumetrics/build_volumetrics_sun_shadow_transform.d.ts +84 -0
- package/src/shade/renderer/volumetrics/build_volumetrics_sun_shadow_transform.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/build_volumetrics_sun_shadow_transform.js +252 -0
- package/src/shade/renderer/volumetrics/chunk_integrate_optical_depth.js +75 -75
- package/src/shade/renderer/volumetrics/chunk_volumetrics_local_light_shadow.d.ts +43 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_local_light_shadow.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_local_light_shadow.js +145 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_sample_froxel_extinction.d.ts +20 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_sample_froxel_extinction.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_sample_froxel_extinction.js +48 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_sun_optical_depth.d.ts +38 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_sun_optical_depth.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_sun_optical_depth.js +130 -0
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +18 -3
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +193 -70
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts +16 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +83 -15
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.js +29 -18
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.js +260 -260
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.d.ts +58 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.js +290 -0
- package/src/shade/wgsl/emulator/CPUBitmapData.d.ts +25 -0
- package/src/shade/wgsl/emulator/CPUBitmapData.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/CPUBitmapData.js +33 -0
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +2228 -2215
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +210 -2
- package/src/shade/wgsl/emulator/cpu_texture_gather.d.ts +69 -0
- package/src/shade/wgsl/emulator/cpu_texture_gather.d.ts.map +1 -0
- package/src/shade/wgsl/emulator/cpu_texture_gather.js +148 -0
- package/src/shade/wgsl/emulator/cpu_texture_sample.d.ts +16 -0
- package/src/shade/wgsl/emulator/cpu_texture_sample.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/cpu_texture_sample.js +176 -172
- package/src/shade/renderer/volumetrics/VOLUMETRICS_WORKGROUP_RESOLUTION.d.ts +0 -2
- package/src/shade/renderer/volumetrics/VOLUMETRICS_WORKGROUP_RESOLUTION.d.ts.map +0 -1
- package/src/shade/renderer/volumetrics/VOLUMETRICS_WORKGROUP_RESOLUTION.js +0 -1
|
@@ -1,261 +1,261 @@
|
|
|
1
|
-
import { CAMERA_UNIFORM_STRUCT } from "../camera/CAMERA_UNIFORM_STRUCT.js";
|
|
2
|
-
import { chunk_stbn_sample_vec3 } from "../shader/chunk/noise/chunk_stbn_sample_vec3.js";
|
|
3
|
-
import {
|
|
4
|
-
chunk_compute_near_far_from_projection
|
|
5
|
-
} from "../shader/chunk/camera/chunk_compute_near_far_from_projection.js";
|
|
6
|
-
import { chunk_rgb_to_luminance } from "../shader/chunk/color/chunk_rgb_to_luminance.js";
|
|
7
|
-
import { chunk_texel_coordinate_to_uv } from "../shader/chunk/texture/chunk_texel_coordinate_to_uv.js";
|
|
8
|
-
import { chunk_uv_to_texel_coordinate } from "../shader/chunk/texture/chunk_uv_to_texel_coordinate.js";
|
|
9
|
-
import { CodeChunk } from "../shader/compiler/CodeChunk.js";
|
|
10
|
-
import { ComputeShader } from "../shader/ComputeShader.js";
|
|
11
|
-
import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
|
|
12
|
-
import { VIEW_UNIFORM_STRUCT } from "../view/VIEW_UNIFORM_STRUCT.js";
|
|
13
|
-
import { chunk_cluster_depth_from_z_slice } from "../light/cluster/chunk_cluster_depth_from_z_slice.js";
|
|
14
|
-
import { chunk_cluster_depth_to_z_slice } from "../light/cluster/chunk_cluster_depth_to_z_slice.js";
|
|
15
|
-
import { VOLUMETRICS_METADATA_STRUCT } from "./VOLUMETRICS_METADATA_STRUCT.js";
|
|
16
|
-
import { WebGPUArray } from "../shader/type/WebGPUArray.js";
|
|
17
|
-
import { chunk_camera_ray_from_uv } from "../shader/chunk/geometry/ray/chunk_camera_ray_from_uv.js";
|
|
18
|
-
import { chunk_directional_lights_iteration_mask } from "../shader/chunk/light/io/chunk_directional_lights_iteration_mask.js";
|
|
19
|
-
import { chunk_get_directional_light_info_by_index } from "../shader/chunk/light/io/chunk_get_directional_light_info_by_index.js";
|
|
20
|
-
import { chunk_sky_lut_compute_uv } from "../atmosphere/chunk_sky_lut_compute_uv.js";
|
|
21
|
-
import { chunk_calculate_multiscattering } from "./chunk_calculate_multiscattering.js";
|
|
22
|
-
import { chunk_camera_ray_planar_depth_scale } from "./chunk_camera_ray_planar_depth_scale.js";
|
|
23
|
-
import { PARTICIPATING_MEDIA_VOLUME_STRUCT } from "./PARTICIPATING_MEDIA_VOLUME_STRUCT.js";
|
|
24
|
-
import { SCENE_VOLUMETRICS_METADATA_STRUCT } from "./SCENE_VOLUMETRICS_METADATA_STRUCT.js";
|
|
25
|
-
|
|
26
|
-
const resources = new ShaderResourceSetDescriptor();
|
|
27
|
-
|
|
28
|
-
resources.createGroup()
|
|
29
|
-
.addUniform("camera", CAMERA_UNIFORM_STRUCT)
|
|
30
|
-
.addUniform("view", VIEW_UNIFORM_STRUCT)
|
|
31
|
-
.addTexture("tSTBN_vec3", "unfilterable-float", "3d")
|
|
32
|
-
.addUniform("volumetrics_metadata", VOLUMETRICS_METADATA_STRUCT)
|
|
33
|
-
.addTexture("tParticipatingMedia0", "float", "3d")
|
|
34
|
-
.addTexture("tParticipatingMedia1", "float", "3d")
|
|
35
|
-
.addTexture("tVolumeLighting", "float", "3d") // pre-integrated volumetric light scattering
|
|
36
|
-
// RDR2-style far field: beyond froxel_far the pass ray-marches the scene volumes directly,
|
|
37
|
-
// lit by the directional sun + atmosphere (single scattering, no self-shadow).
|
|
38
|
-
.addUniform("scene_volumetrics_metadata", SCENE_VOLUMETRICS_METADATA_STRUCT)
|
|
39
|
-
.addStorageBuffer("scene_volumes", WebGPUArray.from(PARTICIPATING_MEDIA_VOLUME_STRUCT))
|
|
40
|
-
.addStorageBuffer("light_data", WebGPUArray.u32)
|
|
41
|
-
.addTexture("tSunTransmittance", "float", "2d")
|
|
42
|
-
.addSampler("sLinear")
|
|
43
|
-
.addStorageTexture("tOutput", "rgba16float", "3d", "write-only");
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* see https://github.com/GPUOpen-Effects/Hybrid-Stochastic-Reflections/blob/b3eef4be70db3522c54d289766e6db797777163c/sample/src/Shaders/Atmosphere.h#L149
|
|
48
|
-
* see https://github.com/AirGuanZ/AtmosphereRenderer/blob/94055f272814a850aafa072555a839311b3d2924/asset/aerial_lut.hlsl#L33
|
|
49
|
-
* @type {CodeChunk}
|
|
50
|
-
*/
|
|
51
|
-
const body = CodeChunk.from(
|
|
52
|
-
//language=WGSL
|
|
53
|
-
`
|
|
54
|
-
struct FarVolumeSample {
|
|
55
|
-
scattering: vec3<f32>,
|
|
56
|
-
extinction: vec3<f32>,
|
|
57
|
-
phase_g: f32,
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Point-sample the scene participating-media volumes (coarse: full density inside the box, no edge
|
|
61
|
-
// fade — that is a near-field nicety). Used only beyond the froxel grid.
|
|
62
|
-
fn far_sample_volumes(world_pos: vec3<f32>) -> FarVolumeSample {
|
|
63
|
-
var scattering = vec3<f32>(0.0);
|
|
64
|
-
var extinction = vec3<f32>(0.0);
|
|
65
|
-
var g_weighted = 0.0;
|
|
66
|
-
var scattering_luma = 0.0;
|
|
67
|
-
|
|
68
|
-
let count = scene_volumetrics_metadata.instance_count;
|
|
69
|
-
for (var i = 0u; i < count; i++) {
|
|
70
|
-
let volume = scene_volumes[i];
|
|
71
|
-
let local = (volume.transform_inverse * vec4<f32>(world_pos, 1.0)).xyz;
|
|
72
|
-
if (any(abs(local) > vec3<f32>(0.5))) {
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
let weight = volume.density;
|
|
76
|
-
let vs = volume.particle_spec.scattering * weight;
|
|
77
|
-
let ve = volume.particle_spec.extinction * weight;
|
|
78
|
-
scattering += vs;
|
|
79
|
-
extinction += ve;
|
|
80
|
-
let luma = rgb_to_luminance(vs);
|
|
81
|
-
g_weighted += volume.particle_spec.g * luma;
|
|
82
|
-
scattering_luma += luma;
|
|
83
|
-
}
|
|
84
|
-
var g = 0.0;
|
|
85
|
-
if (scattering_luma > 0.0) {
|
|
86
|
-
g = g_weighted / scattering_luma;
|
|
87
|
-
}
|
|
88
|
-
return FarVolumeSample(scattering, extinction, g);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// In-scatter (.rgb) + mono extinction (.a) at a march point. Inside the froxel grid (depth <=
|
|
92
|
-
// froxel_far) this is the pre-lit grid sample; beyond it we ray-march the volumes directly and light
|
|
93
|
-
// them with the directional sun + atmospheric transmittance (single scattering, no self-shadow).
|
|
94
|
-
fn far_sample_lighting(depth: f32, uvw_grid: vec3<f32>, world_pos: vec3<f32>, ray_dir: vec3<f32>) -> vec4<f32> {
|
|
95
|
-
if (depth <= volumetrics_metadata.froxel_far) {
|
|
96
|
-
// The froxel grid uses its own (tighter) depth curve, so map this LUT depth to the grid
|
|
97
|
-
// slice before sampling (identity when froxel_far == camera.far).
|
|
98
|
-
let res_z = f32(textureDimensions(tVolumeLighting).z);
|
|
99
|
-
let grid_slice = cluster_depth_to_z_slice(depth, volumetrics_metadata.froxel_cluster_parameters, res_z);
|
|
100
|
-
let vl = textureSampleLevel(tVolumeLighting, sLinear, vec3<f32>(uvw_grid.xy, grid_slice / res_z), 0.0);
|
|
101
|
-
return vec4<f32>(vl.rgb, vl.a);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
let s = far_sample_volumes(world_pos);
|
|
105
|
-
|
|
106
|
-
var inscatter = vec3<f32>(0.0);
|
|
107
|
-
var directional_bits = directional_lights_iteration_mask(&light_data);
|
|
108
|
-
while (directional_bits != 0u) {
|
|
109
|
-
let directional_index = countTrailingZeros(directional_bits);
|
|
110
|
-
directional_bits &= ~(1u << directional_index);
|
|
111
|
-
|
|
112
|
-
let sun = get_directional_light_info_by_index(&light_data, directional_index);
|
|
113
|
-
let u = dot(sun.direction, ray_dir);
|
|
114
|
-
let sun_lut_uv = sky_lut_compute_uv(world_pos, sun.direction);
|
|
115
|
-
let transmittance_atmospheric = textureSampleLevel(tSunTransmittance, sLinear, sun_lut_uv, 0.0).rgb;
|
|
116
|
-
|
|
117
|
-
let ms = calculate_multiscattering(vec3<f32>(0.0), s.scattering, s.extinction, u, s.phase_g, volumetrics_metadata.ms_octave_count, volumetrics_metadata.ms_extinction_decay);
|
|
118
|
-
inscatter += ms * transmittance_atmospheric * sun.color;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return vec4<f32>(inscatter, rgb_to_luminance(s.extinction));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
@compute @workgroup_size(16, 16, 1)
|
|
125
|
-
fn main(
|
|
126
|
-
@builtin(global_invocation_id) voxel_coord: vec3<u32>
|
|
127
|
-
){
|
|
128
|
-
let resolution = textureDimensions(tOutput);
|
|
129
|
-
|
|
130
|
-
if (any(voxel_coord.xy >= resolution.xy)) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
let noise = stbn_sample_vec3(vec3(voxel_coord.xy, view.frame_index));
|
|
135
|
-
|
|
136
|
-
let tile_uv = saturate(
|
|
137
|
-
texel_coordinate_to_uv(vec2f(voxel_coord.xy) + vec2(noise.xy - 0.5), resolution.xy)
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
let camera_near_far = compute_near_far_from_projection(camera.projection_matrix);
|
|
141
|
-
let camera_far = camera_near_far.y;
|
|
142
|
-
|
|
143
|
-
// view ray for this froxel column, used to place far-field march samples in world space
|
|
144
|
-
let view_ray = camera_ray_from_uv(tile_uv, camera);
|
|
145
|
-
|
|
146
|
-
var inScatter = vec3<f32>(0.0);
|
|
147
|
-
var throughput = vec3<f32>(1.0);
|
|
148
|
-
|
|
149
|
-
// Every t below is a PLANAR view-space depth off the froxel curve, but the loop uses their
|
|
150
|
-
// difference as a segment length in Beer's law and walks them along a unit ray to place world
|
|
151
|
-
// positions. Both want arc length, which is longer by 1/cos(theta). Uncorrected, the optical
|
|
152
|
-
// path is under-integrated by cos(theta) and fog thins toward the frame edges.
|
|
153
|
-
//
|
|
154
|
-
// Constant for the whole column, so this is one reciprocal per invocation rather than per slice.
|
|
155
|
-
let depth_to_distance = camera_ray_planar_depth_scale(view_ray.direction, camera);
|
|
156
|
-
|
|
157
|
-
// start at the near plane
|
|
158
|
-
var t_prev = camera_near_far.x;
|
|
159
|
-
|
|
160
|
-
// --- TRAPEZOIDAL SETUP ---
|
|
161
|
-
// Prime the loop with the value at the start (Slice 0)
|
|
162
|
-
let uvw_start = vec3<f32>(tile_uv, 0.0);
|
|
163
|
-
|
|
164
|
-
// in-scatter (.rgb) and the TAA-accumulated mono extinction coefficient (.a) now share the
|
|
165
|
-
// volume-lighting texture, so a single sample provides both.
|
|
166
|
-
let vl_start = far_sample_lighting(camera_near_far.x, uvw_start, view_ray.origin + view_ray.direction * (camera_near_far.x * depth_to_distance), view_ray.direction);
|
|
167
|
-
var light_prev = vl_start.rgb;
|
|
168
|
-
var extinction_prev = vl_start.a;
|
|
169
|
-
|
|
170
|
-
for (var z_index: u32 = 0u; z_index < resolution.z; z_index++ ) {
|
|
171
|
-
|
|
172
|
-
// --- STORE BEFORE INTEGRATE ---
|
|
173
|
-
// Texel z_index holds the cumulative in-scatter / transmittance integrated from the near
|
|
174
|
-
// plane up to the NEAR face of this slab, i.e. up to depth from_z_slice(z_index). Storing
|
|
175
|
-
// the running accumulator BEFORE integrating this slab's segment is what aligns texel
|
|
176
|
-
// z_index with from_z_slice(z_index) -- the same convention the deferred read samples back
|
|
177
|
-
// with (slice + 0.5) / resolution.z (see chunk_sample_volumetrics and
|
|
178
|
-
// volumetrics_position_world_to_froxel_uvw). Storing after-integrate instead would shift
|
|
179
|
-
// every texel one slab deeper, over-attenuating the read by a full froxel.
|
|
180
|
-
let transmittance = rgb_to_luminance( throughput );
|
|
181
|
-
|
|
182
|
-
textureStore(
|
|
183
|
-
tOutput,
|
|
184
|
-
vec3<u32>(voxel_coord.x, voxel_coord.y, z_index),
|
|
185
|
-
vec4<f32>(inScatter, transmittance)
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
// We clamp the index to not sample outside the texture
|
|
189
|
-
let next_index = min(z_index + 1u, resolution.z - 1u);
|
|
190
|
-
let next_index_dithered = f32(next_index) + noise.z;
|
|
191
|
-
|
|
192
|
-
// 1. Calculate Geometry
|
|
193
|
-
let t_next = min(camera_far, cluster_depth_from_z_slice(
|
|
194
|
-
next_index_dithered,
|
|
195
|
-
volumetrics_metadata.cluster_parameters,
|
|
196
|
-
f32(resolution.z)
|
|
197
|
-
));
|
|
198
|
-
|
|
199
|
-
// planar depth difference -> arc length along the view ray (C-01b)
|
|
200
|
-
let dt = max(0.0, t_next - t_prev) * depth_to_distance;
|
|
201
|
-
|
|
202
|
-
// 2. Fetch "Next" Value (The end of this segment)
|
|
203
|
-
let uvw_next = vec3<f32>(tile_uv, next_index_dithered / f32(resolution.z));
|
|
204
|
-
|
|
205
|
-
let world_pos_next = view_ray.origin + view_ray.direction * (t_next * depth_to_distance);
|
|
206
|
-
let vl_next = far_sample_lighting(t_next, uvw_next, world_pos_next, view_ray.direction);
|
|
207
|
-
let media_extinction = vl_next.a;
|
|
208
|
-
let light_next = vl_next.rgb;
|
|
209
|
-
|
|
210
|
-
// TODO we should probably offset this to be linear in view-space distance
|
|
211
|
-
const SAMPLE_CENTER_POINT = 0.5;
|
|
212
|
-
|
|
213
|
-
// 3. Trapezoidal Average
|
|
214
|
-
// Instead of taking just the center, we average start and end to form a slope
|
|
215
|
-
let extinction_step = mix(extinction_prev, media_extinction, SAMPLE_CENTER_POINT);
|
|
216
|
-
let light_step = mix(light_prev, light_next, SAMPLE_CENTER_POINT);
|
|
217
|
-
|
|
218
|
-
// 4. Integration (Hillaire) using the averaged values. Extinction is a mono sigma_t scalar,
|
|
219
|
-
// so transmittance is mono and broadcasts to weight the RGB throughput / in-scatter.
|
|
220
|
-
let sample_extinction = dt * extinction_step;
|
|
221
|
-
let sample_transmittance = exp(-sample_extinction);
|
|
222
|
-
|
|
223
|
-
let media_extinction_safe = max(extinction_step, 1e-9);
|
|
224
|
-
|
|
225
|
-
// "S - S * T" is the integral of constant L over the interval.
|
|
226
|
-
// Since we trapezoid-averaged L (light_step), this is a much better approximation
|
|
227
|
-
// for the interval than just using L_center.
|
|
228
|
-
let light_scattering_integrated = (light_step - light_step * sample_transmittance) / media_extinction_safe;
|
|
229
|
-
|
|
230
|
-
inScatter += throughput * light_scattering_integrated;
|
|
231
|
-
throughput *= sample_transmittance;
|
|
232
|
-
|
|
233
|
-
// Advance
|
|
234
|
-
t_prev = t_next;
|
|
235
|
-
extinction_prev = media_extinction;
|
|
236
|
-
light_prev = light_next;
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
`, [
|
|
241
|
-
chunk_rgb_to_luminance,
|
|
242
|
-
chunk_compute_near_far_from_projection,
|
|
243
|
-
chunk_texel_coordinate_to_uv,
|
|
244
|
-
chunk_uv_to_texel_coordinate,
|
|
245
|
-
chunk_cluster_depth_from_z_slice,
|
|
246
|
-
chunk_cluster_depth_to_z_slice,
|
|
247
|
-
chunk_stbn_sample_vec3,
|
|
248
|
-
chunk_camera_ray_from_uv,
|
|
249
|
-
chunk_camera_ray_planar_depth_scale,
|
|
250
|
-
chunk_directional_lights_iteration_mask,
|
|
251
|
-
chunk_get_directional_light_info_by_index,
|
|
252
|
-
chunk_sky_lut_compute_uv,
|
|
253
|
-
chunk_calculate_multiscattering,
|
|
254
|
-
]
|
|
255
|
-
)
|
|
256
|
-
|
|
257
|
-
export const shader_volumetrics_build_scattering_lut = ComputeShader.from({
|
|
258
|
-
label: "Volumetrics / build scattering lut",
|
|
259
|
-
resources,
|
|
260
|
-
body
|
|
1
|
+
import { CAMERA_UNIFORM_STRUCT } from "../camera/CAMERA_UNIFORM_STRUCT.js";
|
|
2
|
+
import { chunk_stbn_sample_vec3 } from "../shader/chunk/noise/chunk_stbn_sample_vec3.js";
|
|
3
|
+
import {
|
|
4
|
+
chunk_compute_near_far_from_projection
|
|
5
|
+
} from "../shader/chunk/camera/chunk_compute_near_far_from_projection.js";
|
|
6
|
+
import { chunk_rgb_to_luminance } from "../shader/chunk/color/chunk_rgb_to_luminance.js";
|
|
7
|
+
import { chunk_texel_coordinate_to_uv } from "../shader/chunk/texture/chunk_texel_coordinate_to_uv.js";
|
|
8
|
+
import { chunk_uv_to_texel_coordinate } from "../shader/chunk/texture/chunk_uv_to_texel_coordinate.js";
|
|
9
|
+
import { CodeChunk } from "../shader/compiler/CodeChunk.js";
|
|
10
|
+
import { ComputeShader } from "../shader/ComputeShader.js";
|
|
11
|
+
import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
|
|
12
|
+
import { VIEW_UNIFORM_STRUCT } from "../view/VIEW_UNIFORM_STRUCT.js";
|
|
13
|
+
import { chunk_cluster_depth_from_z_slice } from "../light/cluster/chunk_cluster_depth_from_z_slice.js";
|
|
14
|
+
import { chunk_cluster_depth_to_z_slice } from "../light/cluster/chunk_cluster_depth_to_z_slice.js";
|
|
15
|
+
import { VOLUMETRICS_METADATA_STRUCT } from "./VOLUMETRICS_METADATA_STRUCT.js";
|
|
16
|
+
import { WebGPUArray } from "../shader/type/WebGPUArray.js";
|
|
17
|
+
import { chunk_camera_ray_from_uv } from "../shader/chunk/geometry/ray/chunk_camera_ray_from_uv.js";
|
|
18
|
+
import { chunk_directional_lights_iteration_mask } from "../shader/chunk/light/io/chunk_directional_lights_iteration_mask.js";
|
|
19
|
+
import { chunk_get_directional_light_info_by_index } from "../shader/chunk/light/io/chunk_get_directional_light_info_by_index.js";
|
|
20
|
+
import { chunk_sky_lut_compute_uv } from "../atmosphere/chunk_sky_lut_compute_uv.js";
|
|
21
|
+
import { chunk_calculate_multiscattering } from "./chunk_calculate_multiscattering.js";
|
|
22
|
+
import { chunk_camera_ray_planar_depth_scale } from "./chunk_camera_ray_planar_depth_scale.js";
|
|
23
|
+
import { PARTICIPATING_MEDIA_VOLUME_STRUCT } from "./PARTICIPATING_MEDIA_VOLUME_STRUCT.js";
|
|
24
|
+
import { SCENE_VOLUMETRICS_METADATA_STRUCT } from "./SCENE_VOLUMETRICS_METADATA_STRUCT.js";
|
|
25
|
+
|
|
26
|
+
const resources = new ShaderResourceSetDescriptor();
|
|
27
|
+
|
|
28
|
+
resources.createGroup()
|
|
29
|
+
.addUniform("camera", CAMERA_UNIFORM_STRUCT)
|
|
30
|
+
.addUniform("view", VIEW_UNIFORM_STRUCT)
|
|
31
|
+
.addTexture("tSTBN_vec3", "unfilterable-float", "3d")
|
|
32
|
+
.addUniform("volumetrics_metadata", VOLUMETRICS_METADATA_STRUCT)
|
|
33
|
+
.addTexture("tParticipatingMedia0", "float", "3d")
|
|
34
|
+
.addTexture("tParticipatingMedia1", "float", "3d")
|
|
35
|
+
.addTexture("tVolumeLighting", "float", "3d") // pre-integrated volumetric light scattering
|
|
36
|
+
// RDR2-style far field: beyond froxel_far the pass ray-marches the scene volumes directly,
|
|
37
|
+
// lit by the directional sun + atmosphere (single scattering, no self-shadow).
|
|
38
|
+
.addUniform("scene_volumetrics_metadata", SCENE_VOLUMETRICS_METADATA_STRUCT)
|
|
39
|
+
.addStorageBuffer("scene_volumes", WebGPUArray.from(PARTICIPATING_MEDIA_VOLUME_STRUCT))
|
|
40
|
+
.addStorageBuffer("light_data", WebGPUArray.u32)
|
|
41
|
+
.addTexture("tSunTransmittance", "float", "2d")
|
|
42
|
+
.addSampler("sLinear")
|
|
43
|
+
.addStorageTexture("tOutput", "rgba16float", "3d", "write-only");
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* see https://github.com/GPUOpen-Effects/Hybrid-Stochastic-Reflections/blob/b3eef4be70db3522c54d289766e6db797777163c/sample/src/Shaders/Atmosphere.h#L149
|
|
48
|
+
* see https://github.com/AirGuanZ/AtmosphereRenderer/blob/94055f272814a850aafa072555a839311b3d2924/asset/aerial_lut.hlsl#L33
|
|
49
|
+
* @type {CodeChunk}
|
|
50
|
+
*/
|
|
51
|
+
const body = CodeChunk.from(
|
|
52
|
+
//language=WGSL
|
|
53
|
+
`
|
|
54
|
+
struct FarVolumeSample {
|
|
55
|
+
scattering: vec3<f32>,
|
|
56
|
+
extinction: vec3<f32>,
|
|
57
|
+
phase_g: f32,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Point-sample the scene participating-media volumes (coarse: full density inside the box, no edge
|
|
61
|
+
// fade — that is a near-field nicety). Used only beyond the froxel grid.
|
|
62
|
+
fn far_sample_volumes(world_pos: vec3<f32>) -> FarVolumeSample {
|
|
63
|
+
var scattering = vec3<f32>(0.0);
|
|
64
|
+
var extinction = vec3<f32>(0.0);
|
|
65
|
+
var g_weighted = 0.0;
|
|
66
|
+
var scattering_luma = 0.0;
|
|
67
|
+
|
|
68
|
+
let count = scene_volumetrics_metadata.instance_count;
|
|
69
|
+
for (var i = 0u; i < count; i++) {
|
|
70
|
+
let volume = scene_volumes[i];
|
|
71
|
+
let local = (volume.transform_inverse * vec4<f32>(world_pos, 1.0)).xyz;
|
|
72
|
+
if (any(abs(local) > vec3<f32>(0.5))) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
let weight = volume.density;
|
|
76
|
+
let vs = volume.particle_spec.scattering * weight;
|
|
77
|
+
let ve = volume.particle_spec.extinction * weight;
|
|
78
|
+
scattering += vs;
|
|
79
|
+
extinction += ve;
|
|
80
|
+
let luma = rgb_to_luminance(vs);
|
|
81
|
+
g_weighted += volume.particle_spec.g * luma;
|
|
82
|
+
scattering_luma += luma;
|
|
83
|
+
}
|
|
84
|
+
var g = 0.0;
|
|
85
|
+
if (scattering_luma > 0.0) {
|
|
86
|
+
g = g_weighted / scattering_luma;
|
|
87
|
+
}
|
|
88
|
+
return FarVolumeSample(scattering, extinction, g);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// In-scatter (.rgb) + mono extinction (.a) at a march point. Inside the froxel grid (depth <=
|
|
92
|
+
// froxel_far) this is the pre-lit grid sample; beyond it we ray-march the volumes directly and light
|
|
93
|
+
// them with the directional sun + atmospheric transmittance (single scattering, no self-shadow).
|
|
94
|
+
fn far_sample_lighting(depth: f32, uvw_grid: vec3<f32>, world_pos: vec3<f32>, ray_dir: vec3<f32>) -> vec4<f32> {
|
|
95
|
+
if (depth <= volumetrics_metadata.froxel_far) {
|
|
96
|
+
// The froxel grid uses its own (tighter) depth curve, so map this LUT depth to the grid
|
|
97
|
+
// slice before sampling (identity when froxel_far == camera.far).
|
|
98
|
+
let res_z = f32(textureDimensions(tVolumeLighting).z);
|
|
99
|
+
let grid_slice = cluster_depth_to_z_slice(depth, volumetrics_metadata.froxel_cluster_parameters, res_z);
|
|
100
|
+
let vl = textureSampleLevel(tVolumeLighting, sLinear, vec3<f32>(uvw_grid.xy, grid_slice / res_z), 0.0);
|
|
101
|
+
return vec4<f32>(vl.rgb, vl.a);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let s = far_sample_volumes(world_pos);
|
|
105
|
+
|
|
106
|
+
var inscatter = vec3<f32>(0.0);
|
|
107
|
+
var directional_bits = directional_lights_iteration_mask(&light_data);
|
|
108
|
+
while (directional_bits != 0u) {
|
|
109
|
+
let directional_index = countTrailingZeros(directional_bits);
|
|
110
|
+
directional_bits &= ~(1u << directional_index);
|
|
111
|
+
|
|
112
|
+
let sun = get_directional_light_info_by_index(&light_data, directional_index);
|
|
113
|
+
let u = dot(sun.direction, ray_dir);
|
|
114
|
+
let sun_lut_uv = sky_lut_compute_uv(world_pos, sun.direction, vec2<f32>(textureDimensions(tSunTransmittance)));
|
|
115
|
+
let transmittance_atmospheric = textureSampleLevel(tSunTransmittance, sLinear, sun_lut_uv, 0.0).rgb;
|
|
116
|
+
|
|
117
|
+
let ms = calculate_multiscattering(vec3<f32>(0.0), s.scattering, s.extinction, u, s.phase_g, volumetrics_metadata.ms_octave_count, volumetrics_metadata.ms_extinction_decay);
|
|
118
|
+
inscatter += ms * transmittance_atmospheric * sun.color;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return vec4<f32>(inscatter, rgb_to_luminance(s.extinction));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@compute @workgroup_size(16, 16, 1)
|
|
125
|
+
fn main(
|
|
126
|
+
@builtin(global_invocation_id) voxel_coord: vec3<u32>
|
|
127
|
+
){
|
|
128
|
+
let resolution = textureDimensions(tOutput);
|
|
129
|
+
|
|
130
|
+
if (any(voxel_coord.xy >= resolution.xy)) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
let noise = stbn_sample_vec3(vec3(voxel_coord.xy, view.frame_index));
|
|
135
|
+
|
|
136
|
+
let tile_uv = saturate(
|
|
137
|
+
texel_coordinate_to_uv(vec2f(voxel_coord.xy) + vec2(noise.xy - 0.5), resolution.xy)
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
let camera_near_far = compute_near_far_from_projection(camera.projection_matrix);
|
|
141
|
+
let camera_far = camera_near_far.y;
|
|
142
|
+
|
|
143
|
+
// view ray for this froxel column, used to place far-field march samples in world space
|
|
144
|
+
let view_ray = camera_ray_from_uv(tile_uv, camera);
|
|
145
|
+
|
|
146
|
+
var inScatter = vec3<f32>(0.0);
|
|
147
|
+
var throughput = vec3<f32>(1.0);
|
|
148
|
+
|
|
149
|
+
// Every t below is a PLANAR view-space depth off the froxel curve, but the loop uses their
|
|
150
|
+
// difference as a segment length in Beer's law and walks them along a unit ray to place world
|
|
151
|
+
// positions. Both want arc length, which is longer by 1/cos(theta). Uncorrected, the optical
|
|
152
|
+
// path is under-integrated by cos(theta) and fog thins toward the frame edges.
|
|
153
|
+
//
|
|
154
|
+
// Constant for the whole column, so this is one reciprocal per invocation rather than per slice.
|
|
155
|
+
let depth_to_distance = camera_ray_planar_depth_scale(view_ray.direction, camera);
|
|
156
|
+
|
|
157
|
+
// start at the near plane
|
|
158
|
+
var t_prev = camera_near_far.x;
|
|
159
|
+
|
|
160
|
+
// --- TRAPEZOIDAL SETUP ---
|
|
161
|
+
// Prime the loop with the value at the start (Slice 0)
|
|
162
|
+
let uvw_start = vec3<f32>(tile_uv, 0.0);
|
|
163
|
+
|
|
164
|
+
// in-scatter (.rgb) and the TAA-accumulated mono extinction coefficient (.a) now share the
|
|
165
|
+
// volume-lighting texture, so a single sample provides both.
|
|
166
|
+
let vl_start = far_sample_lighting(camera_near_far.x, uvw_start, view_ray.origin + view_ray.direction * (camera_near_far.x * depth_to_distance), view_ray.direction);
|
|
167
|
+
var light_prev = vl_start.rgb;
|
|
168
|
+
var extinction_prev = vl_start.a;
|
|
169
|
+
|
|
170
|
+
for (var z_index: u32 = 0u; z_index < resolution.z; z_index++ ) {
|
|
171
|
+
|
|
172
|
+
// --- STORE BEFORE INTEGRATE ---
|
|
173
|
+
// Texel z_index holds the cumulative in-scatter / transmittance integrated from the near
|
|
174
|
+
// plane up to the NEAR face of this slab, i.e. up to depth from_z_slice(z_index). Storing
|
|
175
|
+
// the running accumulator BEFORE integrating this slab's segment is what aligns texel
|
|
176
|
+
// z_index with from_z_slice(z_index) -- the same convention the deferred read samples back
|
|
177
|
+
// with (slice + 0.5) / resolution.z (see chunk_sample_volumetrics and
|
|
178
|
+
// volumetrics_position_world_to_froxel_uvw). Storing after-integrate instead would shift
|
|
179
|
+
// every texel one slab deeper, over-attenuating the read by a full froxel.
|
|
180
|
+
let transmittance = rgb_to_luminance( throughput );
|
|
181
|
+
|
|
182
|
+
textureStore(
|
|
183
|
+
tOutput,
|
|
184
|
+
vec3<u32>(voxel_coord.x, voxel_coord.y, z_index),
|
|
185
|
+
vec4<f32>(inScatter, transmittance)
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
// We clamp the index to not sample outside the texture
|
|
189
|
+
let next_index = min(z_index + 1u, resolution.z - 1u);
|
|
190
|
+
let next_index_dithered = f32(next_index) + noise.z;
|
|
191
|
+
|
|
192
|
+
// 1. Calculate Geometry
|
|
193
|
+
let t_next = min(camera_far, cluster_depth_from_z_slice(
|
|
194
|
+
next_index_dithered,
|
|
195
|
+
volumetrics_metadata.cluster_parameters,
|
|
196
|
+
f32(resolution.z)
|
|
197
|
+
));
|
|
198
|
+
|
|
199
|
+
// planar depth difference -> arc length along the view ray (C-01b)
|
|
200
|
+
let dt = max(0.0, t_next - t_prev) * depth_to_distance;
|
|
201
|
+
|
|
202
|
+
// 2. Fetch "Next" Value (The end of this segment)
|
|
203
|
+
let uvw_next = vec3<f32>(tile_uv, next_index_dithered / f32(resolution.z));
|
|
204
|
+
|
|
205
|
+
let world_pos_next = view_ray.origin + view_ray.direction * (t_next * depth_to_distance);
|
|
206
|
+
let vl_next = far_sample_lighting(t_next, uvw_next, world_pos_next, view_ray.direction);
|
|
207
|
+
let media_extinction = vl_next.a;
|
|
208
|
+
let light_next = vl_next.rgb;
|
|
209
|
+
|
|
210
|
+
// TODO we should probably offset this to be linear in view-space distance
|
|
211
|
+
const SAMPLE_CENTER_POINT = 0.5;
|
|
212
|
+
|
|
213
|
+
// 3. Trapezoidal Average
|
|
214
|
+
// Instead of taking just the center, we average start and end to form a slope
|
|
215
|
+
let extinction_step = mix(extinction_prev, media_extinction, SAMPLE_CENTER_POINT);
|
|
216
|
+
let light_step = mix(light_prev, light_next, SAMPLE_CENTER_POINT);
|
|
217
|
+
|
|
218
|
+
// 4. Integration (Hillaire) using the averaged values. Extinction is a mono sigma_t scalar,
|
|
219
|
+
// so transmittance is mono and broadcasts to weight the RGB throughput / in-scatter.
|
|
220
|
+
let sample_extinction = dt * extinction_step;
|
|
221
|
+
let sample_transmittance = exp(-sample_extinction);
|
|
222
|
+
|
|
223
|
+
let media_extinction_safe = max(extinction_step, 1e-9);
|
|
224
|
+
|
|
225
|
+
// "S - S * T" is the integral of constant L over the interval.
|
|
226
|
+
// Since we trapezoid-averaged L (light_step), this is a much better approximation
|
|
227
|
+
// for the interval than just using L_center.
|
|
228
|
+
let light_scattering_integrated = (light_step - light_step * sample_transmittance) / media_extinction_safe;
|
|
229
|
+
|
|
230
|
+
inScatter += throughput * light_scattering_integrated;
|
|
231
|
+
throughput *= sample_transmittance;
|
|
232
|
+
|
|
233
|
+
// Advance
|
|
234
|
+
t_prev = t_next;
|
|
235
|
+
extinction_prev = media_extinction;
|
|
236
|
+
light_prev = light_next;
|
|
237
|
+
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
`, [
|
|
241
|
+
chunk_rgb_to_luminance,
|
|
242
|
+
chunk_compute_near_far_from_projection,
|
|
243
|
+
chunk_texel_coordinate_to_uv,
|
|
244
|
+
chunk_uv_to_texel_coordinate,
|
|
245
|
+
chunk_cluster_depth_from_z_slice,
|
|
246
|
+
chunk_cluster_depth_to_z_slice,
|
|
247
|
+
chunk_stbn_sample_vec3,
|
|
248
|
+
chunk_camera_ray_from_uv,
|
|
249
|
+
chunk_camera_ray_planar_depth_scale,
|
|
250
|
+
chunk_directional_lights_iteration_mask,
|
|
251
|
+
chunk_get_directional_light_info_by_index,
|
|
252
|
+
chunk_sky_lut_compute_uv,
|
|
253
|
+
chunk_calculate_multiscattering,
|
|
254
|
+
]
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
export const shader_volumetrics_build_scattering_lut = ComputeShader.from({
|
|
258
|
+
label: "Volumetrics / build scattering lut",
|
|
259
|
+
resources,
|
|
260
|
+
body
|
|
261
261
|
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Q-04. Builds one cascade of the sun's optical-depth volume so the lighting pass can read a
|
|
3
|
+
* froxel's media self-shadowing in one fetch instead of marching 16 steps toward the sun for it.
|
|
4
|
+
*
|
|
5
|
+
* The structure is a light-aligned voxel grid holding a prefix sum of extinction along the sun
|
|
6
|
+
* axis — in the shadow-map taxonomy an opacity shadow map (Kim & Neumann 2001) with enough slices
|
|
7
|
+
* and hardware trilinear reconstruction that the slice artefacts it is remembered for do not
|
|
8
|
+
* appear, and exact rather than approximate for the piecewise-constant field a voxel grid is.
|
|
9
|
+
* Enshrouded (GPC 2024) ships the same thing, cascaded: 3D volumes with their z axis on the primary
|
|
10
|
+
* light, initialised from the participating media and then integrated by a 2D dispatch per column,
|
|
11
|
+
* each cascade seeded from the one outside it. Frostbite (SIGGRAPH 2015) cascades its extinction
|
|
12
|
+
* volume the same way, three clip-map levels of it, for the same reason.
|
|
13
|
+
*
|
|
14
|
+
* Fourier Opacity Mapping is the better-known answer and is the wrong one here. It exists because
|
|
15
|
+
* the medium usually arrives as unordered rasterized particles, where the only thing you can do is
|
|
16
|
+
* accumulate a fixed-size, order-independent, additively-blendable summary — and it pays for that
|
|
17
|
+
* with ringing at sharp density transitions. This engine's medium is already a 3D texture with a
|
|
18
|
+
* defined order along any axis, so the scan is available, exact, and has nothing to ring.
|
|
19
|
+
*
|
|
20
|
+
* Two shaders, written out: the outermost cascade, whose scan starts at zero, and every cascade
|
|
21
|
+
* inside it, whose scan starts from the cascade outside. That is a difference in *bindings* — the
|
|
22
|
+
* second reads a texture the first does not have — so it cannot be data. Which cascade is being
|
|
23
|
+
* built can be, and is: it arrives as immediate data, so the inner cascades share one pipeline.
|
|
24
|
+
*
|
|
25
|
+
* @see chunk_volumetrics_sun_optical_depth for the read side
|
|
26
|
+
* @see build_volumetrics_sun_shadow_transform for where each box is placed, and why it is stable
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Which cascade a dispatch is building.
|
|
30
|
+
*
|
|
31
|
+
* Per-dispatch, uniform, read-only and eight bytes, which is the shape immediate data exists for:
|
|
32
|
+
* no pooled buffer, no staging copy, no bind group.
|
|
33
|
+
*
|
|
34
|
+
* `sub_steps` travels with it rather than being derived in the shader because it is a property of
|
|
35
|
+
* the cascade ladder rather than of the box: {@link volumetrics_sun_shadow_sub_steps} is where the
|
|
36
|
+
* rule that it is even and at least two lives, and nothing in the metadata lets the shader
|
|
37
|
+
* re-derive it.
|
|
38
|
+
*
|
|
39
|
+
* @type {WebGPUStruct}
|
|
40
|
+
*/
|
|
41
|
+
export const VOLUMETRICS_SUN_SHADOW_BUILD_SETTINGS: WebGPUStruct;
|
|
42
|
+
/**
|
|
43
|
+
* The outermost cascade. Nothing is outside it, so its scan starts from zero and it binds no outer
|
|
44
|
+
* volume.
|
|
45
|
+
*
|
|
46
|
+
* @type {ComputeShader}
|
|
47
|
+
*/
|
|
48
|
+
export const shader_volumetrics_build_sun_shadow_volume_outermost: ComputeShader;
|
|
49
|
+
/**
|
|
50
|
+
* Every cascade but the outermost, seeded from the one outside it. Which one that is arrives as
|
|
51
|
+
* immediate data, so the whole inner ladder shares this pipeline.
|
|
52
|
+
*
|
|
53
|
+
* @type {ComputeShader}
|
|
54
|
+
*/
|
|
55
|
+
export const shader_volumetrics_build_sun_shadow_volume_seeded: ComputeShader;
|
|
56
|
+
import { WebGPUStruct } from "../shader/type/WebGPUStruct.js";
|
|
57
|
+
import { ComputeShader } from "../shader/ComputeShader.js";
|
|
58
|
+
//# sourceMappingURL=shader_volumetrics_build_sun_shadow_volume.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shader_volumetrics_build_sun_shadow_volume.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;;;;;;;;;;GAYG;AACH,oDAFU,YAAY,CAKkB;AAaxC;;;;;GAKG;AACH,mEAFU,aAAa,CA8FpB;AAcH;;;;;GAKG;AACH,gEAFU,aAAa,CAwGpB;6BA3R0B,gCAAgC;8BAH/B,4BAA4B"}
|