pub const HDR_TONEMAP_FRAG: &str = r#"
#version 330 core
in vec2 f_uv;
out vec4 frag_color;
uniform sampler2D u_hdr_scene;
uniform float u_exposure;
uniform int u_tonemap_op; // 0=none, 1=reinhard, 2=aces, 3=uncharted2
// Reinhard
vec3 tonemap_reinhard(vec3 c) {
return c / (vec3(1.0) + c);
}
// ACES (Narkowicz approximation)
vec3 tonemap_aces(vec3 c) {
float a = 2.51;
float b = 0.03;
float cc = 2.43;
float d = 0.59;
float e = 0.14;
return clamp((c * (a * c + b)) / (c * (cc * c + d) + e), 0.0, 1.0);
}
// Uncharted 2 (Hable)
vec3 uc2_curve(vec3 x) {
float A = 0.15; float B = 0.50; float C = 0.10;
float D = 0.20; float E = 0.02; float F = 0.30;
return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
}
vec3 tonemap_uncharted2(vec3 c) {
float W = 11.2;
return uc2_curve(c) / uc2_curve(vec3(W));
}
void main() {
vec3 hdr = texture(u_hdr_scene, f_uv).rgb;
// Apply exposure
vec3 exposed = hdr * u_exposure;
// Tone map
vec3 mapped;
if (u_tonemap_op == 0) mapped = clamp(exposed, 0.0, 1.0);
else if (u_tonemap_op == 1) mapped = tonemap_reinhard(exposed);
else if (u_tonemap_op == 2) mapped = tonemap_aces(exposed);
else if (u_tonemap_op == 3) mapped = tonemap_uncharted2(exposed);
else mapped = tonemap_aces(exposed);
// Gamma correction (linear → sRGB)
mapped = pow(mapped, vec3(1.0 / 2.2));
frag_color = vec4(mapped, 1.0);
}
"#;Expand description
HDR tone mapping + exposure fragment shader. Applied as the final post-processing pass before display.