renderling/pbr/ibl/
shader.rs

1//! Shader side of IBL
2use glam::{Vec3, Vec4, Vec4Swizzles};
3#[cfg(gpu)]
4use spirv_std::num_traits::Float;
5use spirv_std::{image::Cubemap, spirv, Sampler};
6
7use crate::math::IsVector;
8
9/// Diffuse irradiance convolution.
10#[spirv(fragment)]
11pub fn di_convolution_fragment(
12    #[spirv(descriptor_set = 0, binding = 1)] environment_texture: &Cubemap,
13    #[spirv(descriptor_set = 0, binding = 2)] environment_sampler: &Sampler,
14    local_pos: Vec3,
15    frag_color: &mut Vec4,
16) {
17    let normal = {
18        let mut n = local_pos.alt_norm_or_zero();
19        n.y *= -1.0;
20        n
21    };
22    let mut irradiance = Vec3::ZERO;
23    let right = Vec3::Y.cross(normal).alt_norm_or_zero();
24    let up = normal.cross(right).alt_norm_or_zero();
25
26    let sample_delta = 0.025;
27    let mut nr_samples = 0.0;
28    let mut phi = 0.0f32;
29    while phi < 2.0 * core::f32::consts::PI {
30        let mut theta = 0.0f32;
31        while theta < core::f32::consts::FRAC_PI_2 {
32            // spherical to cartisian tangent coords
33            let tangent_sample = Vec3::new(
34                theta.sin() * phi.cos(),
35                theta.sin() * phi.sin(),
36                theta.cos(),
37            );
38            // tangent to world coords
39            let sample_vec =
40                (tangent_sample.x * right + tangent_sample.y * up + tangent_sample.z * normal)
41                    .alt_norm_or_zero();
42            let sample = environment_texture.sample(*environment_sampler, sample_vec)
43                * theta.cos()
44                * theta.sin();
45            irradiance += sample.xyz();
46            nr_samples += 1.0;
47
48            theta += sample_delta;
49        }
50        phi += sample_delta
51    }
52
53    *frag_color = (irradiance * (core::f32::consts::PI / nr_samples)).extend(1.0);
54}