X Tutup
Skip to content

Commit 381ad1e

Browse files
committed
Fix LookAtModifier3D / AimModifier3D forward vector
1 parent d48f9d4 commit 381ad1e

File tree

4 files changed

+13
-11
lines changed

4 files changed

+13
-11
lines changed

doc/classes/LookAtModifier3D.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@
9191
<member name="primary_rotation_axis" type="int" setter="set_primary_rotation_axis" getter="get_primary_rotation_axis" enum="Vector3.Axis" default="1">
9292
The axis of the first rotation. This [SkeletonModifier3D] works by compositing the rotation by Euler angles to prevent to rotate the [member forward_axis].
9393
</member>
94-
<member name="relative" type="bool" setter="set_relative" getter="is_relative" default="true">
94+
<member name="relative" type="bool" setter="set_relative" getter="is_relative" default="false">
9595
The relative option. If [code]true[/code], the rotation is applied relative to the pose. If [code]false[/code], the rotation is applied relative to the rest. It means to replace the current pose with the [LookAtModifier3D]'s result.
96+
[b]Note:[/b] This option affects the base angle for [member use_angle_limitation] unlike [IterateIK3D]'s [JointLimitation3D]. Since the [LookAtModifier3D] relies strongly on Euler rotation, the axis that determines the limitation and the actual rotation are strongly tied together.
9697
</member>
9798
<member name="secondary_damp_threshold" type="float" setter="set_secondary_damp_threshold" getter="get_secondary_damp_threshold">
9899
The threshold to start damping for [member secondary_limit_angle].
@@ -124,7 +125,7 @@
124125
</member>
125126
<member name="use_angle_limitation" type="bool" setter="set_use_angle_limitation" getter="is_using_angle_limitation" default="false">
126127
If [code]true[/code], limits the amount of rotation. For example, this helps to prevent a character's neck from rotating 360 degrees.
127-
[b]Note:[/b] As with [AnimationTree] blending, interpolation is provided that favors [method Skeleton3D.get_bone_rest]. This means that interpolation does not select the shortest path in some cases.
128+
[b]Note:[/b] As with [AnimationTree] blending, interpolation is provided that favors [method Skeleton3D.get_bone_rest] or [method Skeleton3D.get_bone_pose] depends on the [member relative] option. This means that interpolation does not select the shortest path in some cases.
128129
[b]Note:[/b] Some values for [member transition_type] (such as [constant Tween.TRANS_BACK], [constant Tween.TRANS_ELASTIC], and [constant Tween.TRANS_SPRING]) may exceed the limitations. If interpolation occurs while overshooting the limitations, the result might not respect the bone rest.
129130
</member>
130131
<member name="use_secondary_rotation" type="bool" setter="set_use_secondary_rotation" getter="is_using_secondary_rotation" default="true">

scene/3d/aim_modifier_3d.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,9 @@ void AimModifier3D::_process_constraint_by_node(int p_index, Skeleton3D *p_skele
204204
if (!nd) {
205205
return;
206206
}
207-
Vector3 reference_origin = nd->get_global_transform_interpolated().origin - p_skeleton->get_global_transform_interpolated().origin;
208-
_process_aim(p_index, p_skeleton, p_apply_bone, reference_origin, p_amount);
207+
Transform3D skel_tr = p_skeleton->get_global_transform_interpolated();
208+
Vector3 reference_origin = nd->get_global_transform_interpolated().origin - skel_tr.origin;
209+
_process_aim(p_index, p_skeleton, p_apply_bone, skel_tr.basis.get_rotation_quaternion().xform_inv(reference_origin), p_amount);
209210
}
210211

211212
void AimModifier3D::_process_aim(int p_index, Skeleton3D *p_skeleton, int p_apply_bone, Vector3 p_target, float p_amount) {

scene/3d/look_at_modifier_3d.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ void LookAtModifier3D::_process_modification(double p_delta) {
559559
forward_vector = Vector3(0, 0, 0); // The zero-vector to be used for checking in the line immediately below to avoid animation glitch.
560560
} else {
561561
destination = look_at_with_axes(bone_rest).basis.get_rotation_quaternion();
562+
forward_vector = bone_rest.basis.xform_inv(forward_vector_nrm); // Forward vector in the "current" bone rest.
562563
}
563564
}
564565

@@ -574,18 +575,17 @@ void LookAtModifier3D::_process_modification(double p_delta) {
574575
init_transition();
575576
} else if (is_flippable && std::signbit(prev_forward_vector[secondary_rotation_axis]) != std::signbit(forward_vector[secondary_rotation_axis])) {
576577
// Flipping by angle_limitation can be detected by sign of secondary rotation axes during forward_vector is rotated more than 90 degree from forward_axis (means dot production is negative).
577-
Vector3 prev_forward_vector_nrm = forward_vector.normalized();
578578
Vector3 rest_forward_vector = get_vector_from_bone_axis(forward_axis);
579579
if (symmetry_limitation) {
580580
if ((is_not_max_influence || !Math::is_equal_approx(primary_limit_angle, (float)Math::TAU)) &&
581-
prev_forward_vector_nrm.dot(rest_forward_vector) < 0 &&
582-
forward_vector_nrm.dot(rest_forward_vector) < 0) {
581+
prev_forward_vector.dot(rest_forward_vector) < 0 &&
582+
forward_vector.dot(rest_forward_vector) < 0) {
583583
init_transition();
584584
}
585585
} else {
586586
if ((is_not_max_influence || !Math::is_equal_approx(primary_positive_limit_angle + primary_negative_limit_angle, (float)Math::TAU)) &&
587-
prev_forward_vector_nrm.dot(rest_forward_vector) < 0 &&
588-
forward_vector_nrm.dot(rest_forward_vector) < 0) {
587+
prev_forward_vector.dot(rest_forward_vector) < 0 &&
588+
forward_vector.dot(rest_forward_vector) < 0) {
589589
init_transition();
590590
}
591591
}
@@ -596,7 +596,7 @@ void LookAtModifier3D::_process_modification(double p_delta) {
596596
remaining = MAX(0, remaining - time_step * p_delta);
597597
if (is_flippable) {
598598
// Interpolate through the rest same as AnimationTree blending for preventing to penetrate the bone into the body.
599-
Quaternion rest = skeleton->get_bone_rest(bone).basis.get_rotation_quaternion();
599+
Quaternion rest = bone_rest.basis.get_rotation_quaternion();
600600
float weight = Tween::run_equation(transition_type, ease_type, 1 - remaining, 0.0, 1.0, 1.0);
601601
destination = Animation::interpolate_via_rest(Animation::interpolate_via_rest(rest, from_q, 1 - weight, rest), destination, weight, rest);
602602
} else {

scene/3d/look_at_modifier_3d.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class LookAtModifier3D : public SkeletonModifier3D {
5353
Vector3::Axis primary_rotation_axis = Vector3::AXIS_Y;
5454
Vector3::Axis secondary_rotation_axis = Vector3::AXIS_X;
5555
bool use_secondary_rotation = true;
56-
bool relative = true;
56+
bool relative = false;
5757

5858
OriginFrom origin_from = ORIGIN_FROM_SELF;
5959
String origin_bone_name;

0 commit comments

Comments
 (0)
X Tutup