Skip to content

Commit

Permalink
Add inherit_scale to bones
Browse files Browse the repository at this point in the history
Add inherit_scale to bones

Adds inherit_scale property to bones in Skeleton3D. Setting this to false
will allow the bone to be scaled independently of its parent.
  • Loading branch information
ElfWitch committed Mar 22, 2024
1 parent fe01776 commit 5ad27b1
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 5 deletions.
15 changes: 15 additions & 0 deletions doc/classes/Skeleton3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,13 @@
Returns whether the bone pose for the bone at [param bone_idx] is enabled.
</description>
</method>
<method name="is_bone_inherit_scale" qualifiers="const">
<return type="bool" />
<param index="0" name="bone_idx" type="int" />
<description>
Returns whether the bone should inherit the scale of its parent bone.
</description>
</method>
<method name="localize_rests">
<return type="void" />
<description>
Expand Down Expand Up @@ -246,6 +253,14 @@
[b]Note:[/b] The pose transform needs to be a global pose! To convert a world transform from a [Node3D] to a global bone pose, multiply the [method Transform3D.affine_inverse] of the node's [member Node3D.global_transform] by the desired world transform.
</description>
</method>
<method name="set_bone_inherit_scale">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
<param index="1" name="inherit_scale" type="bool" default="true" />
<description>
Sets whether the parent's scale should be inherited by the bone.
</description>
</method>
<method name="set_bone_name">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
Expand Down
15 changes: 15 additions & 0 deletions editor/plugins/skeleton_3d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ void BoneTransformEditor::create_editors() {
scale_property->connect("property_keyed", callable_mp(this, &BoneTransformEditor::_property_keyed));
section->get_vbox()->add_child(scale_property);

// Inherit Scale property.
inherit_scale_property = memnew(EditorPropertyCheck());
inherit_scale_property->set_label("Inherit Scale");
inherit_scale_property->set_selectable(false);
inherit_scale_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed));
section->get_vbox()->add_child(inherit_scale_property);

