PPCreateTonemapLUT.bsl 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #include "$ENGINE$\PPTonemapCommon.bslinc"
  2. #include "$ENGINE$\PPWhiteBalance.bslinc"
  3. #include "$ENGINE$\PPBase.bslinc"
  4. shader PPCreateTonemapLUT
  5. {
  6. mixin PPTonemapCommon;
  7. mixin PPWhiteBalance;
  8. #if VOLUME_LUT
  9. featureset = HighEnd;
  10. #else
  11. mixin PPBase;
  12. #endif
  13. variations
  14. {
  15. VOLUME_LUT = { true, false };
  16. };
  17. code
  18. {
  19. [internal]
  20. cbuffer Input
  21. {
  22. // [0]: x - shoulder strength, y - linear strength, z - linear angle, w - toe strength
  23. // [1]: x - toe numerator, y - toe denominator, z - linear white point, w - unused
  24. float4 gTonemapParams[2];
  25. float gGammaAdjustment;
  26. // 0 - sRGB, 1 - Rec.709, 2 - 2.2 gamma
  27. uint gGammaCorrectionType;
  28. float3 gSaturation;
  29. float3 gContrast;
  30. float3 gGain;
  31. float3 gOffset;
  32. };
  33. /**
  34. * Filmic curve used for tonemapping.
  35. *
  36. * @param linearColor Linear color.
  37. * @return Transformed color.
  38. */
  39. float3 FilmicCurve(float3 color)
  40. {
  41. // Formula from John Hable's Uncharted 2 presentation
  42. float3 a = color * (gTonemapParams[0].x * color + gTonemapParams[0].y * gTonemapParams[0].z);
  43. float b = gTonemapParams[0].w * gTonemapParams[1].x;
  44. float3 c = color * (gTonemapParams[0].x * color + gTonemapParams[0].y);
  45. float d = gTonemapParams[0].w * gTonemapParams[1].y;
  46. return (a + b)/(c + d) - gTonemapParams[1].x / gTonemapParams[1].y;
  47. }
  48. /**
  49. * Applies filmic curve tonemapping to the provided color.
  50. *
  51. * @param linearColor Linear color in ACEScg color space.
  52. * @return Tonemapped color in ACEScg color space.
  53. */
  54. float3 FilmicTonemapping(float3 color)
  55. {
  56. return FilmicCurve(color) / FilmicCurve(gTonemapParams[1].z);
  57. }
  58. /**
  59. * Applies color grading to the provided color.
  60. *
  61. * @param linearColor Linear color in ACEScg color space.
  62. * @return Graded color in ACEScg color space.
  63. */
  64. float3 ColorGrading(float3 color)
  65. {
  66. const float3 RGBToY = float3(0.2722287168f, 0.6740817658f, 0.0536895174f);
  67. float luminance = dot(color, RGBToY);
  68. color = max(0, lerp(luminance.xxx, color, gSaturation));
  69. color = pow(color * (1.0f / 0.18f), gContrast) * 0.18f;
  70. color = color * gGain + gOffset;
  71. return color;
  72. }
  73. /** Generates tonemap information to the specified color (in log encoded space). */
  74. float3 tonemapColor(float3 logColor)
  75. {
  76. // Constants
  77. const float3x3 sRGBToACES2065Matrix = mul(XYZToACES2065Matrix, mul(D65ToD60Matrix, sRGBToXYZMatrix));
  78. const float3x3 sRGBToACEScgMatrix = mul(XYZToACEScgMatrix, mul(D65ToD60Matrix, sRGBToXYZMatrix));
  79. const float3x3 ACEScgTosRGBMatrix = mul(XYZTosRGBMatrix, mul(D60ToD65Matrix, ACEScgToXYZMatrix));
  80. float3 linearColor = LogToLinearColor(logColor);
  81. linearColor = WhiteBalance(linearColor);
  82. linearColor = mul(sRGBToACEScgMatrix, linearColor);
  83. linearColor = ColorGrading(linearColor);
  84. // Note: Improve this so it's closer to the ACES curve?
  85. linearColor = FilmicTonemapping(linearColor);
  86. // TODO - Does the white point provided in filmic curve conflict with the white balancing?
  87. linearColor = mul(ACEScgTosRGBMatrix, linearColor);
  88. // Transform to gamma space
  89. float3 gammaColor = pow(linearColor, gGammaAdjustment); // User adjustment, usually 1.0f
  90. if(gGammaCorrectionType == 0)
  91. gammaColor = LinearToGammasRGB(gammaColor);
  92. else if(gGammaCorrectionType == 1)
  93. gammaColor = LinearToGammaRec709(gammaColor);
  94. else
  95. gammaColor = pow(gammaColor, 1.0f/2.2f);
  96. return gammaColor;
  97. }
  98. #if VOLUME_LUT
  99. RWTexture3D<unorm float4> gOutputTex;
  100. [numthreads(8, 8, 1)]
  101. void csmain(
  102. uint3 dispatchThreadId : SV_DispatchThreadID,
  103. uint threadIndex : SV_GroupIndex)
  104. {
  105. float3 logColor = float3(dispatchThreadId.xyz / (float)(LUT_SIZE - 1));
  106. float3 gammaColor = tonemapColor(logColor);
  107. // TODO - Divide by 1.05f here and then re-apply it when decoding from the texture?
  108. gOutputTex[dispatchThreadId] = float4(gammaColor, 1.0f);
  109. }
  110. #else
  111. float4 fsmain(VStoFS input) : SV_Target0
  112. {
  113. float3 logColor;
  114. float2 uv = input.uv0;
  115. // Make sure uv maps to [0,1], as it's currently specified for pixel centers
  116. // (This way we get non-extrapolated color values for 0 and 1)
  117. uv -= float2(0.5f / (LUT_SIZE * LUT_SIZE), 0.5f / LUT_SIZE);
  118. uv *= LUT_SIZE / (LUT_SIZE - 1);
  119. // Red goes from 0 to 1, in each slice along X (LUT_SIZE number of slices)
  120. logColor.r = frac(uv.x * LUT_SIZE);
  121. // Blue value is constant within each slice, and increases by 1/LUT_SIZE with each slice along X
  122. logColor.b = uv.x - logColor.r / LUT_SIZE;
  123. // Green increases linearly with y
  124. logColor.g = uv.y;
  125. float3 gammaColor = tonemapColor(logColor);
  126. // TODO - Divide by 1.05f here and then re-apply it when decoding from the texture?
  127. return float4(gammaColor, 1.0f);
  128. }
  129. #endif
  130. };
  131. };