1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
float srgb_linear_to_nonlinear_channel(float u)
{
return (u <= 0.0031308) ? (12.92 * u) : ((1.055 * pow(u, 1. / 2.4)) - 0.055);
}
float3 srgb_linear_to_nonlinear(float3 v)
{
return float3(srgb_linear_to_nonlinear_channel(v.r), srgb_linear_to_nonlinear_channel(v.g), srgb_linear_to_nonlinear_channel(v.b));
}
float srgb_nonlinear_to_linear_channel(float u)
{
return (u <= 0.04045) ? (u / 12.92) : pow((u + 0.055) / 1.055, 2.4);
}
float3 srgb_nonlinear_to_linear(float3 v)
{
return float3(srgb_nonlinear_to_linear_channel(v.r), srgb_nonlinear_to_linear_channel(v.g), srgb_nonlinear_to_linear_channel(v.b));
}
float3 rec709_to_rec2020(float3 v)
{
float r = dot(v, float3(0.62740389593469903, 0.32928303837788370, 0.043313065687417225));
float g = dot(v, float3(0.069097289358232075, 0.91954039507545871, 0.011362315566309178));
float b = dot(v, float3(0.016391438875150280, 0.088013307877225749, 0.89559525324762401));
return float3(r, g, b);
}
float3 d65p3_to_rec709(float3 v)
{
float r = dot(v, float3(1.2249401762805598, -0.22494017628055996, 0.));
float g = dot(v, float3(-0.042056954709688163, 1.0420569547096881, 0.));
float b = dot(v, float3(-0.019637554590334432, -0.078636045550631889, 1.0982736001409663));
return float3(r, g, b);
}
float3 rec2020_to_rec709(float3 v)
{
float r = dot(v, float3(1.6604910021084345, -0.58764113878854951, -0.072849863319884883));
float g = dot(v, float3(-0.12455047452159074, 1.1328998971259603, -0.0083494226043694768));
float b = dot(v, float3(-0.018150763354905303, -0.10057889800800739, 1.1187296613629127));
return float3(r, g, b);
}
float3 reinhard(float3 rgb)
{
rgb /= rgb + float3(1., 1., 1.);
rgb = saturate(rgb);
rgb = pow(rgb, float3(1. / 2.4, 1. / 2.4, 1. / 2.4));
rgb = srgb_nonlinear_to_linear(rgb);
return rgb;
}
float linear_to_st2084_channel(float x)
{
float c = pow(abs(x), 0.1593017578);
return pow((0.8359375 + 18.8515625 * c) / (1. + 18.6875 * c), 78.84375);
}
float3 linear_to_st2084(float3 rgb)
{
return float3(linear_to_st2084_channel(rgb.r), linear_to_st2084_channel(rgb.g), linear_to_st2084_channel(rgb.b));
}
float st2084_to_linear_channel(float u)
{
float c = pow(abs(u), 1. / 78.84375);
return pow(abs(max(c - 0.8359375, 0.) / (18.8515625 - 18.6875 * c)), 1. / 0.1593017578);
}
float3 st2084_to_linear(float3 rgb)
{
return float3(st2084_to_linear_channel(rgb.r), st2084_to_linear_channel(rgb.g), st2084_to_linear_channel(rgb.b));
}
float eetf_0_Lmax(float maxRGB1_pq, float Lw, float Lmax)
{
float Lw_pq = linear_to_st2084_channel(Lw / 10000.);
float E1 = saturate(maxRGB1_pq / Lw_pq); // Ensure normalization in case Lw is a lie
float maxLum = linear_to_st2084_channel(Lmax / 10000.) / Lw_pq;
float KS = (1.5 * maxLum) - 0.5;
float E2 = E1;
if (E1 > KS)
{
float T = (E1 - KS) / (1. - KS);
float Tsquared = T * T;
float Tcubed = Tsquared * T;
float P = (2. * Tcubed - 3. * Tsquared + 1.) * KS + (Tcubed - 2. * Tsquared + T) * (1. - KS) + (-2. * Tcubed + 3. * Tsquared) * maxLum;
E2 = P;
}
float E3 = E2;
float E4 = E3 * Lw_pq;
return E4;
}
float3 maxRGB_eetf_internal(float3 rgb_linear, float maxRGB1_linear, float maxRGB1_pq, float Lw, float Lmax)
{
float maxRGB2_pq = eetf_0_Lmax(maxRGB1_pq, Lw, Lmax);
float maxRGB2_linear = st2084_to_linear_channel(maxRGB2_pq);
// avoid divide-by-zero possibility
maxRGB1_linear = max(6.10352e-5, maxRGB1_linear);
rgb_linear *= maxRGB2_linear / maxRGB1_linear;
return rgb_linear;
}
float3 maxRGB_eetf_pq_to_linear(float3 rgb_pq, float Lw, float Lmax)
{
float3 rgb_linear = st2084_to_linear(rgb_pq);
float maxRGB1_linear = max(max(rgb_linear.r, rgb_linear.g), rgb_linear.b);
float maxRGB1_pq = max(max(rgb_pq.r, rgb_pq.g), rgb_pq.b);
return maxRGB_eetf_internal(rgb_linear, maxRGB1_linear, maxRGB1_pq, Lw, Lmax);
}
float3 maxRGB_eetf_linear_to_linear(float3 rgb_linear, float Lw, float Lmax)
{
float maxRGB1_linear = max(max(rgb_linear.r, rgb_linear.g), rgb_linear.b);
float maxRGB1_pq = linear_to_st2084_channel(maxRGB1_linear);
return maxRGB_eetf_internal(rgb_linear, maxRGB1_linear, maxRGB1_pq, Lw, Lmax);
}
float3 st2084_to_linear_eetf(float3 rgb, float Lw, float Lmax)
{
return (Lw > Lmax) ? maxRGB_eetf_pq_to_linear(rgb, Lw, Lmax) : st2084_to_linear(rgb);
}
float linear_to_hlg_channel(float u)
{
float ln2_i = 1. / log(2.);
float m = 0.17883277 / ln2_i;
return (u <= (1. / 12.)) ? sqrt(3. * u) : ((log2((12. * u) - 0.28466892) * m) + 0.55991073);
}
float3 linear_to_hlg(float3 rgb, float Lw)
{
rgb = saturate(rgb);
if (Lw > 1000.)
{
rgb = maxRGB_eetf_linear_to_linear(rgb, Lw, 1000.);
rgb *= 10000. / Lw;
}
else
{
rgb *= 10.;
}
float Yd = dot(rgb, float3(0.2627, 0.678, 0.0593));
// pow(0., exponent) can lead to NaN, use smallest positive normal number
Yd = max(6.10352e-5, Yd);
rgb *= pow(Yd, -1. / 6.);
return float3(linear_to_hlg_channel(rgb.r), linear_to_hlg_channel(rgb.g), linear_to_hlg_channel(rgb.b));
}
float hlg_to_linear_channel(float u)
{
float ln2_i = 1. / log(2.);
float m = ln2_i / 0.17883277;
float a = -ln2_i * 0.55991073 / 0.17883277;
return (u <= 0.5) ? ((u * u) / 3.) : ((exp2(u * m + a) + 0.28466892) / 12.);
}
float3 hlg_to_linear(float3 v, float exponent)
{
float3 rgb = float3(hlg_to_linear_channel(v.r), hlg_to_linear_channel(v.g), hlg_to_linear_channel(v.b));
float Ys = dot(rgb, float3(0.2627, 0.678, 0.0593));
rgb *= pow(Ys, exponent);
return rgb;
}
|