Created
October 6, 2021 05:48
-
-
Save Pikachuxxxx/136940d6d0d64074aba51246f514bd26 to your computer and use it in GitHub Desktop.
A Fragment Shader with various tone mapping algorithms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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