Skip to content

Conversation

lawnjelly
Copy link
Member

@lawnjelly lawnjelly commented Apr 2, 2025

Adds framework for InterpolatedProperties.
Adds interpolated properties to Camera.

Interpolates:

  • Perspective (fov, near, far)
  • Orthogonal (size, near, far)
  • Frustum (size, frustum_offset, near, far)

Implements godotengine/godot-proposals#9964 .

Notes

  • The move from server to scene side FTI makes this far easier.
  • Camera provides a good test case for adding some custom interpolated properties.
  • We could do all of it manually, but it makes some sense to create a helper template to reduce boiler plate.
  • The InterpolatedProperty emulates the underlying type (for when FTI is off), but has some extra functionality available.
  • Standardizes the use of fti_pump() for more reset functionality in Spatial derived classes.
  • Automatically responds to reset_physics_interpolation() user calls.

Discussion

While implementing this I made some minor adjustments to SceneTreeFTI to better support properties.

Properties aren't inherited and concatenated like scene tree xforms, so it turned out these are more efficient to handle separately.

  • They only need to be updated once per frame (at the end) instead of two passes.
  • They can maintain their own frame update list, instead of checking each node in the SceneTree, as often only a few nodes will need properties interpolating.
  • Nodes when notifying changes now indicate via a bool whether the changes are to the transform, or to properties. In most cases transforms are already handled by the Spatial base class, so in most custom cases in the future contributors will be notifying custom property changes.

fti_pump and fti_update_servers

One slightly controversial change it that fti_pump() and fti_update_servers is now separated into two versions - for xforms and for properties.

As far as I can see this is the most efficient way of handling it, even if it may look slightly more confusing in say the Camera class, where we have to update servers for both xform and properties.

An alternative would be to send e.g. a bool with the two routines, however there is more opportunity to "shoot yourself in the foot" with that approach, particularly regarding calling the parent class routines.

In practice, most classes that custom interpolate will only be updating properties, and will rely on Spatial for xforms, so will only have to implement fti_pump_property() and fti_update_servers_property() - Camera is to some extent an anomaly and a worst case situation, so good to handle first.

@lawnjelly lawnjelly added this to the 3.7 milestone Apr 2, 2025
@lawnjelly lawnjelly force-pushed the fti_interpolated_prop branch 7 times, most recently from 83f3ac7 to 80d8496 Compare April 3, 2025 06:59
first_print = false; \
} \
} else \
((void)0)
Copy link
Member Author

Choose a reason for hiding this comment

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

Note: I just changed this to be slightly more efficient in the case of slow checks.

It now checks the static before doing the condition, so once it has triggered the first time, it no longer does the condition check.

@lawnjelly lawnjelly marked this pull request as ready for review April 3, 2025 07:33
@lawnjelly lawnjelly requested review from a team as code owners April 3, 2025 07:33
Copy link
Member

@rburing rburing left a comment

Choose a reason for hiding this comment

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

This looks quite nice from the API perspective, and I appreciate the defensive dev checks.

I'll have to defer to you for the implementation. I can say it looks believable.

T prev;

public:
void pump() {
Copy link
Member

Choose a reason for hiding this comment

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

I'm not familiar with the term "pump" in this context. Is it a common name for this operation?
How about adding a comment? Or maybe a more descriptive name like snap_to_current_value / jump_to_current_value?

Copy link
Member Author

Choose a reason for hiding this comment

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

Naming is always one of the most difficult problems in programming 😁 .. I've tried a few different names for this over the years but currently am tending towards pump or fti_pump. It essentially acts like a pump, on every tick you are moving current values over to previous values (it is also sometimes reused for reset, but resetting refers to the intention in a specific circumstance, not the mechanism).

(This is also why teleport is imo a better naming than reset_physics_interpolation, because it makes the intention clear, whereas reset is very vague and users often get confused about it.)

This pump is the core of how fixed timestep interpolation works, it relies on maintaining a continuous flow of previous and current transforms / properties / whatever, and then interpolating between them using the interpolation fraction.

I'm happy to put some more comments in.

snap_to_current_value / jump_to_current_value I'm not sure describe what is going on, I for one have no idea what they are referring to (and I've been using FTI for 25 years lol 😁 ).

Copy link
Member Author

@lawnjelly lawnjelly Apr 7, 2025

Choose a reason for hiding this comment

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

Actually thinking about it, it may be possible to use fti_tick() here, let me have a look through.

Hmm, not absolutely sure tick is an improvement, as fti_pump() is also used for resets, and not just ticking, so in exchange for a more familiar name we would be introducing an element of confusion. What happens if we start requiring users / contributors to call tick() outside of ticks?

I'm tending towards preferring sticking with bespoke terminology for physics interpolation, because in retrospect I think Juan fell into the same trap here with this desire to use "familiar" words:

  • "FTI" became "physics interpolation" - caused confusion because it is nothing to do with physics
  • "teleport" became "reset physics interpolation" - again users have no idea what this does or when to use

And add some basic interpolated properties to Camera.
@lawnjelly lawnjelly force-pushed the fti_interpolated_prop branch from 80d8496 to 18c01b2 Compare April 7, 2025 07:19
@lawnjelly
Copy link
Member Author

Have pushed some changes in response to the suggestions:

  • Moved the lerp functions to InterpolatedProperty (actually in a namespace so they could be in the cpp to avoid header includes, as InterpolatedProperty itself is a template)
  • Fixed up the == and != operators
  • Added some more comments to the pump functions
  • Changed interp() to interpolated()

@lawnjelly lawnjelly merged commit 383ecda into godotengine:3.x Apr 7, 2025
14 checks passed
@lawnjelly lawnjelly deleted the fti_interpolated_prop branch April 7, 2025 12:25
@lawnjelly
Copy link
Member Author

Thanks!

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.

3 participants