From 3b70fbdc3cd0fea0e8c3de193ab6c8db2d37049b Mon Sep 17 00:00:00 2001 From: devloglogan Date: Tue, 10 Dec 2024 13:41:04 -0600 Subject: [PATCH] Implement motion vectors in mobile renderer --- .../platform/openxr_vulkan_extension.cpp | 4 + .../forward_mobile/render_forward_mobile.cpp | 111 +++++-- .../forward_mobile/render_forward_mobile.h | 14 +- .../scene_shader_forward_mobile.cpp | 7 +- .../scene_shader_forward_mobile.h | 1 + .../forward_mobile/scene_forward_mobile.glsl | 300 ++++++++++++++---- .../scene_forward_mobile_inc.glsl | 6 +- .../storage_rd/render_scene_buffers_rd.cpp | 6 + .../storage_rd/render_scene_buffers_rd.h | 2 + .../storage_rd/texture_storage.cpp | 8 + .../renderer_rd/storage_rd/texture_storage.h | 3 +- 11 files changed, 373 insertions(+), 89 deletions(-) diff --git a/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp b/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp index f935dde4446..bec4940568a 100644 --- a/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp +++ b/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp @@ -320,6 +320,10 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UINT; usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; break; + case VK_FORMAT_R16G16B16A16_SFLOAT: + format = RenderingDevice::DATA_FORMAT_R16G16B16A16_SFLOAT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + break; case VK_FORMAT_D32_SFLOAT: format = RenderingDevice::DATA_FORMAT_D32_SFLOAT; usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index d3e1abc7c9c..c9d0d7b63c9 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -166,6 +166,34 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RenderSceneBu ERR_FAIL_NULL(render_buffers); // Huh? really? } +RID RendererSceneRenderImplementation::RenderForwardMobile::RenderBufferDataForwardMobile::get_motion_vectors_fb() { + ERR_FAIL_NULL_V(render_buffers, RID()); + + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + ERR_FAIL_NULL_V(texture_storage, RID()); + + RID velocity = render_buffers->get_velocity_buffer(false); + RID velocity_depth = render_buffers->get_velocity_depth_buffer(); + + if (velocity.is_valid() && velocity_depth.is_valid()) { + Vector textures; + textures.push_back(velocity); + textures.push_back(velocity_depth); + + Vector passes; + RD::FramebufferPass pass; + pass.color_attachments.push_back(0); + pass.depth_attachment = 1; + passes.push_back(pass); + + uint32_t view_count = render_buffers->get_view_count(); + + return FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, view_count); + } + + return RID(); +} + RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(FramebufferConfigType p_config_type) { ERR_FAIL_NULL_V(render_buffers, RID()); @@ -776,19 +804,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RENDER_TIMESTAMP("Setup 3D Scene"); - /* TODO - // check if we need motion vectors - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) { - p_render_data->scene_data->calculate_motion_vectors = true; - } else if (_compositor_effects_has_flag(p_render_data, RS::COMPOSITOR_EFFECT_FLAG_NEEDS_MOTION_VECTORS)) { - p_render_data->scene_data->calculate_motion_vectors = true; - } else if (render target has velocity override) { // TODO - p_render_data->scene_data->calculate_motion_vectors = true; - } else { - p_render_data->scene_data->calculate_motion_vectors = false; - } - */ - p_render_data->scene_data->calculate_motion_vectors = false; // for now, not yet supported... + p_render_data->scene_data->calculate_motion_vectors = RendererRD::TextureStorage::get_singleton()->render_target_get_override_velocity(rb->get_render_target()).is_valid(); p_render_data->scene_data->directional_light_count = 0; p_render_data->scene_data->opaque_prepass_threshold = 0.0; @@ -1098,6 +1114,25 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color breadcrumb = RDD::BreadcrumbMarker::REFLECTION_PROBES; } + if (rb_data.is_valid() && p_render_data->scene_data->calculate_motion_vectors) { + RID mv_fb = rb_data->get_motion_vectors_fb(); + + if (mv_fb.is_valid()) { + RENDER_TIMESTAMP("Render Motion Vectors"); + + Vector mv_pass_clear; + mv_pass_clear.push_back(Color(0, 0, 0, 0)); + + RD::get_singleton()->draw_command_begin_label("Render Motion Vectors"); + + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID(), samplers); + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_MOTION_VECTORS, rp_uniform_set, base_specialization); + _render_list_with_draw_list(&render_list_params, mv_fb, RD::DRAW_CLEAR_ALL, mv_pass_clear); + + RD::get_singleton()->draw_command_end_label(); + } + } + // opaque pass RD::get_singleton()->draw_command_begin_label("Render Opaque"); @@ -1871,14 +1906,22 @@ void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint scene_state.instance_data[p_render_list].resize(p_offset + element_total); rl->element_info.resize(p_offset + element_total); + uint64_t frame = RSG::rasterizer->get_frame_number(); + for (uint32_t i = 0; i < element_total; i++) { GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset]; GeometryInstanceForwardMobile *inst = surface->owner; SceneState::InstanceData &instance_data = scene_state.instance_data[p_render_list][i + p_offset]; + if (inst->prev_transform_dirty && frame > inst->prev_transform_change_frame + 1 && inst->prev_transform_change_frame) { + inst->prev_transform = inst->transform; + inst->prev_transform_dirty = false; + } + if (inst->store_transform_cache) { RendererRD::MaterialStorage::store_transform(inst->transform, instance_data.transform); + RendererRD::MaterialStorage::store_transform(inst->prev_transform, instance_data.prev_transform); #ifdef REAL_T_IS_DOUBLE // Split the origin into two components, the float approximation and the missing precision. @@ -1889,6 +1932,7 @@ void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint #endif } else { RendererRD::MaterialStorage::store_transform(Transform3D(), instance_data.transform); + RendererRD::MaterialStorage::store_transform(Transform3D(), instance_data.prev_transform); } instance_data.flags = inst->flags_cache; @@ -2068,7 +2112,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const } // ADD Element - if (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) { + if (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT || p_pass_mode == PASS_MODE_MOTION_VECTORS) { #ifdef DEBUG_ENABLED bool force_alpha = unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW); #else @@ -2155,6 +2199,9 @@ void RenderForwardMobile::_render_list(RenderingDevice::DrawListID p_draw_list, case PASS_MODE_DEPTH_MATERIAL: { _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); } break; + case PASS_MODE_MOTION_VECTORS: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } } } @@ -2170,6 +2217,7 @@ void RenderForwardMobile::_render_list_with_draw_list(RenderListParameters *p_pa template void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); + RendererRD::ParticlesStorage *particles_storage = RendererRD::ParticlesStorage::get_singleton(); RD::DrawListID draw_list = p_draw_list; RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format; @@ -2215,11 +2263,10 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr push_constant.base_index = i + p_params->element_offset; if constexpr (p_pass_mode == PASS_MODE_DEPTH_MATERIAL) { - push_constant.uv_offset[0] = p_params->uv_offset.x; - push_constant.uv_offset[1] = p_params->uv_offset.y; + push_constant.uv_offset = Math::make_half_float(p_params->uv_offset.y) << 16; + push_constant.uv_offset |= Math::make_half_float(p_params->uv_offset.x); } else { - push_constant.uv_offset[0] = 0.0; - push_constant.uv_offset[1] = 0.0; + push_constant.uv_offset = 0; } if (shadow_pass) { @@ -2301,6 +2348,9 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr ERR_FAIL_COND_MSG(p_params->view_count > 1, "Multiview not supported for material pass"); pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL; } break; + case PASS_MODE_MOTION_VECTORS: { + pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_MOTION_VECTORS_MULTIVIEW; + } } pipeline_key.framebuffer_format_id = framebuffer_format; @@ -2319,9 +2369,9 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr // Skeleton and blend shape. uint64_t input_mask = shader->get_vertex_input_mask(pipeline_key.version, pipeline_key.ubershader); if (surf->owner->mesh_instance.is_valid()) { - mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, input_mask, false, vertex_array_rd, vertex_format); + mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, input_mask, p_pass_mode == PASS_MODE_MOTION_VECTORS, vertex_array_rd, vertex_format); } else { - mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, input_mask, false, vertex_array_rd, vertex_format); + mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, input_mask, p_pass_mode == PASS_MODE_MOTION_VECTORS, vertex_array_rd, vertex_format); } pipeline_key.vertex_format_id = vertex_format; @@ -2388,6 +2438,15 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr prev_material_uniform_set = material_uniform_set; } + if (surf->owner->base_flags & INSTANCE_DATA_FLAG_PARTICLES) { + particles_storage->particles_get_instance_buffer_motion_vectors_offsets(surf->owner->data->base, push_constant.multimesh_motion_vectors_current_offset, push_constant.multimesh_motion_vectors_previous_offset); + } else if (surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH) { + mesh_storage->_multimesh_get_motion_vectors_offsets(surf->owner->data->base, push_constant.multimesh_motion_vectors_current_offset, push_constant.multimesh_motion_vectors_previous_offset); + } else { + push_constant.multimesh_motion_vectors_current_offset = 0; + push_constant.multimesh_motion_vectors_previous_offset = 0; + } + size_t push_constant_size = 0; if (pipeline_key.ubershader) { push_constant_size = sizeof(SceneState::PushConstant); @@ -2439,6 +2498,17 @@ RenderGeometryInstance *RenderForwardMobile::geometry_instance_create(RID p_base return ginstance; } +void RendererSceneRenderImplementation::RenderForwardMobile::GeometryInstanceForwardMobile::set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { + uint64_t frame = RSG::rasterizer->get_frame_number(); + if (frame != prev_transform_change_frame) { + prev_transform = transform; + prev_transform_change_frame = frame; + prev_transform_dirty = true; + } + + RenderGeometryInstanceBase::set_transform(p_transform, p_aabb, p_transformed_aabb); +} + void RenderForwardMobile::GeometryInstanceForwardMobile::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) { lightmap_instance = p_lightmap_instance; lightmap_uv_scale = p_lightmap_uv_scale; @@ -2847,6 +2917,7 @@ void RenderForwardMobile::_geometry_instance_update(RenderGeometryInstance *p_ge ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_PARTICLES; ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; if (false) { // 2D particles ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index a3bfb86ccdd..5aa536c7df6 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -89,6 +89,8 @@ private: virtual void free_data() override; virtual void configure(RenderSceneBuffersRD *p_render_buffers) override; + RID get_motion_vectors_fb(); + private: RenderSceneBuffersRD *render_buffers = nullptr; }; @@ -108,6 +110,7 @@ private: // PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI, PASS_MODE_DEPTH_MATERIAL, // PASS_MODE_SDF, + PASS_MODE_MOTION_VECTORS, }; struct RenderElementInfo; @@ -198,14 +201,16 @@ private: }; struct PushConstant { - float uv_offset[2]; + uint32_t uv_offset; uint32_t base_index; - uint32_t pad; + uint32_t multimesh_motion_vectors_current_offset; + uint32_t multimesh_motion_vectors_previous_offset; PushConstantUbershader ubershader; }; struct InstanceData { float transform[16]; + float prev_transform[16]; uint32_t flags; uint32_t instance_uniforms_ofs; // Base offset in global buffer for instance variables. uint32_t gi_offset; // GI information when using lightmapping (VCT or lightmap index). @@ -497,6 +502,10 @@ protected: uint32_t instance_count = 0; uint32_t trail_steps = 1; + uint64_t prev_transform_change_frame = UINT_MAX; + bool prev_transform_dirty = true; + Transform3D prev_transform; + // lightmap uint32_t gi_offset_cache = 0; // !BAS! Should rename this to lightmap_offset_cache, in forward clustered this was shared between gi and lightmap RID lightmap_instance; @@ -524,6 +533,7 @@ protected: virtual void _mark_dirty() override; + virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override; virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index b32e00bfad4..732d4305316 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -307,7 +307,7 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli multisample_state.enable_alpha_to_one = true; } - if (p_pipeline_key.version == SHADER_VERSION_COLOR_PASS || p_pipeline_key.version == SHADER_VERSION_COLOR_PASS_MULTIVIEW || p_pipeline_key.version == SHADER_VERSION_LIGHTMAP_COLOR_PASS || p_pipeline_key.version == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW) { + if (p_pipeline_key.version == SHADER_VERSION_COLOR_PASS || p_pipeline_key.version == SHADER_VERSION_COLOR_PASS_MULTIVIEW || p_pipeline_key.version == SHADER_VERSION_LIGHTMAP_COLOR_PASS || p_pipeline_key.version == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW || p_pipeline_key.version == SHADER_VERSION_MOTION_VECTORS_MULTIVIEW) { blend_state = blend_state_blend; if (depth_draw == DEPTH_DRAW_OPAQUE && !uses_alpha_clip) { // Alpha does not write to depth. @@ -322,7 +322,7 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli // Do not use this version (error case). } } else { - if (p_pipeline_key.version == SHADER_VERSION_COLOR_PASS || p_pipeline_key.version == SHADER_VERSION_COLOR_PASS_MULTIVIEW || p_pipeline_key.version == SHADER_VERSION_LIGHTMAP_COLOR_PASS || p_pipeline_key.version == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW) { + if (p_pipeline_key.version == SHADER_VERSION_COLOR_PASS || p_pipeline_key.version == SHADER_VERSION_COLOR_PASS_MULTIVIEW || p_pipeline_key.version == SHADER_VERSION_LIGHTMAP_COLOR_PASS || p_pipeline_key.version == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW || p_pipeline_key.version == SHADER_VERSION_MOTION_VECTORS_MULTIVIEW) { blend_state = blend_state_opaque; } else if (p_pipeline_key.version == SHADER_VERSION_SHADOW_PASS || p_pipeline_key.version == SHADER_VERSION_SHADOW_PASS_MULTIVIEW || p_pipeline_key.version == SHADER_VERSION_SHADOW_PASS_DP) { // Contains nothing. @@ -502,6 +502,7 @@ void SceneShaderForwardMobile::init(const String p_defines) { shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, base_define + "\n#define USE_MULTIVIEW\n", false)); // SHADER_VERSION_COLOR_PASS_MULTIVIEW shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, base_define + "\n#define USE_MULTIVIEW\n#define USE_LIGHTMAP\n", false)); // SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, base_define + "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n#define SHADOW_PASS\n", false)); // SHADER_VERSION_SHADOW_PASS_MULTIVIEW + shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, base_define + "\n#define USE_MULTIVIEW\n#define MODE_RENDER_MOTION_VECTORS\n", false)); // SHADER_VERSION_MOTION_VECTORS_MULTIVIEW } Vector immutable_samplers; @@ -711,7 +712,7 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.base_texture_binding_index = 1; actions.texture_layout_set = RenderForwardMobile::MATERIAL_UNIFORM_SET; actions.base_uniform_string = "material."; - actions.base_varying_index = 10; + actions.base_varying_index = 14; actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 51ca5628eac..29fc5bb2a52 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -52,6 +52,7 @@ public: SHADER_VERSION_COLOR_PASS_MULTIVIEW, SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW, SHADER_VERSION_SHADOW_PASS_MULTIVIEW, + SHADER_VERSION_MOTION_VECTORS_MULTIVIEW, SHADER_VERSION_MAX }; diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 5842d054cd1..be37e837abf 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -66,6 +66,15 @@ layout(location = 10) in uvec4 bone_attrib; layout(location = 11) in vec4 weight_attrib; #endif +#if defined(MODE_RENDER_MOTION_VECTORS) +layout(location = 12) in vec4 previous_vertex_attrib; + +#if defined(NORMAL_USED) || defined(TANGENT_USED) +layout(location = 13) in vec4 previous_normal_attrib; +#endif + +#endif // MODE_RENDER_MOTION_VECTORS + vec3 oct_to_vec3(vec2 e) { vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); float t = max(-v.z, 0.0); @@ -127,6 +136,11 @@ layout(location = 9) out highp float dp_clip; #endif +#if defined(MODE_RENDER_MOTION_VECTORS) +layout(location = 12) out highp vec4 screen_position; +layout(location = 13) out highp vec4 prev_screen_position; +#endif + #ifdef USE_MULTIVIEW #extension GL_EXT_multiview : enable #define ViewIndex gl_ViewIndex @@ -185,15 +199,77 @@ uint multimesh_stride() { return stride; } -void main() { +void _unpack_vertex_attributes(vec4 p_vertex_in, vec3 p_compressed_aabb_position, vec3 p_compressed_aabb_size, +#if defined(NORMAL_USED) || defined(TANGENT_USED) + vec4 p_normal_in, +#ifdef NORMAL_USED + out vec3 r_normal, +#endif + out vec3 r_tangent, + out vec3 r_binormal, +#endif + out vec3 r_vertex) { + + r_vertex = p_vertex_in.xyz * p_compressed_aabb_size + p_compressed_aabb_position; +#ifdef NORMAL_USED + r_normal = oct_to_vec3(p_normal_in.xy * 2.0 - 1.0); +#endif + +#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + float binormal_sign; + + // This works because the oct value (0, 1) maps onto (0, 0, -1) which encodes to (1, 1). + // Accordingly, if p_normal_in.z contains octahedral values, it won't equal (0, 1). + if (p_normal_in.z > 0.0 || p_normal_in.w < 1.0) { + // Uncompressed format. + vec2 signed_tangent_attrib = p_normal_in.zw * 2.0 - 1.0; + r_tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); + binormal_sign = sign(signed_tangent_attrib.y); + r_binormal = normalize(cross(r_normal, r_tangent) * binormal_sign); + } else { + // Compressed format. + float angle = p_vertex_in.w; + binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller. + angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably. + vec3 axis = r_normal; + axis_angle_to_tbn(axis, angle, r_tangent, r_binormal, r_normal); + r_binormal *= binormal_sign; + } +#endif +} + +void vertex_shader(in vec3 vertex, +#ifdef NORMAL_USED + in vec3 normal, +#endif +#if defined(NORMAL_USED) || defined(TANGENT_USED) + in vec3 tangent, + in vec3 binormal, +#endif + in uint instance_index, in uint multimesh_offset, in mat4 model_matrix, +#ifdef MODE_DUAL_PARABOLOID + in float dual_paraboloid_side, + in float z_far, +#endif +#if defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) + in uint scene_flags, +#endif + in mat4 projection_matrix, + in mat4 inv_projection_matrix, +#ifdef USE_MULTIVIEW + in vec4 scene_eye_offset, +#endif + in mat4 view_matrix, + in mat4 inv_view_matrix, + in vec2 viewport_size, + in uint scene_directional_light_count, + out vec4 screen_position_output) { vec4 instance_custom = vec4(0.0); #if defined(COLOR_USED) color_interp = color_attrib; #endif - mat4 model_matrix = instances.data[draw_call.instance_index].transform; - mat4 inv_view_matrix = scene_data.inv_view_matrix; - #ifdef USE_DOUBLE_PRECISION vec3 model_precision = vec3(model_matrix[0][3], model_matrix[1][3], model_matrix[2][3]); model_matrix[0][3] = 0.0; @@ -206,7 +282,7 @@ void main() { #endif mat3 model_normal_matrix; - if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) { + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) { model_normal_matrix = transpose(inverse(mat3(model_matrix))); } else { model_normal_matrix = mat3(model_matrix); @@ -219,7 +295,7 @@ void main() { //multimesh, instances are for it #ifdef USE_PARTICLE_TRAILS - uint trail_size = (instances.data[draw_call.instance_index].flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK; + uint trail_size = (instances.data[instance_index].flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK; uint stride = 3 + 1 + 1; //particles always uses this format uint offset = trail_size * stride * gl_InstanceIndex; @@ -264,7 +340,7 @@ void main() { #else uint stride = multimesh_stride(); - uint offset = stride * gl_InstanceIndex; + uint offset = stride * (gl_InstanceIndex + multimesh_offset); if (sc_multimesh_format_2d()) { matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); @@ -300,33 +376,6 @@ void main() { model_normal_matrix = model_normal_matrix * mat3(matrix); } - vec3 vertex = vertex_angle_attrib.xyz * instances.data[draw_call.instance_index].compressed_aabb_size_pad.xyz + instances.data[draw_call.instance_index].compressed_aabb_position_pad.xyz; -#ifdef NORMAL_USED - vec3 normal = oct_to_vec3(axis_tangent_attrib.xy * 2.0 - 1.0); -#endif - -#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - - vec3 binormal; - float binormal_sign; - vec3 tangent; - if (axis_tangent_attrib.z > 0.0 || axis_tangent_attrib.w < 1.0) { - // Uncompressed format. - vec2 signed_tangent_attrib = axis_tangent_attrib.zw * 2.0 - 1.0; - tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); - binormal_sign = sign(signed_tangent_attrib.y); - binormal = normalize(cross(normal, tangent) * binormal_sign); - } else { - // Compressed format. - float angle = vertex_angle_attrib.w; - binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller. - angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably. - vec3 axis = normal; - axis_angle_to_tbn(axis, angle, tangent, binormal, normal); - binormal *= binormal_sign; - } -#endif - #ifdef UV_USED uv_interp = uv_attrib; #endif @@ -335,7 +384,7 @@ void main() { uv2_interp = uv2_attrib; #endif - vec4 uv_scale = instances.data[draw_call.instance_index].uv_scale; + vec4 uv_scale = instances.data[instance_index].uv_scale; if (uv_scale != vec4(0.0)) { // Compression enabled #ifdef UV_USED @@ -351,14 +400,10 @@ void main() { #endif #ifdef USE_MULTIVIEW - mat4 projection_matrix = scene_data.projection_matrix_view[ViewIndex]; - mat4 inv_projection_matrix = scene_data.inv_projection_matrix_view[ViewIndex]; - vec3 eye_offset = scene_data.eye_offset[ViewIndex].xyz; + vec3 eye_offset = scene_eye_offset.xyz; #else - mat4 projection_matrix = scene_data.projection_matrix; - mat4 inv_projection_matrix = scene_data.inv_projection_matrix; vec3 eye_offset = vec3(0.0, 0.0, 0.0); -#endif //USE_MULTIVIEW +#endif // USE_MULTIVIEW //using world coordinates #if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) @@ -383,10 +428,10 @@ void main() { float roughness = 1.0; - mat4 modelview = scene_data.view_matrix * model_matrix; - mat3 modelview_normal = mat3(scene_data.view_matrix) * model_normal_matrix; - mat4 read_view_matrix = scene_data.view_matrix; - vec2 read_viewport_size = scene_data.viewport_size; + mat4 modelview = view_matrix * model_matrix; + mat3 modelview_normal = mat3(view_matrix) * model_normal_matrix; + mat4 read_view_matrix = view_matrix; + vec2 read_viewport_size = viewport_size; { #CODE : VERTEX @@ -406,8 +451,8 @@ void main() { } vertex = mat3(inv_view_matrix * modelview) * vertex; vec3 temp_precision; - vertex += double_add_vec3(model_origin, model_precision, scene_data.inv_view_matrix[3].xyz, view_precision, temp_precision); - vertex = mat3(scene_data.view_matrix) * vertex; + vertex += double_add_vec3(model_origin, model_precision, inv_view_matrix[3].xyz, view_precision, temp_precision); + vertex = mat3(view_matrix) * vertex; #else vertex = (modelview * vec4(vertex, 1.0)).xyz; #endif @@ -425,14 +470,14 @@ void main() { //using world coordinates #if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - vertex = (scene_data.view_matrix * vec4(vertex, 1.0)).xyz; + vertex = (view_matrix * vec4(vertex, 1.0)).xyz; #ifdef NORMAL_USED - normal = (scene_data.view_matrix * vec4(normal, 0.0)).xyz; + normal = (view_matrix * vec4(normal, 0.0)).xyz; #endif #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - binormal = (scene_data.view_matrix * vec4(binormal, 0.0)).xyz; - tangent = (scene_data.view_matrix * vec4(tangent, 0.0)).xyz; + binormal = (view_matrix * vec4(binormal, 0.0)).xyz; + tangent = (view_matrix * vec4(tangent, 0.0)).xyz; #endif #endif @@ -461,7 +506,7 @@ void main() { specular_light_interp = vec4(0.0); uint omni_light_count = sc_omni_lights(8); - uvec2 omni_light_indices = instances.data[draw_call.instance_index].omni_lights; + uvec2 omni_light_indices = instances.data[instance_index].omni_lights; for (uint i = 0; i < omni_light_count; i++) { uint light_index = (i > 3) ? ((omni_light_indices.y >> ((i - 4) * 8)) & 0xFF) : ((omni_light_indices.x >> (i * 8)) & 0xFF); if (i > 0 && light_index == 0xFF) { @@ -472,7 +517,7 @@ void main() { } uint spot_light_count = sc_spot_lights(8); - uvec2 spot_light_indices = instances.data[draw_call.instance_index].spot_lights; + uvec2 spot_light_indices = instances.data[instance_index].spot_lights; for (uint i = 0; i < spot_light_count; i++) { uint light_index = (i > 3) ? ((spot_light_indices.y >> ((i - 4) * 8)) & 0xFF) : ((spot_light_indices.x >> (i * 8)) & 0xFF); if (i > 0 && light_index == 0xFF) { @@ -482,18 +527,18 @@ void main() { light_process_spot_vertex(light_index, vertex, view, normal_interp, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb); } - uint directional_lights_count = sc_directional_lights(scene_data.directional_light_count); + uint directional_lights_count = sc_directional_lights(scene_directional_light_count); if (directional_lights_count > 0) { // We process the first directional light separately as it may have shadows. vec3 directional_diffuse = vec3(0.0); vec3 directional_specular = vec3(0.0); for (uint i = 0; i < directional_lights_count; i++) { - if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) { + if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) { continue; // Not masked, skip. } - if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { + if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { continue; // Statically baked light and object uses lightmap, skip. } if (i == 0) { @@ -539,7 +584,7 @@ void main() { #ifdef MODE_DUAL_PARABOLOID - vertex_interp.z *= scene_data.dual_paraboloid_side; + vertex_interp.z *= dual_paraboloid_side; dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias @@ -549,7 +594,7 @@ void main() { float distance = length(vtx); vtx = normalize(vtx); vtx.xy /= 1.0 - vtx.z; - vtx.z = (distance / scene_data.z_far); + vtx.z = (distance / z_far); vtx.z = vtx.z * 2.0 - 1.0; vertex_interp = vtx; @@ -568,14 +613,14 @@ void main() { #endif #ifdef MODE_RENDER_DEPTH - if (bool(scene_data.flags & SCENE_DATA_FLAGS_USE_PANCAKE_SHADOWS)) { + if (bool(scene_flags & SCENE_DATA_FLAGS_USE_PANCAKE_SHADOWS)) { if (gl_Position.z >= 0.9999) { gl_Position.z = 0.9999; } } #endif // MODE_RENDER_DEPTH #ifdef MODE_RENDER_MATERIAL - if (bool(scene_data.flags & SCENE_DATA_FLAGS_USE_UV2_MATERIAL)) { + if (bool(scene_flags & SCENE_DATA_FLAGS_USE_UV2_MATERIAL)) { vec2 uv_dest_attrib; if (uv_scale != vec4(0.0)) { uv_dest_attrib = (uv2_attrib.xy - 0.5) * uv_scale.zw; @@ -583,11 +628,128 @@ void main() { uv_dest_attrib = uv2_attrib.xy; } - gl_Position.xy = (uv_dest_attrib + draw_call.uv_offset) * 2.0 - 1.0; + vec2 uv_offset = unpackHalf2x16(draw_call.uv_offset); + gl_Position.xy = (uv_dest_attrib + uv_offset) * 2.0 - 1.0; gl_Position.z = 0.00001; gl_Position.w = 1.0; } #endif // MODE_RENDER_MATERIAL +#ifdef MODE_RENDER_MOTION_VECTORS + screen_position_output = gl_Position; +#endif // MODE_RENDER_MOTION_VECTORS +} + +void main() { +#if defined(MODE_RENDER_MOTION_VECTORS) + vec3 prev_vertex; +#ifdef NORMAL_USED + vec3 prev_normal; +#endif +#if defined(NORMAL_USED) || defined(TANGENT_USED) + vec3 prev_tangent; + vec3 prev_binormal; +#endif + + _unpack_vertex_attributes( + previous_vertex_attrib, + instances.data[draw_call.instance_index].compressed_aabb_position_pad.xyz, + instances.data[draw_call.instance_index].compressed_aabb_size_pad.xyz, +#if defined(NORMAL_USED) || defined(TANGENT_USED) + previous_normal_attrib, +#ifdef NORMAL_USED + prev_normal, +#endif + prev_tangent, + prev_binormal, +#endif + prev_vertex); + + vertex_shader(prev_vertex, +#ifdef NORMAL_USED + prev_normal, +#endif +#if defined(NORMAL_USED) || defined(TANGENT_USED) + prev_tangent, + prev_binormal, +#endif + draw_call.instance_index, draw_call.multimesh_motion_vectors_previous_offset, instances.data[draw_call.instance_index].prev_transform, +#ifdef MODE_DUAL_PARABOLOID + scene_data_block.prev_data.dual_paraboloid_side, + scene_data_block.prev_data.z_far, +#endif +#if defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) + scene_data_block.prev_data.flags, +#endif +#ifdef USE_MULTIVIEW + scene_data_block.prev_data.projection_matrix_view[ViewIndex], + scene_data_block.prev_data.inv_projection_matrix_view[ViewIndex], + scene_data_block.prev_data.eye_offset[ViewIndex], +#else + scene_data_block.prev_data.projection_matrix, + scene_data_block.prev_data.inv_projection_matrix, +#endif + scene_data_block.prev_data.view_matrix, + scene_data_block.prev_data.inv_view_matrix, + scene_data_block.prev_data.viewport_size, + scene_data_block.prev_data.directional_light_count, + prev_screen_position); +#else + // Unused output. + vec4 screen_position; +#endif // MODE_RENDER_MOTION_VECTORS + + vec3 vertex; +#ifdef NORMAL_USED + vec3 normal; +#endif +#if defined(NORMAL_USED) || defined(TANGENT_USED) + vec3 tangent; + vec3 binormal; +#endif + + _unpack_vertex_attributes( + vertex_angle_attrib, + instances.data[draw_call.instance_index].compressed_aabb_position_pad.xyz, + instances.data[draw_call.instance_index].compressed_aabb_size_pad.xyz, +#if defined(NORMAL_USED) || defined(TANGENT_USED) + axis_tangent_attrib, +#ifdef NORMAL_USED + normal, +#endif + tangent, + binormal, +#endif + vertex); + + vertex_shader(vertex, +#ifdef NORMAL_USED + normal, +#endif +#if defined(NORMAL_USED) || defined(TANGENT_USED) + tangent, + binormal, +#endif + draw_call.instance_index, draw_call.multimesh_motion_vectors_current_offset, instances.data[draw_call.instance_index].transform, +#ifdef MODE_DUAL_PARABOLOID + scene_data_block.data.dual_paraboloid_side, + scene_data_block.data.z_far, +#endif +#if defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) + scene_data_block.data.flags, +#endif +#ifdef USE_MULTIVIEW + scene_data_block.data.projection_matrix_view[ViewIndex], + scene_data_block.data.inv_projection_matrix_view[ViewIndex], + scene_data_block.data.eye_offset[ViewIndex], +#else + scene_data_block.data.projection_matrix, + scene_data_block.data.inv_projection_matrix, +#endif + scene_data_block.data.view_matrix, + scene_data_block.data.inv_view_matrix, + scene_data_block.data.viewport_size, + scene_data_block.data.directional_light_count, + screen_position); } #[fragment] @@ -644,6 +806,11 @@ layout(location = 9) highp in float dp_clip; #endif +#if defined(MODE_RENDER_MOTION_VECTORS) +layout(location = 12) in highp vec4 screen_position; +layout(location = 13) in highp vec4 prev_screen_position; +#endif + #ifdef USE_LIGHTMAP // w0, w1, w2, and w3 are the four cubic B-spline basis functions float w0(float a) { @@ -1970,4 +2137,15 @@ void main() { #endif //MODE_MULTIPLE_RENDER_TARGETS #endif //MODE_RENDER_DEPTH + +#ifdef MODE_RENDER_MOTION_VECTORS + // These motion vectors are in NDC space (as opposed to screen space) to fit the OpenXR XR_FB_space_warp specification. + // https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_FB_space_warp + + vec3 ndc = screen_position.xyz / screen_position.w; + ndc.y = -ndc.y; + vec3 prev_ndc = prev_screen_position.xyz / prev_screen_position.w; + prev_ndc.y = -prev_ndc.y; + frag_color = vec4(ndc - prev_ndc, 0.0); +#endif } diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl index 86bca89a6c0..8c7cd0fd54b 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl @@ -13,9 +13,10 @@ #define USING_MOBILE_RENDERER layout(push_constant, std430) uniform DrawCall { - vec2 uv_offset; + uint uv_offset; uint instance_index; - uint pad; + uint multimesh_motion_vectors_current_offset; + uint multimesh_motion_vectors_previous_offset; #ifdef UBERSHADER uint sc_packed_0; uint sc_packed_1; @@ -303,6 +304,7 @@ scene_data_block; struct InstanceData { highp mat4 transform; // 64 - 64 + highp mat4 prev_transform; uint flags; // 04 - 68 uint instance_uniforms_ofs; // Base offset in global buffer for instance variables. // 04 - 72 uint gi_offset; // GI information when using lightmapping (VCT or lightmap index). // 04 - 76 diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp index a06df3a79e0..63aa4760e19 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp @@ -702,6 +702,12 @@ RID RenderSceneBuffersRD::get_velocity_buffer(bool p_get_msaa, uint32_t p_layer) } } +RID RenderSceneBuffersRD::get_velocity_depth_buffer() { + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + RID velocity_depth = texture_storage->render_target_get_override_velocity_depth(render_target); + return velocity_depth; +} + uint32_t RenderSceneBuffersRD::get_color_usage_bits(bool p_resolve, bool p_msaa, bool p_storage) { DEV_ASSERT((!p_resolve && !p_msaa) || (p_resolve != p_msaa)); diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h index ba42970a5d7..11c593001d9 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h @@ -312,6 +312,8 @@ public: RID get_velocity_buffer(bool p_get_msaa); RID get_velocity_buffer(bool p_get_msaa, uint32_t p_layer); + RID get_velocity_depth_buffer(); + // Samplers adjusted with the mipmap bias that is best fit for the configuration of these render buffers. _FORCE_INLINE_ RendererRD::MaterialStorage::Samplers get_samplers() const { diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index f01edd2d2df..1cc192cfe01 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -3526,6 +3526,7 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color rt->overridden.color = p_color_texture; rt->overridden.depth = p_depth_texture; rt->overridden.velocity = p_velocity_texture; + rt->overridden.velocity_depth = p_velocity_depth_texture; } RID TextureStorage::render_target_get_override_color(RID p_render_target) const { @@ -3587,6 +3588,13 @@ RID TextureStorage::render_target_get_override_velocity_slice(RID p_render_targe } } +RID TextureStorage::render_target_get_override_velocity_depth(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_NULL_V(rt, RID()); + + return rt->overridden.velocity_depth; +} + void RendererRD::TextureStorage::render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_NULL(rt); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 89690498d4c..8db9a565ab1 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -399,6 +399,7 @@ private: RID color; RID depth; RID velocity; + RID velocity_depth; // In a multiview scenario, which is the most likely where we // override our destination textures, we need to obtain slices @@ -791,7 +792,7 @@ public: RID render_target_get_override_depth_slice(RID p_render_target, const uint32_t p_layer) const; virtual RID render_target_get_override_velocity(RID p_render_target) const override; RID render_target_get_override_velocity_slice(RID p_render_target, const uint32_t p_layer) const; - virtual RID render_target_get_override_velocity_depth(RID p_render_target) const override { return RID(); } + virtual RID render_target_get_override_velocity_depth(RID p_render_target) const override; virtual void render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) override; virtual Rect2i render_target_get_render_region(RID p_render_target) const override;