BloomExtractAndDownsampleLdrCS.hlsl 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. // RUN: %dxc -E main -T cs_6_0 %s | FileCheck %s
  2. // CHECK: threadId
  3. // CHECK: dot3
  4. // CHECK: FMax
  5. //
  6. // Copyright (c) Microsoft. All rights reserved.
  7. // This code is licensed under the MIT License (MIT).
  8. // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
  9. // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
  10. // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
  11. // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
  12. //
  13. // Developed by Minigraph
  14. //
  15. // Author: James Stanard
  16. //
  17. // The CS for extracting bright pixels and downsampling them to an unblurred bloom buffer.
  18. #include "ShaderUtility.hlsli"
  19. #include "PostEffectsRS.hlsli"
  20. SamplerState BiLinearClamp : register( s0 );
  21. Texture2D<float3> SourceTex : register( t0 );
  22. RWTexture2D<float3> BloomResult : register( u0 );
  23. cbuffer cb0
  24. {
  25. float2 g_inverseOutputSize;
  26. float g_bloomThreshold;
  27. }
  28. [RootSignature(PostEffects_RootSig)]
  29. [numthreads( 8, 8, 1 )]
  30. void main( uint3 DTid : SV_DispatchThreadID )
  31. {
  32. // We need the scale factor and the size of one pixel so that our four samples are right in the middle
  33. // of the quadrant they are covering.
  34. float2 uv = (DTid.xy + 0.5) * g_inverseOutputSize;
  35. float2 offset = g_inverseOutputSize * 0.25;
  36. // Use 4 bilinear samples to guarantee we don't undersample when downsizing by more than 2x
  37. float3 color1 = SourceTex.SampleLevel( BiLinearClamp, uv + float2(-offset.x, -offset.y), 0 );
  38. float3 color2 = SourceTex.SampleLevel( BiLinearClamp, uv + float2( offset.x, -offset.y), 0 );
  39. float3 color3 = SourceTex.SampleLevel( BiLinearClamp, uv + float2(-offset.x, offset.y), 0 );
  40. float3 color4 = SourceTex.SampleLevel( BiLinearClamp, uv + float2( offset.x, offset.y), 0 );
  41. float luma1 = RGBToLuminance(color1);
  42. float luma2 = RGBToLuminance(color2);
  43. float luma3 = RGBToLuminance(color3);
  44. float luma4 = RGBToLuminance(color4);
  45. const float kSmallEpsilon = 0.0001;
  46. float ScaledThreshold = g_bloomThreshold;
  47. // We perform a brightness filter pass, where lone bright pixels will contribute less.
  48. color1 *= max(kSmallEpsilon, luma1 - ScaledThreshold) / (luma1 + kSmallEpsilon);
  49. color2 *= max(kSmallEpsilon, luma2 - ScaledThreshold) / (luma2 + kSmallEpsilon);
  50. color3 *= max(kSmallEpsilon, luma3 - ScaledThreshold) / (luma3 + kSmallEpsilon);
  51. color4 *= max(kSmallEpsilon, luma4 - ScaledThreshold) / (luma4 + kSmallEpsilon);
  52. // The shimmer filter helps remove stray bright pixels from the bloom buffer by inversely weighting
  53. // them by their luminance. The overall effect is to shrink bright pixel regions around the border.
  54. // Lone pixels are likely to dissolve completely. This effect can be tuned by adjusting the shimmer
  55. // filter inverse strength. The bigger it is, the less a pixel's luminance will matter.
  56. const float kShimmerFilterInverseStrength = 1.0f;
  57. float weight1 = 1.0f / (luma1 + kShimmerFilterInverseStrength);
  58. float weight2 = 1.0f / (luma2 + kShimmerFilterInverseStrength);
  59. float weight3 = 1.0f / (luma3 + kShimmerFilterInverseStrength);
  60. float weight4 = 1.0f / (luma4 + kShimmerFilterInverseStrength);
  61. float weightSum = weight1 + weight2 + weight3 + weight4;
  62. BloomResult[DTid.xy] = (color1 * weight1 + color2 * weight2 + color3 * weight3 + color4 * weight4) / weightSum;
  63. }