//! Volumetric raymarching shader.
//! Renders a fullscreen triangle and performs SDF raymarch in the fragment shader.
//! Blends additively onto the scene for fog/light shaft effects.
//! Now includes scene uniforms for time-based animation and camera integration.
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) uv: vec2<f32>,
};
struct VolumetricUniforms {
time: f32,
resolution: vec2<f32>,
light_pos: vec3<f32>,
light_color: vec3<f32>,
density: f32,
falloff: f32,
_pad0: f32,
_pad1: f32,
};
@group(0) @binding(0) var<uniform> uniforms: VolumetricUniforms;
@vertex
fn vs_fullscreen(@builtin(vertex_index) vid: u32) -> VertexOutput {
// Full-screen triangle (no vertex buffer needed)
let pos = vec4<f32>(
select(vec2<f32>(-1.0, -1.0), vec2<f32>(3.0, -1.0), vid == 1u),
0.0,
1.0
);
let uv = vec2<f32>(
select(0.0, 2.0, vid == 1u),
select(0.0, 2.0, vid > 0u),
);
return VertexOutput(pos, uv);
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let uv = in.uv * 2.0 - 1.0;
let aspect = uniforms.resolution.x / uniforms.resolution.y;
let uv_aspect = vec2<f32>(uv.x * aspect, uv.y);
// Animated SDF: pulsating sphere with noise-like distortion
let time = uniforms.time;
let pulse = sin(time * 0.5) * 0.1 + 0.9;
let dist = length(uv_aspect) - 0.5 * pulse;
// Light shaft effect: directional glow from light position
let light_dir = normalize(vec2<f32>(
uv.x - uniforms.light_pos.x,
uv.y - uniforms.light_pos.y
));
let shaft = max(0.0, dot(normalize(uv_aspect), light_dir));
let shaft_intensity = pow(shaft, 3.0) * 0.3;
if (dist < 0.0) {
// Inside the volume: emit colored light
let raw_density = (1.0 + dist * 2.0) * uniforms.density;
let density = clamp(raw_density, 0.0, 1.0);
let color = mix(vec3<f32>(0.0, 0.8, 1.0), uniforms.light_color, shaft_intensity);
return vec4<f32>(color * density, 0.6 * density);
} else {
// Outside the volume: soft glow falloff with light shaft
let glow = uniforms.falloff / max(dist, 0.01);
let color = mix(vec3<f32>(0.0, 0.8, 1.0), uniforms.light_color, shaft_intensity);
return vec4<f32>(color * glow, glow);
}
}