Add SkeletonModifier3D IKs as IKModifier3D#110120
Conversation
ffd8842 to
6c2c13b
Compare
|
Cool PR |
ca9d2b8 to
ecc0595
Compare
SkeletonModifier3Ds for IK as ManyBoneIK3DSkeletonModifier3D IKs as ManyBoneIK3D
52af90b to
a3dda7d
Compare
15bbd6a to
3a0315a
Compare
SkeletonModifier3D IKs as ModifierIK3DSkeletonModifier3D IKs as IKModifier3D
|
I have adopted the name IKModifier for the base class.
@ettiSurreal Considering the possibility that SkeletonIK may become available in Godot 5 and rename this to that, I assume the child classes can remain as-is. @AThousandShips Thank you very much for the large amount of proofreading. I appreciate it, as reviewing this much must have taken a lot of time. Regarding line break spacing, it wasn't marked as outdated since diffs don't detect it, but I should have fixed it. |
3a0315a to
bf22eb2
Compare
|
Thank god for this. LookUpModifier3D ain't it. |
|
Let's combine this with master! |
|
Thanks! |
|
@TokageItLab Also, if SkeletonIK3D does get removed in the future, I think we should just keep "IKModifier3D" as this modifier's name. I think it works better than "SkeletonIK3D", is more consistent with other modifiers, and by that point users will be used to the name of the new modifier. |
@jitspoe As I mentioned in the description, we consider this to be the role of BoneConstraint rather than IK, so it is supplemented by #110336. Another possible cause is when the change of the bone pose position or scale from the bone rest is included in the chain, but that needs to be supplemented by #111815. FYI, in FABRIK, setting the |
|
Try this: I made a simplified example. SkeletonIK3D goes straight to the target, but the FABRIK3D meanders and twists around. |
|
@jitspoe As mentioned above, meanders twisting is related to the angular delta limit.
The old SkeletonIK has no rotation limit per iteration, making it equivalent to setting an 180-degree angular delta limit. And another difference between old SkeletonIK vs IKModifier3D's FABRIK is whether it is deterministic or not (IKModifier3D's FABRIK is non-deterministic). As mentioned in #110120 (comment), resetting rotation every frame to the rest makes deterministic results. But this increases the number of calculations required to reach the result, depending on the angular delta limit, impacting performance. In other words, after resetting the rotation in the beggining of the each frame, if the angular delta limit is set too small with less iteration, the end bone will never reach the target, no matter how many frames are progressed. However, in cases without the limitations mentioned above, such as setting the angular delta limit to 180 degrees, performance should not be significantly affected (since a large number of iterations is not required). Therefore, I believe deterministic behavior can be added as an option (I already discussed this with @lyuma during the review meeting). |
|
@jitspoe @ettiSurreal @lyuma I sent a PR #112524 to add deterministic option, so you can test it. |
|
@jitspoe The JacobianIK requires a small angular delta limit for stable results, so this is expected behavior (although the behavior outside the range might be stabilized a bit more). I assume we should document the recommended settings somewhere. Edited: Godot.Engine.2025.11.09.-.16.07.52.04.mp4 |
|
Hi I'm currently using Godot 4.6 dev 4, and I'm doing some tests for the new IKs system. While I'm pretty happy with the results when it comes to bones positioning, I don't see anything related to rotation (For example, rotating the hand of a player model in a way the entire arm will react to the changes of the hand) . I wanted to know if I'm missing something or if it's not in the scope of this PR in the first place. Thanks ahead! |
|
@YahelBaram That is considered more the role of BoneConstraint than IK, and we agreed it upon during the animation meeting. For example, when the twist axis is +Y, the propagation of hand rotation can be fulfilled by transferring the +Y rotation of the hand to the +Y axis rotation of the LowerArm/UpperArm using BoneConstraint(Copy/ConvertTransformModifier3D). See also #100984, #110336 and #111367.
When propagating a child's rotation to its parent using constraints, a final constraint for canceling by self-references is required (as above image, processing the sequence that UpperLeg 0.25 of Foot -> LowerLeg 0.5 of Foot -> Foot -0.75 of Foot), but it should work as intended as long as the rotation does not exceed 180 degrees from rest. |
|
Hi I've been playing around with TwoBoneIK3D in 4.6 dev 4, and it's been working great so far. However, today I built master from commit 235a32a to test out #110336 and some other changes, and now TwoBoneIK3D logs repeatedly: @TokageItLab have you tested TwoBoneIK3D against a more recent master? If it's not happening in your tests, let me know and I can put together an MRP. I built Godot with: System info: |
|
@x0r-b0t It seems to be an issue with the dynamic bone axis direction calculation by mutable_bone_axis. I'll take a look. Edited: |







