ContrastAdaptiveSharpening.azsl 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  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. #include <Atom/Features/PostProcessing/PostProcessUtil.azsli>
  10. #define TILE_DIM_X 16
  11. #define TILE_DIM_Y 16
  12. ShaderResourceGroup PassSrg : SRG_PerPass
  13. {
  14. Texture2D<float4> m_inputColor;
  15. RWTexture2D<float4> m_outputColor;
  16. float m_strength; // Strength of the sharpening effect. Range from 0 to 1.
  17. }
  18. // Constrast Adaptive Sharpening, based on AMD FidelityFX CAS - https://gpuopen.com/fidelityfx-cas/
  19. // This shader sharpens the input based on the contrast of the local neighborhood
  20. // so that only areas that need sharpening are sharpened, while high constast areas
  21. // are mostly left alone.
  22. [numthreads(TILE_DIM_X, TILE_DIM_Y, 1)]
  23. void MainCS(
  24. uint3 dispatchThreadID : SV_DispatchThreadID,
  25. uint3 groupID : SV_GroupID,
  26. uint groupIndex : SV_GroupIndex)
  27. {
  28. uint2 pixelCoord = dispatchThreadID.xy;
  29. // Fetch local neighborhood to determin sharpening weight.
  30. // a
  31. // b c d
  32. // e
  33. float3 sampleA = PassSrg::m_inputColor[pixelCoord + int2( 0, -1)].rgb;
  34. float3 sampleB = PassSrg::m_inputColor[pixelCoord + int2(-1, 0)].rgb;
  35. float3 sampleC = PassSrg::m_inputColor[pixelCoord + int2( 0, 0)].rgb;
  36. float3 sampleD = PassSrg::m_inputColor[pixelCoord + int2( 1, 0)].rgb;
  37. float3 sampleE = PassSrg::m_inputColor[pixelCoord + int2( 0, 1)].rgb;
  38. float lumA = GetLuminance(sampleA);
  39. float lumB = GetLuminance(sampleB);
  40. float lumC = GetLuminance(sampleC);
  41. float lumD = GetLuminance(sampleD);
  42. float lumE = GetLuminance(sampleE);
  43. // Get the min and max. Just use the green channel for luminance.
  44. float minLum = min(min(lumA, lumB), min(lumC, min(lumD, lumE)));
  45. float maxLum = max(max(lumA, lumB), max(lumC, max(lumD, lumE)));
  46. float dMinLum = minLum; // Distance from 0 to minimum
  47. float dMaxLum = 1.0 - maxLum; // Distance from 1 to the maximum
  48. // baseSharpening is higher when local contrast is lower to avoid over-sharpening.
  49. float baseSharpening = min(dMinLum, dMaxLum) / max(maxLum, 0.0001);
  50. baseSharpening = sqrt(baseSharpening); // bias towards more sharpening
  51. // Negative weights for sharpening effect, center pixel is always weighted 1.
  52. float developerMaximum = lerp(-0.125, -0.2, PassSrg::m_strength);
  53. float weight = baseSharpening * developerMaximum;
  54. float totalWeight = weight * 4 + 1.0;
  55. float3 output =
  56. (
  57. sampleA * weight +
  58. sampleB * weight +
  59. sampleC +
  60. sampleD * weight +
  61. sampleE * weight
  62. ) / totalWeight;
  63. PassSrg::m_outputColor[pixelCoord] = float4(output, 1.0);
  64. }