soorat 1.0.0

Soorat — GPU rendering engine for AGNOS
Documentation
// Full-screen post-processing shader.
// Tone mapping (Reinhard/ACES) + bloom composite.

struct PostProcessUniforms {
    // x = exposure, y = bloom_threshold, z = bloom_intensity, w = tone_map_mode (0=Reinhard, 1=ACES)
    params: vec4<f32>,
}

@group(0) @binding(0) var t_input: texture_2d<f32>;
@group(0) @binding(1) var s_input: sampler;
@group(0) @binding(2) var<uniform> uniforms: PostProcessUniforms;

// Bloom texture (optional — if not bound, bloom_intensity should be 0)
@group(1) @binding(0) var t_bloom: texture_2d<f32>;
@group(1) @binding(1) var s_bloom: sampler;

struct VertexOutput {
    @builtin(position) position: vec4<f32>,
    @location(0) tex_coords: vec2<f32>,
}

@vertex
fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
    var out: VertexOutput;
    let x = f32(i32(vertex_index) / 2) * 4.0 - 1.0;
    let y = f32(i32(vertex_index) % 2) * 4.0 - 1.0;
    out.position = vec4<f32>(x, y, 0.0, 1.0);
    out.tex_coords = vec2<f32>((x + 1.0) / 2.0, (1.0 - y) / 2.0);
    return out;
}

fn aces_filmic(x: vec3<f32>) -> vec3<f32> {
    let a = 2.51;
    let b = 0.03;
    let c = 2.43;
    let d = 0.59;
    let e = 0.14;
    return clamp((x * (a * x + b)) / (x * (c * x + d) + e), vec3<f32>(0.0), vec3<f32>(1.0));
}

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    var color = textureSample(t_input, s_input, in.tex_coords).rgb;

    // Add bloom
    let bloom_intensity = uniforms.params.z;
    if bloom_intensity > 0.0 {
        let bloom = textureSample(t_bloom, s_bloom, in.tex_coords).rgb;
        color += bloom * bloom_intensity;
    }

    let exposure = uniforms.params.x;
    let tone_map_mode = u32(uniforms.params.w);

    // Apply exposure
    color = color * exposure;

    // Tone mapping
    if tone_map_mode == 1u {
        color = aces_filmic(color);
    } else {
        color = color / (color + vec3<f32>(1.0));
    }

    return vec4<f32>(color, 1.0);
}

// Simple pass-through for when bloom group isn't bound
@fragment
fn fs_no_bloom(in: VertexOutput) -> @location(0) vec4<f32> {
    var color = textureSample(t_input, s_input, in.tex_coords).rgb;

    let exposure = uniforms.params.x;
    let tone_map_mode = u32(uniforms.params.w);

    color = color * exposure;

    if tone_map_mode == 1u {
        color = aces_filmic(color);
    } else {
        color = color / (color + vec3<f32>(1.0));
    }

    return vec4<f32>(color, 1.0);
}