MotionVectors.ankiprog 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. // Calculates the motion vectors that will be used to sample from the previous frame
  6. ANKI_SPECIALIZATION_CONSTANT_UVEC2(FB_SIZE, 0u);
  7. const F32 MAX_REJECTION_DISTANCE = 2.0; // In meters
  8. #define VARIANCE_CLIPPING 0
  9. const F32 VARIANCE_CLIPPING_GAMMA = 2.0;
  10. #pragma anki start comp
  11. #include <AnKi/Shaders/Functions.glsl>
  12. const UVec2 WORKGROUP_SIZE = UVec2(8, 8);
  13. layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
  14. layout(set = 0, binding = 0) uniform sampler u_linearClampSampler;
  15. layout(set = 0, binding = 1) uniform texture2D u_currentDepthTex;
  16. layout(set = 0, binding = 2) uniform texture2D u_historyDepthTex;
  17. layout(set = 0, binding = 3) uniform texture2D u_velocityTex;
  18. layout(set = 0, binding = 4) uniform writeonly image2D u_motionVectorsImage;
  19. layout(set = 0, binding = 5) uniform writeonly image2D u_rejectionFactorImage;
  20. layout(push_constant, std140, row_major) uniform b_pc
  21. {
  22. Mat4 u_reprojectionMat;
  23. Mat4 u_prevViewProjectionInvMat;
  24. };
  25. #define readDepth(texture_, uv, offsetX, offsetY) \
  26. textureLodOffset(sampler2D(texture_, u_linearClampSampler), uv, 0.0, IVec2(offsetX, offsetY)).r
  27. void main()
  28. {
  29. if((FB_SIZE.x % WORKGROUP_SIZE.x) != 0u || (FB_SIZE.y % WORKGROUP_SIZE.y) != 0u) // This check is free
  30. {
  31. if(gl_GlobalInvocationID.x >= FB_SIZE.x || gl_GlobalInvocationID.y >= FB_SIZE.y)
  32. {
  33. return;
  34. }
  35. }
  36. const Vec2 uv = (Vec2(gl_GlobalInvocationID.xy) + 0.5) / Vec2(FB_SIZE);
  37. const F32 depth = readDepth(u_currentDepthTex, uv, 0, 0);
  38. const Vec2 velocity = textureLod(u_velocityTex, u_linearClampSampler, uv, 0.0).rg;
  39. Vec2 historyUv;
  40. if(velocity.x != 1.0)
  41. {
  42. historyUv = uv + velocity;
  43. }
  44. else
  45. {
  46. const Vec4 v4 = u_reprojectionMat * Vec4(UV_TO_NDC(uv), depth, 1.0);
  47. historyUv = NDC_TO_UV(v4.xy / v4.w);
  48. }
  49. //
  50. // Compute rejection factor
  51. //
  52. F32 rejection = 0.0;
  53. // Clamp history to neghbours of current pixel
  54. const F32 near0 = readDepth(u_currentDepthTex, uv, 1, 1);
  55. const F32 near1 = readDepth(u_currentDepthTex, uv, -1, 1);
  56. const F32 near2 = readDepth(u_currentDepthTex, uv, 1, -1);
  57. const F32 near3 = readDepth(u_currentDepthTex, uv, -1, -1);
  58. #if VARIANCE_CLIPPING
  59. const F32 m1 = depth + near0 + near1 + near2 + near3;
  60. const F32 m2 = depth * depth + near0 * near0 + near1 * near1 + near2 * near2 + near3 * near3;
  61. const F32 mu = m1 / 5.0;
  62. const F32 sigma = sqrt(m2 / 5.0 - mu * mu);
  63. const F32 boxMin = mu - VARIANCE_CLIPPING_GAMMA * sigma;
  64. const F32 boxMax = mu + VARIANCE_CLIPPING_GAMMA * sigma;
  65. #else
  66. const F32 boxMin = min(depth, min(near0, min(near1, min(near2, near3))));
  67. const F32 boxMax = max(depth, max(near0, max(near1, max(near2, near3))));
  68. #endif
  69. const F32 historyDepth = readDepth(u_historyDepthTex, historyUv, 0, 0);
  70. const F32 clampedHistoryDepth = clamp(historyDepth, boxMin, boxMax);
  71. // This factor shows when new pixels appeared by checking depth differences
  72. const Vec4 historyViewSpace4 = u_prevViewProjectionInvMat * Vec4(UV_TO_NDC(historyUv), historyDepth, 1.0);
  73. const Vec3 historyViewSpace = historyViewSpace4.xyz / historyViewSpace4.w;
  74. const Vec4 clampedHistoryViewSpace4 =
  75. u_prevViewProjectionInvMat * Vec4(UV_TO_NDC(historyUv), clampedHistoryDepth, 1.0);
  76. const Vec3 clampedHistoryViewSpace = clampedHistoryViewSpace4.xyz / clampedHistoryViewSpace4.w;
  77. const Vec3 delta = clampedHistoryViewSpace - historyViewSpace;
  78. const F32 distSquared = dot(delta, delta);
  79. const F32 disocclusionFactor = min(1.0, distSquared / (MAX_REJECTION_DISTANCE * MAX_REJECTION_DISTANCE));
  80. rejection = max(rejection, disocclusionFactor);
  81. // New pixels might appeared, add them to the disocclusion
  82. const F32 minUv = min(historyUv.x, historyUv.y);
  83. const F32 maxUv = max(historyUv.x, historyUv.y);
  84. if(minUv <= 0.0 || maxUv >= 1.0)
  85. {
  86. rejection = 1.0;
  87. }
  88. // Write out
  89. imageStore(u_motionVectorsImage, IVec2(gl_GlobalInvocationID.xy), Vec4(historyUv - uv, rejection, 0.0));
  90. imageStore(u_rejectionFactorImage, IVec2(gl_GlobalInvocationID.xy), Vec4(rejection));
  91. }
  92. #pragma anki end