Remove REST transform influence in skeleton bones

* Animations and Skeletons are now pose-only.
* Rest transform is kept as reference (when it exists) and for IK
* Improves 3D model compatibility (non uniform transforms will properly work, as well as all animations coming from Autodesk products).
This commit is contained in:
reduz 2021-10-13 09:37:40 -03:00
parent 004b44e915
commit 2dc823273e
15 changed files with 107 additions and 279 deletions

View File

@ -47,6 +47,11 @@
Removes the local pose override on all bones in the skeleton. Removes the local pose override on all bones in the skeleton.
</description> </description>
</method> </method>
<method name="create_skin_from_rest_transforms">
<return type="Skin" />
<description>
</description>
</method>
<method name="execute_modifications"> <method name="execute_modifications">
<return type="void" /> <return type="void" />
<argument index="0" name="delta" type="float" /> <argument index="0" name="delta" type="float" />
@ -88,13 +93,6 @@
Returns the amount of bones in the skeleton. Returns the amount of bones in the skeleton.
</description> </description>
</method> </method>
<method name="get_bone_custom_pose" qualifiers="const">
<return type="Transform3D" />
<argument index="0" name="bone_idx" type="int" />
<description>
Returns the custom pose of the specified bone. Custom pose is applied on top of the rest pose.
</description>
</method>
<method name="get_bone_global_pose" qualifiers="const"> <method name="get_bone_global_pose" qualifiers="const">
<return type="Transform3D" /> <return type="Transform3D" />
<argument index="0" name="bone_idx" type="int" /> <argument index="0" name="bone_idx" type="int" />
@ -214,13 +212,6 @@
Returns whether the bone pose for the bone at [code]bone_idx[/code] is enabled. Returns whether the bone pose for the bone at [code]bone_idx[/code] is enabled.
</description> </description>
</method> </method>
<method name="is_bone_rest_disabled" qualifiers="const">
<return type="bool" />
<argument index="0" name="bone_idx" type="int" />
<description>
Returns whether the bone rest for the bone at [code]bone_idx[/code] is disabled.
</description>
</method>
<method name="local_pose_to_global_pose"> <method name="local_pose_to_global_pose">
<return type="Transform3D" /> <return type="Transform3D" />
<argument index="0" name="bone_idx" type="int" /> <argument index="0" name="bone_idx" type="int" />
@ -290,23 +281,6 @@
Sets the children for the passed in bone, [code]bone_idx[/code], to the passed-in array of bone indexes, [code]bone_children[/code]. Sets the children for the passed in bone, [code]bone_idx[/code], to the passed-in array of bone indexes, [code]bone_children[/code].
</description> </description>
</method> </method>
<method name="set_bone_custom_pose">
<return type="void" />
<argument index="0" name="bone_idx" type="int" />
<argument index="1" name="custom_pose" type="Transform3D" />
<description>
Sets the custom pose transform, [code]custom_pose[/code], for the bone at [code]bone_idx[/code]. This pose is an addition to the bone rest pose.
[b]Note:[/b] The pose transform needs to be in bone space. Use [method world_transform_to_global_pose] to convert a world transform, like one you can get from a [Node3D], to bone space.
</description>
</method>
<method name="set_bone_disable_rest">
<return type="void" />
<argument index="0" name="bone_idx" type="int" />
<argument index="1" name="disable" type="bool" />
<description>
Disables the rest pose for the bone at [code]bone_idx[/code] if [code]true[/code], enables the bone rest if [code]false[/code].
</description>
</method>
<method name="set_bone_enabled"> <method name="set_bone_enabled">
<return type="void" /> <return type="void" />
<argument index="0" name="bone_idx" type="int" /> <argument index="0" name="bone_idx" type="int" />

View File

