Add relative option to LookAt/AimModifier3D

This commit is contained in:
Silc Lizard (Tokage) Renew
2025-10-07 22:51:42 +09:00
parent ef34c3d534
commit e32f7de33d
6 changed files with 62 additions and 5 deletions

View File

@ -24,6 +24,13 @@
Returns the axis of the first rotation. It is enabled only if [method is_using_euler] is [code]true[/code]. Returns the axis of the first rotation. It is enabled only if [method is_using_euler] is [code]true[/code].
</description> </description>
</method> </method>
<method name="is_relative" qualifiers="const">
<return type="bool" />
<param index="0" name="index" type="int" />
<description>
Returns [code]true[/code] if the relative option is enabled in the setting at [param index].
</description>
</method>
<method name="is_using_euler" qualifiers="const"> <method name="is_using_euler" qualifiers="const">
<return type="bool" /> <return type="bool" />
<param index="0" name="index" type="int" /> <param index="0" name="index" type="int" />
@ -54,6 +61,16 @@
Sets the axis of the first rotation. It is enabled only if [method is_using_euler] is [code]true[/code]. Sets the axis of the first rotation. It is enabled only if [method is_using_euler] is [code]true[/code].
</description> </description>
</method> </method>
<method name="set_relative">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="enabled" type="bool" />
<description>
Sets relative option in the setting at [param index] to [param enabled].
If sets [param enabled] to [code]true[/code], the rotation is applied relative to the pose.
If sets [param enabled] to [code]false[/code], the rotation is applied relative to the rest. It means to replace the current pose with the [AimModifier3D]'s result.
</description>
</method>
<method name="set_use_euler"> <method name="set_use_euler">
<return type="void" /> <return type="void" />
<param index="0" name="index" type="int" /> <param index="0" name="index" type="int" />

View File

@ -91,6 +91,9 @@
<member name="primary_rotation_axis" type="int" setter="set_primary_rotation_axis" getter="get_primary_rotation_axis" enum="Vector3.Axis" default="1"> <member name="primary_rotation_axis" type="int" setter="set_primary_rotation_axis" getter="get_primary_rotation_axis" enum="Vector3.Axis" default="1">
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 axis of the first rotation. This [SkeletonModifier3D] works by compositing the rotation by Euler angles to prevent to rotate the [member forward_axis].
</member> </member>
<member name="relative" type="bool" setter="set_relative" getter="is_relative" default="true">
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.
</member>
<member name="secondary_damp_threshold" type="float" setter="set_secondary_damp_threshold" getter="get_secondary_damp_threshold"> <member name="secondary_damp_threshold" type="float" setter="set_secondary_damp_threshold" getter="get_secondary_damp_threshold">
The threshold to start damping for [member secondary_limit_angle]. The threshold to start damping for [member secondary_limit_angle].
</member> </member>

View File

