Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Physics interpolation (3D): Issue when setting the position of a Rigidbody or Kinematicbody #59173

Closed
FilipLundby opened this issue Mar 15, 2022 · 8 comments

Comments

@FilipLundby
Copy link

Godot version

Godot 3.5 beta 2

System information

Ubuntu 21.10, GLES3

Issue description

When I instance a Rigidbody or Kinematicbody and immediately set the position right after, the object blinks for at least 1 frame before moving to the desired position.

This is not an issue when Physics Interpolation is disabled (Project Settings -> Physics -> Common).

Steps to reproduce

  1. Instance a Rigidbody or Kinematicbody and add it as a child node. Either call_deferred("add_child", body) or add_child(body) - doesn't matter.
  2. Set the position using body.global_transform.origin = Vector3(5, 0, 0)

Minimal reproduction project

Run the game and left-click your mouse.

Godot-3.5.beta2.PhyInt.zip

@lawnjelly
Copy link
Member

lawnjelly commented Mar 15, 2022

See the in progress docs:
https://github.com/lawnjelly/Misc/blob/master/FTIDocs/FTI.md

Specifically this section:
https://github.com/lawnjelly/Misc/blob/master/FTIDocs/FTI.md#call-reset_physics_interpolation-when-teleporting-objects-large-distances

This is expected 👍 and not a bug. This is one of the gotchas of using interpolation, you need to call reset_physics_interpolation() after moving to a new location (teleport) rather than regular movement, in order to prevent this "streaking".

To quote:

Call reset_physics_interpolation when teleporting objects large distances
Although 99% of the time interpolation is what you want between two physics ticks, there is one situation in which it may not be what you want. That is when you are initially placing objects, or moving them to a new location, when you do not want a smooth motion between the two, but an instantaneous move.

The solution to this is quite simple, each Node has a reset_physics_interpolation() function which you can call after setting the position / transform. The rest is done for you automatically.

Even if you forget to call this, it is not usually a problem in most situations (especially at high tick rates), and is something you can easily leave to the polishing phase of your game. The worst that will happen is seeing a streaking motion for a frame or so when you move them - you will know when you need it!

Note: It is important to call reset_physics_interpolation() after setting the new position, rather than before, otherwise you may still see the unwanted streaking motion.

If you add the last line here, the effect is cured:

func _input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT and event.pressed:
			var sphere = _sphere.instance()
			call_deferred("add_child", sphere)
			yield(sphere, "ready")
			sphere.global_transform.origin = Vector3(5, 0, 0)
			sphere.reset_physics_interpolation()

@rburing
Copy link
Member

rburing commented Mar 15, 2022

By the way, you can avoid the deferring and the yielding by setting the correct position from the start, like this:

func _input(event: InputEvent) -> void:
    if event is InputEventMouseButton:
        if event.button_index == BUTTON_LEFT and event.pressed:
            var sphere = _sphere.instance()
            sphere.translation = to_local(Vector3(5, 0, 0))
            add_child(sphere)
            sphere.reset_physics_interpolation()

The "difficult" part of this alternative is using local coordinates instead of global coordinates. In my opinion it's conceptually easier than deferring and yielding. Moreover, it ensures that the object in the physics server is created with the correct values on the first frame. @lawnjelly Why is the reset needed in this case as well (in 3.5 beta 2)?

Edit: In this case I guess the transform is set correctly by the time the physics simulation starts, but even before that the transform is initialized to the identity, and only after NOTIFICATION_PARENTED it is set to the desired value. So it is understandable that the reset is needed.

@lawnjelly
Copy link
Member

@lawnjelly Why is the reset needed in this case as well (in 3.5 beta 2)?

It could either be some transform being set at the origin in the client code, or even just the previous transform in the physics interpolation code is unset on the first tick. So calling the reset_physics_interpolation() is always best practice I think.

@RPicster
Copy link
Contributor

Hm, I'm not sure if this is the right issue to append my problem to, but from my initial search it seems like it.

I am unsure if it is a problem from my side but it seems that adding nodes to the tree in general seems to interpolate from their "original" translation.

So:

var new_thing = Thing.instance()
new_thing.translation = Vector3(300,0,0)
add_child(new_thing)

would interpolate from Vector3.ZERO.
To have the behaviour that I guess most users would expect, I need to do:

var new_thing = Thing.instance()
new_thing.translation = Vector3(300,0,0)
add_child(new_thing)
new_thing.reset_physics_interpolation()

Is that correct?

@lawnjelly
Copy link
Member

To have the behaviour that I guess most users would expect, I need to do:
Is that correct?

Yes, this is correct, adding a new object to the scene (in a location other than the origin) is one of the cases where a reset_physics_interpolation() is needed.

I think at some point I did consider automatically doing a reset_physics_interpolation() when adding to the scene tree, but there are so many cases where this would break down, it might be more confusing than helpful.

In short any time you are instantaneously moving to a new location (teleport, often referred to), including adding to the scene tree you should call reset_physics_interpolation() to prevent "streaking".

@lawnjelly lawnjelly modified the milestones: 3.5, 3.x Dec 13, 2022
@FeralBytes
Copy link
Contributor

@lawnjelly there is no equivalent that I see for Godot 4.0 that is for calling reset_physics_interpolation(), how would I do this in 4.0?

@Calinou
Copy link
Member

Calinou commented Oct 5, 2023

@lawnjelly there is no equivalent that I see for Godot 4.0 that is for calling reset_physics_interpolation(), how would I do this in 4.0?

Physics interpolation isn't implemented yet in 4.x. It's planned, but only after 4.2.

@FilipLundby
Copy link
Author

Closing, cause lawnjelly answered #59173 (comment)

For 4.x see #92391

@Calinou Calinou removed this from the 3.x milestone Jul 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants