Help me understand Skeleton3D modifier callback mode. How to get accurate bone position in the _process_physics?

Godot Version

Godot 4.6.1 stable

Question

Hi! Question might be two fold, I am more interested in second half, so don’t get too caught up on the first two paragraphs, they are mostly there to provide motivation for making this post.

This might be a bug(unlikely). So do tell me if it is, or if its an intended limitation of godot, I am not 100% sure so I am posting here first.
I have a skeleton3D with an IK constraint. The IK constraint doesn’t guarantee the target bone reaches it. I want to update another object to always hit the target bone, this seems to not be possible to do in the _physics_process(think of a auto targetting bullet(or an activeragdoll for a more complicated example which i had)(or a character with a gun which a modifier for rotation of a torso, and you want the bullet to be synchronized with the world view of the character, so you cant just shoot at the marker since the character might not be able to twist that far)). I have found a workaround to achieve this effect by saving delta from _physics_processto a variable and then updating the velocities in the skeleton_updated signal. This feels yucky and prone to breaking(besides it being 1 frame late).

Now to the important part:
Intuitively the Skeleton3D.modifier_callback_mode_processsounds like the thing i need to change, however upon changing it, I noticed exactly no difference between them. I did also change AnimationPlayers callback mode to match the one in the Skeleton3D since modifiers have to run after the animation(even though I didn’t play animations). Glanced at the source code and the process callback mode is used(so its implemented), I am just unsure how it changes things.

Here are results from MVP project I made.

Red shape changes its global_position in _physics_processwith a priority of 100 to be that of a target bone, green shape in the signal, yellow shape in the _process. For manual callback Skeleton3D.advance(delta) is called in _physics_processwith a priority of 0. The position that yellow and red shape end up below is the position of the target bone before the IK is applied.

Here are the results I expected:

I’m not an expert and I wouldn’t be able to tell you all the details of how exactly processes and internal and deferred processes work and how they are ordered, but intuitively this is how I think it should work.

I would greatly appreciate if someone could tell me what Skeleton3D.modifier_callback_mode_process affects and when to use it. Aaand if its possible to get accurate bone transforms inside of a physics process, for the gameplay purposes since well iks are really helpful there sometimes.

P.S whoops it seems like I can’t upload my MVP project if anyone wanted to take a peek(only allows images), this is a right place to ask this question, right?

(p.s. i did read Design of the Skeleton Modifier 3D – Godot Engine and understand that modifiers run in the deferred process and after animation, i just expected at the very least manual override to process the bones instantly to get accurate positions. Well In general I just expect the process callback parameter to work similarly to the animation one. After writing this all out it does seem like this is a limitation of the engine, process callback mode means you run modifiers deferred every visual frame, physics means deferred every physical one, but i still can’t quite understand what manual means then, upon calling advance() nothing happens and then in the deferred process it gets called, what if i call advance() twice, will the non deterministic IK do two steps instead of 1 or still just one then.)

I think I figured it out, mostly for ppl who also stumble on this later.
I thought about it more and it does seem to all happen in the deferred process like the web page describes.
Completely missed the Note:Thedeltais temporarily accumulated in theSkeleton3D, and the deferred process uses the accumulated value to process the modification.from the docs for the advance(delta) function.

So I’m like 90% sure it does very little, just makes a deferred call either in physics process or idle process.

WHIIIIIICHH is still very confusing to me for why this parameter even exists since the deferred calls seem to only be processed after the _process for whatever reason(i was under the assumption that physics tick happened before process tick and deferred calls could be evaluated after, but seems to not be the case).

So yeah modifying physical variables inside of a _physics_process that depend on the actual post-modifications bone position seems to be impossible. Saving delta and modifying them in the signal seems to be the next best thing, which is unfortunate, as that feels unsafe(changing physics variables outside of _physics_process).

Do correct me if I’m wrong and came to the wrong conclusions, because what I came to is that the parameter practically does nothing and that’s intended.

If you want to attach an object to a bone you can use the BoneAttachment3D node or the ModifierBoneTarget3D node if you want to chain in into your skeleton modifiers to apply its modifications to other modifiers.

If you want to get the bone pose after the modifier has been processed you’ll need to listen to the SkeletonModifier3D.modification_processed signal. You can use Skeleton3D.get_bone_pose() or Skeleton3D.get_bone_global_pose() to get the pose of the bones at that point in the skeleton modifier chain. You can also listen to Skeleton3D.skeleton_updated to get the final pose of the skeleton.

Yeah, I mean that’s what I mentioned I currently do. I am unhappy with it because I’m basically modifying physics variables like velocities in the deferred process by doing this method, this is 1 frame late(not a big deal), I’m mostly just worried about modifying physics stuff outside of the physics tick, something tells me that is prone to errors.

But, yup, I think there is no other way to do it.
What I ended up doing in the end is saving the last seen bone transforms from Skeleton3D.skeleton_updated to a variable, and using that in the physics tick, this way my physics logic is being updated in the physics tick and just lags behind by 1 frame.

edit: continuing to work with this approach and its really unwieldy, wish godot had a way to force calculate all the modifications