| | |
| | | #ifndef __TONEMAPPING__ |
| | | #define __TONEMAPPING__ |
| | | |
| | | #include "ACES.cginc" |
| | | |
| | | // Set to 1 to use the full reference ACES tonemapper. This should only be used for research |
| | | // purposes and it's quite heavy and generally overkill. |
| | | #define TONEMAPPING_USE_FULL_ACES 0 |
| | | |
| | | // |
| | | // Neutral tonemapping (Hable/Hejl/Frostbite) |
| | | // Input is linear RGB |
| | | // |
| | | half3 NeutralCurve(half3 x, half a, half b, half c, half d, half e, half f) |
| | | { |
| | | return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f; |
| | | } |
| | | |
| | | half3 NeutralTonemap(half3 x, half4 params1, half4 params2) |
| | | { |
| | | // ACES supports negative color values and WILL output negative values when coming from ACES or ACEScg |
| | | // Make sure negative channels are clamped to 0.0 as this neutral tonemapper can't deal with them properly |
| | | x = max((0.0).xxx, x); |
| | | |
| | | // Tonemap |
| | | half a = params1.x; |
| | | half b = params1.y; |
| | | half c = params1.z; |
| | | half d = params1.w; |
| | | half e = params2.x; |
| | | half f = params2.y; |
| | | half whiteLevel = params2.z; |
| | | half whiteClip = params2.w; |
| | | |
| | | half3 whiteScale = (1.0).xxx / NeutralCurve(whiteLevel, a, b, c, d, e, f); |
| | | x = NeutralCurve(x * whiteScale, a, b, c, d, e, f); |
| | | x *= whiteScale; |
| | | |
| | | // Post-curve white point adjustment |
| | | x /= whiteClip.xxx; |
| | | |
| | | return x; |
| | | } |
| | | |
| | | // |
| | | // Filmic tonemapping (ACES fitting, unless TONEMAPPING_USE_FULL_ACES is set to 1) |
| | | // Input is ACES2065-1 (AP0 w/ linear encoding) |
| | | // |
| | | half3 FilmicTonemap(half3 aces) |
| | | { |
| | | #if TONEMAPPING_USE_FULL_ACES |
| | | |
| | | half3 oces = RRT(aces); |
| | | half3 odt = ODT_RGBmonitor_100nits_dim(oces); |
| | | return odt; |
| | | |
| | | #else |
| | | |
| | | // --- Glow module --- // |
| | | half saturation = rgb_2_saturation(aces); |
| | | half ycIn = rgb_2_yc(aces); |
| | | half s = sigmoid_shaper((saturation - 0.4) / 0.2); |
| | | half addedGlow = 1.0 + glow_fwd(ycIn, RRT_GLOW_GAIN * s, RRT_GLOW_MID); |
| | | aces *= addedGlow; |
| | | |
| | | // --- Red modifier --- // |
| | | half hue = rgb_2_hue(aces); |
| | | half centeredHue = center_hue(hue, RRT_RED_HUE); |
| | | half hueWeight; |
| | | { |
| | | //hueWeight = cubic_basis_shaper(centeredHue, RRT_RED_WIDTH); |
| | | hueWeight = Pow2(smoothstep(0.0, 1.0, 1.0 - abs(2.0 * centeredHue / RRT_RED_WIDTH))); |
| | | } |
| | | |
| | | aces.r += hueWeight * saturation * (RRT_RED_PIVOT - aces.r) * (1.0 - RRT_RED_SCALE); |
| | | |
| | | // --- ACES to RGB rendering space --- // |
| | | half3 acescg = max(0.0, ACES_to_ACEScg(aces)); |
| | | |
| | | // --- Global desaturation --- // |
| | | //acescg = mul(RRT_SAT_MAT, acescg); |
| | | acescg = lerp(dot(acescg, AP1_RGB2Y).xxx, acescg, RRT_SAT_FACTOR.xxx); |
| | | |
| | | // Luminance fitting of *RRT.a1.0.3 + ODT.Academy.RGBmonitor_100nits_dim.a1.0.3*. |
| | | // https://github.com/colour-science/colour-unity/blob/master/Assets/Colour/Notebooks/CIECAM02_Unity.ipynb |
| | | // RMSE: 0.0012846272106 |
| | | const half a = 278.5085; |
| | | const half b = 10.7772; |
| | | const half c = 293.6045; |
| | | const half d = 88.7122; |
| | | const half e = 80.6889; |
| | | half3 x = acescg; |
| | | half3 rgbPost = (x * (a * x + b)) / (x * (c * x + d) + e); |
| | | |
| | | // Scale luminance to linear code value |
| | | // half3 linearCV = Y_2_linCV(rgbPost, CINEMA_WHITE, CINEMA_BLACK); |
| | | |
| | | // Apply gamma adjustment to compensate for dim surround |
| | | half3 linearCV = darkSurround_to_dimSurround(rgbPost); |
| | | |
| | | // Apply desaturation to compensate for luminance difference |
| | | //linearCV = mul(ODT_SAT_MAT, color); |
| | | linearCV = lerp(dot(linearCV, AP1_RGB2Y).xxx, linearCV, ODT_SAT_FACTOR.xxx); |
| | | |
| | | // Convert to display primary encoding |
| | | // Rendering space RGB to XYZ |
| | | half3 XYZ = mul(AP1_2_XYZ_MAT, linearCV); |
| | | |
| | | // Apply CAT from ACES white point to assumed observer adapted white point |
| | | XYZ = mul(D60_2_D65_CAT, XYZ); |
| | | |
| | | // CIE XYZ to display primaries |
| | | linearCV = mul(XYZ_2_REC709_MAT, XYZ); |
| | | |
| | | return linearCV; |
| | | |
| | | #endif |
| | | } |
| | | |
| | | #endif // __TONEMAPPING__ |
| | | #ifndef __TONEMAPPING__
|
| | | #define __TONEMAPPING__
|
| | |
|
| | | #include "ACES.cginc"
|
| | |
|
| | | // Set to 1 to use the full reference ACES tonemapper. This should only be used for research
|
| | | // purposes and it's quite heavy and generally overkill.
|
| | | #define TONEMAPPING_USE_FULL_ACES 0
|
| | |
|
| | | //
|
| | | // Neutral tonemapping (Hable/Hejl/Frostbite)
|
| | | // Input is linear RGB
|
| | | //
|
| | | half3 NeutralCurve(half3 x, half a, half b, half c, half d, half e, half f)
|
| | | {
|
| | | return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f;
|
| | | }
|
| | |
|
| | | half3 NeutralTonemap(half3 x, half4 params1, half4 params2)
|
| | | {
|
| | | // ACES supports negative color values and WILL output negative values when coming from ACES or ACEScg
|
| | | // Make sure negative channels are clamped to 0.0 as this neutral tonemapper can't deal with them properly
|
| | | x = max((0.0).xxx, x);
|
| | |
|
| | | // Tonemap
|
| | | half a = params1.x;
|
| | | half b = params1.y;
|
| | | half c = params1.z;
|
| | | half d = params1.w;
|
| | | half e = params2.x;
|
| | | half f = params2.y;
|
| | | half whiteLevel = params2.z;
|
| | | half whiteClip = params2.w;
|
| | |
|
| | | half3 whiteScale = (1.0).xxx / NeutralCurve(whiteLevel, a, b, c, d, e, f);
|
| | | x = NeutralCurve(x * whiteScale, a, b, c, d, e, f);
|
| | | x *= whiteScale;
|
| | |
|
| | | // Post-curve white point adjustment
|
| | | x /= whiteClip.xxx;
|
| | |
|
| | | return x;
|
| | | }
|
| | |
|
| | | //
|
| | | // Filmic tonemapping (ACES fitting, unless TONEMAPPING_USE_FULL_ACES is set to 1)
|
| | | // Input is ACES2065-1 (AP0 w/ linear encoding)
|
| | | //
|
| | | half3 FilmicTonemap(half3 aces)
|
| | | {
|
| | | #if TONEMAPPING_USE_FULL_ACES
|
| | |
|
| | | half3 oces = RRT(aces);
|
| | | half3 odt = ODT_RGBmonitor_100nits_dim(oces);
|
| | | return odt;
|
| | |
|
| | | #else
|
| | |
|
| | | // --- Glow module --- //
|
| | | half saturation = rgb_2_saturation(aces);
|
| | | half ycIn = rgb_2_yc(aces);
|
| | | half s = sigmoid_shaper((saturation - 0.4) / 0.2);
|
| | | half addedGlow = 1.0 + glow_fwd(ycIn, RRT_GLOW_GAIN * s, RRT_GLOW_MID);
|
| | | aces *= addedGlow;
|
| | |
|
| | | // --- Red modifier --- //
|
| | | half hue = rgb_2_hue(aces);
|
| | | half centeredHue = center_hue(hue, RRT_RED_HUE);
|
| | | half hueWeight;
|
| | | {
|
| | | //hueWeight = cubic_basis_shaper(centeredHue, RRT_RED_WIDTH);
|
| | | hueWeight = Pow2(smoothstep(0.0, 1.0, 1.0 - abs(2.0 * centeredHue / RRT_RED_WIDTH)));
|
| | | }
|
| | |
|
| | | aces.r += hueWeight * saturation * (RRT_RED_PIVOT - aces.r) * (1.0 - RRT_RED_SCALE);
|
| | |
|
| | | // --- ACES to RGB rendering space --- //
|
| | | half3 acescg = max(0.0, ACES_to_ACEScg(aces));
|
| | |
|
| | | // --- Global desaturation --- //
|
| | | //acescg = mul(RRT_SAT_MAT, acescg);
|
| | | acescg = lerp(dot(acescg, AP1_RGB2Y).xxx, acescg, RRT_SAT_FACTOR.xxx);
|
| | |
|
| | | // Luminance fitting of *RRT.a1.0.3 + ODT.Academy.RGBmonitor_100nits_dim.a1.0.3*.
|
| | | // https://github.com/colour-science/colour-unity/blob/master/Assets/Colour/Notebooks/CIECAM02_Unity.ipynb
|
| | | // RMSE: 0.0012846272106
|
| | | const half a = 278.5085;
|
| | | const half b = 10.7772;
|
| | | const half c = 293.6045;
|
| | | const half d = 88.7122;
|
| | | const half e = 80.6889;
|
| | | half3 x = acescg;
|
| | | half3 rgbPost = (x * (a * x + b)) / (x * (c * x + d) + e);
|
| | |
|
| | | // Scale luminance to linear code value
|
| | | // half3 linearCV = Y_2_linCV(rgbPost, CINEMA_WHITE, CINEMA_BLACK);
|
| | |
|
| | | // Apply gamma adjustment to compensate for dim surround
|
| | | half3 linearCV = darkSurround_to_dimSurround(rgbPost);
|
| | |
|
| | | // Apply desaturation to compensate for luminance difference
|
| | | //linearCV = mul(ODT_SAT_MAT, color);
|
| | | linearCV = lerp(dot(linearCV, AP1_RGB2Y).xxx, linearCV, ODT_SAT_FACTOR.xxx);
|
| | |
|
| | | // Convert to display primary encoding
|
| | | // Rendering space RGB to XYZ
|
| | | half3 XYZ = mul(AP1_2_XYZ_MAT, linearCV);
|
| | |
|
| | | // Apply CAT from ACES white point to assumed observer adapted white point
|
| | | XYZ = mul(D60_2_D65_CAT, XYZ);
|
| | |
|
| | | // CIE XYZ to display primaries
|
| | | linearCV = mul(XYZ_2_REC709_MAT, XYZ);
|
| | |
|
| | | return linearCV;
|
| | |
|
| | | #endif
|
| | | }
|
| | |
|
| | | #endif // __TONEMAPPING__
|