@ -47,6 +47,8 @@ bool AimModifier3D::_set(const StringName &p_path, const Variant &p_value) {
set_primary_rotation_axis(which, static_cast<Vector3::Axis>((int)p_value)); set_primary_rotation_axis(which, static_cast<Vector3::Axis>((int)p_value));
} else if (what == "use_secondary_rotation") { } else if (what == "use_secondary_rotation") {
set_use_secondary_rotation(which, p_value); set_use_secondary_rotation(which, p_value);
} else if (what == "relative") {
set_relative(which, p_value);
} else { } else {
return false; return false;
} }
@ -70,6 +72,8 @@ bool AimModifier3D::_get(const StringName &p_path, Variant &r_ret) const {
r_ret = (int)get_primary_rotation_axis(which); r_ret = (int)get_primary_rotation_axis(which);
} else if (what == "use_secondary_rotation") { } else if (what == "use_secondary_rotation") {
r_ret = is_using_secondary_rotation(which); r_ret = is_using_secondary_rotation(which);
} else if (what == "relative") {
r_ret = is_relative(which);
} else { } else {
return false; return false;
} }
@ -88,6 +92,7 @@ void AimModifier3D::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, path + "use_euler")); p_list->push_back(PropertyInfo(Variant::BOOL, path + "use_euler"));
p_list->push_back(PropertyInfo(Variant::INT, path + "primary_rotation_axis", PROPERTY_HINT_ENUM, "X,Y,Z", rotation_usage)); p_list->push_back(PropertyInfo(Variant::INT, path + "primary_rotation_axis", PROPERTY_HINT_ENUM, "X,Y,Z", rotation_usage));
p_list->push_back(PropertyInfo(Variant::BOOL, path + "use_secondary_rotation", PROPERTY_HINT_NONE, "", rotation_usage)); p_list->push_back(PropertyInfo(Variant::BOOL, path + "use_secondary_rotation", PROPERTY_HINT_NONE, "", rotation_usage));
p_list->push_back(PropertyInfo(Variant::BOOL, path + "relative"));
} }
} }
@ -158,6 +163,18 @@ bool AimModifier3D::is_using_secondary_rotation(int p_index) const {
return setting->use_secondary_rotation; return setting->use_secondary_rotation;
} }
void AimModifier3D::set_relative(int p_index, bool p_enabled) {
ERR_FAIL_INDEX(p_index, (int)settings.size());
AimModifier3DSetting *setting = static_cast<AimModifier3DSetting *>(settings[p_index]);
setting->relative = p_enabled;
}
bool AimModifier3D::is_relative(int p_index) const {
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), 0);
AimModifier3DSetting *setting = static_cast<AimModifier3DSetting *>(settings[p_index]);
return setting->relative;
}
void AimModifier3D::_bind_methods() { void AimModifier3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_forward_axis", "index", "axis"), &AimModifier3D::set_forward_axis); ClassDB::bind_method(D_METHOD("set_forward_axis", "index", "axis"), &AimModifier3D::set_forward_axis);
ClassDB::bind_method(D_METHOD("get_forward_axis", "index"), &AimModifier3D::get_forward_axis); ClassDB::bind_method(D_METHOD("get_forward_axis", "index"), &AimModifier3D::get_forward_axis);
@ -167,6 +184,8 @@ void AimModifier3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_primary_rotation_axis", "index"), &AimModifier3D::get_primary_rotation_axis); ClassDB::bind_method(D_METHOD("get_primary_rotation_axis", "index"), &AimModifier3D::get_primary_rotation_axis);
ClassDB::bind_method(D_METHOD("set_use_secondary_rotation", "index", "enabled"), &AimModifier3D::set_use_secondary_rotation); ClassDB::bind_method(D_METHOD("set_use_secondary_rotation", "index", "enabled"), &AimModifier3D::set_use_secondary_rotation);
ClassDB::bind_method(D_METHOD("is_using_secondary_rotation", "index"), &AimModifier3D::is_using_secondary_rotation); ClassDB::bind_method(D_METHOD("is_using_secondary_rotation", "index"), &AimModifier3D::is_using_secondary_rotation);
ClassDB::bind_method(D_METHOD("set_relative", "index", "enabled"), &AimModifier3D::set_relative);
ClassDB::bind_method(D_METHOD("is_relative", "index"), &AimModifier3D::is_relative);
ADD_ARRAY_COUNT("Settings", "setting_count", "set_setting_count", "get_setting_count", "settings/"); ADD_ARRAY_COUNT("Settings", "setting_count", "set_setting_count", "get_setting_count", "settings/");
} }
@ -193,7 +212,7 @@ void AimModifier3D::_process_aim(int p_index, Skeleton3D *p_skeleton, int p_appl
AimModifier3DSetting *setting = static_cast<AimModifier3DSetting *>(settings[p_index]); AimModifier3DSetting *setting = static_cast<AimModifier3DSetting *>(settings[p_index]);
// Prepare forward_vector and rest. // Prepare forward_vector and rest.
Transform3D src_bone_rest = p_skeleton->get_bone_rest(p_apply_bone); Transform3D src_bone_rest = setting->relative ? p_skeleton->get_bone_pose(p_apply_bone) : p_skeleton->get_bone_rest(p_apply_bone);
Transform3D bone_rest_space; Transform3D bone_rest_space;
int parent_bone = p_skeleton->get_bone_parent(p_apply_bone); int parent_bone = p_skeleton->get_bone_parent(p_apply_bone);
if (parent_bone < 0) { if (parent_bone < 0) {

View File

@ -41,6 +41,7 @@ public:
bool use_euler = false; bool use_euler = false;
Vector3::Axis primary_rotation_axis = Vector3::AXIS_X; Vector3::Axis primary_rotation_axis = Vector3::AXIS_X;
bool use_secondary_rotation = true; bool use_secondary_rotation = true;
bool relative = true;
}; };
protected: protected:
@ -65,6 +66,8 @@ public:
Vector3::Axis get_primary_rotation_axis(int p_index) const; Vector3::Axis get_primary_rotation_axis(int p_index) const;
void set_use_secondary_rotation(int p_index, bool p_enabled); void set_use_secondary_rotation(int p_index, bool p_enabled);
bool is_using_secondary_rotation(int p_index) const; bool is_using_secondary_rotation(int p_index) const;
void set_relative(int p_index, bool p_enabled);
bool is_relative(int p_index) const;
~AimModifier3D(); ~AimModifier3D();
}; };

