WhiteBalance.azsl 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <scenesrg_all.srgi>
  9. ShaderResourceGroup PassSrg : SRG_PerPass
  10. {
  11. Texture2D<float4> m_inputColor;
  12. RWTexture2D<float4> m_outputColor;
  13. // Must match the struct in WhiteBalancePass.cpp
  14. struct Constants
  15. {
  16. uint2 m_outputSize; // texture size of output
  17. float2 m_outputCenter; // center of image in pixel coords
  18. float m_temperature; // Color temperature. Higher values result in a warmer color temperature and lower values result in a colder color temperature.
  19. float m_tint; // Factor for compensate for a green or magenta tint
  20. [[pad_to(16)]]
  21. };
  22. Constants m_constants;
  23. }
  24. [numthreads(8, 8, 1)]
  25. void MainCS(uint3 dispatchThreadID : SV_DispatchThreadID)
  26. {
  27. if (dispatchThreadID.x >= PassSrg::m_constants.m_outputSize.x || dispatchThreadID.y >= PassSrg::m_constants.m_outputSize.y)
  28. {
  29. return;
  30. }
  31. // Range ~[-1.67;1.67] works best
  32. float t1 = PassSrg::m_constants.m_temperature;
  33. float t2 = PassSrg::m_constants.m_tint;
  34. // Get the CIE xy chromaticity of the reference white point.
  35. // Note: 0.31271 = x value on the D65 white point
  36. float x = 0.31271 - t1 * (t1 < 0 ? 0.1 : 0.05);
  37. float standardIlluminantY = 2.87 * x - 3 * x * x - 0.27509507;
  38. float y = standardIlluminantY + t2 * 0.05;
  39. // Calculate the coefficients in the LMS space.
  40. float3 w1 = float3(0.949237, 1.03542, 1.08728); // D65 white point
  41. // CIExyToLMS
  42. float Y = 1;
  43. float X = Y * x / y;
  44. float Z = Y * (1 - x - y) / y;
  45. float L = 0.7328 * X + 0.4296 * Y - 0.1624 * Z;
  46. float M = -0.7036 * X + 1.6975 * Y + 0.0061 * Z;
  47. float S = 0.0030 * X + 0.0136 * Y + 0.9834 * Z;
  48. float3 w2 = float3(L, M, S);
  49. float3 balance = float3(w1.x / w2.x, w1.y / w2.y, w1.z / w2.z);
  50. // Recommended workspace: ACEScg (linear)
  51. //
  52. static const float3x3 LIN_2_LMS_MAT = {
  53. 3.90405e-1, 5.49941e-1, 8.92632e-3,
  54. 7.08416e-2, 9.63172e-1, 1.35775e-3,
  55. 2.31082e-2, 1.28021e-1, 9.36245e-1
  56. };
  57. static const float3x3 LMS_2_LIN_MAT = {
  58. 2.85847e+0, -1.62879e+0, -2.48910e-2,
  59. -2.10182e-1, 1.15820e+0, 3.24281e-4,
  60. -4.18120e-2, -1.18169e-1, 1.06867e+0
  61. };
  62. float3 input = PassSrg::m_inputColor[dispatchThreadID.xy].rgb;
  63. float3 lms = mul(LIN_2_LMS_MAT, input);
  64. lms *= balance;
  65. float3 finalOut = mul(LMS_2_LIN_MAT, lms);
  66. PassSrg::m_outputColor[dispatchThreadID.xy] = float4(finalOut.x, finalOut.y, finalOut.z, 1.0);
  67. }