Add BoneSpreader3D & skin_scale property to Bone in Skeleton3D#120609
Add BoneSpreader3D & skin_scale property to Bone in Skeleton3D#120609TokageItLab wants to merge 2 commits into
BoneSpreader3D & skin_scale property to Bone in Skeleton3D#120609Conversation
|
This pull request reminds me of fbx-maya ssc http://forum.mgear-framework.com/t/how-to-prevent-shear-on-joints/3252 I had an absolute nightmare for several years with re-implementing ssc (segment scale compensation) in fbx-maya. Can you confirm? |
|
@fire This PR implements a different approach from Segment Scale Compensate. Rather, the PR by #83903 is attempting to implement something like Segment Scale Compensate. As explained in the description, I considered Segment Scale Compensate to have consistency issues with coordinate calculation systems in Godot's Node3D and other classes (such as Node2D/Skeleton/Physics/glTF IO/etc.), so #120610 and this PR as one approach to address the need to "dynamically change the thickness of bones (and skins)". |
|
I'm a bit confused, does this mean we'd still need to update the rest bone positions to match the scale if we plan to stretch the bone? Or just updating the scale on the correct axis + pushing the child's position further on that axis would visually do it? |
|
For example, in a case where there is only one child on the Y-axis, you simply offset the child’s position along the Y-axis.In the method using Constraints, there is a demo that uses However, in 1-vs-N cases like the "Hand", more calculations (although The reason the BoneExpander implementation stalled previously was that attempting to perform skin deformation within the SkeletonModifier caused instability. I believe it would be safe if the Skeleton handled skin scaling, while the BoneExpander only modified the bone positions. |
skin_scale property to Bone in Skeleton3DBoneSpreader3D & skin_scale property to Bone in Skeleton3D
|
I added "BoneExpander3D" now renamed "BoneSpreader3D". When using this modifier, positional shifts in the BoneEditor/IK Gizmo are tracked as a separate issue as #117350, but there should be no problems with script control or runtime behavior.
BTW, since I reused the BoneExpander icon from when it was used for deforming Skin, it might be a little confusing as the icon for a "Repositioning" modifier. I’ll reconsider the icon later. |
|
What a coincidence. Just four days ago, I was trying to solve a problem in my project related to how to improve character customization by changing the player's height, head size, leg length, and everything else that can't be changed using Blend Shapes in Blender. If I understand correctly, this PR can solve these problems? |
|
@JekSun97 To be honest, it depends on your use case. For example, I think this feature would be useful in applications where the length of the arms and legs changes depending on the character's status. However, if you want to create a character model in Godot and export it or cases involving static scaling such as character creation, it generally makes more sense to set the bone pose scale to a pose like the T-pose and then bake (with a function similar to applying scale in Blender) it to bone rest, not the skin. Well, while this feature is primarily designed for dynamic scale changes, but it should work just fine if you’re not concerned with exporting or similar considerations. |

What problem(s) does this PR solve?
When scaling is applied to a bone, children inherit the parent’s scale. Some ideas have been proposed in #83903 and #79364 (comment) to remove this inheritance, but that would break consistency with Node3D’s calculation method and create new problems dependent on whether inheritance is enabled or not. We can state with almost certainty that no such change will occur, at least until Godot 5.
However, the issue of scaling being difficult to handle remains, so this PR will address for that case in some extent.
This PR will add
SkinScaleas a property of the bone. This will allow us to change only the visual scale of the skin bound to the bone without affectingbone_pose. This approach was discussed with @lyuma before.Since
SkinScaleis calculated only when passing skin information to the rendering server during bone updates, this scaling will not be retained on theMeshInstance’s skin resource side. Ifskin_scaleis a Vector3(1, 1, 1), a boolean cache is maintained to avoid calculating the scaling.If there is a drawback compared to applying scaling directly to
bone_pose, it is that this method cannot be used to change the length of the bone. In other words, the position of child objects will not synchronize with the scaling applied byskin_scale.If you want to synchronize the child’s position, you can convert the scaling along the parent-to-child axis to a position and set it to the child’s
bone_pose_positionto achieve synchronization with the scaling. Even without that, this approach should be sufficient usable for applications where you simply want to change the thickness without change bone structures.Edited:
I added a BoneSpreader to adjust the positions of child bones. We should not change the skin within the SkeletonModifier. However, this is safe because the roles are clearly separated, like "the Skeleton modifies change the skin" and "the SkeletonModifier modifies change the bone position".
Additionally, since this involves moving the position rather than scaling from the sight of bone transform, it is compatible with IK.
BTW, you must be careful when using this with RetargetModifier in retargeting mode. In cases where this feature is used, it is probably better to use the OverwriteRest retargeting method, which does not use RetargetModifier. If you absolutely must use RetargetModifier, you need to be careful about synchronizing the SkinScale between GeneralSkeleton and OriginalSkeleton.