// Transform/Matrix section.
rest_section = memnew(EditorInspectorSection);
rest_section->setup("trf_properties_transform", "Rest", this, Color(0.0f, 0.0f, 0.0f), true);
Expand Down Expand Up @@ -151,6 +158,9 @@ void BoneTransformEditor::set_target(const String &p_prop) {
scale_property->set_object_and_property(skeleton, p_prop + "scale");
scale_property->update_property();

inherit_scale_property->set_object_and_property(skeleton, p_prop + "inherit_scale");
inherit_scale_property->update_property();

rest_matrix->set_object_and_property(skeleton, p_prop + "rest");
rest_matrix->update_property();
}
Expand Down Expand Up @@ -207,6 +217,11 @@ void BoneTransformEditor::_update_properties() {
scale_property->update_property();
scale_property->queue_redraw();
}
if (split[2] == "inherit_bone") {
scale_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
scale_property->update_property();
scale_property->queue_redraw();
}
if (split[2] == "rest") {
rest_matrix->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
rest_matrix->update_property();
Expand Down
1 change: 1 addition & 0 deletions editor/plugins/skeleton_3d_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class BoneTransformEditor : public VBoxContainer {
EditorPropertyVector3 *position_property = nullptr;
EditorPropertyQuaternion *rotation_property = nullptr;
EditorPropertyVector3 *scale_property = nullptr;
EditorPropertyCheck *inherit_scale_property = nullptr;

EditorInspectorSection *rest_section = nullptr;
EditorPropertyTransform3D *rest_matrix = nullptr;
Expand Down
56 changes: 51 additions & 5 deletions scene/3d/skeleton_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) {
set_bone_pose_rotation(which, p_value);
} else if (what == "scale") {
set_bone_pose_scale(which, p_value);
} else if (what == "inherit_scale") {
set_bone_inherit_scale(which, p_value);
#ifndef DISABLE_DEPRECATED
} else if (what == "pose" || what == "bound_children") {
// Kept for compatibility from 3.x to 4.x.
Expand Down Expand Up @@ -157,6 +159,8 @@ bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const {
r_ret = get_bone_pose_rotation(which);
} else if (what == "scale") {
r_ret = get_bone_pose_scale(which);
} else if (what == "inherit_scale") {
r_ret = is_bone_inherit_scale(which);
} else {
return false;
}
Expand All @@ -174,6 +178,7 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + PNAME("position"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
p_list->push_back(PropertyInfo(Variant::QUATERNION, prep + PNAME("rotation"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + PNAME("scale"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
p_list->push_back(PropertyInfo(Variant::BOOL, prep + PNAME("inherit_scale"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
}

for (PropertyInfo &E : *p_list) {
Expand All @@ -200,6 +205,9 @@ void Skeleton3D::_validate_property(PropertyInfo &p_property) const {
if (split[2] == "scale") {
p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (split[2] == "inherit_scale") {
p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
} else if (!is_bone_enabled(split[1].to_int())) {
if (split[2] == "position") {
p_property.usage |= PROPERTY_USAGE_READ_ONLY;
Expand All @@ -210,6 +218,9 @@ void Skeleton3D::_validate_property(PropertyInfo &p_property) const {
if (split[2] == "scale") {
p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (split[2] == "inherit_scale") {
p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
}
}
}
Expand Down Expand Up @@ -619,6 +630,23 @@ void Skeleton3D::set_bone_pose_scale(int p_bone, const Vector3 &p_scale) {
}
}

bool Skeleton3D::is_bone_inherit_scale(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, false);
return bones[p_bone].inherit_scale;
}

void Skeleton3D::set_bone_inherit_scale(int p_bone, bool inherit_scale) {
const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone, bone_size);

bones.write[p_bone].inherit_scale = inherit_scale;
bones.write[p_bone].pose_cache_dirty = true;
if (is_inside_tree()) {
_make_dirty();
}
}

Vector3 Skeleton3D::get_bone_pose_position(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, Vector3());
Expand Down Expand Up @@ -941,6 +969,21 @@ void Skeleton3D::force_update_all_bone_transforms() {
rest_dirty = false;
}

// Applies transform to child while preserving child scale, and corrects rotation if inherit is false.
// Otherwise, just does a regular transformation.
Transform3D transform_local_scale(Transform3D parent, Transform3D child, bool inherit) {
if (inherit == true) {
return parent * child;
} else {
// apply full transform
Transform3D output = parent * child;

// replace basis with custom scaled
output.basis = Basis(parent.basis.get_rotation_quaternion() * child.basis.get_rotation_quaternion(), child.basis.get_scale());
return output;
}
}

void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone_idx, bone_size);
Expand All @@ -961,23 +1004,23 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
Transform3D pose = b.pose_cache;

if (b.parent >= 0) {
b.pose_global = bonesptr[b.parent].pose_global * pose;
b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * pose;
b.pose_global = transform_local_scale(bonesptr[b.parent].pose_global, pose, b.inherit_scale);
b.pose_global_no_override = transform_local_scale(bonesptr[b.parent].pose_global_no_override, pose, b.inherit_scale);
} else {
b.pose_global = pose;
b.pose_global_no_override = pose;
}
} else {
if (b.parent >= 0) {
b.pose_global = bonesptr[b.parent].pose_global * b.rest;
b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * b.rest;
b.pose_global = transform_local_scale(bonesptr[b.parent].pose_global, b.rest, b.inherit_scale);
b.pose_global_no_override = transform_local_scale(bonesptr[b.parent].pose_global_no_override, b.rest, b.inherit_scale);
} else {
b.pose_global = b.rest;
b.pose_global_no_override = b.rest;
}
}
if (rest_dirty) {
b.global_rest = b.parent >= 0 ? bonesptr[b.parent].global_rest * b.rest : b.rest;
b.global_rest = b.parent >= 0 ? transform_local_scale(bonesptr[b.parent].global_rest, b.rest, b.inherit_scale) : b.rest;
}

if (b.global_pose_override_amount >= CMP_EPSILON) {
Expand Down Expand Up @@ -1032,6 +1075,9 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bone_pose_rotation", "bone_idx", "rotation"), &Skeleton3D::set_bone_pose_rotation);
ClassDB::bind_method(D_METHOD("set_bone_pose_scale", "bone_idx", "scale"), &Skeleton3D::set_bone_pose_scale);

ClassDB::bind_method(D_METHOD("is_bone_inherit_scale", "bone_idx"), &Skeleton3D::is_bone_inherit_scale);
ClassDB::bind_method(D_METHOD("set_bone_inherit_scale", "bone_idx", "inherit_scale"), &Skeleton3D::set_bone_inherit_scale, DEFVAL(true));

ClassDB::bind_method(D_METHOD("get_bone_pose_position", "bone_idx"), &Skeleton3D::get_bone_pose_position);
ClassDB::bind_method(D_METHOD("get_bone_pose_rotation", "bone_idx"), &Skeleton3D::get_bone_pose_rotation);
ClassDB::bind_method(D_METHOD("get_bone_pose_scale", "bone_idx"), &Skeleton3D::get_bone_pose_scale);
Expand Down
4 changes: 4 additions & 0 deletions scene/3d/skeleton_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class Skeleton3D : public Node3D {
Quaternion pose_rotation;
Vector3 pose_scale = Vector3(1, 1, 1);

bool inherit_scale = true;
Transform3D pose_global;
Transform3D pose_global_no_override;

Expand Down Expand Up @@ -198,6 +199,9 @@ class Skeleton3D : public Node3D {
void set_bone_pose_rotation(int p_bone, const Quaternion &p_rotation);
void set_bone_pose_scale(int p_bone, const Vector3 &p_scale);

bool is_bone_inherit_scale(int p_bone) const;
void set_bone_inherit_scale(int p_bone, bool inherit_scale);

Transform3D get_bone_pose(int p_bone) const;

Vector3 get_bone_pose_position(int p_bone) const;
Expand Down

0 comments on commit 5ad27b1

Please sign in to comment.