Add several IK modifiers. As the nameTentatively it now named asSkeletonIK3Dconflicts with an older node, I will adopt the provisional nameManyBoneIK3D. Considering that the LookAtModifier targets only a single bone, I think this is a reasonable name.IKModifier3D.ManyBoneIK3D has the following extended classes:
There may be demand for FullbodyIK3D, but for now, this PR aims to fulfill the need for SkeletonModificationStack3D which was removed from 3.x to 4.0. (So don't close - godotengine/godot-proposals#6039)
I expect that FullbodyIK3D could be implemented in the future by extending one of the base classes. Until then, I assume PhysicalBoneSimulator can serve as a substitute in some extent.
Also this PR includes refactoring to unify enums for bone direction among some SkeletonModifiers.
IKModifier3D
It has a virtual method for having multiple configurations and a virtual bone structure for simulating IK to be able to hold poses and rests separately from the Skeleton.
TwoBoneIK3D
It provides deterministic results by constructing a plane from each joint and pole target and finding the intersection of two circles (disks in 3D). This IK can handle twist by setting the knuckle direction.
tbik.mp4
If there are more than one bones between each set bone, their rotations are ignored, and the straight line connecting the root-middle and middle-end joints are treated as virtual bones.
Godot.Engine.2025.08.30.-.22.29.34.06.mp4
ChainIK3D
It has a virtual method that generates a chain by setting root bone and end bone.
SplineIK3D
This IK aligning bones on Path3D. Bone twist is determined relatively based on the curve's tilt.
Godot.Engine.2025.08.30.-.22.29.34.05.mp4
If the root bone joint and the start point of Curve3D are apart, it assumes that there is a linear line segment between them. If the end bone joint exceeds the path length, bend the first joint exceeding the path length as close as possible to the end point of the Curve3D, and from there it is extended straight ahead - it should look almost the same as Blender's SplineIK.
IterateIK3D
It has a virtual method to approach the goal by repeating small rotations.
Godot.Engine.2025.08.30.-.22.29.34.04.mp4
Each bone chain (setting) has one effector, which is processed in order of setting list. You can set some limitations for each joint.
Limitations currently only support rotation axis and cone shapes. You can set arbitrary rotation offsets on each joint. BTW, there is potential for future reuse in SpringBone (ref. vrm-c/vrm-specification#496). Also I expect that kusudama shapes like godotengine/godot-proposals#11208 will be added in the future.
Known issue
Moving the position breaks the rendering of the Limitation gizmo because binding to position alone is impossible. To fix it, an approach such as canceling rotation within the shader like godotengine/godot-proposals#9735 is required. Currently, it is drawn by a hack to bind the limitation to the parent joint. See also #111815.
Incompatibility with old SkeletonIK3D
Regarding the pole target (magnet), I tried implementing it but finally decided against it because I couldn't stabilize it. This was due to strong conflicts with limitations and the difficulty in acquiring good results with solvers other than FABRIK. Even with FABRIK (both the version implemented this time and the current SkeletonIK3D), it is difficult to consistently obtain ideal results.
For these purposes, I determined it is more appropriate to use IK that can deterministically control direction, such as the TwoBoneIK and SplineIK described above, depending on the use case.
If someone needs a magnet no matter what, it possibly could be added later as a follow up PR. (If it can be stabilized)
If you want rotation on a plane, you can set the RotationAxis for absolute axis specification. For dynamic planes, you can use a LookAtModifier to orient the chain root specific (knuckle) axis to secondary (or same) target before IterateIK, which should achieve that. In other words, probably the general (other software's) chain IK's pole is processed in this way - only determining the twist of the first joint.
Also, omitted the functionality to apply the target's rotation to the tip. If we needed, the correct approach should be to allow users to specify a node in BoneConstraint3D (CopyTransformModifier3D) for arbitrary rotation transformations, rather than hard-coding it into the IK. See also #110336.
Demo project
ik_test.zip