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

Rotating 3D camera parent with physics interpolation make it jump around #101814

Open
Radivarig opened this issue Jan 19, 2025 · 3 comments
Open

Comments

@Radivarig
Copy link

Radivarig commented Jan 19, 2025

Tested versions

Reproducible in 4.4-beta1, 4.4-dev7, not sure for prior versions

System information

Windows 11

Issue description

Rotating camera parent with having physics interpolation enabled on the camera shakes the camera instead of retaining its focus and only interpolating the parent rotation.

Steps to reproduce

Attached is a minimal reproducible project which rotates the camera parent on mouse scroll and a button to toggle camera interpolation for comparison.

Minimal reproduction project (MRP)

rotationbug.zip

@lawnjelly lawnjelly changed the title Rotating camera parent with physics interpolation make it jump around Rotating 3D camera parent with physics interpolation make it jump around Jan 20, 2025
@lawnjelly
Copy link
Member

See the docs:

https://docs.godotengine.org/en/3.6/tutorials/physics/interpolation/
https://docs.godotengine.org/en/3.6/tutorials/physics/interpolation/physics_interpolation_quick_start_guide.html

"Make sure you move objects and run your game logic in _physics_process() rather than _process(). This includes moving objects directly and indirectly (by e.g. moving a parent, or using another mechanism to automatically move nodes)."

You are moving your camera parent outside of _physics_process(), which will cause glitches.

If you change your script to this it works nicely:

var _rot_change = 0

func _input(event: InputEvent) -> void:
...
		if direction:
			_rot_change = direction * sensitivity
			
func _physics_process(delta: float) -> void:
	if _rot_change:
			rotate_y(_rot_change)
			_rot_change = 0

As a tip, if you want to see what is going on with physics interpolation, always test with a low physics tick rate (e.g. 10tps).

I'm not sure the 4.x docs have been copied across yet, so this is understandable.

@Radivarig
Copy link
Author

@lawnjelly I tried your suggestion and got the same result, even more pronounced on lower tick rate so I can screen capture it.

Does this not happen for you on this same project?
Here is the _physics_process version project rotationbug (2).zip

physics_interpolation_rotation_bug.mp4

@lawnjelly
Copy link
Member

lawnjelly commented Jan 21, 2025

Large rotations

Just to note your script is different to what I wrote above.

mine:

_rot_change = direction * sensitivity

yours:

if event.button_index == MOUSE_BUTTON_WHEEL_UP: direction -= scroll_amount
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN: direction += scroll_amount

This means yours will do larger rotations during the tick when your mouse wheel moves several clicks on a tick (this seems when the rotation looks stranger).

If you fix the rotation change to a smaller amount it looks fine, so it looks like the rotation you are using is too much for interpolation to handle on this tick size. Alternatively if you bump the tick rate back up to 60, with your script it is less likely to do a large rotation on a single tick, and you don't see the problem so much.

Phasing and Throbbing

The interpolation breaks down when rotations of more than around 90 degrees are used per tick (depending on whether linear interpolation or slerping can be used internally).

See the issue described here:
#52846 (comment)

This is typically a problem for e.g. helicopter blades, or wheels.

Part of the reason 3D interpolation breaks down with large changes, particularly with pivot relationships is that in 3D only the global transform is sent to the VisualServer (due to historical design) and so interpolation has little to work with and the result is an approximation.

In 2D the entire hierarchy is available for interpolation and it works accurately with pivots. I did offer to investigate changing the 3D to closer to the 2D method but reduz preferred not to change this .. it's a historical snag because interpolation was never foreseen when Godot was first designed.

In these circumstances you are recommended to turn interpolation off for that branch of the scene tree (using the physics_interpolation_mode at runtime, or the Physics Interpolation section of the Node in the inspector), and handle any interpolation manually yourself.

In particular Cameras in 3D, particularly mouse controlled, I recommend to handle manually, there is a special section in the docs for this describing problems and gotchas:
https://docs.godotengine.org/en/3.6/tutorials/physics/interpolation/advanced_physics_interpolation.html#cameras

The very first step when performing manual Camera interpolation is to make sure the Camera transform is specified in global space rather than inheriting the transform of a moving parent. This is because feedback can occur between the movement of a parent node of a Camera and the movement of the Camera Node itself, which can mess up the interpolation.

If necessary with manual interpolation you can even include pivot relationships by calculating and interpolating the whole branch that the camera is on.

Summary

Interpolation does have some quirks and you will gradually learn them by just using it. In places you may want to revert to manual interpolation (or even just not use interpolation at all in some cases). In particular in 4.x, particles has not been dealt with, so if these work it is more by luck than design.

I gather @rburing is starting to look at particles, so this may be easier soon.

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

2 participants