// References: // https://www.unravel.com.au/understanding-color-spaces // SMPTE 170M - BT.601 (NTSC-M) -> BT.709 mat3 from_NTSCM = transpose(mat3( 0.939497225737661, 0.0502268452914346, 0.0102759289709032, 0.0177558637510127, 0.965824605885027, 0.0164195303639603, -0.00162163209967010, -0.00437400622653655, 1.00599563832621)); // ARIB TR-B9 (9300K+27MPCD with chromatic adaptation) (NTSC-J) -> BT.709 mat3 from_NTSCJ = transpose(mat3( 0.823613036967492, -0.0943227111084757, 0.00799341532931119, 0.0289258355537324, 1.02310733489462, 0.00243547111576797, -0.00569501554980891, 0.0161828357559315, 1.22328453915712)); // EBU - BT.470BG/BT.601 (PAL) -> BT.709 mat3 from_PAL = transpose(mat3( 1.04408168421813, -0.0440816842181253, 0.000000000000000, 0.000000000000000, 1.00000000000000, 0.000000000000000, 0.000000000000000, 0.0118044782106489, 0.988195521789351)); float3 LinearTosRGBGamma(float3 color) { float a = 0.055; for (int i = 0; i < 3; ++i) { float x = color[i]; if (x <= 0.0031308) x = x * 12.92; else x = (1.0 + a) * pow(x, 1.0 / 2.4) - a; color[i] = x; } return color; } void main() { // Note: sampling in gamma space is "wrong" if the source // and target resolution don't match exactly. // Fortunately at the moment here they always should but to do this correctly, // we'd need to sample from 4 pixels, de-apply the gamma from each of these, // and then do linear sampling on their corrected value. float4 color = Sample(); // Convert to linear space to do any other kind of operation color.rgb = pow(color.rgb, float3(game_gamma)); if (OptionEnabled(correct_color_space)) { if (game_color_space == 0) color.rgb = color.rgb * from_NTSCM; else if (game_color_space == 1) color.rgb = color.rgb * from_NTSCJ; else if (game_color_space == 2) color.rgb = color.rgb * from_PAL; } if (OptionEnabled(hdr_output)) { float hdr_paper_white = hdr_paper_white_nits / hdr_sdr_white_nits; color.rgb *= hdr_paper_white; } if (OptionEnabled(linear_space_output)) { // Nothing to do here } // Correct the SDR gamma for sRGB (PC/Monitor) or ~2.2 (Common TV gamma) else if (OptionEnabled(correct_gamma)) { if (OptionEnabled(sdr_display_gamma_sRGB)) color.rgb = LinearTosRGBGamma(color.rgb); else color.rgb = pow(color.rgb, float3(1.0 / sdr_display_custom_gamma)); } // Restore the original gamma without changes else { color.rgb = pow(color.rgb, float3(1.0 / game_gamma)); } SetOutput(color); }