Skip to content

Commit

Permalink
Merge pull request #80723 from DarioSamo/debug-motion-vectors
Browse files Browse the repository at this point in the history
Improve visual feedback when using the motion vectors debug view option
  • Loading branch information
akien-mga committed Aug 29, 2023
2 parents bec94a6 + e7d3a7c commit 9d74c24
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 2 deletions.
36 changes: 36 additions & 0 deletions servers/rendering/renderer_rd/effects/debug_effects.cpp
Expand Up @@ -51,6 +51,17 @@ DebugEffects::DebugEffects() {
raster_state.wireframe = true;
shadow_frustum.pipelines[SFP_WIREFRAME].setup(shadow_frustum.shader.version_get_shader(shadow_frustum.shader_version, 0), RD::RENDER_PRIMITIVE_LINES, raster_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
}

{
// Motion Vectors debug shader.
Vector<String> modes;
modes.push_back("");

motion_vectors.shader.initialize(modes);
motion_vectors.shader_version = motion_vectors.shader.version_create();

motion_vectors.pipeline.setup(motion_vectors.shader.version_get_shader(motion_vectors.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0);
}
}

void DebugEffects::_create_frustum_arrays() {
Expand Down Expand Up @@ -163,6 +174,8 @@ DebugEffects::~DebugEffects() {
if (frustum.lines_buffer.is_valid()) {
RD::get_singleton()->free(frustum.lines_buffer); // Array gets freed as dependency.
}

motion_vectors.shader.version_free(motion_vectors.shader_version);
}

void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect) {
Expand Down Expand Up @@ -326,3 +339,26 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj
}
}
}

void DebugEffects::draw_motion_vectors(RID p_velocity, RID p_dest_fb, Size2i p_velocity_size) {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);

UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);

RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_source_velocity(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_velocity }));

RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, motion_vectors.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_fb), false, RD::get_singleton()->draw_list_get_current_pass()));

motion_vectors.push_constant.velocity_resolution[0] = p_velocity_size.width;
motion_vectors.push_constant.velocity_resolution[1] = p_velocity_size.height;

RID shader = motion_vectors.shader.version_get_shader(motion_vectors.shader_version, 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_velocity), 0);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &motion_vectors.push_constant, sizeof(MotionVectorsPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u);
RD::get_singleton()->draw_list_end();
}
14 changes: 14 additions & 0 deletions servers/rendering/renderer_rd/effects/debug_effects.h
Expand Up @@ -32,6 +32,7 @@
#define DEBUG_EFFECTS_RD_H

#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/motion_vectors.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"

Expand Down Expand Up @@ -70,6 +71,18 @@ class DebugEffects {
PipelineCacheRD pipelines[SFP_MAX];
} shadow_frustum;

struct MotionVectorsPushConstant {
float velocity_resolution[2];
float pad[2];
};

struct {
MotionVectorsShaderRD shader;
RID shader_version;
PipelineCacheRD pipeline;
MotionVectorsPushConstant push_constant;
} motion_vectors;

void _create_frustum_arrays();

protected:
Expand All @@ -78,6 +91,7 @@ class DebugEffects {
~DebugEffects();

void draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect);
void draw_motion_vectors(RID p_velocity, RID p_dest_fb, Size2i p_velocity_size);
};

} // namespace RendererRD
Expand Down
3 changes: 1 addition & 2 deletions servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
Expand Up @@ -745,8 +745,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(const RenderDataRD *p_ren
}

if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS && _render_buffers_get_velocity_texture(rb).is_valid()) {
Size2i rtsize = texture_storage->render_target_get_size(render_target);
copy_effects->copy_to_fb_rect(_render_buffers_get_velocity_texture(rb), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
debug_effects->draw_motion_vectors(_render_buffers_get_velocity_texture(rb), texture_storage->render_target_get_rd_framebuffer(render_target), rb->get_internal_size());
}
}

Expand Down
80 changes: 80 additions & 0 deletions servers/rendering/renderer_rd/shaders/effects/motion_vectors.glsl
@@ -0,0 +1,80 @@
#[vertex]

#version 450

#VERSION_DEFINES

layout(location = 0) out vec2 uv_interp;

void main() {
vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0);
uv_interp = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0
}

#[fragment]

#version 450

#VERSION_DEFINES

layout(location = 0) in vec2 uv_interp;

layout(set = 0, binding = 0) uniform sampler2D source_velocity;

layout(location = 0) out vec4 frag_color;

layout(push_constant, std430) uniform Params {
vec2 resolution;
}
params;

// Based on distance to line segment from https://www.shadertoy.com/view/3tdSDj

float line_segment(in vec2 p, in vec2 a, in vec2 b) {
vec2 aspect = vec2(params.resolution.x / params.resolution.y, 1.0f);
vec2 ba = (b - a) * aspect;
vec2 pa = (p - a) * aspect;
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0f, 1.0f);
return length(pa - h * ba) * (params.resolution.y / 2.0f);
}

void main() {
// Retrieve motion vector data.
float cell_size = 32.0f;
float circle_radius = 2.0f;
vec3 nan_color = vec3(1.0f, 0.0f, 0.0f);
vec3 active_color = vec3(1.0f, 0.8f, 0.1f);
vec3 inactive_color = vec3(0.5f, 0.5f, 0.5f);
vec2 pos_pixel = uv_interp * params.resolution;
vec2 cell_pos_pixel = floor(pos_pixel / cell_size) * cell_size + (cell_size * 0.5f);
vec2 cell_pos_uv = cell_pos_pixel / params.resolution;
vec2 cell_pos_previous_uv = cell_pos_uv + textureLod(source_velocity, cell_pos_uv, 0.0f).xy;

// Draw the shapes.
float epsilon = 1e-6f;
vec2 cell_pos_delta_uv = cell_pos_uv - cell_pos_previous_uv;
bool motion_active = length(cell_pos_delta_uv) > epsilon;
vec3 color;
if (any(isnan(cell_pos_delta_uv))) {
color = nan_color;
} else if (motion_active) {
color = active_color;
} else {
color = inactive_color;
}

float alpha;
if (length(cell_pos_pixel - pos_pixel) <= circle_radius) {
// Circle center.
alpha = 1.0f;
} else if (motion_active) {
// Motion vector line.
alpha = 1.0f - line_segment(uv_interp, cell_pos_uv, cell_pos_previous_uv);
} else {
// Ignore pixel.
alpha = 0.0f;
}

frag_color = vec4(color, alpha);
}

0 comments on commit 9d74c24

Please sign in to comment.