Search across packages, versions, files, declarations, and comments. Use multiple terms to narrow results (AND), and add @vertex, @fragment, or @compute to filter by shader stage.
1import package::light_probe::{light_probe_iterator_new, light_probe_iterator_next};
2import package::render::mesh_view_bindings::{
3 irradiance_volumes,
4 irradiance_volume,
5 irradiance_volume_sampler,
6 light_probes,
7};
8import package::render::clustered_forward::ClusterableObjectIndexRanges;
10@if(LIGHTMAP) import package::render::mesh_view_types::LIGHT_PROBE_FLAG_AFFECTS_LIGHTMAPPED_MESH_DIFFUSE;
12@if(IRRADIANCE_VOLUMES_ARE_USABLE)
14/// See:
15/// https://advances.realtimerendering.com/s2006/Mitchell-ShadingInValvesSourceEngine.pdf
16/// Slide 28, "Ambient Cube Basis"
17fn irradiance_volume_light(
18 world_position: vec3<f32>,
19 N: vec3<f32>,
20 clusterable_object_index_ranges: ptr<function, ClusterableObjectIndexRanges>,
21) -> vec3<f32> {
22 // Find all irradiance volumes that contain the fragment. We're going to
23 // accumulate all the irradiance from them in a weighted sum.
24 var iterator = light_probe_iterator_new(
25 world_position,
26 /*is_irradiance_volume=*/ true,
27 clusterable_object_index_ranges,
28 );
30 var total_weight = 0.0;
31 var total_irradiance = vec3(0.0);
33 while (true) {
34 var query_result = light_probe_iterator_next(&iterator);
36 // If there was no irradiance volume found, we're done.
37 if (query_result.texture_index < 0) {
38 break;
39 }
41 // If we're lightmapped, and the irradiance volume contributes no diffuse
42 // light, then bail out.
43 @if(LIGHTMAP)
44 if ((query_result.flags & LIGHT_PROBE_FLAG_AFFECTS_LIGHTMAPPED_MESH_DIFFUSE) == 0u) {
45 continue;
46 }
48 @if(MULTIPLE_LIGHT_PROBES_IN_ARRAY)
49 let irradiance_volume_texture = irradiance_volumes[query_result.texture_index];
50 @else
51 let irradiance_volume_texture = irradiance_volume;
53 let atlas_resolution = vec3<f32>(textureDimensions(irradiance_volume_texture));
54 let resolution = vec3<f32>(textureDimensions(irradiance_volume_texture) / vec3(1u, 2u, 3u));
56 // Make sure to clamp to the edges to avoid texture bleed.
57 var unit_pos = (query_result.light_from_world * vec4(world_position, 1.0f)).xyz;
58 let stp = clamp((unit_pos + 0.5) * resolution, vec3(0.5f), resolution - vec3(0.5f));
59 let uvw = stp / atlas_resolution;
61 // The bottom half of each cube slice is the negative part, so choose it if applicable on each
62 // slice.
63 let neg_offset = select(vec3(0.0f), vec3(0.5f), N < vec3(0.0f));
65 let uvw_x = uvw + vec3(0.0f, neg_offset.x, 0.0f);
66 let uvw_y = uvw + vec3(0.0f, neg_offset.y, 1.0f / 3.0f);
67 let uvw_z = uvw + vec3(0.0f, neg_offset.z, 2.0f / 3.0f);
69 let rgb_x = textureSampleLevel(irradiance_volume_texture, irradiance_volume_sampler, uvw_x, 0.0).rgb;
70 let rgb_y = textureSampleLevel(irradiance_volume_texture, irradiance_volume_sampler, uvw_y, 0.0).rgb;
71 let rgb_z = textureSampleLevel(irradiance_volume_texture, irradiance_volume_sampler, uvw_z, 0.0).rgb;
73 // Use Valve's formula to sample.
74 let NN = N * N;
75 total_irradiance += (rgb_x * NN.x + rgb_y * NN.y + rgb_z * NN.z) * query_result.intensity *
76 query_result.weight;
78 total_weight += query_result.weight;
79 }
81 if (total_weight != 0.0) {
82 total_irradiance /= total_weight;
83 }
85 return total_irradiance;
Contents