@ -120,6 +120,15 @@ Error ColladaImport::_populate_skeleton(Skeleton3D *p_skeleton, Collada::Node *p
skeleton_bone_map[p_skeleton][joint->sid] = r_bone; skeleton_bone_map[p_skeleton][joint->sid] = r_bone;
{
Transform3D xform = joint->compute_transform(collada);
collada.fix_transform(xform) * joint->post_transform;
p_skeleton->set_bone_pose_position(r_bone, xform.origin);
p_skeleton->set_bone_pose_rotation(r_bone, xform.basis.get_rotation_quaternion());
p_skeleton->set_bone_pose_scale(r_bone, xform.basis.get_scale());
}
if (collada.state.bone_rest_map.has(joint->sid)) { if (collada.state.bone_rest_map.has(joint->sid)) {
p_skeleton->set_bone_rest(r_bone, collada.fix_transform(collada.state.bone_rest_map[joint->sid])); p_skeleton->set_bone_rest(r_bone, collada.fix_transform(collada.state.bone_rest_map[joint->sid]));
//should map this bone to something for animation? //should map this bone to something for animation?
@ -1639,16 +1648,6 @@ void ColladaImport::create_animation(int p_clip, bool p_import_value_tracks) {
Transform3D xform = cn->compute_transform(collada); Transform3D xform = cn->compute_transform(collada);
xform = collada.fix_transform(xform) * cn->post_transform; xform = collada.fix_transform(xform) * cn->post_transform;
if (nm.bone >= 0) {
//make bone transform relative to rest (in case of skeleton)
Skeleton3D *sk = Object::cast_to<Skeleton3D>(nm.node);
if (sk) {
xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform;
} else {
ERR_PRINT("Collada: Invalid skeleton");
}
}
Vector3 s = xform.basis.get_scale(); Vector3 s = xform.basis.get_scale();
bool singular_matrix = Math::is_zero_approx(s.x) || Math::is_zero_approx(s.y) || Math::is_zero_approx(s.z); bool singular_matrix = Math::is_zero_approx(s.x) || Math::is_zero_approx(s.y) || Math::is_zero_approx(s.z);
Quaternion q = singular_matrix ? Quaternion() : Quaternion q = singular_matrix ? Quaternion() :

View File

@ -200,12 +200,7 @@ void BoneTransformEditor::_value_changed_transform(const String p_property_name,
} }
void BoneTransformEditor::_change_transform(Transform3D p_new_transform) { void BoneTransformEditor::_change_transform(Transform3D p_new_transform) {
if (property.get_slicec('/', 0) == "bones" && property.get_slicec('/', 2) == "custom_pose") { if (property.get_slicec('/', 0) == "bones") {
undo_redo->create_action(TTR("Set Custom Bone Pose Transform"), UndoRedo::MERGE_ENDS);
undo_redo->add_undo_method(skeleton, "set_bone_custom_pose", property.get_slicec('/', 1).to_int(), skeleton->get_bone_custom_pose(property.get_slicec('/', 1).to_int()));
undo_redo->add_do_method(skeleton, "set_bone_custom_pose", property.get_slicec('/', 1).to_int(), p_new_transform);
undo_redo->commit_action();
} else if (property.get_slicec('/', 0) == "bones") {
undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS); undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
undo_redo->add_undo_property(skeleton, property, skeleton->get(property)); undo_redo->add_undo_property(skeleton, property, skeleton->get(property));
undo_redo->add_do_property(skeleton, property, p_new_transform); undo_redo->add_do_property(skeleton, property, p_new_transform);
@ -236,21 +231,6 @@ void BoneTransformEditor::_update_properties() {
_update_transform_properties(tform); _update_transform_properties(tform);
} }
void BoneTransformEditor::_update_custom_pose_properties() {
if (updating) {
return;
}
if (!skeleton) {
return;
}
updating = true;
Transform3D tform = skeleton->get_bone_custom_pose(property.to_int());
_update_transform_properties(tform);
}
void BoneTransformEditor::_update_transform_properties(Transform3D tform) { void BoneTransformEditor::_update_transform_properties(Transform3D tform) {
Basis rotation_basis = tform.get_basis(); Basis rotation_basis = tform.get_basis();
Vector3 rotation_radians = rotation_basis.get_rotation_euler(); Vector3 rotation_radians = rotation_basis.get_rotation_euler();
@ -463,9 +443,7 @@ void Skeleton3DEditor::pose_to_rest() {
ur->add_do_method(skeleton, "set_bone_pose", selected_bone, Transform3D()); ur->add_do_method(skeleton, "set_bone_pose", selected_bone, Transform3D());
ur->add_undo_method(skeleton, "set_bone_pose", selected_bone, skeleton->get_bone_pose(selected_bone)); ur->add_undo_method(skeleton, "set_bone_pose", selected_bone, skeleton->get_bone_pose(selected_bone));
ur->add_do_method(skeleton, "set_bone_custom_pose", selected_bone, Transform3D()); ur->add_do_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_rest(selected_bone) * skeleton->get_bone_pose(selected_bone));
ur->add_undo_method(skeleton, "set_bone_custom_pose", selected_bone, skeleton->get_bone_custom_pose(selected_bone));
ur->add_do_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_rest(selected_bone) * skeleton->get_bone_custom_pose(selected_bone) * skeleton->get_bone_pose(selected_bone));
ur->add_undo_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_rest(selected_bone)); ur->add_undo_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_rest(selected_bone));
ur->commit_action(); ur->commit_action();
@ -654,11 +632,9 @@ void Skeleton3DEditor::_joint_tree_selection_changed() {
pose_editor->set_target(bone_path + "pose"); pose_editor->set_target(bone_path + "pose");
rest_editor->set_target(bone_path + "rest"); rest_editor->set_target(bone_path + "rest");
custom_pose_editor->set_target(bone_path + "custom_pose");
pose_editor->set_visible(true); pose_editor->set_visible(true);
rest_editor->set_visible(true); rest_editor->set_visible(true);
custom_pose_editor->set_visible(true);
selected_bone = b_idx; selected_bone = b_idx;
} }
@ -679,9 +655,6 @@ void Skeleton3DEditor::_update_properties() {
if (pose_editor) { if (pose_editor) {
pose_editor->_update_properties(); pose_editor->_update_properties();
} }
if (custom_pose_editor) {
custom_pose_editor->_update_custom_pose_properties();
}
_update_gizmo_transform(); _update_gizmo_transform();
} }
@ -820,12 +793,6 @@ void Skeleton3DEditor::create_editors() {
rest_editor->set_visible(false); rest_editor->set_visible(false);
add_child(rest_editor); add_child(rest_editor);
rest_editor->set_transform_read_only(true); rest_editor->set_transform_read_only(true);
custom_pose_editor = memnew(BoneTransformEditor(skeleton));
custom_pose_editor->set_label(TTR("Bone Custom Pose"));
custom_pose_editor->set_visible(false);
add_child(custom_pose_editor);
custom_pose_editor->set_transform_read_only(true);
} }
void Skeleton3DEditor::_notification(int p_what) { void Skeleton3DEditor::_notification(int p_what) {
@ -1289,7 +1256,6 @@ void Skeleton3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gi
if (parent_idx >= 0) { if (parent_idx >= 0) {
original_to_local = original_to_local * skeleton->get_bone_global_pose(parent_idx); original_to_local = original_to_local * skeleton->get_bone_global_pose(parent_idx);
} }
original_to_local = original_to_local * skeleton->get_bone_rest(p_id) * skeleton->get_bone_custom_pose(p_id);
Basis to_local = original_to_local.get_basis().inverse(); Basis to_local = original_to_local.get_basis().inverse();
// Prepare transform. // Prepare transform.
@ -1518,5 +1484,5 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
} }
Ref<ArrayMesh> m = surface_tool->commit(); Ref<ArrayMesh> m = surface_tool->commit();
p_gizmo->add_mesh(m, Ref<Material>(), Transform3D(), skeleton->register_skin(Ref<Skin>())); p_gizmo->add_mesh(m, Ref<Material>(), Transform3D(), skeleton->register_skin(skeleton->create_skin_from_rest_transforms()));
} }

