motion_vectors.glsl 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. #[vertex]
  2. #version 450
  3. #VERSION_DEFINES
  4. layout(location = 0) out vec2 uv_interp;
  5. void main() {
  6. vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
  7. gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
  8. uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
  9. }
  10. #[fragment]
  11. #version 450
  12. #VERSION_DEFINES
  13. #include "motion_vector_inc.glsl"
  14. layout(location = 0) in vec2 uv_interp;
  15. layout(set = 0, binding = 0) uniform sampler2D source_velocity;
  16. layout(set = 0, binding = 1) uniform sampler2D source_depth;
  17. layout(location = 0) out vec4 frag_color;
  18. layout(push_constant, std430) uniform Params {
  19. highp mat4 reprojection_matrix;
  20. vec2 resolution;
  21. bool force_derive_from_depth;
  22. }
  23. params;
  24. // Based on distance to line segment from https://www.shadertoy.com/view/3tdSDj
  25. float line_segment(in vec2 p, in vec2 a, in vec2 b) {
  26. vec2 aspect = vec2(params.resolution.x / params.resolution.y, 1.0f);
  27. vec2 ba = (b - a) * aspect;
  28. vec2 pa = (p - a) * aspect;
  29. float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0f, 1.0f);
  30. return length(pa - h * ba) * (params.resolution.y / 2.0f);
  31. }
  32. void main() {
  33. // Retrieve motion vector data.
  34. float cell_size = 32.0f;
  35. float circle_radius = 2.0f;
  36. vec3 nan_color = vec3(1.0f, 0.0f, 0.0f);
  37. vec3 active_color = vec3(1.0f, 0.8f, 0.1f);
  38. vec3 inactive_color = vec3(0.5f, 0.5f, 0.5f);
  39. vec2 pos_pixel = uv_interp * params.resolution;
  40. vec2 cell_pos_pixel = floor(pos_pixel / cell_size) * cell_size + (cell_size * 0.5f);
  41. vec2 cell_pos_uv = cell_pos_pixel / params.resolution;
  42. vec2 cell_pos_velocity = textureLod(source_velocity, cell_pos_uv, 0.0f).xy;
  43. bool derive_velocity = params.force_derive_from_depth || all(lessThanEqual(cell_pos_velocity, vec2(-1.0f, -1.0f)));
  44. if (derive_velocity) {
  45. float depth = textureLod(source_depth, cell_pos_uv, 0.0f).x;
  46. cell_pos_velocity = derive_motion_vector(cell_pos_uv, depth, params.reprojection_matrix);
  47. }
  48. vec2 cell_pos_previous_uv = cell_pos_uv + cell_pos_velocity;
  49. // Draw the shapes.
  50. float epsilon = 1e-6f;
  51. vec2 cell_pos_delta_uv = cell_pos_uv - cell_pos_previous_uv;
  52. bool motion_active = length(cell_pos_delta_uv) > epsilon;
  53. vec3 color;
  54. if (any(isnan(cell_pos_delta_uv))) {
  55. color = nan_color;
  56. } else if (motion_active) {
  57. color = active_color;
  58. } else {
  59. color = inactive_color;
  60. }
  61. float alpha;
  62. if (length(cell_pos_pixel - pos_pixel) <= circle_radius) {
  63. // Circle center.
  64. alpha = 1.0f;
  65. } else if (motion_active) {
  66. // Motion vector line.
  67. alpha = 1.0f - line_segment(uv_interp, cell_pos_uv, cell_pos_previous_uv);
  68. } else {
  69. // Ignore pixel.
  70. alpha = 0.0f;
  71. }
  72. if (derive_velocity) {
  73. color = vec3(1.0f, 1.0f, 1.0f) - color;
  74. alpha *= 0.5f;
  75. }
  76. frag_color = vec4(color, alpha);
  77. }