diff --git a/doc/classes/LookAtModifier3D.xml b/doc/classes/LookAtModifier3D.xml
index 48f9d4b970f..1d458ef2363 100644
--- a/doc/classes/LookAtModifier3D.xml
+++ b/doc/classes/LookAtModifier3D.xml
@@ -91,8 +91,9 @@
The axis of the first rotation. This [SkeletonModifier3D] works by compositing the rotation by Euler angles to prevent to rotate the [member forward_axis].
-
+
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.
+ [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.
The threshold to start damping for [member secondary_limit_angle].
@@ -124,7 +125,7 @@
If [code]true[/code], limits the amount of rotation. For example, this helps to prevent a character's neck from rotating 360 degrees.
- [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.
+ [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.
[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.
diff --git a/scene/3d/aim_modifier_3d.cpp b/scene/3d/aim_modifier_3d.cpp
index 931a0683caf..fc7dfe73037 100644
--- a/scene/3d/aim_modifier_3d.cpp
+++ b/scene/3d/aim_modifier_3d.cpp
@@ -204,8 +204,9 @@ void AimModifier3D::_process_constraint_by_node(int p_index, Skeleton3D *p_skele
if (!nd) {
return;
}
- Vector3 reference_origin = nd->get_global_transform_interpolated().origin - p_skeleton->get_global_transform_interpolated().origin;
- _process_aim(p_index, p_skeleton, p_apply_bone, reference_origin, p_amount);
+ Transform3D skel_tr = p_skeleton->get_global_transform_interpolated();
+ Vector3 reference_origin = nd->get_global_transform_interpolated().origin - skel_tr.origin;
+ _process_aim(p_index, p_skeleton, p_apply_bone, skel_tr.basis.get_rotation_quaternion().xform_inv(reference_origin), p_amount);
}
void AimModifier3D::_process_aim(int p_index, Skeleton3D *p_skeleton, int p_apply_bone, Vector3 p_target, float p_amount) {
diff --git a/scene/3d/look_at_modifier_3d.cpp b/scene/3d/look_at_modifier_3d.cpp
index e02197cced4..e03ef428d55 100644
--- a/scene/3d/look_at_modifier_3d.cpp
+++ b/scene/3d/look_at_modifier_3d.cpp
@@ -559,6 +559,7 @@ void LookAtModifier3D::_process_modification(double p_delta) {
forward_vector = Vector3(0, 0, 0); // The zero-vector to be used for checking in the line immediately below to avoid animation glitch.
} else {
destination = look_at_with_axes(bone_rest).basis.get_rotation_quaternion();
+ forward_vector = bone_rest.basis.xform_inv(forward_vector_nrm); // Forward vector in the "current" bone rest.
}
}
@@ -574,18 +575,17 @@ void LookAtModifier3D::_process_modification(double p_delta) {
init_transition();
} else if (is_flippable && std::signbit(prev_forward_vector[secondary_rotation_axis]) != std::signbit(forward_vector[secondary_rotation_axis])) {
// 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).
- Vector3 prev_forward_vector_nrm = forward_vector.normalized();
Vector3 rest_forward_vector = get_vector_from_bone_axis(forward_axis);
if (symmetry_limitation) {
if ((is_not_max_influence || !Math::is_equal_approx(primary_limit_angle, (float)Math::TAU)) &&
- prev_forward_vector_nrm.dot(rest_forward_vector) < 0 &&
- forward_vector_nrm.dot(rest_forward_vector) < 0) {
+ prev_forward_vector.dot(rest_forward_vector) < 0 &&
+ forward_vector.dot(rest_forward_vector) < 0) {
init_transition();
}
} else {
if ((is_not_max_influence || !Math::is_equal_approx(primary_positive_limit_angle + primary_negative_limit_angle, (float)Math::TAU)) &&
- prev_forward_vector_nrm.dot(rest_forward_vector) < 0 &&
- forward_vector_nrm.dot(rest_forward_vector) < 0) {
+ prev_forward_vector.dot(rest_forward_vector) < 0 &&
+ forward_vector.dot(rest_forward_vector) < 0) {
init_transition();
}
}
@@ -596,7 +596,7 @@ void LookAtModifier3D::_process_modification(double p_delta) {
remaining = MAX(0, remaining - time_step * p_delta);
if (is_flippable) {
// Interpolate through the rest same as AnimationTree blending for preventing to penetrate the bone into the body.
- Quaternion rest = skeleton->get_bone_rest(bone).basis.get_rotation_quaternion();
+ Quaternion rest = bone_rest.basis.get_rotation_quaternion();
float weight = Tween::run_equation(transition_type, ease_type, 1 - remaining, 0.0, 1.0, 1.0);
destination = Animation::interpolate_via_rest(Animation::interpolate_via_rest(rest, from_q, 1 - weight, rest), destination, weight, rest);
} else {
diff --git a/scene/3d/look_at_modifier_3d.h b/scene/3d/look_at_modifier_3d.h
index fea1e99b4ad..e4110ebc2f6 100644
--- a/scene/3d/look_at_modifier_3d.h
+++ b/scene/3d/look_at_modifier_3d.h
@@ -53,7 +53,7 @@ private:
Vector3::Axis primary_rotation_axis = Vector3::AXIS_Y;
Vector3::Axis secondary_rotation_axis = Vector3::AXIS_X;
bool use_secondary_rotation = true;
- bool relative = true;
+ bool relative = false;
OriginFrom origin_from = ORIGIN_FROM_SELF;
String origin_bone_name;