glsl-tone-map
ACES
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);
}
float aces(float 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);
}
AGX
const mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(
1.6605, -0.1246, -0.0182,
-0.5876, 1.1329, -0.1006,
-0.0728, -0.0083, 1.1187
);
const mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(
0.6274, 0.0691, 0.0164,
0.3293, 0.9195, 0.0880,
0.0433, 0.0113, 0.8956
);
const mat3 AgXInsetMatrix = mat3(
0.856627153315983, 0.137318972929847, 0.11189821299995,
0.0951212405381588, 0.761241990602591, 0.0767994186031903,
0.0482516061458583, 0.101439036467562, 0.811302368396859
);
const mat3 AgXOutsetMatrix = mat3(
1.1271005818144368, -0.1413297634984383, -0.14132976349843826,
-0.11060664309660323, 1.157823702216272, -0.11060664309660294,
-0.016493938717834573, -0.016493938717834257, 1.2519364065950405
);
const float AgxMinEv = -12.47393;
const float AgxMaxEv = 4.026069;
#ifndef AGX_LOOK
#define AGX_LOOK 0
#endif
vec3 agxAscCdl(vec3 color, vec3 slope, vec3 offset, vec3 power, float sat) {
const vec3 lw = vec3(0.2126, 0.7152, 0.0722);
float luma = dot(color, lw);
vec3 c = pow(color * slope + offset, power);
return luma + sat * (c - luma);
}
vec3 agx(vec3 color) {
color = LINEAR_SRGB_TO_LINEAR_REC2020 * color;
color = AgXInsetMatrix * color;
color = max(color, 1e-10);
color = clamp(log2(color), AgxMinEv, AgxMaxEv);
color = (color - AgxMinEv) / (AgxMaxEv - AgxMinEv);
color = clamp(color, 0.0, 1.0);
vec3 x2 = color * color;
vec3 x4 = x2 * x2;
color = + 15.5 * x4 * x2
- 40.14 * x4 * color
+ 31.96 * x4
- 6.868 * x2 * color
+ 0.4298 * x2
+ 0.1191 * color
- 0.00232;
#if AGX_LOOK == 1
color = agxAscCdl(color, vec3(1.0, 0.9, 0.5), vec3(0.0), vec3(0.8), 1.3);
#elif AGX_LOOK == 2
color = agxAscCdl(color, vec3(1.0), vec3(0.0), vec3(1.35), 1.4);
#endif
color = AgXOutsetMatrix * color;
color = pow(max(vec3(0.0), color), vec3(2.2));
color = LINEAR_REC2020_TO_LINEAR_SRGB * color;
color = clamp(color, 0.0, 1.0);
return color;
}
FILMIC
vec3 filmic(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));
}
float filmic(float x) {
float X = max(0.0, x - 0.004);
float result = (X * (6.2 * X + 0.5)) / (X * (6.2 * X + 1.7) + 0.06);
return pow(result, 2.2);
}
LOTTES
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);
}
float lottes(float x) {
const float a = 1.6;
const float d = 0.977;
const float hdrMax = 8.0;
const float midIn = 0.18;
const float midOut = 0.267;
const float b =
(-pow(midIn, a) + pow(hdrMax, a) * midOut) /
((pow(hdrMax, a * d) - pow(midIn, a * d)) * midOut);
const float 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);
}
NEUTRAL
vec3 neutral(vec3 color) {
const float startCompression = 0.8 - 0.04;
const float desaturation = 0.15;
float x = min(color.r, min(color.g, color.b));
float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;
color -= offset;
float peak = max(color.r, max(color.g, color.b));
if (peak < startCompression) return color;
const float d = 1.0 - startCompression;
float newPeak = 1.0 - d * d / (peak + d - startCompression);
color *= newPeak / peak;
float g = 1.0 - 1.0 / (desaturation * (peak - newPeak) + 1.0);
return mix(color, vec3(newPeak), g);
}
REINHARD
vec3 reinhard(vec3 x) {
return x / (1.0 + x);
}
float reinhard(float x) {
return x / (1.0 + x);
}
REINHARD2
vec3 reinhard2(vec3 x) {
const float L_white = 4.0;
return (x * (1.0 + x / (L_white * L_white))) / (1.0 + x);
}
float reinhard2(float x) {
const float L_white = 4.0;
return (x * (1.0 + x / (L_white * L_white))) / (1.0 + x);
}
UCHIMURA
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;
const float a = 1.0;
const float m = 0.22;
const float l = 0.4;
const float c = 1.33;
const float b = 0.0;
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;
const float a = 1.0;
const float m = 0.22;
const float l = 0.4;
const float c = 1.33;
const float b = 0.0;
return uchimura(x, P, a, m, l, c, b);
}
UNCHARTED2
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
vec3 unreal(vec3 x) {
return x / (x + 0.155) * 1.019;
}
float unreal(float x) {
return x / (x + 0.155) * 1.019;
}