Skip to content

Fix springbones physics interpolation stutter#110032

Merged
Repiteo merged 1 commit into
godotengine:masterfrom
doggamers:springbone-physicsinterp-fix
Mar 11, 2026
Merged

Fix springbones physics interpolation stutter#110032
Repiteo merged 1 commit into
godotengine:masterfrom
doggamers:springbone-physicsinterp-fix

Conversation

@dog-on-moon

Copy link
Copy Markdown
Contributor

When using physics interpolation, springbones do not calculate their target transforms using the correct transform. This causes noticeable stuttering when the skeleton's transform is being influenced by physics interpolation.

Before fix:

godot.windows.editor.x86_64_fsQFeN8k1g.mp4

After fix:

godot.windows.editor.x86_64_fYMlwB9s0F.mp4

Demo project: springbones_stutter_demo_2025-08-27_14-11-43.zip

@dog-on-moon dog-on-moon requested a review from a team as a code owner August 27, 2025 19:17
@Chaosus Chaosus added this to the 4.5 milestone Aug 27, 2025
@Calinou Calinou requested a review from lawnjelly August 27, 2025 22:33
@dog-on-moon

Copy link
Copy Markdown
Contributor Author

Also I think the code here will also need a similar fix (noticed similar jittering with colliders), but Node3D::get_global_transform is const and Node3D::get_global_transform_interpolated isn't (which the compiler is upset about), and I'm not C++ savvy enough to know what the preferred way of addressing it is :P

Transform3D SpringBoneCollision3D::get_transform_from_skeleton(const Transform3D &p_center) const {
Transform3D gtr = get_global_transform();
Skeleton3D *sk = get_skeleton();
if (sk) {
Transform3D tr = sk->get_global_transform();
gtr = tr.affine_inverse() * p_center * gtr;
}
return gtr;
}

@lawnjelly

lawnjelly commented Aug 28, 2025

Copy link
Copy Markdown
Member

Node3D::get_global_transform is const and Node3D::get_global_transform_interpolated isn't (which the compiler is upset about), and I'm not C++ savvy enough to know what the preferred way of addressing it is :P

You may be able to simply make get_global_transform_interpolated() const, this is likely historical from before SceneTreeFTI (might be used by the ifdeffed backup path, but that's just for testing).

This is very probably fine but I haven't looked at all at this class (it may not be present in 3.x), so it could do with checking by someone more familiar with SpringBone3D.

Often things like this are processed on physics tick in which case the non-interpolated is fine, but if this is causing a problem presumably it is being called on the frame. get_transform_interpolated() should work either way and fallback to the normal method if called on a physics tick.

BTW I would also double check this function is not being called on invisible nodes, as get_global_transform_interpolated() can get rather expensive when called on invisible nodes (as the xform has to be calculated through the chain on demand).

@Repiteo Repiteo modified the milestones: 4.5, 4.6 Sep 8, 2025
@Repiteo Repiteo modified the milestones: 4.6, 4.x Nov 19, 2025
@TokageItLab TokageItLab modified the milestones: 4.x, 4.7 Mar 10, 2026
@TokageItLab TokageItLab added the cherrypick:4.6 Considered for cherry-picking into a future 4.6.x release label Mar 10, 2026
@Repiteo Repiteo merged commit fc88f80 into godotengine:master Mar 11, 2026
20 checks passed
@Repiteo

Repiteo commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

Thanks!

@Repiteo Repiteo removed the cherrypick:4.6 Considered for cherry-picking into a future 4.6.x release label May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment