vert 0.1.1

The 51th Rust Game Engine, to write the 6th Game in Rust
Documentation
// Source: Adapted from Bevy Source code, which in turn is from COD GDC talk.

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


struct ScreenSpace {
    width: f32,
    height: f32,
    aspect: f32,
}

@group(0) @binding(0)
var<uniform> screen: ScreenSpace;

@group(1)
@binding(0)
var hdr_image: texture_2d<f32>;

@group(1)
@binding(1)
var hdr_sampler: sampler;

@fragment
fn downsample(vs: VertexOutput) -> @location(0) vec4<f32> {
    let sample = sample_input_13_tap(vs.uv);
    return vec4(sample, 1.0);
}

@fragment
fn threshold_downsample(vs: VertexOutput) -> @location(0) vec4<f32> {
    let sample = sample_input_13_tap(vs.uv);
    return vec4(soft_threshold(sample.xyz), 1.0);
}

@fragment
fn upsample(vs: VertexOutput) -> @location(0) vec4<f32> {
    let sample = sample_input_3x3_tent(vs.uv);
    return vec4(sample,1.0);
}


// // [COD] slide 162
fn sample_input_3x3_tent(uv: vec2<f32>) -> vec3<f32> {
    // Radius. Empirically chosen by and tweaked from the LearnOpenGL article.
    let x = 0.004 / screen.aspect;
    let y = 0.004;

    let a = textureSample(hdr_image, hdr_sampler, vec2<f32>(uv.x - x, uv.y + y)).rgb;
    let b = textureSample(hdr_image, hdr_sampler, vec2<f32>(uv.x, uv.y + y)).rgb;
    let c = textureSample(hdr_image, hdr_sampler, vec2<f32>(uv.x + x, uv.y + y)).rgb;

    let d = textureSample(hdr_image, hdr_sampler, vec2<f32>(uv.x - x, uv.y)).rgb;
    let e = textureSample(hdr_image, hdr_sampler, vec2<f32>(uv.x, uv.y)).rgb;
    let f = textureSample(hdr_image, hdr_sampler, vec2<f32>(uv.x + x, uv.y)).rgb;

    let g = textureSample(hdr_image, hdr_sampler, vec2<f32>(uv.x - x, uv.y - y)).rgb;
    let h = textureSample(hdr_image, hdr_sampler, vec2<f32>(uv.x, uv.y - y)).rgb;
    let i = textureSample(hdr_image, hdr_sampler, vec2<f32>(uv.x + x, uv.y - y)).rgb;

    var sample = e * 0.25;
    sample += (b + d + f + h) * 0.125;
    sample += (a + c + g + i) * 0.0625;

    return sample;
}

/// Todo! look at bevy code where this comes from and 
const x: f32 = 0.5;
const y: f32 = 1.0;
const z: f32 = 1.0;
const w: f32 = 1.0;

fn soft_threshold(color: vec3<f32>) -> vec3<f32> {
    let brightness = max(color.r, max(color.g, color.b));
    var softness = brightness - y;
    softness = clamp(softness, 0.0, z);
    softness = softness * softness * w;
    var contribution = max(brightness - x, softness);
    contribution /= max(brightness, 0.00001); // Prevent division by 0
    return color * contribution;
}


// [COD] slide 153
fn sample_input_13_tap(uv: vec2<f32>) -> vec3<f32> {
    let a = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(-2, 2)).rgb;
    let b = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(0, 2)).rgb;
    let c = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(2, 2)).rgb;
    let d = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(-2, 0)).rgb;
    let e = textureSample(hdr_image, hdr_sampler, uv).rgb;
    let f = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(2, 0)).rgb;
    let g = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(-2, -2)).rgb;
    let h = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(0, -2)).rgb;
    let i = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(2, -2)).rgb;
    let j = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(-1, 1)).rgb;
    let k = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(1, 1)).rgb;
    let l = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(-1, -1)).rgb;
    let m = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(1, -1)).rgb;

    var sample = (a + c + g + i) * 0.03125;
    sample += (b + d + f + h) * 0.0625;
    sample += (e + j + k + l + m) * 0.125;
    return sample;
}



// fn sample_input_13_tap_initial(uv: vec2<f32>) -> vec3<f32> {
//     let a = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(-2, 2)).rgb;
//     let b = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(0, 2)).rgb;
//     let c = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(2, 2)).rgb;
//     let d = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(-2, 0)).rgb;
//     let e = textureSample(hdr_image, hdr_sampler, uv).rgb;
//     let f = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(2, 0)).rgb;
//     let g = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(-2, -2)).rgb;
//     let h = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(0, -2)).rgb;
//     let i = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(2, -2)).rgb;
//     let j = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(-1, 1)).rgb;
//     let k = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(1, 1)).rgb;
//     let l = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(-1, -1)).rgb;
//     let m = textureSample(hdr_image, hdr_sampler, uv, vec2<i32>(1, -1)).rgb;

//     // [COD] slide 168
//     //
//     // The first downsample pass reads from the rendered frame which may exhibit
//     // 'fireflies' (individual very bright pixels) that should not cause the bloom effect.
//     //
//     // The first downsample uses a firefly-reduction method proposed by Brian Karis
//     // which takes a weighted-average of the samples to limit their luma range to [0, 1].
//     // This implementation matches the LearnOpenGL article [PBB].
//     var group0 = (a + b + d + e) * (0.125f / 4.0f);
//     var group1 = (b + c + e + f) * (0.125f / 4.0f);
//     var group2 = (d + e + g + h) * (0.125f / 4.0f);
//     var group3 = (e + f + h + i) * (0.125f / 4.0f);
//     var group4 = (j + k + l + m) * (0.5f / 4.0f);
//     // group0 *= karis_average(group0);
//     // group1 *= karis_average(group1);
//     // group2 *= karis_average(group2);
//     // group3 *= karis_average(group3);
//     // group4 *= karis_average(group4);
//     return group0 + group1 + group2 + group3 + group4;
// }


// fn karis_average(color: vec3<f32>) -> f32 {
//     // Luminance calculated by gamma-correcting linear RGB to non-linear sRGB using pow(color, 1.0 / 2.2)
//     // and then calculating luminance based on Rec. 709 color primaries.
//     let luma = tonemapping_luminance(rgb_to_srgb_simple(color)) / 4.0;
//     return 1.0 / (1.0 + luma);
// }