View File

@ -102,13 +102,12 @@ public:
void set_label(const String &p_label) { label = p_label; } void set_label(const String &p_label) { label = p_label; }
void _update_properties(); void _update_properties();
void _update_custom_pose_properties();
void _update_transform_properties(Transform3D p_transform); void _update_transform_properties(Transform3D p_transform);
// Transform can be keyed, whether or not to show the button. // Transform can be keyed, whether or not to show the button.
void set_keyable(const bool p_keyable); void set_keyable(const bool p_keyable);
// When rest mode, pose and custom_pose editor are diasbled. // When rest mode, pose editor are diasbled.
void set_properties_read_only(const bool p_readonly); void set_properties_read_only(const bool p_readonly);
void set_transform_read_only(const bool p_readonly); void set_transform_read_only(const bool p_readonly);
@ -151,7 +150,6 @@ class Skeleton3DEditor : public VBoxContainer {
Tree *joint_tree = nullptr; Tree *joint_tree = nullptr;
BoneTransformEditor *rest_editor = nullptr; BoneTransformEditor *rest_editor = nullptr;
BoneTransformEditor *pose_editor = nullptr; BoneTransformEditor *pose_editor = nullptr;
BoneTransformEditor *custom_pose_editor = nullptr;
VSeparator *separator; VSeparator *separator;
MenuButton *skeleton_options = nullptr; MenuButton *skeleton_options = nullptr;

View File

@ -104,6 +104,13 @@ void FBXSkeleton::init_skeleton(const ImportState &state) {
print_verbose("working on bone: " + itos(bone_index) + " bone name:" + bone->bone_name); print_verbose("working on bone: " + itos(bone_index) + " bone name:" + bone->bone_name);
skeleton->set_bone_rest(bone->godot_bone_id, get_unscaled_transform(bone->node->pivot_transform->LocalTransform, state.scale)); skeleton->set_bone_rest(bone->godot_bone_id, get_unscaled_transform(bone->node->pivot_transform->LocalTransform, state.scale));
{
Transform3D base_xform = bone->node->pivot_transform->LocalTransform;
skeleton->set_bone_pose_position(bone_index, base_xform.origin);
skeleton->set_bone_pose_rotation(bone_index, base_xform.basis.get_rotation_quaternion());
skeleton->set_bone_pose_scale(bone_index, base_xform.basis.get_scale());
}
// lookup parent ID // lookup parent ID
if (bone->valid_parent && state.fbx_bone_map.has(bone->parent_bone_id)) { if (bone->valid_parent && state.fbx_bone_map.has(bone->parent_bone_id)) {

View File

@ -1227,20 +1227,6 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
AssetImportAnimation::INTERP_LINEAR); AssetImportAnimation::INTERP_LINEAR);
} }
// node animations must also include pivots
if (skeleton_bone >= 0) {
Transform3D xform = Transform3D();
xform.basis.set_quaternion_scale(rot, scale);
xform.origin = pos;
const Transform3D t = bone_rest.affine_inverse() * xform;
// populate this again
rot = t.basis.get_rotation_quaternion();
rot.normalize();
scale = t.basis.get_scale();
pos = t.origin;
}
if (position_idx >= 0) { if (position_idx >= 0) {
animation->position_track_insert_key(position_idx, time, pos); animation->position_track_insert_key(position_idx, time, pos);
} }

