godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.15k stars 21.19k forks source link

Reparenting RigidBody2D with physics interpolation enabled causes ghosting #96663

Open blam23 opened 2 months ago

blam23 commented 2 months ago

Tested versions

System information

Godot v4.3.stable - Windows 10.0.22631 - GLES3 (Compatibility) - NVIDIA GeForce RTX 3080 Ti (NVIDIA; 31.0.15.5161) - AMD Ryzen 9 5900X 12-Core Processor (24 Threads)

Issue description

When reparenting a node, and keeping it's global position the same, the physics interpolation will cause a ghosting effect:

https://github.com/user-attachments/assets/ec97e25e-d4f6-474c-b2bc-2084ef747270

Here you can see when the parent node changes, there is a noticable ghosting - note that I have physics ticks per secondturned way down to 10 here to emphasise the issue.

I'm not sure if this is intentional or not - it can be addressed with reset_physics_interpolation (although that adds a bit of a stutter, might be due to very low physics tick rate) but I thought I'd report it here as it could be seen as unexpected as the body is technically in the same position, but with a different parent / local position.

Documentation of reset_physics_interpolation states:

When physics interpolation is active, moving a node to a radically different transform (such as placement within a level) can result in a visible glitch as the object is rendered moving from the old to new position over the physics tick.

I'm not sure I'd count the same global position as a "radically different transform" - I'd understand if the local transform changing radically is the cause of this flicker, I just think it should be explicitly stated.

Steps to reproduce

Minimal reproduction project (MRP)

4.3 project as per video: interpolation-reparent.zip

Sjoerd1988 commented 1 month ago

I'm having the same issue. Calling ResetPhysicsInterpolation() directly after a Reparent() call fixed it for me. But like @blam23 said, this feels more like a work-around than an actual solution.

blam23 commented 1 month ago

To be clear as to what worked for me:

  1. Store global position of child
  2. Remove child from old parent
  3. Add child to new parent
  4. Set global position to stored position
  5. Call child.reset_physics_interpolation()
func swap_parent(body : RigidBody2D, new_parent : Node2D) -> void:
    var pos := body.global_position
    body.get_parent().remove_child(body)
    new_parent.add_child(body)
    body.global_position = pos
    body.reset_physics_interpolation()