-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix SkeletonModification2DTwoBoneIK with negative scales. #81051
base: master
Are you sure you want to change the base?
Fix SkeletonModification2DTwoBoneIK with negative scales. #81051
Conversation
b8b6998
to
48ff535
Compare
joint_one_bone->set_global_rotation(angle_atan - angle_0 - joint_one_bone->get_bone_angle()); | ||
joint_two_bone->set_rotation(-Math_PI - angle_1 - joint_two_bone->get_bone_angle() + joint_one_bone->get_bone_angle()); | ||
} else { | ||
joint_one_bone->set_global_rotation(angle_atan + angle_0 + joint_one_bone->get_bone_angle()); | ||
joint_two_bone->set_rotation(-Math_PI - angle_1 - joint_two_bone->get_bone_angle() + joint_one_bone->get_bone_angle()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, but it feels like you could keep the general else block from before commit then handle both cases at once:
- for the first line, a -1/+1 multiplier would do the trick
- the second line is always the same, could be preserved at end of else block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About the first point, you mean creating a variable to hold -1 ou 1, them multiplying angle_0 + joint_one_bone->get_bone_angle()
by the variable? Can you show me what you mean?
About the second point, like this?
if (isnan(angle_0) || isnan(angle_1)) {
// We cannot solve for this angle! Do nothing to avoid setting the rotation (and scale) to NaN.
} else {
if (same_scale_sign) {
joint_one_bone->set_global_rotation(angle_atan - angle_0 - joint_one_bone->get_bone_angle());
} else {
joint_one_bone->set_global_rotation(angle_atan + angle_0 + joint_one_bone->get_bone_angle());
}
joint_two_bone->set_rotation(-Math_PI - angle_1 - joint_two_bone->get_bone_angle() + joint_one_bone->get_bone_angle());
}
EDIT: I agree in letting the second line at the end of else
block so I'm changing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, using a float multiplier like this:
float sign_multiplier = same_scale_sign ? -1.0f : 1.0f;
joint_one_bone->set_global_rotation(angle_atan + sign_multiplier * (angle_0 + joint_one_bone->get_bone_angle()));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But looking at your comment below, else
looks fine too.
} else { | ||
joint_one_bone->set_global_rotation(angle_atan + joint_one_bone->get_bone_angle()); | ||
joint_two_bone->set_global_rotation(angle_atan + joint_two_bone->get_bone_angle()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same remark here except you already got a big else block so you'd just have to use the sign multiplier to factorize.
Unless there's a particular policy on this file that developers prefer explicit full line operations with +/- rather than -1/+1 multipliers to make it easier to read? I haven't checked other math code so I don't know what style they picked.
EDIT: I'd say it is indeed very clear on this block because all the lines are uniform and the +/- symbols perfectly aligned; while above, the global_rotation and rotation lines are alternating so it's not that easy to spot what's different.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm holding back with this because could impact the readability and I really want to maintain clear which is the main logic and which is the exception (different scales).
I don't think that would be easy to understand from something like this:
angle_atan + joint_one_bone->get_bone_angle() * rotation_dir
Or this:
angle_atan + (angle_0 + joint_one_bone->get_bone_angle()) * rotation_dir
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, you can keep the else case then. In this case, for consistency you can also keep the else case above and don't use a multiplier. You can add a comment indicating which one is the more rare case if you want.
48ff535
to
fc845ce
Compare
- Identifies when only one scale axis is negative and change the logic - Take in count scales when drawing gizmo - Fix typo
fc845ce
to
3e02983
Compare
can this be pushed as patch update.. the ik bug is making the ik chain unusable |
I'm not actually happy with this solution (using |
float bone_one_length = joint_one_bone->get_length() * MIN(joint_one_bone->get_global_scale().abs().x, joint_one_bone->get_global_scale().abs().y); | ||
float bone_two_length = joint_two_bone->get_length() * MIN(joint_two_bone->get_global_scale().abs().x, joint_two_bone->get_global_scale().abs().y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part is attempting to give scale to bones length and could probably be solving by calculating length
with scale: #83397 (comment)
is there anything blocking this PR as of now? |
Is better to wait someone with knowledge like @TokageItLab to review |
Since TwoBoneIK is separated from any other node in the first place, so the change should be safe, at least from a code standpoint. Also, if this change is mainly dedicated to flips due to scaling, then there seems to be fine. I am a little concerned about whether it will work well when combined with the #91731 fix. If we can confirm that much, I think it is safe to merge. BTW, since the ModificationStack2D is experimental to begin with, so I think in the future it will be necessary to migrate into SkeletonModifier2D in the same way as the SkeletonModifier3D. |
Is this plan for 4.3 or 4.4? |
@TokageItLab We can review this for 4.4 |
The pull request became stale and requires a rebase. @SaracenOne, @TokageItLab, @fire and Cthulhu discussed this briefly at the animation meeting. We discussed the problems with using the scale to flip 2d and 3d animation in general. We wanted a proposal for modifying the godot human skeleton profile to add a hard-defined mirror boolean for regular and mirrored left hand to right hand. |
There is a list? All I know is that is not possible to differ 2D matrices that had X scaled by -1 from those that had Y scaled by -1 and rotate by 180º. At least not without a variable to store this information.
I don't understand how this would work under the hood. There is a change in "modification" logic? Or would be something like: if (!mirrored) {
joint_one_bone->set_global_rotation(angle_atan - angle_0 - joint_one_bone->get_bone_angle());
} else {
joint_one_bone->set_global_rotation(angle_atan + angle_0 + joint_one_bone->get_bone_angle());
} Instead of my propose: if (same_scale_sign) {
joint_one_bone->set_global_rotation(angle_atan - angle_0 - joint_one_bone->get_bone_angle());
} else {
joint_one_bone->set_global_rotation(angle_atan + angle_0 + joint_one_bone->get_bone_angle());
} |
Issues: #80252
This is an attempt to fix
SkeletonModification2DTwoBoneIK
when only one scale is negative.Note: Last bone will be inverted due to issue #80643 (PR to fix this: #81048)