View File

@ -4319,6 +4319,9 @@ Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) {
skeleton->add_bone(node->get_name()); skeleton->add_bone(node->get_name());
skeleton->set_bone_rest(bone_index, node->xform); skeleton->set_bone_rest(bone_index, node->xform);
skeleton->set_bone_pose_position(bone_index, node->position);
skeleton->set_bone_pose_rotation(bone_index, node->rotation.normalized());
skeleton->set_bone_pose_scale(bone_index, node->scale);
if (node->parent >= 0 && state->nodes[node->parent]->skeleton == skel_i) { if (node->parent >= 0 && state->nodes[node->parent]->skeleton == skel_i) {
const int bone_parent = skeleton->find_bone(state->nodes[node->parent]->get_name()); const int bone_parent = skeleton->find_bone(state->nodes[node->parent]->get_name());
@ -5470,7 +5473,7 @@ void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFS
// Note that we cannot use _gen_unique_bone_name here, because glTF spec requires all node // Note that we cannot use _gen_unique_bone_name here, because glTF spec requires all node
// names to be unique regardless of whether or not they are used as joints. // names to be unique regardless of whether or not they are used as joints.
joint_node->set_name(_gen_unique_name(state, skeleton->get_bone_name(bone_i))); joint_node->set_name(_gen_unique_name(state, skeleton->get_bone_name(bone_i)));
Transform3D xform = skeleton->get_bone_rest(bone_i) * skeleton->get_bone_pose(bone_i); Transform3D xform = skeleton->get_bone_pose(bone_i);
joint_node->scale = xform.basis.get_scale(); joint_node->scale = xform.basis.get_scale();
joint_node->rotation = xform.basis.get_rotation_quaternion(); joint_node->rotation = xform.basis.get_rotation_quaternion();
joint_node->position = xform.origin; joint_node->position = xform.origin;
@ -5958,38 +5961,16 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (position_idx >= 0) { if (position_idx >= 0) {
pos = _interpolate_track<Vector3>(track.position_track.times, track.position_track.values, time, track.position_track.interpolation); pos = _interpolate_track<Vector3>(track.position_track.times, track.position_track.values, time, track.position_track.interpolation);
animation->position_track_insert_key(position_idx, time, pos);
} }
if (rotation_idx >= 0) { if (rotation_idx >= 0) {
rot = _interpolate_track<Quaternion>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation); rot = _interpolate_track<Quaternion>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation);
animation->rotation_track_insert_key(rotation_idx, time, rot);
} }
if (scale_idx >= 0) { if (scale_idx >= 0) {
scale = _interpolate_track<Vector3>(track.scale_track.times, track.scale_track.values, time, track.scale_track.interpolation); scale = _interpolate_track<Vector3>(track.scale_track.times, track.scale_track.values, time, track.scale_track.interpolation);
}
if (gltf_node->skeleton >= 0) {
Transform3D xform;
xform.basis.set_quaternion_scale(rot, scale);
xform.origin = pos;
const Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton;
const int bone_idx = skeleton->find_bone(gltf_node->get_name());
xform = skeleton->get_bone_rest(bone_idx).affine_inverse() * xform;
rot = xform.basis.get_rotation_quaternion();
rot.normalize();
scale = xform.basis.get_scale();
pos = xform.origin;
}
if (position_idx >= 0) {
animation->position_track_insert_key(position_idx, time, pos);
}
if (rotation_idx >= 0) {
animation->rotation_track_insert_key(rotation_idx, time, rot);
}
if (scale_idx >= 0) {
animation->scale_track_insert_key(scale_idx, time, scale); animation->scale_track_insert_key(scale_idx, time, scale);
} }
@ -6108,7 +6089,7 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
} else { } else {
if (skin.is_null()) { if (skin.is_null()) {
// Note that gltf_skin_key should remain null, so these can share a reference. // Note that gltf_skin_key should remain null, so these can share a reference.
skin = skeleton->register_skin(nullptr)->get_skin(); skin = skeleton->create_skin_from_rest_transforms();
} }
gltf_skin.instantiate(); gltf_skin.instantiate();
gltf_skin->godot_skin = skin; gltf_skin->godot_skin = skin;

View File

@ -215,8 +215,6 @@ void BoneAttachment3D::_transform_changed() {
sk->set_bone_global_pose_override(bone_idx, our_trans, 1.0, true); sk->set_bone_global_pose_override(bone_idx, our_trans, 1.0, true);
} else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) { } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
sk->set_bone_local_pose_override(bone_idx, sk->global_pose_to_local_pose(bone_idx, our_trans), 1.0, true); sk->set_bone_local_pose_override(bone_idx, sk->global_pose_to_local_pose(bone_idx, our_trans), 1.0, true);
} else if (override_mode == OVERRIDE_MODES::MODE_CUSTOM_POSE) {
sk->set_bone_custom_pose(bone_idx, sk->global_pose_to_local_pose(bone_idx, our_trans));
} }
} }
} }
@ -273,8 +271,6 @@ void BoneAttachment3D::set_override_pose(bool p_override) {
sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false); sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false);
} else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) { } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false); sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false);
} else if (override_mode == OVERRIDE_MODES::MODE_CUSTOM_POSE) {
sk->set_bone_custom_pose(bone_idx, Transform3D());
} }
} }
_transform_changed(); _transform_changed();
@ -294,8 +290,6 @@ void BoneAttachment3D::set_override_mode(int p_mode) {
sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false); sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false);
} else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) { } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false); sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false);
} else if (override_mode == OVERRIDE_MODES::MODE_CUSTOM_POSE) {
sk->set_bone_custom_pose(bone_idx, Transform3D());
} }
} }
override_mode = p_mode; override_mode = p_mode;

