Skip to main content

HDR_TONEMAP_FRAG

Constant HDR_TONEMAP_FRAG 

Source
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.