BilateralFilter.glsl 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. // Contains a bounch of edge stopping functions plus some other things
  6. #pragma once
  7. #include <AnKi/Shaders/Common.glsl>
  8. // https://cs.dartmouth.edu/~wjarosz/publications/mara17towards.html
  9. F32 calculateBilateralWeightDepth(F32 depthCenter, F32 depthTap, F32 phi)
  10. {
  11. const F32 diff = abs(depthTap - depthCenter);
  12. #if 0
  13. return max(0.0, 1.0 - diff * phi);
  14. #else
  15. return sqrt(1.0 / (EPSILON + diff)) * phi;
  16. #endif
  17. }
  18. // From the SVGF sample code. Depth is linear
  19. F32 calculateBilateralWeightDepth2(F32 depthCenter, F32 depthTap, F32 phi)
  20. {
  21. return (phi == 0.0) ? 0.0 : abs(depthCenter - depthTap) / phi;
  22. }
  23. // https://cs.dartmouth.edu/~wjarosz/publications/mara17towards.html
  24. F32 calculateBilateralWeightNormal(Vec3 center, Vec3 tap, F32 phi)
  25. {
  26. F32 normalCloseness = dot(tap, center);
  27. normalCloseness = normalCloseness * normalCloseness;
  28. normalCloseness = normalCloseness * normalCloseness;
  29. const F32 normalError = (1.0 - normalCloseness);
  30. return max((1.0 - normalError * phi), 0.0);
  31. }
  32. F32 calculateBilateralWeightNormalCos(Vec3 ref, Vec3 tap, F32 phi)
  33. {
  34. return pow(saturate(dot(ref, tap)), phi);
  35. }
  36. // https://cs.dartmouth.edu/~wjarosz/publications/mara17towards.html
  37. F32 calculateBilateralWeightPlane(Vec3 positionCenter, Vec3 centerNormal, Vec3 positionTap, Vec3 normalTap, F32 phi)
  38. {
  39. const F32 lowDistanceThreshold2 = 0.001;
  40. // Change in position in camera space
  41. const Vec3 dq = positionCenter - positionTap;
  42. // How far away is this point from the original sample in camera space? (Max value is unbounded)
  43. const F32 distance2 = dot(dq, dq);
  44. // How far off the expected plane (on the perpendicular) is this point? Max value is unbounded.
  45. const F32 planeError = max(abs(dot(dq, normalTap)), abs(dot(dq, centerNormal)));
  46. return (distance2 < lowDistanceThreshold2) ? 1.0
  47. : pow(max(0.0, 1.0 - 2.0 * phi * planeError / sqrt(distance2)), 2.0);
  48. }
  49. // https://cs.dartmouth.edu/~wjarosz/publications/mara17towards.html
  50. F32 calculateBilateralWeightRoughness(F32 roughnessCenter, F32 roughnessTap, F32 phi)
  51. {
  52. const F32 gDiff = abs(roughnessCenter - roughnessTap) * 10.0;
  53. return max(0.0, 1.0 - (gDiff * phi));
  54. }
  55. // From SVGF sample code.
  56. F32 calculateBilateralWeightLinearDepthAndLuminance(F32 depthCenter, F32 luminanceCenter, F32 depthTap,
  57. F32 luminanceTap, F32 phiDepth, F32 phiLuminance)
  58. {
  59. const F32 wZ = calculateBilateralWeightDepth2(depthCenter, depthTap, phiDepth);
  60. const F32 wL = abs(luminanceCenter - luminanceTap) / phiLuminance;
  61. return exp(0.0 - max(wL, 0.0) - max(wZ, 0.0));
  62. }
  63. // Compute a weight given 2 viewspace positions.
  64. F32 calculateBilateralWeightViewspacePosition(Vec3 posCenter, Vec3 posTap, F32 sigma)
  65. {
  66. const Vec3 t = posCenter - posTap;
  67. const F32 dist2 = dot(t, t) + t.z * t.z;
  68. return min(exp(-(dist2) / sigma), 1.0);
  69. }
  70. struct SpatialBilateralContext
  71. {
  72. U32 sampleCount;
  73. UVec2 referencePointUnormalizedTextureUv;
  74. U32 maxRadiusPixels;
  75. U32 spiralTurnCount;
  76. F32 randomRotationAngle;
  77. };
  78. // Initialize the spatial bilateral context. Its purpose it to create samples that form a spiral around the reference
  79. // point. To experiment and play with the values use this: https://www.shadertoy.com/view/3s3BRs
  80. SpatialBilateralContext spatialBilateralInit(U32 sampleCount, UVec2 referencePointUnormalizedTextureUv,
  81. U32 maxRadiusPixels, U32 spiralTurnCount, F32 time)
  82. {
  83. SpatialBilateralContext ctx;
  84. ctx.sampleCount = sampleCount;
  85. ctx.referencePointUnormalizedTextureUv = referencePointUnormalizedTextureUv;
  86. ctx.maxRadiusPixels = maxRadiusPixels;
  87. ctx.spiralTurnCount = spiralTurnCount;
  88. const UVec2 ref = referencePointUnormalizedTextureUv;
  89. ctx.randomRotationAngle = F32((3u * ref.x) ^ (ref.y + ref.x * ref.y)) + time;
  90. return ctx;
  91. }
  92. // Iterate to get a new sample. See spatialBilateralInit()
  93. UVec2 spatialBilateralIterate(SpatialBilateralContext ctx, U32 iteration)
  94. {
  95. const F32 alpha = F32(F32(iteration) + 0.5) * (1.0 / F32(ctx.sampleCount));
  96. const F32 angle = alpha * F32(ctx.spiralTurnCount) * 6.28 + ctx.randomRotationAngle;
  97. const Vec2 unitOffset = Vec2(cos(angle), sin(angle));
  98. const IVec2 tapOffset = IVec2(alpha * F32(ctx.maxRadiusPixels) * unitOffset);
  99. return UVec2(IVec2(ctx.referencePointUnormalizedTextureUv) + tapOffset);
  100. }