View File

@ -143,6 +143,14 @@ bool LookAtModifier3D::is_using_secondary_rotation() const {
return use_secondary_rotation; return use_secondary_rotation;
} }
void LookAtModifier3D::set_relative(bool p_enabled) {
relative = p_enabled;
}
bool LookAtModifier3D::is_relative() const {
return relative;
}
void LookAtModifier3D::set_target_node(const NodePath &p_target_node) { void LookAtModifier3D::set_target_node(const NodePath &p_target_node) {
if (target_node != p_target_node) { if (target_node != p_target_node) {
init_transition(); init_transition();
@ -394,9 +402,11 @@ void LookAtModifier3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_primary_rotation_axis"), &LookAtModifier3D::get_primary_rotation_axis); ClassDB::bind_method(D_METHOD("get_primary_rotation_axis"), &LookAtModifier3D::get_primary_rotation_axis);
ClassDB::bind_method(D_METHOD("set_use_secondary_rotation", "enabled"), &LookAtModifier3D::set_use_secondary_rotation); ClassDB::bind_method(D_METHOD("set_use_secondary_rotation", "enabled"), &LookAtModifier3D::set_use_secondary_rotation);
ClassDB::bind_method(D_METHOD("is_using_secondary_rotation"), &LookAtModifier3D::is_using_secondary_rotation); ClassDB::bind_method(D_METHOD("is_using_secondary_rotation"), &LookAtModifier3D::is_using_secondary_rotation);
ClassDB::bind_method(D_METHOD("set_relative", "enabled"), &LookAtModifier3D::set_relative);
ClassDB::bind_method(D_METHOD("is_relative"), &LookAtModifier3D::is_relative);
ClassDB::bind_method(D_METHOD("set_origin_safe_margin", "margin"), &LookAtModifier3D::set_origin_safe_margin); ClassDB::bind_method(D_METHOD("set_origin_safe_margin", "margin"), &LookAtModifier3D::set_origin_safe_margin);
ClassDB::bind_method(D_METHOD("get_origin_safe_margin"), &LookAtModifier3D::get_origin_safe_margin); ClassDB::bind_method(D_METHOD("get_origin_safe_margin"), &LookAtModifier3D::get_origin_safe_margin);
ClassDB::bind_method(D_METHOD("set_origin_from", "origin_from"), &LookAtModifier3D::set_origin_from); ClassDB::bind_method(D_METHOD("set_origin_from", "origin_from"), &LookAtModifier3D::set_origin_from);
ClassDB::bind_method(D_METHOD("get_origin_from"), &LookAtModifier3D::get_origin_from); ClassDB::bind_method(D_METHOD("get_origin_from"), &LookAtModifier3D::get_origin_from);
ClassDB::bind_method(D_METHOD("set_origin_bone_name", "bone_name"), &LookAtModifier3D::set_origin_bone_name); ClassDB::bind_method(D_METHOD("set_origin_bone_name", "bone_name"), &LookAtModifier3D::set_origin_bone_name);
@ -460,6 +470,7 @@ void LookAtModifier3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "forward_axis", PROPERTY_HINT_ENUM, SkeletonModifier3D::get_hint_bone_axis()), "set_forward_axis", "get_forward_axis"); ADD_PROPERTY(PropertyInfo(Variant::INT, "forward_axis", PROPERTY_HINT_ENUM, SkeletonModifier3D::get_hint_bone_axis()), "set_forward_axis", "get_forward_axis");
ADD_PROPERTY(PropertyInfo(Variant::INT, "primary_rotation_axis", PROPERTY_HINT_ENUM, "X,Y,Z"), "set_primary_rotation_axis", "get_primary_rotation_axis"); ADD_PROPERTY(PropertyInfo(Variant::INT, "primary_rotation_axis", PROPERTY_HINT_ENUM, "X,Y,Z"), "set_primary_rotation_axis", "get_primary_rotation_axis");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_secondary_rotation"), "set_use_secondary_rotation", "is_using_secondary_rotation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_secondary_rotation"), "set_use_secondary_rotation", "is_using_secondary_rotation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "relative"), "set_relative", "is_relative");
ADD_GROUP("Origin Settings", "origin_"); ADD_GROUP("Origin Settings", "origin_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "origin_from", PROPERTY_HINT_ENUM, "Self,SpecificBone,ExternalNode"), "set_origin_from", "get_origin_from"); ADD_PROPERTY(PropertyInfo(Variant::INT, "origin_from", PROPERTY_HINT_ENUM, "Self,SpecificBone,ExternalNode"), "set_origin_from", "get_origin_from");
@ -506,14 +517,15 @@ void LookAtModifier3D::_process_modification(double p_delta) {
} }
// Calculate bone rest space in the world. // Calculate bone rest space in the world.
Transform3D bone_rest = relative ? skeleton->get_bone_pose(bone) : skeleton->get_bone_rest(bone);
Transform3D bone_rest_space; Transform3D bone_rest_space;
int parent_bone = skeleton->get_bone_parent(bone); int parent_bone = skeleton->get_bone_parent(bone);
if (parent_bone < 0) { if (parent_bone < 0) {
bone_rest_space = skeleton->get_global_transform_interpolated(); bone_rest_space = skeleton->get_global_transform_interpolated();
bone_rest_space.translate_local(skeleton->get_bone_rest(bone).origin); bone_rest_space.translate_local(bone_rest.origin);
} else { } else {
bone_rest_space = skeleton->get_global_transform_interpolated() * skeleton->get_bone_global_pose(parent_bone); bone_rest_space = skeleton->get_global_transform_interpolated() * skeleton->get_bone_global_pose(parent_bone);
bone_rest_space.translate_local(skeleton->get_bone_rest(bone).origin); bone_rest_space.translate_local(bone_rest.origin);
} }
// Calculate forward_vector and destination. // Calculate forward_vector and destination.
@ -543,7 +555,7 @@ void LookAtModifier3D::_process_modification(double p_delta) {
destination = skeleton->get_bone_pose_rotation(bone); destination = skeleton->get_bone_pose_rotation(bone);
forward_vector = Vector3(0, 0, 0); // The zero-vector to be used for checking in the line immediately below to avoid animation glitch. forward_vector = Vector3(0, 0, 0); // The zero-vector to be used for checking in the line immediately below to avoid animation glitch.
} else { } else {
destination = look_at_with_axes(skeleton->get_bone_rest(bone)).basis.get_rotation_quaternion(); destination = look_at_with_axes(bone_rest).basis.get_rotation_quaternion();
} }
} }

View File

@ -53,6 +53,7 @@ private:
Vector3::Axis primary_rotation_axis = Vector3::AXIS_Y; Vector3::Axis primary_rotation_axis = Vector3::AXIS_Y;
Vector3::Axis secondary_rotation_axis = Vector3::AXIS_X; Vector3::Axis secondary_rotation_axis = Vector3::AXIS_X;
bool use_secondary_rotation = true; bool use_secondary_rotation = true;
bool relative = true;
OriginFrom origin_from = ORIGIN_FROM_SELF; OriginFrom origin_from = ORIGIN_FROM_SELF;
String origin_bone_name; String origin_bone_name;
@ -123,6 +124,8 @@ public:
Vector3::Axis get_primary_rotation_axis() const; Vector3::Axis get_primary_rotation_axis() const;
void set_use_secondary_rotation(bool p_enabled); void set_use_secondary_rotation(bool p_enabled);
bool is_using_secondary_rotation() const; bool is_using_secondary_rotation() const;
void set_relative(bool p_enabled);
bool is_relative() const;
void set_origin_from(OriginFrom p_origin_from); void set_origin_from(OriginFrom p_origin_from);
OriginFrom get_origin_from() const; OriginFrom get_origin_from() const;