View File

@ -47,7 +47,6 @@ class BoneAttachment3D : public Node3D {
enum OVERRIDE_MODES { enum OVERRIDE_MODES {
MODE_GLOBAL_POSE, MODE_GLOBAL_POSE,
MODE_LOCAL_POSE, MODE_LOCAL_POSE,
MODE_CUSTOM_POSE
}; };
bool use_external_skeleton = false; bool use_external_skeleton = false;

View File

@ -146,11 +146,13 @@ void MeshInstance3D::_resolve_skeleton_path() {
if (!skeleton_path.is_empty()) { if (!skeleton_path.is_empty()) {
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(get_node(skeleton_path)); Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(get_node(skeleton_path));
if (skeleton) { if (skeleton) {
new_skin_reference = skeleton->register_skin(skin_internal);
if (skin_internal.is_null()) { if (skin_internal.is_null()) {
new_skin_reference = skeleton->register_skin(skeleton->create_skin_from_rest_transforms());
//a skin was created for us //a skin was created for us
skin_internal = new_skin_reference->get_skin(); skin_internal = new_skin_reference->get_skin();
notify_property_list_changed(); notify_property_list_changed();
} else {
new_skin_reference = skeleton->register_skin(skin_internal);
} }
} }
} }

View File

@ -557,18 +557,6 @@ void Skeleton3D::unparent_bone_and_rest(int p_bone) {
_make_dirty(); _make_dirty();
} }
void Skeleton3D::set_bone_disable_rest(int p_bone, bool p_disable) {
const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].disable_rest = p_disable;
}
bool Skeleton3D::is_bone_rest_disabled(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, false);
return bones[p_bone].disable_rest;
}
int Skeleton3D::get_bone_parent(int p_bone) const { int Skeleton3D::get_bone_parent(int p_bone) const {
const int bone_size = bones.size(); const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, -1); ERR_FAIL_INDEX_V(p_bone, bone_size, -1);
@ -723,23 +711,6 @@ Transform3D Skeleton3D::get_bone_pose(int p_bone) const {
return bones[p_bone].pose_cache; return bones[p_bone].pose_cache;
} }
void Skeleton3D::set_bone_custom_pose(int p_bone, const Transform3D &p_custom_pose) {
const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone, bone_size);
//ERR_FAIL_COND( !is_inside_scene() );
bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform3D());
bones.write[p_bone].custom_pose = p_custom_pose;
_make_dirty();
}
Transform3D Skeleton3D::get_bone_custom_pose(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
return bones[p_bone].custom_pose;
}
void Skeleton3D::_make_dirty() { void Skeleton3D::_make_dirty() {
if (dirty) { if (dirty) {
return; return;
@ -938,59 +909,57 @@ void Skeleton3D::_skin_changed() {
_make_dirty(); _make_dirty();
} }
Ref<Skin> Skeleton3D::create_skin_from_rest_transforms() {
Ref<Skin> skin;
skin.instantiate();
skin->set_bind_count(bones.size());
_update_process_order(); // Just in case.
// Pose changed, rebuild cache of inverses.
const Bone *bonesptr = bones.ptr();
int len = bones.size();
// Calculate global rests and invert them.
LocalVector<int> bones_to_process;
bones_to_process = get_parentless_bones();
while (bones_to_process.size() > 0) {
int current_bone_idx = bones_to_process[0];
const Bone &b = bonesptr[current_bone_idx];
bones_to_process.erase(current_bone_idx);
LocalVector<int> child_bones_vector;
child_bones_vector = get_bone_children(current_bone_idx);
int child_bones_size = child_bones_vector.size();
if (b.parent < 0) {
skin->set_bind_pose(current_bone_idx, b.rest);
}
for (int i = 0; i < child_bones_size; i++) {
int child_bone_idx = child_bones_vector[i];
const Bone &cb = bonesptr[child_bone_idx];
skin->set_bind_pose(child_bone_idx, skin->get_bind_pose(current_bone_idx) * cb.rest);
// Add the bone's children to the list of bones to be processed.
bones_to_process.push_back(child_bones_vector[i]);
}
}
for (int i = 0; i < len; i++) {
// The inverse is what is actually required.
skin->set_bind_bone(i, i);
skin->set_bind_pose(i, skin->get_bind_pose(i).affine_inverse());
}
return skin;
}
Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) { Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
ERR_FAIL_COND_V(p_skin.is_null(), Ref<SkinReference>());
for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) { for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
if (E->get()->skin == p_skin) { if (E->get()->skin == p_skin) {
return Ref<SkinReference>(E->get()); return Ref<SkinReference>(E->get());
} }
} }
Ref<Skin> skin = p_skin;
if (skin.is_null()) {
// Need to create one from existing code, this is for compatibility only
// when skeletons did not support skins. It is also used by gizmo
// to display the skeleton.
skin.instantiate();
skin->set_bind_count(bones.size());
_update_process_order(); // Just in case.
// Pose changed, rebuild cache of inverses.
const Bone *bonesptr = bones.ptr();
int len = bones.size();
// Calculate global rests and invert them.
LocalVector<int> bones_to_process;
bones_to_process = get_parentless_bones();
while (bones_to_process.size() > 0) {
int current_bone_idx = bones_to_process[0];
const Bone &b = bonesptr[current_bone_idx];
bones_to_process.erase(current_bone_idx);
LocalVector<int> child_bones_vector;
child_bones_vector = get_bone_children(current_bone_idx);
int child_bones_size = child_bones_vector.size();
if (b.parent < 0) {
skin->set_bind_pose(current_bone_idx, b.rest);
}
for (int i = 0; i < child_bones_size; i++) {
int child_bone_idx = child_bones_vector[i];
const Bone &cb = bonesptr[child_bone_idx];
skin->set_bind_pose(child_bone_idx, skin->get_bind_pose(current_bone_idx) * cb.rest);
// Add the bone's children to the list of bones to be processed.
bones_to_process.push_back(child_bones_vector[i]);
}
}
for (int i = 0; i < len; i++) {
// The inverse is what is actually required.
skin->set_bind_bone(i, i);
skin->set_bind_pose(i, skin->get_bind_pose(i).affine_inverse());
}
}
ERR_FAIL_COND_V(skin.is_null(), Ref<SkinReference>());
Ref<SkinReference> skin_ref; Ref<SkinReference> skin_ref;
skin_ref.instantiate(); skin_ref.instantiate();
@ -998,11 +967,11 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
skin_ref->bind_count = 0; skin_ref->bind_count = 0;
skin_ref->skeleton = RenderingServer::get_singleton()->skeleton_create(); skin_ref->skeleton = RenderingServer::get_singleton()->skeleton_create();
skin_ref->skeleton_node = this; skin_ref->skeleton_node = this;
skin_ref->skin = skin; skin_ref->skin = p_skin;
skin_bindings.insert(skin_ref.operator->()); skin_bindings.insert(skin_ref.operator->());
skin->connect("changed", Callable(skin_ref.operator->(), "_skin_changed")); skin_ref->skin->connect("changed", Callable(skin_ref.operator->(), "_skin_changed"));
_make_dirty(); // Skin needs to be updated, so update skeleton. _make_dirty(); // Skin needs to be updated, so update skeleton.
@ -1038,61 +1007,33 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
Bone &b = bonesptr[current_bone_idx]; Bone &b = bonesptr[current_bone_idx];
bool bone_enabled = b.enabled && !show_rest_only; bool bone_enabled = b.enabled && !show_rest_only;
if (b.disable_rest) { if (bone_enabled) {
if (bone_enabled) { b.update_pose_cache();
b.update_pose_cache(); Transform3D pose = b.pose_cache;
Transform3D pose = b.pose_cache;
if (b.custom_pose_enable) {
pose = b.custom_pose * pose;
}
if (b.parent >= 0) {
b.pose_global = bonesptr[b.parent].pose_global * pose;
b.pose_global_no_override = b.pose_global;
} else {
b.pose_global = pose;
b.pose_global_no_override = b.pose_global;
}
} else {
if (b.parent >= 0) {
b.pose_global = bonesptr[b.parent].pose_global;
b.pose_global_no_override = b.pose_global;
} else {
b.pose_global = Transform3D();
b.pose_global_no_override = b.pose_global;
}
}
} else { if (b.parent >= 0) {
if (bone_enabled) { b.pose_global = bonesptr[b.parent].pose_global * pose;
b.update_pose_cache(); b.pose_global_no_override = b.pose_global;
Transform3D pose = b.pose_cache;
if (b.custom_pose_enable) {
pose = b.custom_pose * pose;
}
if (b.parent >= 0) {
b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose);
b.pose_global_no_override = b.pose_global;
} else {
b.pose_global = b.rest * pose;
b.pose_global_no_override = b.pose_global;
}
} else { } else {
if (b.parent >= 0) { b.pose_global = pose;
b.pose_global = bonesptr[b.parent].pose_global * b.rest; b.pose_global_no_override = b.pose_global;
b.pose_global_no_override = b.pose_global; }
} else { } else {
b.pose_global = b.rest; if (b.parent >= 0) {
b.pose_global_no_override = b.pose_global; b.pose_global = bonesptr[b.parent].pose_global * b.rest;
} b.pose_global_no_override = b.pose_global;
} else {
b.pose_global = b.rest;
b.pose_global_no_override = b.pose_global;
} }
} }
if (b.local_pose_override_amount >= CMP_EPSILON) { if (b.local_pose_override_amount >= CMP_EPSILON) {
Transform3D override_local_pose; Transform3D override_local_pose;
if (b.parent >= 0) { if (b.parent >= 0) {
override_local_pose = bonesptr[b.parent].pose_global * (b.rest * b.local_pose_override); override_local_pose = bonesptr[b.parent].pose_global * b.local_pose_override;
} else { } else {
override_local_pose = (b.rest * b.local_pose_override); override_local_pose = b.local_pose_override;
} }
b.pose_global = b.pose_global.interpolate_with(override_local_pose, b.local_pose_override_amount); b.pose_global = b.pose_global.interpolate_with(override_local_pose, b.local_pose_override_amount);
} }
@ -1133,8 +1074,8 @@ Transform3D Skeleton3D::global_pose_to_local_pose(int p_bone_idx, Transform3D p_
ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D()); ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D());
if (bones[p_bone_idx].parent >= 0) { if (bones[p_bone_idx].parent >= 0) {
int parent_bone_idx = bones[p_bone_idx].parent; int parent_bone_idx = bones[p_bone_idx].parent;
Transform3D conversion_transform = (bones[parent_bone_idx].pose_global * bones[p_bone_idx].rest); Transform3D conversion_transform = bones[parent_bone_idx].pose_global.affine_inverse();
return conversion_transform.affine_inverse() * p_global_pose; return conversion_transform * p_global_pose;
} else { } else {
return p_global_pose; return p_global_pose;
} }
@ -1145,8 +1086,7 @@ Transform3D Skeleton3D::local_pose_to_global_pose(int p_bone_idx, Transform3D p_
ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D()); ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D());
if (bones[p_bone_idx].parent >= 0) { if (bones[p_bone_idx].parent >= 0) {
int parent_bone_idx = bones[p_bone_idx].parent; int parent_bone_idx = bones[p_bone_idx].parent;
Transform3D conversion_transform = (bones[parent_bone_idx].pose_global * bones[p_bone_idx].rest); return bones[parent_bone_idx].pose_global * p_local_pose;
return conversion_transform * p_local_pose;
} else { } else {
return p_local_pose; return p_local_pose;
} }
@ -1236,13 +1176,11 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton3D::get_bone_rest); ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton3D::get_bone_rest);
ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton3D::set_bone_rest); ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton3D::set_bone_rest);
ClassDB::bind_method(D_METHOD("create_skin_from_rest_transforms"), &Skeleton3D::create_skin_from_rest_transforms);
ClassDB::bind_method(D_METHOD("register_skin", "skin"), &Skeleton3D::register_skin); ClassDB::bind_method(D_METHOD("register_skin", "skin"), &Skeleton3D::register_skin);
ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton3D::localize_rests); ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton3D::localize_rests);
ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton3D::set_bone_disable_rest);
ClassDB::bind_method(D_METHOD("is_bone_rest_disabled", "bone_idx"), &Skeleton3D::is_bone_rest_disabled);
ClassDB::bind_method(D_METHOD("clear_bones"), &Skeleton3D::clear_bones); ClassDB::bind_method(D_METHOD("clear_bones"), &Skeleton3D::clear_bones);
ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton3D::get_bone_pose); ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton3D::get_bone_pose);
@ -1267,9 +1205,6 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bone_local_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_local_pose_override, DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_bone_local_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_local_pose_override, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_bone_local_pose_override", "bone_idx"), &Skeleton3D::get_bone_local_pose_override); ClassDB::bind_method(D_METHOD("get_bone_local_pose_override", "bone_idx"), &Skeleton3D::get_bone_local_pose_override);
ClassDB::bind_method(D_METHOD("get_bone_custom_pose", "bone_idx"), &Skeleton3D::get_bone_custom_pose);
ClassDB::bind_method(D_METHOD("set_bone_custom_pose", "bone_idx", "custom_pose"), &Skeleton3D::set_bone_custom_pose);
ClassDB::bind_method(D_METHOD("force_update_all_bone_transforms"), &Skeleton3D::force_update_all_bone_transforms); ClassDB::bind_method(D_METHOD("force_update_all_bone_transforms"), &Skeleton3D::force_update_all_bone_transforms);
ClassDB::bind_method(D_METHOD("force_update_bone_child_transform", "bone_idx"), &Skeleton3D::force_update_bone_children_transforms); ClassDB::bind_method(D_METHOD("force_update_bone_child_transform", "bone_idx"), &Skeleton3D::force_update_bone_children_transforms);

