Skip to content

[3.x] Physics Interpolation - Add 3D helper for using servers directly.#112119

Open
lawnjelly wants to merge 1 commit intogodotengine:3.xfrom
lawnjelly:fti_instance_helper_new
Open

[3.x] Physics Interpolation - Add 3D helper for using servers directly.#112119
lawnjelly wants to merge 1 commit intogodotengine:3.xfrom
lawnjelly:fti_instance_helper_new

Conversation

@lawnjelly
Copy link
Copy Markdown
Member

Also uses the helper to provide FTI for debug collision shapes.

Fixes #110824 (for 3.x)
Supersedes #104518
(This PR seems a little easier to use than #104518, and the PR is a bit more polished, and handles debug collision shapes as an example.)

Introduction

#103685 by design removes server side physics interpolation, which has the side effect of removing in-built physics interpolation for users who create 3D nodes directly using servers, rather than via SceneTree nodes, and ideally we don't want these users to feel they are "losing out".

This use case is far simpler than SceneTree interpolation, because only global xforms need be supported.

There are several options to deal with this area, including:

  1. Provide no engine support and leave it to users (as was the case before physics interpolation PRs)
  2. Provide support via an addon
  3. Provide a simple helper in engine code to make this task much easier

This PR provides a simple solution for (3) for instances on the server, via a wrapper object called fti_instance.
It should be fairly simple to use, although admittedly there are a couple more lines to type than the old system.

The fti_instance is created in VisualServer like an instance, and it creates a regular instance internally.
Then the user should call fti_set_transform() on the fti_instance instead of instance_set_transform(), and can call fti_instance_reset() to reset physics interpolation.

All the regular instance functions can be called after retrieving the regular instance via fti_instance_get_instance().

Everything else should work automagically. Nearly everything in 3D works via instances so this should cover most cases. Cameras are not covered and would have to be interpolated manually, but as far as I remember this was also the case before #103685.

Model at 5 ticks per second with FTI

2025-04-03.09-27-22.mp4

Usage Example

# VisualServer expects references to be kept around.
var _mesh
var _instance
var _fti_instance
var _time = 0

func _enter_tree():
	# Create an FTI instance and link it to the actual instance,
	# so we can use the interpolation functionality.
	_fti_instance = VisualServer.fti_instance_create()
	_instance = VisualServer.fti_instance_get_instance(_fti_instance)
	
	# Set the scenario from the world, this ensures it
	# appears with the same objects as the scene.
	var scenario = get_world().scenario
	VisualServer.instance_set_scenario(_instance, scenario)
	
	# Add a mesh to it.
	# Remember, keep the reference.
	_mesh = load("res://Model/scarab.obj")
	VisualServer.instance_set_base(_instance, _mesh)
	
func _exit_tree():
	# Make sure to free rids when we are finished,
	# to prevent memory leaks.
	VisualServer.free_rid(_fti_instance)
	_fti_instance = RID()
	_instance = RID()

func _physics_process(delta):
	_time += delta

	# Move the model around.
	VisualServer.fti_instance_set_transform(_fti_instance, Transform(Basis(), Vector3(sin(_time) * 4, 0, 0)))
	
	# Test resetting.
	if Input.is_action_just_pressed("ui_accept"):
		VisualServer.fti_instance_reset(_fti_instance)

Notes

  • This also applies in 4.x so a port can be made once we have decided to go ahead.
  • I did test making the multithreaded versions of the functions just act single threaded and push the wrapped commands directly on the queue, but I don't think this should be necessary as the queue can add commands to the tail while being processed, and I don't see any obvious reason the ordering should matter. If there are any problems in the wild though it's fairly easy to change (and it won't cause anything catastrophic, worst case some jitter in multithread mode).
  • There are several ways of doing this. This is the second version after [3.x] Physics Interpolation - Add 3D helper for using servers directly. #104518, that version left managing the lifetime of the instance to the user, whereas this version handles the instance lifetime automatically.
  • One downside is that calling instance_get_instance() can possibly cause a stall as it is retrieving data from the server, but it should be called as a one off when creating the fti_instance.
  • I haven't found a straightforward way of combining this and returning both RIDs in the create_fti_instance() call, however I'm welcome to suggestions. (The existing create functions assume returning a single RID. It is just possible we could add a specific macro for this case, but I'm not sure it is worth it.)

Also uses the helper to provide FTI for debug collision shapes.
Copy link
Copy Markdown
Member

@Calinou Calinou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested locally, it works as expected. Code looks good to me.

The fti_ naming prefix for functions looks a bit strange to me though. It's not a standard acronym that is used often outside of Godot, and we call it "physics interpolation" elsewhere already. I would just name these functions interpolated_, e.g. interpolated_instance_reset().

It may be worth adding a project setting to disable debug shape interpolation as well, but this can be decided in a future PR.

Debug collision shapes at 10 TPS:

Before

fti_before.mp4

After

fti_after.mp4

@lawnjelly
Copy link
Copy Markdown
Member Author

lawnjelly commented Nov 2, 2025

On the naming, I wrote a little on this subject here:
https://x.com/lawnjelly/status/1951575972689416420

Key things in naming imo:

  • Don't name things for what they are not (e.g. physics interpolation)
  • Don't use ambiguous names. Interpolation is used in multiple places in game engines (interpolated cameras, tweens, etc etc). We are referring to a specific type of interpolation, fixed timestep interpolation

This is why I'm trying to push for at least internally using the correct fixed timestep interpolation terminology.

It is the standard way of referring to fixed timestep interpolation:
https://letmegooglethat.com/?q=fixed+timestep+interpolation

i.e. The correct term for fixed timestep interpolation IS fixed timestep interpolation. (The term was popularized by Gaffer on Games article 2004ish?), but the technique was in use beforehand, we used it certainly from 2000/2001 and I remember teaching it to our tech guys at the time (who then went on to use it at other companies), I probably read it from flipcode or similar).

Imo we have the choice of either doubling down on the misnaming and using physics_interpolation, or using fti internally, as we do for SceneTreeFTI etc.

I actually had a look with Grok to find where I might have read it originally, and it didn't find much before 2004 initially, but with some prompting it found some articles by Tom Forsyth on flipcode from Jan 2002, and certainly I read a lot of Tom's stuff at the time (one of my friend's worked at same company if I remember right). If I remember I read at least 3 / 4 articles on it even back then, and got the impression it had been in use from at least the late 90s.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants