xfy a7490c0c2f render: composite + ACES tone-map (bloom stage [5]), replaces upscale
Adds CompositeMaterial + composite.wgsl: combines the HDR scene with the
bloom pyramid output, applies ACES (Narkowicz) tone mapping, and writes
LDR to the window. Removes UpscaleMaterial + upscale.wgsl.

mirror_params now updates composite (bloom_strength, exposure) and
brightpass (threshold) uniforms each frame. resize_offscreen rebuilds
the full bloom pyramid targets on window resize.
2026-07-15 00:14:03 +08:00

34 lines
1.1 KiB
WebGPU Shading Language

#import bevy_sprite::mesh2d_vertex_output::VertexOutput
struct CompositeUniform {
bloom_strength: f32,
exposure: f32,
_pad0: f32,
_pad1: f32,
};
@group(#{MATERIAL_BIND_GROUP}) @binding(0) var<uniform> u: CompositeUniform;
@group(#{MATERIAL_BIND_GROUP}) @binding(1) var scene_tex: texture_2d<f32>;
@group(#{MATERIAL_BIND_GROUP}) @binding(2) var scene_samp: sampler;
@group(#{MATERIAL_BIND_GROUP}) @binding(3) var bloom_tex: texture_2d<f32>;
@group(#{MATERIAL_BIND_GROUP}) @binding(4) var bloom_samp: sampler;
// ACES Narkowicz fit (5 ops, clamped to [0,1]).
fn aces_tonemap(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 fragment(in: VertexOutput) -> @location(0) vec4<f32> {
let hdr = textureSample(scene_tex, scene_samp, in.uv).rgb;
let bloom = textureSample(bloom_tex, bloom_samp, in.uv).rgb;
let combined = hdr + bloom * u.bloom_strength;
let mapped = aces_tonemap(combined * u.exposure);
return vec4<f32>(mapped, 1.0);
}