Skip to content

Commit bc0eba5

Browse files
Fixed Skeleton2D TwoBoneIK and LookAt mirroring
Co-authored-by: thiagola92 <[email protected]>
1 parent 3c7f9b9 commit bc0eba5

File tree

2 files changed

+42
-30
lines changed

2 files changed

+42
-30
lines changed

scene/resources/2d/skeleton/skeleton_modification_2d_lookat.cpp

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -141,37 +141,32 @@ void SkeletonModification2DLookAt::_execute(float p_delta) {
141141
return;
142142
}
143143

144-
Transform2D operation_transform = operation_bone->get_global_transform();
145-
Transform2D target_trans = target_node_reference->get_global_transform();
144+
real_t angle_to_target = operation_bone->get_angle_to(target_node_reference->get_global_position());
146145

147-
// Look at the target!
148-
operation_transform = operation_transform.looking_at(target_trans.get_origin());
149-
// Apply whatever scale it had prior to looking_at
150-
operation_transform.set_scale(operation_bone->get_global_scale());
151-
152-
// Account for the direction the bone faces in:
153-
operation_transform.set_rotation(operation_transform.get_rotation() - operation_bone->get_bone_angle());
146+
// Account for the direction the bone faces in
147+
angle_to_target -= operation_bone->get_bone_angle();
154148

155149
// Apply additional rotation
156-
operation_transform.set_rotation(operation_transform.get_rotation() + additional_rotation);
157-
158-
// Apply constraints in globalspace:
159-
if (enable_constraint && !constraint_in_localspace) {
160-
operation_transform.set_rotation(clamp_angle(operation_transform.get_rotation(), constraint_angle_min, constraint_angle_max, constraint_angle_invert));
161-
}
150+
angle_to_target += additional_rotation;
162151

163-
// Convert from a global transform to a local transform via the Bone2D node
164-
operation_bone->set_global_transform(operation_transform);
165-
operation_transform = operation_bone->get_transform();
152+
if (enable_constraint) {
153+
real_t new_angle = angle_to_target;
166154

167-
// Apply constraints in localspace:
168-
if (enable_constraint && constraint_in_localspace) {
169-
operation_transform.set_rotation(clamp_angle(operation_transform.get_rotation(), constraint_angle_min, constraint_angle_max, constraint_angle_invert));
155+
if (constraint_in_localspace) {
156+
new_angle += operation_bone->get_rotation();
157+
new_angle = clamp_angle(new_angle, constraint_angle_min, constraint_angle_max, constraint_angle_invert);
158+
operation_bone->set_rotation(new_angle);
159+
} else {
160+
new_angle += operation_bone->get_global_rotation();
161+
new_angle = clamp_angle(new_angle, constraint_angle_min, constraint_angle_max, constraint_angle_invert);
162+
operation_bone->set_global_rotation(new_angle);
163+
}
164+
} else {
165+
operation_bone->rotate(angle_to_target);
170166
}
171167

172168
// Set the local pose override, and to make sure child bones are also updated, set the transform of the bone.
173-
stack->skeleton->set_bone_local_pose_override(bone_idx, operation_transform, stack->strength, true);
174-
operation_bone->set_transform(operation_transform);
169+
stack->skeleton->set_bone_local_pose_override(bone_idx, operation_bone->get_transform(), stack->strength, true);
175170
}
176171

177172
void SkeletonModification2DLookAt::_setup_modification(SkeletonModificationStack2D *p_stack) {

scene/resources/2d/skeleton/skeleton_modification_2d_twoboneik.cpp

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,17 +142,18 @@ void SkeletonModification2DTwoBoneIK::_execute(float p_delta) {
142142
return;
143143
}
144144

145-
// Adopted from the links below:
145+
// Adapted from the links below:
146146
// http://theorangeduck.com/page/simple-two-joint
147147
// https://www.alanzucconi.com/2018/05/02/ik-2d-2/
148148
// With modifications by TwistedTwigleg
149149
Vector2 target_difference = target->get_global_position() - joint_one_bone->get_global_position();
150150
float joint_one_to_target = target_difference.length();
151151
float angle_atan = target_difference.angle();
152152

153-
float bone_one_length = joint_one_bone->get_length() * MIN(joint_one_bone->get_global_scale().x, joint_one_bone->get_global_scale().y);
154-
float bone_two_length = joint_two_bone->get_length() * MIN(joint_two_bone->get_global_scale().x, joint_two_bone->get_global_scale().y);
153+
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);
154+
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);
155155
bool override_angles_due_to_out_of_range = false;
156+
bool same_scale_sign = true;
156157

