// SPDX-License-Identifier: Apache-2.0 // Copyright Contributors to the ACES Project. // urn:ampas:aces:transformId:v2.0:Lib.Academy.Tonescale.a2.v1 // Tonescale Functions // // Library File with functions used for pre-calculating the tonescale parameters and // applying the fwd/inv tonescale function // struct TSParams { float n; float n_r; float g; float t_1; float c_t; float s_2; float u_2; float m_2; float forward_limit; float inverse_limit; float log_peak; }; // Tonescale pre-calculations TSParams init_TSParams(float peakLuminance) { // Preset constants that set the desired behavior for the curve const float n = peakLuminance; const float n_r = 100.0; // normalized white in nits (what 1.0 should be) const float g = 1.15; // surround / contrast const float c = 0.18; // anchor for 18% grey const float c_d = 10.013; // output luminance of 18% grey (in nits) const float w_g = 0.14; // change in grey between different peak luminance const float t_1 = 0.04; // shadow toe or flare/glare compensation const float r_hit_min = 128.; // scene-referred value "hitting the roof" for SDR (e.g. when n = 100 nits) const float r_hit_max = 896.; // scene-referred value "hitting the roof" for when n = 10000 nits // Calculate output constants const float r_hit = r_hit_min + (r_hit_max - r_hit_min) * (log(n / n_r) / log(10000. / 100.)); const float m_0 = (n / n_r); const float m_1 = 0.5 * (m_0 + sqrt(m_0 * (m_0 + 4. * t_1))); const float u = pow((r_hit / m_1) / ((r_hit / m_1) + 1), g); const float m = m_1 / u; const float w_i = log(n / 100.) / log(2.); const float c_t = c_d / n_r * (1. + w_i * w_g); const float g_ip = 0.5 * (c_t + sqrt(c_t * (c_t + 4. * t_1))); const float g_ipp2 = -(m_1 * pow((g_ip / m), (1. / g))) / (pow(g_ip / m, 1. / g) - 1.); const float w_2 = c / g_ipp2; const float s_2 = w_2 * m_1; const float u_2 = pow((r_hit / m_1) / ((r_hit / m_1) + w_2), g); const float m_2 = m_1 / u_2; TSParams p; p.n = n; p.n_r = n_r; p.g = g; p.t_1 = t_1; p.c_t = c_t; p.s_2 = s_2; p.u_2 = u_2; p.m_2 = m_2; p.forward_limit = 8.0 * r_hit; p.inverse_limit = n / (u_2 * n_r); p.log_peak = log10(n / n_r); return p; } /* --- Tone scale math --- */ float tonescale_fwd(float x, // scene-referred input (i.e. linear ACES2065-1) TSParams params // struct of type TSParams ) { // forward MM tone scale float f = params.m_2 * pow(max(0.0, x) / (x + params.s_2), params.g); float h = max(0., f * f / (f + params.t_1)); // forward flare return h * params.n_r; // output is luminance in cd/m^2 } float tonescale_inv(float Y, // luminance in cd/m^2 TSParams params // struct of type TSParams ) { float Z = max(0., min(params.n / (params.u_2 * params.n_r), Y)); float h = (Z + sqrt(Z * (4. * params.t_1 + Z))) / 2.; float f = params.s_2 / (pow((params.m_2 / h), (1. / params.g)) - 1.); return f; // output is scene-referred input }