irradiance_convolution.slang

cross platform rendering playground

src/shaders/ibl/irradiance_convolution.slang

1.42 KB
#include "shared.h"
#include "renderer_types.h"
#include "cubemap.slang"

[[vk::push_constant]]
IblConstants pc;

[shader("vertex")]
VtxOut vsMain(u32 vertexID: SV_VertexID) {
    VtxOut o;
    vec2 positions[3] = { vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0) };

    vec2 pos = positions[vertexID];
    o.clip_pos = vec4(pos, 0.0, 1.0);
    o.uv = pos * 0.5 + 0.5;
    return o;
}

[shader("fragment")]
vec4 fsMain(VtxOut input) : SV_Target0 {
    vec3 N = CubemapFaceDirection(pc.faceidx, input.uv);

    vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
    vec3 T = normalize(cross(up, N));
    vec3 B = cross(N, T);

    TextureCube<float4> env = pc.environment;
    SamplerState samp = pc.samp;

    vec3 irradiance = 0.0;
    u32 sampleCount = 0;

    const f32 PI = 3.14159265359;
    const f32 sampleDelta = 0.0025;

    for (f32 phi = 0.0; phi < 2.0 * PI; phi += sampleDelta) {
        for (f32 theta = 0.0; theta < 0.5 * PI; theta += sampleDelta) {
            vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));

            vec3 sampleDir = tangentSample.x * T + tangentSample.y * B + tangentSample.z * N;

            irradiance += env.SampleLevel(samp, sampleDir, 0.0).rgb * cos(theta) * sin(theta);
            sampleCount++;
        }
    }

    irradiance = PI * irradiance / f32(sampleCount);
    // irradiance *= sampleDelta * sampleDelta;
    return vec4(irradiance, 1.0);
}