View File

@ -76,7 +76,6 @@ private:
bool enabled; bool enabled;
int parent; int parent;
bool disable_rest = false;
Transform3D rest; Transform3D rest;
_FORCE_INLINE_ void update_pose_cache() { _FORCE_INLINE_ void update_pose_cache() {
@ -95,9 +94,6 @@ private:
Transform3D pose_global; Transform3D pose_global;
Transform3D pose_global_no_override; Transform3D pose_global_no_override;
bool custom_pose_enable = false;
Transform3D custom_pose;
real_t global_pose_override_amount = 0.0; real_t global_pose_override_amount = 0.0;
bool global_pose_override_reset = false; bool global_pose_override_reset = false;
Transform3D global_pose_override; Transform3D global_pose_override;
@ -119,8 +115,6 @@ private:
Bone() { Bone() {
parent = -1; parent = -1;
enabled = true; enabled = true;
disable_rest = false;
custom_pose_enable = false;
global_pose_override_amount = 0; global_pose_override_amount = 0;
global_pose_override_reset = false; global_pose_override_reset = false;
#ifndef _3D_DISABLED #ifndef _3D_DISABLED
@ -199,9 +193,6 @@ public:
void remove_bone_child(int p_bone, int p_child); void remove_bone_child(int p_bone, int p_child);
Vector<int> get_parentless_bones(); Vector<int> get_parentless_bones();
void set_bone_disable_rest(int p_bone, bool p_disable);
bool is_bone_rest_disabled(int p_bone) const;
int get_bone_count() const; int get_bone_count() const;
void set_bone_rest(int p_bone, const Transform3D &p_rest); void set_bone_rest(int p_bone, const Transform3D &p_rest);
@ -228,9 +219,6 @@ public:
Quaternion get_bone_pose_rotation(int p_bone) const; Quaternion get_bone_pose_rotation(int p_bone) const;
Vector3 get_bone_pose_scale(int p_bone) const; Vector3 get_bone_pose_scale(int p_bone) const;
void set_bone_custom_pose(int p_bone, const Transform3D &p_custom_pose);
Transform3D get_bone_custom_pose(int p_bone) const;
void clear_bones_global_pose_override(); void clear_bones_global_pose_override();
Transform3D get_bone_global_pose_override(int p_bone) const; Transform3D get_bone_global_pose_override(int p_bone) const;
void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false); void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false);
@ -241,6 +229,8 @@ public:
void localize_rests(); // used for loaders and tools void localize_rests(); // used for loaders and tools
Ref<Skin> create_skin_from_rest_transforms();
Ref<SkinReference> register_skin(const Ref<Skin> &p_skin); Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
void force_update_all_dirty_bones(); void force_update_all_dirty_bones();

View File

@ -1360,9 +1360,6 @@ void AnimationTree::_process_graph(real_t p_delta) {
root_motion_transform = xform; root_motion_transform = xform;
if (t->skeleton && t->bone_idx >= 0) {
root_motion_transform = (t->skeleton->get_bone_rest(t->bone_idx) * root_motion_transform) * t->skeleton->get_bone_rest(t->bone_idx).affine_inverse();
}
} else if (t->skeleton && t->bone_idx >= 0) { } else if (t->skeleton && t->bone_idx >= 0) {
if (t->loc_used) { if (t->loc_used) {
t->skeleton->set_bone_pose_position(t->bone_idx, t->loc); t->skeleton->set_bone_pose_position(t->bone_idx, t->loc);

View File

@ -168,7 +168,7 @@ void SkeletonModification3DFABRIK::_execute(real_t p_delta) {
// Apply magnet positions: // Apply magnet positions:
if (stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx) >= 0) { if (stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx) >= 0) {
int parent_bone_idx = stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx); int parent_bone_idx = stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx);
Transform3D conversion_transform = (stack->skeleton->get_bone_global_pose(parent_bone_idx) * stack->skeleton->get_bone_rest(parent_bone_idx)); Transform3D conversion_transform = (stack->skeleton->get_bone_global_pose(parent_bone_idx));
local_pose_override.origin += conversion_transform.basis.xform_inv(fabrik_data_chain[i].magnet_position); local_pose_override.origin += conversion_transform.basis.xform_inv(fabrik_data_chain[i].magnet_position);
} else { } else {
local_pose_override.origin += fabrik_data_chain[i].magnet_position; local_pose_override.origin += fabrik_data_chain[i].magnet_position;

View File

@ -455,7 +455,7 @@ void SkeletonModification3DTwoBoneIK::calculate_joint_lengths() {
joint_two_length = 0; joint_two_length = 0;
for (int i = 0; i < bone_two_children.size(); i++) { for (int i = 0; i < bone_two_children.size(); i++) {
joint_two_length += bone_two_rest_trans.origin.distance_to( joint_two_length += bone_two_rest_trans.origin.distance_to(
stack->skeleton->local_pose_to_global_pose(bone_two_children[i], stack->skeleton->get_bone_rest(bone_two_children[i])).origin); stack->skeleton->get_bone_global_pose(bone_two_children[i]).origin);
} }
joint_two_length = joint_two_length / bone_two_children.size(); joint_two_length = joint_two_length / bone_two_children.size();
} else { } else {