157158
if (joint_one_to_target < target_minimum_distance) {
158159
joint_one_to_target = target_minimum_distance;
@@ -165,6 +166,10 @@ void SkeletonModification2DTwoBoneIK::_execute(float p_delta) {
165166
override_angles_due_to_out_of_range = true;
166167
}
167168

169+
if (joint_one_bone->get_global_scale().sign().x != joint_one_bone->get_global_scale().sign().y) {
170+
same_scale_sign = false;
171+
}
172+
168173
if (!override_angles_due_to_out_of_range) {
169174
float angle_0 = Math::acos(((joint_one_to_target * joint_one_to_target) + (bone_one_length * bone_one_length) - (bone_two_length * bone_two_length)) / (2.0 * joint_one_to_target * bone_one_length));
170175
float angle_1 = Math::acos(((bone_two_length * bone_two_length) + (bone_one_length * bone_one_length) - (joint_one_to_target * joint_one_to_target)) / (2.0 * bone_two_length * bone_one_length));
@@ -177,12 +182,23 @@ void SkeletonModification2DTwoBoneIK::_execute(float p_delta) {
177182
if (std::isnan(angle_0) || std::isnan(angle_1)) {
178183
// We cannot solve for this angle! Do nothing to avoid setting the rotation (and scale) to NaN.
179184
} else {
180-
joint_one_bone->set_global_rotation(angle_atan - angle_0 - joint_one_bone->get_bone_angle());
185+
if (same_scale_sign) {
186+
joint_one_bone->set_global_rotation(angle_atan - angle_0 - joint_one_bone->get_bone_angle());
187+
} else {
188+
joint_one_bone->set_global_rotation(angle_atan + angle_0 + joint_one_bone->get_bone_angle());
189+
}
190+
181191
joint_two_bone->set_rotation(-Math::PI - angle_1 - joint_two_bone->get_bone_angle() + joint_one_bone->get_bone_angle());
182192
}
193+
183194
} else {
184-
joint_one_bone->set_global_rotation(angle_atan - joint_one_bone->get_bone_angle());
185-
joint_two_bone->set_global_rotation(angle_atan - joint_two_bone->get_bone_angle());
195+
if (same_scale_sign) {
196+
joint_one_bone->set_global_rotation(angle_atan - joint_one_bone->get_bone_angle());
197+
joint_two_bone->set_global_rotation(angle_atan - joint_two_bone->get_bone_angle());
198+
} else {
199+
joint_one_bone->set_global_rotation(angle_atan + joint_one_bone->get_bone_angle());
200+
joint_two_bone->set_global_rotation(angle_atan + joint_two_bone->get_bone_angle());
201+
}
186202
}
187203

188204
stack->skeleton->set_bone_local_pose_override(joint_one_bone_idx, joint_one_bone->get_transform(), stack->strength, true);
@@ -211,7 +227,8 @@ void SkeletonModification2DTwoBoneIK::_draw_editor_gizmo() {
211227
}
212228
stack->skeleton->draw_set_transform(
213229
stack->skeleton->to_local(operation_bone_one->get_global_position()),
214-
operation_bone_one->get_global_rotation() - stack->skeleton->get_global_rotation());
230+
operation_bone_one->get_global_rotation() - stack->skeleton->get_global_rotation(),
231+
operation_bone_one->get_global_scale());
215232

216233
Color bone_ik_color = Color(1.0, 0.65, 0.0, 0.4);
217234
#ifdef TOOLS_ENABLED

0 commit comments

Comments
 (0)