struct VertexOutput {
@builtin(position) position: vec4f,
@location(1) uv: vec2f
};
@group(0) @binding(0)
var screen_linear: texture_2d<f32>;
@group(0) @binding(1)
var sampler_screen_linear: sampler;
@group(1) @binding(0)
var color_lut: texture_1d<f32>;
@group(1) @binding(1)
var sampler_color_lut: sampler;
@if(auto_intensity_enabled)
@group(2) @binding(0)
var<storage, read> max_value: u32;
@endif
@group(3) @binding(0)
var<uniform> viewport: ViewportUniform;
struct ViewportUniform {
transform: mat3x3<f32>, // the transform from scene coordinates to pixel coordinates
resolution: vec2<u32>, // the size of the viewport
beam_radius: f32, // the size of the beam (in pixels)
intensity: f32,
gamma: f32,
decay_per_sample: f32
};
@vertex
fn postfx_vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
// Generate full-screen triangle:
// -> uv (0,0), (2,0), (0,2)
// -> positions (-1,1), (3,1), (-1,-3)
var out: VertexOutput;
out.uv = vec2f(f32(vertex_index & 1), f32(vertex_index >> 1)) * 2.0;
var pos: vec2f = (out.uv * 2.0 - vec2f(1., 1.));
pos.y = - pos.y;
out.position = vec4f(pos, 0.0, 1.0);
return out;
}
@fragment
fn postfx_fs_main(in: VertexOutput) -> @location(0) vec4f {
var sampled_intensity = textureSample(screen_linear, sampler_screen_linear, in.uv).x;
sampled_intensity *= viewport.intensity;
@if(auto_intensity_enabled)
// Rescale using the computed maximum value
let max_value_f32 = f32(max_value) / f32(1 << 16);
if (max_value_f32 > 0.0) {
sampled_intensity /= max_value_f32;
}
@endif
sampled_intensity = pow(sampled_intensity, viewport.gamma); // gamma correction
var sampled_color = textureSample(color_lut, sampler_color_lut, sampled_intensity).xyz;
return vec4(sampled_color, 1.0);
}