Skip to content
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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

thiagola92
Copy link
Contributor

@thiagola92 thiagola92 commented Aug 27, 2023

Issues: #80252

This is an attempt to fix SkeletonModification2DTwoBoneIK when only one scale is negative.

  • Identifies when only one scale axis is negative and change the logic
  • Take in count scales when drawing gizmo
  • Fix typo

Note: Last bone will be inverted due to issue #80643 (PR to fix this: #81048)

image

image

@AThousandShips AThousandShips added this to the 4.2 milestone Aug 27, 2023
@YuriSizov YuriSizov requested a review from a team August 30, 2023 19:39
@thiagola92 thiagola92 force-pushed the fix_twoboneik_with_negative_scale branch from b8b6998 to 48ff535 Compare September 11, 2023 11:21
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());
Copy link
Contributor

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

Copy link
Contributor Author

@thiagola92 thiagola92 Sep 17, 2023

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.

Copy link
Contributor

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()));

Copy link
Contributor

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());
}
Copy link
Contributor

@hsandt hsandt Sep 17, 2023

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.

Copy link
Contributor Author

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

Copy link
Contributor

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.

@thiagola92 thiagola92 force-pushed the fix_twoboneik_with_negative_scale branch from 48ff535 to fc845ce Compare September 19, 2023 19:10
- Identifies when only one scale axis is negative and change the logic
- Take in count scales when drawing gizmo
- Fix typo
@thiagola92 thiagola92 force-pushed the fix_twoboneik_with_negative_scale branch from fc845ce to 3e02983 Compare September 19, 2023 19:32
@thecodacus
Copy link

can this be pushed as patch update.. the ik bug is making the ik chain unusable

@thiagola92
Copy link
Contributor Author

I'm not actually happy with this solution (using if to check scales and decide the action).
And I hope someone knows a better way 🤣.

@YuriSizov YuriSizov modified the milestones: 4.2, 4.3 Nov 13, 2023
@YuriSizov YuriSizov added the cherrypick:4.2 Considered for cherry-picking into a future 4.2.x release label Nov 13, 2023
@YuriSizov YuriSizov removed the cherrypick:4.2 Considered for cherry-picking into a future 4.2.x release label Dec 4, 2023
@YuriSizov YuriSizov modified the milestones: 4.3, 4.x Dec 4, 2023
Comment on lines +149 to +150
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);
Copy link
Contributor Author

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)

@GopherDevGames
Copy link

is there anything blocking this PR as of now?

@thiagola92
Copy link
Contributor Author

is there anything blocking this PR as of now?

Is better to wait someone with knowledge like @TokageItLab to review
Someone that could tell if there is or not a better way to solve this (or tell if this solutions brings any problem)

@TokageItLab
Copy link
Member

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.

@CsloudX
Copy link

CsloudX commented Jul 28, 2024

Is this plan for 4.3 or 4.4?

@fire
Copy link
Member

fire commented Aug 17, 2024

@TokageItLab We can review this for 4.4

@fire
Copy link
Member

fire commented Nov 17, 2024

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.

@thiagola92
Copy link
Contributor Author

We discussed the problems with using the scale to flip 2d and 3d animation in general.

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.

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.

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());
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
9 participants