FilmGrain.azsl 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  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. Texture2D<float4> m_grain;
  14. Sampler m_sampler
  15. {
  16. AddressU = Mirror;
  17. AddressV = Mirror;
  18. AddressW = Mirror;
  19. };
  20. // Must match the struct in FilmGrainPass.cpp
  21. struct Constants
  22. {
  23. uint2 m_outputSize; // texture size of output
  24. uint2 m_grainTextureSize; // texture size of grain noise
  25. float m_intensity; // intensity of effect (0 to 1)
  26. float m_luminanceDampening; // factor for dampening effect in areas of high and low luminance
  27. float m_tilingScale; // scaling factor for tiling
  28. [[pad_to(16)]]
  29. };
  30. Constants m_constants;
  31. }
  32. [numthreads(8, 8, 1)]
  33. void MainCS(uint3 dispatchThreadID : SV_DispatchThreadID)
  34. {
  35. if (dispatchThreadID.x >= PassSrg::m_constants.m_outputSize.x || dispatchThreadID.y >= PassSrg::m_constants.m_outputSize.y)
  36. {
  37. return;
  38. }
  39. float3 rgb = PassSrg::m_inputColor[dispatchThreadID.xy].rgb;
  40. // Determine UV wrt tiling scale and vary UV according to time
  41. // The float2 is random and acts as a way of "skipping" across the grain texture
  42. // The multiplier is equivalent to dividing by 1/24, mimicking a frame rate of 24fps as found in many films
  43. float2 grainUV = PassSrg::m_constants.m_tilingScale * dispatchThreadID.xy / PassSrg::m_constants.m_grainTextureSize;
  44. grainUV += float2(0.6379, 1.7358) * trunc(SceneSrg::m_time * 24);
  45. // Determine grain
  46. float grain = PassSrg::m_grain.SampleLevel(PassSrg::m_sampler, grainUV, 0).r;
  47. // Apply dampening
  48. // Note: magic numbers correspond to the contribution of each channel to luminance
  49. // Note: dampening is applied based on the formula y = 4x(1-x^2), which means that y=1 when x=0.5 and drops off to y=0 at x=0 and x=1
  50. float lum = dot(rgb, float3(0.21, 0.72, 0.07));
  51. grain *= lerp(1, (lum - lum * lum) * 4, PassSrg::m_constants.m_luminanceDampening);
  52. // Apply intensity
  53. rgb = lerp(rgb, grain, PassSrg::m_constants.m_intensity);
  54. PassSrg::m_outputColor[dispatchThreadID.xy] = float4(rgb.r, rgb.g, rgb.b, PassSrg::m_inputColor[dispatchThreadID.xy].a);
  55. }