fs_denoise_temporal.sc 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. $input v_texcoord0
  2. /*
  3. * Copyright 2021 elven cache. All rights reserved.
  4. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  5. */
  6. #include "../common/common.sh"
  7. #include "parameters.sh"
  8. #include "normal_encoding.sh"
  9. #include "shared_functions.sh"
  10. SAMPLER2D(s_color, 0);
  11. SAMPLER2D(s_normal, 1);
  12. SAMPLER2D(s_velocity, 2);
  13. SAMPLER2D(s_previousColor, 3); // previous color
  14. SAMPLER2D(s_previousNormal, 4); // previous normal
  15. #define COS_PI_OVER_4 0.70710678118
  16. void main()
  17. {
  18. vec2 texCoord = v_texcoord0;
  19. // read center pixel
  20. vec4 color = texture2D(s_color, texCoord);
  21. vec3 normal = NormalDecode(texture2D(s_normal, texCoord).xyz);
  22. // offset to last pixel
  23. vec2 velocity = texture2D(s_velocity, texCoord).xy;
  24. vec2 texCoordPrev = GetTexCoordPreviousNoJitter(texCoord, velocity);
  25. // SVGF approach suggests sampling and test/rejecting 4 contributing
  26. // samples individually and then doing custom bilinear filter of result
  27. // multiply texCoordPrev by dimensions to get nearest pixels, produces (X.5, Y.5) coordinate
  28. // under no motion, so subtract half here to get correct weights for bilinear filter.
  29. // not thrilled by this, feels like something is wrong.
  30. vec2 screenPixelPrev = texCoordPrev * u_viewRect.zw - vec2_splat(0.5);
  31. vec2 screenPixelMin = floor(screenPixelPrev);
  32. vec2 screenPixelMix = fract(screenPixelPrev);
  33. float x0 = 1.0 - screenPixelMix.x;
  34. float x1 = screenPixelMix.x;
  35. float y0 = 1.0 - screenPixelMix.y;
  36. float y1 = screenPixelMix.y;
  37. float coordWeights[4];
  38. coordWeights[0] = x0*y0;
  39. coordWeights[1] = x1*y0;
  40. coordWeights[2] = x0*y1;
  41. coordWeights[3] = x1*y1;
  42. // adding a half texel here to correct the modification above, in addition to pixel offset
  43. // to grab adjacent pixels for bilinear filter. not thrilled by this, feels like something is wrong.
  44. vec2 coords[4];
  45. coords[0] = (screenPixelMin + vec2(0.5, 0.5)) * u_viewTexel.xy;
  46. coords[1] = (screenPixelMin + vec2(1.5, 0.5)) * u_viewTexel.xy;
  47. coords[2] = (screenPixelMin + vec2(0.5, 1.5)) * u_viewTexel.xy;
  48. coords[3] = (screenPixelMin + vec2(1.5, 1.5)) * u_viewTexel.xy;
  49. // SVGF paper mentions comparing depths and normals to establish
  50. // whether samples are similar enough to contribute, but does not
  51. // describe how. References the following paper, which uses threshold
  52. // of cos(PI/4) to accept/reject.
  53. // https://software.intel.com/content/www/us/en/develop/articles/streaming-g-buffer-compression-for-multi-sample-anti-aliasing.html
  54. // this paper also discusses using depth derivatives to estimate overlapping depth range
  55. vec4 accumulatedColor = vec4_splat(0.0);
  56. float accumulatedWeight = 0.0;
  57. for (int i = 0; i < 4; ++i)
  58. {
  59. vec3 sampleNormal = NormalDecode(texture2D(s_previousNormal, coords[i]).xyz);
  60. float normalSimilarity = dot(normal, sampleNormal);
  61. float weight = (normalSimilarity < COS_PI_OVER_4) ? 0.0 : 1.0;
  62. vec4 sampleColor = texture2D(s_previousColor, coords[i]);
  63. weight *= coordWeights[i];
  64. accumulatedColor += sampleColor * weight;
  65. accumulatedWeight += weight;
  66. }
  67. if (0.0 < accumulatedWeight)
  68. {
  69. accumulatedColor *= (1.0 / accumulatedWeight);
  70. color = mix(color, accumulatedColor, 0.8);
  71. }
  72. else
  73. {
  74. // debug colorize
  75. //color.xyz *= vec3(0.5, 0.01, 0.65);
  76. }
  77. gl_FragColor = color;
  78. }