LookModificationTransform.azsl 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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 <viewsrg_all.srgi>
  9. #include <Atom/Features/PostProcessing/Aces.azsli>
  10. #include <Atom/Features/PostProcessing/FullscreenPixelInfo.azsli>
  11. #include <Atom/Features/PostProcessing/FullscreenVertex.azsli>
  12. #include <Atom/Features/PostProcessing/PostProcessUtil.azsli>
  13. #include <Atom/Features/PostProcessing/Shapers.azsli>
  14. #include "EyeAdaptationUtil.azsli"
  15. ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback
  16. {
  17. Texture2D<float4> m_framebuffer;
  18. Sampler LinearSampler
  19. {
  20. MinFilter = Linear;
  21. MagFilter = Linear;
  22. MipFilter = Linear;
  23. AddressU = Clamp;
  24. AddressV = Clamp;
  25. AddressW = Clamp;
  26. };
  27. // These parameters contain exposure control parameters.
  28. StructuredBuffer<EyeAdaptation> m_eyeAdaptation;
  29. Texture3D<float4> m_gradingLut;
  30. int m_shaperType;
  31. float m_shaperBias;
  32. float m_shaperScale;
  33. }
  34. // Option shader variable to enable the exposure control feature.
  35. option bool o_enableExposureControlFeature = false;
  36. // Option shader variable to enable color grading LUT.
  37. option bool o_enableColorGradingLut = false;
  38. // Controls the sampling quality of the blended LUT. Setting this higher can improve the quality of particularly tricky luts.
  39. // 0 - linear
  40. // 1 - 7 tap b-spline
  41. // 2 - 19 tap b-spline
  42. [[range(0, 2)]]
  43. option int o_lutSampleQuality = 0;
  44. // Sample a 3dtexture with a 7 or 19 tap B-Spline. Consider ripping this out and putting in a more general location.
  45. // This function samples a 4x4x4 neighborhood around the uv. Normally this would take 64 samples, but by taking
  46. // advantage of bilinear filtering this can be done with 27 taps on the edges between pixels. The cost is further
  47. // reduced by dropping either the 8 corners (19 total taps) or also dropping the 12 edges (7 total taps).
  48. float4 SampleBSpline3D(Texture3D<float4> texture, SamplerState linearSampler, float3 uv, float3 textureSize, float3 rcpTextureSize)
  49. {
  50. // Think of sample locations in the 4x4 neighborhood as having a top left coordinate of 0,0 and
  51. // a bottom right coordinate of 3,3.
  52. // Find the position in texture space then round it to get the center of the 1,1 pixel (tc1)
  53. float3 texelPos = uv * textureSize;
  54. float3 tc1= floor(texelPos - 0.5) + 0.5;
  55. // Offset from center position to texel
  56. float3 f = texelPos - tc1;
  57. // Compute B-Spline weights based on the offset
  58. float3 OneMinusF = (1.0 - f);
  59. float3 OneMinusF2 = OneMinusF * OneMinusF;
  60. float3 OneMinusF3 = OneMinusF2 * OneMinusF;
  61. float3 w0 = OneMinusF3;
  62. float3 w1 = 4.0 + 3.0 * f * f * f - 6.0 * f * f;
  63. float3 w2 = 4.0 + 3.0 * OneMinusF3 - 6.0 * OneMinusF2;
  64. float3 w3 = f * f * f;
  65. float3 w12 = w1 + w2;
  66. // Compute uv coordinates for sampling the texture
  67. float3 tc0 = (tc1 - 1.0f) * rcpTextureSize;
  68. float3 tc3 = (tc1 + 2.0f) * rcpTextureSize;
  69. float3 tc12 = (tc1 + w2 / w12) * rcpTextureSize;
  70. // Compute sample weights
  71. float sw0 = w12.x * w0.y * w12.z;
  72. float sw1 = w0.x * w12.y * w12.z;
  73. float sw2 = w12.x * w12.y * w12.z;
  74. float sw3 = w3.x * w12.y * w12.z;
  75. float sw4 = w12.x * w3.y * w12.z;
  76. float sw5 = w12.x * w12.y * w0.z;
  77. float sw6 = w12.x * w12.y * w3.z;
  78. // total weight of samples to normalize result.
  79. float totalWeight = sw0 + sw1 + sw2 + sw3 + sw4 + sw5 + sw6;
  80. float4 result = 0.0f;
  81. result += texture.SampleLevel(linearSampler, float3(tc12.x, tc0.y, tc12.z), 0.0) * sw0;
  82. result += texture.SampleLevel(linearSampler, float3( tc0.x, tc12.y, tc12.z), 0.0) * sw1;
  83. result += texture.SampleLevel(linearSampler, float3(tc12.x, tc12.y, tc12.z), 0.0) * sw2;
  84. result += texture.SampleLevel(linearSampler, float3( tc3.x, tc12.y, tc12.z), 0.0) * sw3;
  85. result += texture.SampleLevel(linearSampler, float3(tc12.x, tc3.y, tc12.z), 0.0) * sw4;
  86. result += texture.SampleLevel(linearSampler, float3(tc12.x, tc12.y, tc0.z), 0.0) * sw5;
  87. result += texture.SampleLevel(linearSampler, float3(tc12.x, tc12.y, tc3.z), 0.0) * sw6;
  88. if (o_lutSampleQuality == 2)
  89. {
  90. // Extra 12 taps for Diagonals to increase the quality further.
  91. float sw7 = w0.x * w0.y * w12.z;
  92. float sw8 = w0.x * w3.y * w12.z;
  93. float sw9 = w3.x * w0.y * w12.z;
  94. float sw10 = w3.x * w3.y * w12.z;
  95. float sw11 = w12.x * w0.y * w0.z;
  96. float sw12 = w12.x * w0.y * w3.z;
  97. float sw13 = w12.x * w3.y * w0.z;
  98. float sw14 = w12.x * w3.y * w3.z;
  99. float sw15 = w0.x * w12.y * w0.z;
  100. float sw16 = w0.x * w12.y * w3.z;
  101. float sw17 = w3.x * w12.y * w0.z;
  102. float sw18 = w3.x * w12.y * w3.z;
  103. totalWeight += sw7 + sw8 + sw9 + sw10 + sw11 + sw12 + sw13 + sw14 + sw15 + sw16 + sw17 + sw18;
  104. result += texture.SampleLevel(linearSampler, float3(tc0.x, tc0.y, tc12.z), 0.0) * sw7;
  105. result += texture.SampleLevel(linearSampler, float3(tc0.x, tc3.y, tc12.z), 0.0) * sw8;
  106. result += texture.SampleLevel(linearSampler, float3(tc3.x, tc0.y, tc12.z), 0.0) * sw9;
  107. result += texture.SampleLevel(linearSampler, float3(tc3.x, tc3.y, tc12.z), 0.0) * sw10;
  108. result += texture.SampleLevel(linearSampler, float3(tc12.x, tc0.y, tc0.z), 0.0) * sw11;
  109. result += texture.SampleLevel(linearSampler, float3(tc12.x, tc0.y, tc3.z), 0.0) * sw12;
  110. result += texture.SampleLevel(linearSampler, float3(tc12.x, tc3.y, tc0.z), 0.0) * sw13;
  111. result += texture.SampleLevel(linearSampler, float3(tc12.x, tc3.y, tc3.z), 0.0) * sw14;
  112. result += texture.SampleLevel(linearSampler, float3(tc0.x, tc12.y, tc0.z), 0.0) * sw15;
  113. result += texture.SampleLevel(linearSampler, float3(tc0.x, tc12.y, tc3.z), 0.0) * sw16;
  114. result += texture.SampleLevel(linearSampler, float3(tc3.x, tc12.y, tc0.z), 0.0) * sw17;
  115. result += texture.SampleLevel(linearSampler, float3(tc3.x, tc12.y, tc3.z), 0.0) * sw18;
  116. }
  117. return result / totalWeight;
  118. }
  119. PSOutput MainPS(VSOutput IN)
  120. {
  121. PSOutput OUT;
  122. // Fetch the pixel color from the input texture
  123. float3 color = PassSrg::m_framebuffer.SampleLevel(PassSrg::LinearSampler, IN.m_texCoord, 0.0).rgb;
  124. if (o_enableExposureControlFeature)
  125. {
  126. // Apply auto exposure
  127. color.rgb *= PassSrg::m_eyeAdaptation[0].m_exposureValue;
  128. // Apply manual exposure compensation
  129. color *= pow(2.0, ViewSrg::GetExposureValueCompensation());
  130. }
  131. // Apply color grading LUT
  132. ShaperType shaperType = (ShaperType)PassSrg::m_shaperType;
  133. if (o_enableColorGradingLut)
  134. {
  135. // Convert from working color space to lut coordinates by applying the shaper function
  136. float3 lutCoordinate = LinearToShaper(color, shaperType, PassSrg::m_shaperBias, PassSrg::m_shaperScale);
  137. // Adjust coordinate to the domain excluding the outer half texel in all directions
  138. uint3 outputDimensions;
  139. PassSrg::m_gradingLut.GetDimensions(outputDimensions.x, outputDimensions.y, outputDimensions.z);
  140. float3 coordBias = 0.5f / outputDimensions;
  141. float3 sizeMinusOne = outputDimensions - 1.0;
  142. float3 coordScale = sizeMinusOne / outputDimensions;
  143. lutCoordinate = (lutCoordinate * coordScale) + coordBias;
  144. float3 lutColor = float3(0.0, 0.0, 0.0);
  145. if (o_lutSampleQuality == 0)
  146. {
  147. lutColor = PassSrg::m_gradingLut.SampleLevel(PassSrg::LinearSampler, lutCoordinate, 0.0).rgb;
  148. }
  149. else
  150. {
  151. lutColor = SampleBSpline3D(PassSrg::m_gradingLut, PassSrg::LinearSampler, lutCoordinate, float3(outputDimensions), 1.0 / float3(outputDimensions)).rgb;
  152. }
  153. // Apply the inverse of the shaper function to give the color in the working color space
  154. color = ShaperToLinear(lutColor, shaperType, PassSrg::m_shaperBias, PassSrg::m_shaperScale);
  155. }
  156. OUT.m_color.rgb = color;
  157. OUT.m_color.w = 1;
  158. return OUT;
  159. }