TemporalAA.hlsl 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. // Contains functions useful for temporal AA like accumulations
  6. #pragma once
  7. #include <AnKi/Shaders/Common.hlsl>
  8. /// Accumualte color using texture gather.
  9. template<typename T, typename TPostProcessTextureFunc>
  10. void accumulateSourceColor(Texture2D<Vec4> tex, SamplerState linearAnyClampSampler, Vec2 newUv, Vec4 texelWeights, TPostProcessTextureFunc func,
  11. inout vector<T, 3> m1, inout vector<T, 3> m2, inout vector<T, 3> sourceSample, inout vector<T, 3> neighboorMin,
  12. inout vector<T, 3> neighboorMax)
  13. {
  14. const vector<T, 4> red = tex.GatherRed(linearAnyClampSampler, newUv);
  15. const vector<T, 4> green = tex.GatherGreen(linearAnyClampSampler, newUv);
  16. const vector<T, 4> blue = tex.GatherBlue(linearAnyClampSampler, newUv);
  17. [unroll] for(U32 c = 0; c < 4; ++c)
  18. {
  19. if(texelWeights[c] > 0.0)
  20. {
  21. const vector<T, 3> neighbor = func(vector<T, 3>(red[c], green[c], blue[c]));
  22. sourceSample += neighbor * texelWeights[c];
  23. neighboorMin = min(neighboorMin, neighbor);
  24. neighboorMax = max(neighboorMax, neighbor);
  25. m1 += neighbor;
  26. m2 += neighbor * neighbor;
  27. }
  28. }
  29. }
  30. /// Accumualte color using plain texture sampling.
  31. template<typename T, typename TPostProcessTextureFunc>
  32. void accumulateSourceColor(Texture2D<Vec4> tex, Vec2 coord, Vec2 textureSize, T weight, TPostProcessTextureFunc func, inout vector<T, 3> m1,
  33. inout vector<T, 3> m2, inout vector<T, 3> sourceSample, inout vector<T, 3> neighboorMin, inout vector<T, 3> neighboorMax)
  34. {
  35. coord = clamp(coord, 0.0, textureSize - 1.0);
  36. const vector<T, 3> neighbor = func(TEX(tex, coord).xyz);
  37. sourceSample += neighbor * weight;
  38. neighboorMin = min(neighboorMin, neighbor);
  39. neighboorMax = max(neighboorMax, neighbor);
  40. m1 += neighbor;
  41. m2 += neighbor * neighbor;
  42. }
  43. template<typename T>
  44. struct DefaultPostProcessTextureFunc
  45. {
  46. vector<T, 3> operator()(vector<T, 3> inp)
  47. {
  48. return inp;
  49. }
  50. };
  51. /// Compute the source color and a few other things like moments for temporal AA.
  52. template<typename T, typename TPostProcessTextureFunc = DefaultPostProcessTextureFunc<T> >
  53. void computeSourceColor(Texture2D<Vec4> tex, SamplerState linearAnyClampSampler, Vec2 coord, out vector<T, 3> m1, out vector<T, 3> m2,
  54. out vector<T, 3> sourceSample, out vector<T, 3> neighboorMin, out vector<T, 3> neighboorMax,
  55. TPostProcessTextureFunc func = (DefaultPostProcessTextureFunc<T>)0)
  56. {
  57. sourceSample = 0.0;
  58. neighboorMin = kMaxF32;
  59. neighboorMax = kMinF32;
  60. m1 = 0.0;
  61. m2 = 0.0;
  62. Vec2 textureSize;
  63. tex.GetDimensions(textureSize.x, textureSize.y);
  64. const Vec2 uv = (coord + 0.5) / textureSize;
  65. const Vec2 texelSize = 1.0 / textureSize;
  66. const Vec2 halfTexelSize = texelSize / 2.0;
  67. // Positioning mentioned bellow is in screen space (bottom left is in the bottom left of the screen)
  68. // Alogithm wants to sample 9 taps of this:
  69. // +-+-+-+
  70. // |6|7|8|
  71. // +-+-+-+
  72. // |3|4|5|
  73. // +-+-+-+
  74. // |0|1|2|
  75. // +-+-+-+
  76. // "uv" points to the middle of 4
  77. // Bottom left (0, 1, 4, 3)
  78. Vec2 newUv = uv + Vec2(-halfTexelSize.x, +halfTexelSize.y);
  79. accumulateSourceColor(tex, linearAnyClampSampler, newUv, vector<T, 4>(0.5, 0.5, 1.0, 0.5), func, m1, m2, sourceSample, neighboorMin,
  80. neighboorMax);
  81. // Top right (4, 5, 8, 7)
  82. newUv = uv + Vec2(+halfTexelSize.x, -halfTexelSize.y);
  83. accumulateSourceColor(tex, linearAnyClampSampler, newUv, vector<T, 4>(0.0, 0.5, 0.5, 0.5), func, m1, m2, sourceSample, neighboorMin,
  84. neighboorMax);
  85. // Top left
  86. accumulateSourceColor(tex, coord + IVec2(-1, -1), textureSize, T(0.5), func, m1, m2, sourceSample, neighboorMin, neighboorMax);
  87. // Bottom right
  88. accumulateSourceColor(tex, coord + IVec2(+1, +1), textureSize, T(0.5), func, m1, m2, sourceSample, neighboorMin, neighboorMax);
  89. // Misc
  90. sourceSample /= T(1.0 + 0.5 * 8.0);
  91. }
  92. template<typename T, typename TPostProcessTextureFunc = DefaultPostProcessTextureFunc<T> >
  93. vector<T, 3> computeTemporalAA(Texture2D<Vec4> currentTex, SamplerState linearAnyClampSampler, Vec3 history, Vec2 coord,
  94. T temporalSourceWeight = 0.01, T temporalGamma = 1.0,
  95. TPostProcessTextureFunc func = (DefaultPostProcessTextureFunc<T>)0)
  96. {
  97. vector<T, 3> m1;
  98. vector<T, 3> m2;
  99. vector<T, 3> sourceSample;
  100. vector<T, 3> neighboorMin;
  101. vector<T, 3> neighboorMax;
  102. computeSourceColor(currentTex, linearAnyClampSampler, coord, m1, m2, sourceSample, neighboorMin, neighboorMax, func);
  103. const T sampleCount = 9.0;
  104. const vector<T, 3> mu = m1 / sampleCount;
  105. const vector<T, 3> sigma = sqrt(abs((m2 / sampleCount) - (mu * mu)));
  106. const vector<T, 3> minc = mu - temporalGamma * sigma;
  107. const vector<T, 3> maxc = mu + temporalGamma * sigma;
  108. history = clamp(history, minc, maxc);
  109. // Blend history and current
  110. const vector<T, 3> compressedSource = sourceSample * rcp(max3(sourceSample) + T(1));
  111. const vector<T, 3> compressedHistory = history * rcp(max3(history) + T(1));
  112. const T luminanceSource = computeLuminance(compressedSource);
  113. const T luminanceHistory = computeLuminance(compressedHistory);
  114. T sourceWeight = temporalSourceWeight;
  115. T historyWeight = T(1) - sourceWeight;
  116. sourceWeight *= T(1) / (T(1) + luminanceSource);
  117. historyWeight *= T(1) / (T(1) + luminanceHistory);
  118. const vector<T, 3> finalVal = (sourceSample * sourceWeight + history * historyWeight) / max(sourceWeight + historyWeight, T(0.00001));
  119. return finalVal;
  120. }