Skip to content

Instantly share code, notes, and snippets.

@Pikachuxxxx
Created October 6, 2021 05:48
Show Gist options
  • Save Pikachuxxxx/136940d6d0d64074aba51246f514bd26 to your computer and use it in GitHub Desktop.
Save Pikachuxxxx/136940d6d0d64074aba51246f514bd26 to your computer and use it in GitHub Desktop.
A Fragment Shader with various tone mapping algorithms
#version 330 core
#extension GL_ARB_shading_language_include : require
out vec4 color;
uniform sampler2D renderTex;
uniform vec2 resolution;
uniform int toneMapMode;
////////////////////////////////////////////////////////////////////////////////
// Narkowicz 2015, "ACES Filmic Tone Mapping Curve"
vec3 aces(vec3 x) {
const float a = 2.51;
const float b = 0.03;
const float c = 2.43;
const float d = 0.59;
const float e = 0.14;
return clamp((x * (a * x + b)) / (x * (c * x + d) + e), 0.0, 1.0);
}
////////////////////////////////////////////////////////////////////////////////
// Filmic Tonemapping Operators http://filmicworlds.com/blog/filmic-tonemapping-operators/
vec3 tonemapFilmic(vec3 x) {
vec3 X = max(vec3(0.0), x - 0.004);
vec3 result = (X * (6.2 * X + 0.5)) / (X * (6.2 * X + 1.7) + 0.06);
return pow(result, vec3(2.2));
}
////////////////////////////////////////////////////////////////////////////////
// Lottes 2016, "Advanced Techniques and Optimization of HDR Color Pipelines"
vec3 lottes(vec3 x) {
const vec3 a = vec3(1.6);
const vec3 d = vec3(0.977);
const vec3 hdrMax = vec3(8.0);
const vec3 midIn = vec3(0.18);
const vec3 midOut = vec3(0.267);
const vec3 b =
(-pow(midIn, a) + pow(hdrMax, a) * midOut) /
((pow(hdrMax, a * d) - pow(midIn, a * d)) * midOut);
const vec3 c =
(pow(hdrMax, a * d) * pow(midIn, a) - pow(hdrMax, a) * pow(midIn, a * d) * midOut) /
((pow(hdrMax, a * d) - pow(midIn, a * d)) * midOut);
return pow(x, a) / (pow(x, a * d) * b + c);
}
////////////////////////////////////////////////////////////////////////////////
// Reinhard
vec3 reinhard(vec3 x) {
return x / (1.0 + x);
}
////////////////////////////////////////////////////////////////////////////////
// Reinhard II (variant)
vec3 reinhard2(vec3 x) {
const float L_white = 4.0;
return (x * (1.0 + x / (L_white * L_white))) / (1.0 + x);
}
////////////////////////////////////////////////////////////////////////////////
// Uchimura 2017, "HDR theory and practice"
// Math: https://www.desmos.com/calculator/gslcdxvipg
// Source: https://www.slideshare.net/nikuque/hdr-theory-and-practicce-jp
vec3 uchimura(vec3 x, float P, float a, float m, float l, float c, float b) {
float l0 = ((P - m) * l) / a;
float L0 = m - m / a;
float L1 = m + (1.0 - m) / a;
float S0 = m + l0;
float S1 = m + a * l0;
float C2 = (a * P) / (P - S1);
float CP = -C2 / P;
vec3 w0 = vec3(1.0 - smoothstep(0.0, m, x));
vec3 w2 = vec3(step(m + l0, x));
vec3 w1 = vec3(1.0 - w0 - w2);
vec3 T = vec3(m * pow(x / m, vec3(c)) + b);
vec3 S = vec3(P - (P - S1) * exp(CP * (x - S0)));
vec3 L = vec3(m + a * (x - m));
return T * w0 + L * w1 + S * w2;
}
vec3 uchimura(vec3 x) {
const float P = 1.0; // max display brightness
const float a = 1.0; // contrast
const float m = 0.22; // linear section start
const float l = 0.4; // linear section length
const float c = 1.33; // black
const float b = 0.0; // pedestal
return uchimura(x, P, a, m, l, c, b);
}
float uchimura(float x, float P, float a, float m, float l, float c, float b) {
float l0 = ((P - m) * l) / a;
float L0 = m - m / a;
float L1 = m + (1.0 - m) / a;
float S0 = m + l0;
float S1 = m + a * l0;
float C2 = (a * P) / (P - S1);
float CP = -C2 / P;
float w0 = 1.0 - smoothstep(0.0, m, x);
float w2 = step(m + l0, x);
float w1 = 1.0 - w0 - w2;
float T = m * pow(x / m, c) + b;
float S = P - (P - S1) * exp(CP * (x - S0));
float L = m + a * (x - m);
return T * w0 + L * w1 + S * w2;
}
float uchimura(float x) {
const float P = 1.0; // max display brightness
const float a = 1.0; // contrast
const float m = 0.22; // linear section start
const float l = 0.4; // linear section length
const float c = 1.33; // black
const float b = 0.0; // pedestal
return uchimura(x, P, a, m, l, c, b);
}
////////////////////////////////////////////////////////////////////////////////
// Uncharted 2
vec3 uncharted2Tonemap(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;
float W = 11.2;
return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
}
vec3 uncharted2(vec3 color) {
const float W = 11.2;
float exposureBias = 2.0;
vec3 curr = uncharted2Tonemap(exposureBias * color);
vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
return curr * whiteScale;
}
float uncharted2Tonemap(float 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;
float W = 11.2;
return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
}
float uncharted2(float color) {
const float W = 11.2;
const float exposureBias = 2.0;
float curr = uncharted2Tonemap(exposureBias * color);
float whiteScale = 1.0 / uncharted2Tonemap(W);
return curr * whiteScale;
}
////////////////////////////////////////////////////////////////////////////////
// Unreal
// Unreal 3, Documentation: "Color Grading"
// Adapted to be close to Tonemap_ACES, with similar range
// Gamma 2.2 correction is baked in, don't use with sRGB conversion!
vec3 unreal(vec3 x) {
return x / (x + 0.155) * 1.019;
}
float unreal(float x) {
return x / (x + 0.155) * 1.019;
}
////////////////////////////////////////////////////////////////////////////////
void main()
{
vec2 uv = vec2(gl_FragCoord.xy / resolution);
vec3 tex = texture(renderTex, uv).rgb;
switch(toneMapMode)
{
case 0:
color = vec4(aces(tex), 1.0f);
break;
case 1:
color = vec4(tonemapFilmic(tex), 1.0f);
break;
case 2:
color = vec4(lottes(tex), 1.0f);
break;
case 3:
color = vec4(reinhard(tex), 1.0f);
break;
case 4:
color = vec4(reinhard2(tex), 1.0f);
break;
case 5:
color = vec4(uchimura(tex), 1.0f);
break;
case 6:
color = vec4(uncharted2(tex), 1.0f);
break;
case 7:
color = vec4(unreal(tex), 1.0f);
break;
case 8:
color = vec4(tex, 1.0f);
break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment