From a4a5f4ed017f90dc1a48d6f926d94f69f5e82494 Mon Sep 17 00:00:00 2001 From: Ansraer Date: Thu, 17 Apr 2025 19:39:53 +0200 Subject: [PATCH] allow moving meshes without motion vectors --- doc/classes/RenderingServer.xml | 7 +++++++ scene/3d/visual_instance_3d.cpp | 1 + servers/rendering/dummy/rasterizer_scene_dummy.h | 1 + servers/rendering/renderer_geometry_instance.cpp | 3 +++ servers/rendering/renderer_geometry_instance.h | 4 ++++ .../render_forward_clustered.cpp | 15 +++++++++++---- .../forward_clustered/render_forward_clustered.h | 7 ++++++- servers/rendering/renderer_scene_cull.cpp | 13 +++++++++++-- servers/rendering/renderer_scene_cull.h | 3 +++ servers/rendering/rendering_method.h | 2 ++ servers/rendering/rendering_server_default.h | 2 ++ servers/rendering_server.cpp | 2 ++ servers/rendering_server.h | 2 ++ 13 files changed, 55 insertions(+), 7 deletions(-) diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 048b024e62f..820563af0e8 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -2046,6 +2046,13 @@ Sets whether an instance is drawn or not. Equivalent to [member Node3D.visible]. + + + + + Resets motion vectors and other interpolated values. Use this [i]after[/i] teleporting a mesh from one position to another to avoid ghosting artifacts. + + diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 9617e0b9127..a40d76dacc6 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -110,6 +110,7 @@ void VisualInstance3D::_notification(int p_what) { if (!_is_using_identity_transform()) { RenderingServer::get_singleton()->instance_set_transform(instance, get_global_transform()); } + RenderingServer::get_singleton()->instance_teleport(instance); RenderingServer::get_singleton()->instance_reset_physics_interpolation(instance); } diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h index 7f42662e874..4e86732d5e6 100644 --- a/servers/rendering/dummy/rasterizer_scene_dummy.h +++ b/servers/rendering/dummy/rasterizer_scene_dummy.h @@ -49,6 +49,7 @@ public: virtual void set_surface_materials(const Vector &p_materials) override {} virtual void set_mesh_instance(RID p_mesh_instance) override {} virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override {} + virtual void reset_motion_vectors() override {} virtual void set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) override {} virtual void set_lod_bias(float p_lod_bias) override {} virtual void set_layer_mask(uint32_t p_layer_mask) override {} diff --git a/servers/rendering/renderer_geometry_instance.cpp b/servers/rendering/renderer_geometry_instance.cpp index 4bdd1ea5a4b..4b3e4c6cedf 100644 --- a/servers/rendering/renderer_geometry_instance.cpp +++ b/servers/rendering/renderer_geometry_instance.cpp @@ -134,6 +134,9 @@ void RenderGeometryInstanceBase::set_cast_double_sided_shadows(bool p_enable) { _mark_dirty(); } +void RenderGeometryInstanceBase::reset_motion_vectors() { +} + Transform3D RenderGeometryInstanceBase::get_transform() { return transform; } diff --git a/servers/rendering/renderer_geometry_instance.h b/servers/rendering/renderer_geometry_instance.h index 94b668291ae..eb613072219 100644 --- a/servers/rendering/renderer_geometry_instance.h +++ b/servers/rendering/renderer_geometry_instance.h @@ -61,6 +61,8 @@ public: virtual void set_instance_shader_uniforms_offset(int32_t p_offset) = 0; virtual void set_cast_double_sided_shadows(bool p_enable) = 0; + virtual void reset_motion_vectors() = 0; + virtual Transform3D get_transform() = 0; virtual AABB get_aabb() = 0; @@ -145,6 +147,8 @@ public: virtual void set_instance_shader_uniforms_offset(int32_t p_offset) override; virtual void set_cast_double_sided_shadows(bool p_enable) override; + virtual void reset_motion_vectors() override; + virtual Transform3D get_transform() override; virtual AABB get_aabb() override; }; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 7268ebea5c7..5848be9d4b1 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1015,7 +1015,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con } } if (p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI || p_pass_mode == PASS_MODE_COLOR) { - bool transform_changed = inst->prev_transform_change_frame == frame; + bool transform_changed = inst->transform_status == GeometryInstanceForwardClustered::TransformStatus::MOVED; bool has_mesh_instance = inst->mesh_instance.is_valid(); bool uses_particles = inst->base_flags & INSTANCE_DATA_FLAG_PARTICLES; bool is_multimesh_with_motion = !uses_particles && (inst->base_flags & INSTANCE_DATA_FLAG_MULTIMESH) && mesh_storage->_multimesh_uses_motion_vectors_offsets(inst->data->base); @@ -1044,9 +1044,9 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con lod_distance = surface_distance.length(); } - if (unlikely(inst->prev_transform_dirty && frame > inst->prev_transform_change_frame + 1 && inst->prev_transform_change_frame)) { + if (unlikely(inst->transform_status != GeometryInstanceForwardClustered::TransformStatus::NONE && frame > inst->prev_transform_change_frame + 1 && inst->prev_transform_change_frame)) { inst->prev_transform = inst->transform; - inst->prev_transform_dirty = false; + inst->transform_status = GeometryInstanceForwardClustered::TransformStatus::NONE; } while (surf) { @@ -4694,12 +4694,19 @@ void RenderForwardClustered::GeometryInstanceForwardClustered::set_transform(con if (frame != prev_transform_change_frame) { prev_transform = transform; prev_transform_change_frame = frame; - prev_transform_dirty = true; + transform_status = TransformStatus::MOVED; + } else if (unlikely(transform_status == TransformStatus::TELEPORTED)) { + prev_transform = transform; } RenderGeometryInstanceBase::set_transform(p_transform, p_aabb, p_transformed_aabb); } +void RenderForwardClustered::GeometryInstanceForwardClustered::reset_motion_vectors() { + prev_transform = transform; + transform_status = TransformStatus::TELEPORTED; +} + void RenderForwardClustered::GeometryInstanceForwardClustered::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; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index a8d0a7b2cfd..745e9aef119 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -544,7 +544,11 @@ private: //used during setup uint64_t prev_transform_change_frame = 0xFFFFFFFF; - bool prev_transform_dirty = true; + enum TransformStatus { + NONE, + MOVED, + TELEPORTED, + } transform_status = TransformStatus::MOVED; Transform3D prev_transform; RID voxel_gi_instances[MAX_VOXEL_GI_INSTANCESS_PER_INSTANCE]; GeometryInstanceSurfaceDataCache *surface_caches = nullptr; @@ -556,6 +560,7 @@ private: 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 reset_motion_vectors() 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_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index b9c6c0863a3..a00b9bfa0a9 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -1044,6 +1044,8 @@ void RendererSceneCull::instance_reset_physics_interpolation(RID p_instance) { Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_NULL(instance); + instance->teleported = true; + if (_interpolation_data.interpolation_enabled && instance->interpolated) { instance->transform_prev = instance->transform_curr; instance->transform_checksum_prev = instance->transform_checksum_curr; @@ -1156,8 +1158,10 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) { } } -inline bool is_geometry_instance(RenderingServer::InstanceType p_type) { - return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_PARTICLES; +void RendererSceneCull::instance_teleport(RID p_instance) { + Instance *instance = instance_owner.get_or_null(p_instance); + ERR_FAIL_NULL(instance); + instance->teleported = true; } void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { @@ -1790,7 +1794,11 @@ void RendererSceneCull::_update_instance(Instance *p_instance) const { } ERR_FAIL_NULL(geom->geometry_instance); + geom->geometry_instance->set_transform(*instance_xform, p_instance->aabb, p_instance->transformed_aabb); + if (p_instance->teleported) { + geom->geometry_instance->reset_motion_vectors(); + } } // note: we had to remove is equal approx check here, it meant that det == 0.000004 won't work, which is the case for some of our scenes. @@ -4204,6 +4212,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) const { _update_instance(p_instance); + p_instance->teleported = false; p_instance->update_aabb = false; p_instance->update_dependencies = false; } diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 924279b9326..2bcbf700b5d 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -412,6 +412,7 @@ public: // This will either be the interpolated transform (when using fixed timestep interpolation) // or the ONLY transform (when not using FTI). Transform3D transform; + bool teleported = false; // For interpolation we store the current transform (this physics tick) // and the transform in the previous tick. @@ -1054,6 +1055,8 @@ public: virtual void instance_set_visible(RID p_instance, bool p_visible); virtual void instance_geometry_set_transparency(RID p_instance, float p_transparency); + virtual void instance_teleport(RID p_instance); + virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb); virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton); diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h index 4bbc609437b..98286045def 100644 --- a/servers/rendering/rendering_method.h +++ b/servers/rendering/rendering_method.h @@ -90,6 +90,8 @@ public: virtual void instance_set_visible(RID p_instance, bool p_visible) = 0; virtual void instance_geometry_set_transparency(RID p_instance, float p_transparency) = 0; + virtual void instance_teleport(RID p_instance) = 0; + virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb) = 0; virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0; diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 748cc3706f8..9967019fda9 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -887,6 +887,8 @@ public: FUNC3(instance_set_surface_override_material, RID, int, RID) FUNC2(instance_set_visible, RID, bool) + FUNC1(instance_teleport, RID) + FUNC2(instance_set_custom_aabb, RID, AABB) FUNC2(instance_attach_skeleton, RID, RID) diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index ef8cc6469bc..d0cb25d3237 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -3172,6 +3172,8 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("instance_set_visible", "instance", "visible"), &RenderingServer::instance_set_visible); ClassDB::bind_method(D_METHOD("instance_geometry_set_transparency", "instance", "transparency"), &RenderingServer::instance_geometry_set_transparency); + ClassDB::bind_method(D_METHOD("instance_teleport", "instance"), &RenderingServer::instance_teleport); + ClassDB::bind_method(D_METHOD("instance_set_custom_aabb", "instance", "aabb"), &RenderingServer::instance_set_custom_aabb); ClassDB::bind_method(D_METHOD("instance_attach_skeleton", "instance", "skeleton"), &RenderingServer::instance_attach_skeleton); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index af8be9db32c..77497022362 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1434,6 +1434,8 @@ public: virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0; virtual void instance_set_visible(RID p_instance, bool p_visible) = 0; + virtual void instance_teleport(RID p_instance) = 0; + virtual void instance_set_custom_aabb(RID p_instance, AABB aabb) = 0; virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0;