From 2dc823273e8d7d0eb92049c0d687f6a2c247ce13 Mon Sep 17 00:00:00 2001
From: reduz <reduzio@gmail.com>
Date: Wed, 13 Oct 2021 09:37:40 -0300
Subject: [PATCH] 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).
---
 doc/classes/Skeleton3D.xml                    |  36 +---
 editor/import/editor_import_collada.cpp       |  19 +-
 editor/plugins/skeleton_3d_editor_plugin.cpp  |  40 +---
 editor/plugins/skeleton_3d_editor_plugin.h    |   4 +-
 modules/fbx/data/fbx_skeleton.cpp             |   7 +
 modules/fbx/editor_scene_importer_fbx.cpp     |  14 --
 modules/gltf/gltf_document.cpp                |  33 +--
 scene/3d/bone_attachment_3d.cpp               |   6 -
 scene/3d/bone_attachment_3d.h                 |   1 -
 scene/3d/mesh_instance_3d.cpp                 |   4 +-
 scene/3d/skeleton_3d.cpp                      | 201 ++++++------------
 scene/3d/skeleton_3d.h                        |  14 +-
 scene/animation/animation_tree.cpp            |   3 -
 .../skeleton_modification_3d_fabrik.cpp       |   2 +-
 .../skeleton_modification_3d_twoboneik.cpp    |   2 +-
 15 files changed, 107 insertions(+), 279 deletions(-)

diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index e046527b171..e804e7bf24d 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -47,6 +47,11 @@
 				Removes the local pose override on all bones in the skeleton.
 			</description>
 		</method>
+		<method name="create_skin_from_rest_transforms">
+			<return type="Skin" />
+			<description>
+			</description>
+		</method>
 		<method name="execute_modifications">
 			<return type="void" />
 			<argument index="0" name="delta" type="float" />
@@ -88,13 +93,6 @@
 				Returns the amount of bones in the skeleton.
 			</description>
 		</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">
 			<return type="Transform3D" />
 			<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.
 			</description>
 		</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">
 			<return type="Transform3D" />
 			<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].
 			</description>
 		</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">
 			<return type="void" />
 			<argument index="0" name="bone_idx" type="int" />
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 022dc899da9..d1bacf54dec 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -120,6 +120,15 @@ Error ColladaImport::_populate_skeleton(Skeleton3D *p_skeleton, Collada::Node *p
 
 	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)) {
 		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?
@@ -1639,16 +1648,6 @@ void ColladaImport::create_animation(int p_clip, bool p_import_value_tracks) {
 			Transform3D xform = cn->compute_transform(collada);
 			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();
 			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() :
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 3a67c5415cd..f9c46d35c44 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -200,12 +200,7 @@ void BoneTransformEditor::_value_changed_transform(const String p_property_name,
 }
 
 void BoneTransformEditor::_change_transform(Transform3D p_new_transform) {
-	if (property.get_slicec('/', 0) == "bones" && property.get_slicec('/', 2) == "custom_pose") {
-		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") {
+	if (property.get_slicec('/', 0) == "bones") {
 		undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
 		undo_redo->add_undo_property(skeleton, property, skeleton->get(property));
 		undo_redo->add_do_property(skeleton, property, p_new_transform);
@@ -236,21 +231,6 @@ void BoneTransformEditor::_update_properties() {
 	_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) {
 	Basis rotation_basis = tform.get_basis();
 	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_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_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_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_rest", selected_bone, skeleton->get_bone_rest(selected_bone));
 
 	ur->commit_action();
@@ -654,11 +632,9 @@ void Skeleton3DEditor::_joint_tree_selection_changed() {
 
 			pose_editor->set_target(bone_path + "pose");
 			rest_editor->set_target(bone_path + "rest");
-			custom_pose_editor->set_target(bone_path + "custom_pose");
 
 			pose_editor->set_visible(true);
 			rest_editor->set_visible(true);
-			custom_pose_editor->set_visible(true);
 
 			selected_bone = b_idx;
 		}
@@ -679,9 +655,6 @@ void Skeleton3DEditor::_update_properties() {
 	if (pose_editor) {
 		pose_editor->_update_properties();
 	}
-	if (custom_pose_editor) {
-		custom_pose_editor->_update_custom_pose_properties();
-	}
 	_update_gizmo_transform();
 }
 
@@ -820,12 +793,6 @@ void Skeleton3DEditor::create_editors() {
 	rest_editor->set_visible(false);
 	add_child(rest_editor);
 	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) {
@@ -1289,7 +1256,6 @@ void Skeleton3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gi
 	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_rest(p_id) * skeleton->get_bone_custom_pose(p_id);
 	Basis to_local = original_to_local.get_basis().inverse();
 
 	// Prepare transform.
@@ -1518,5 +1484,5 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 	}
 
 	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()));
 }
diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h
index e2a1d9a6286..2c21aab739e 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.h
+++ b/editor/plugins/skeleton_3d_editor_plugin.h
@@ -102,13 +102,12 @@ public:
 	void set_label(const String &p_label) { label = p_label; }
 
 	void _update_properties();
-	void _update_custom_pose_properties();
 	void _update_transform_properties(Transform3D p_transform);
 
 	// Transform can be keyed, whether or not to show the button.
 	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_transform_read_only(const bool p_readonly);
 
@@ -151,7 +150,6 @@ class Skeleton3DEditor : public VBoxContainer {
 	Tree *joint_tree = nullptr;
 	BoneTransformEditor *rest_editor = nullptr;
 	BoneTransformEditor *pose_editor = nullptr;
-	BoneTransformEditor *custom_pose_editor = nullptr;
 
 	VSeparator *separator;
 	MenuButton *skeleton_options = nullptr;
diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp
index 3dc163964ca..11eed2576f4 100644
--- a/modules/fbx/data/fbx_skeleton.cpp
+++ b/modules/fbx/data/fbx_skeleton.cpp
@@ -104,6 +104,13 @@ void FBXSkeleton::init_skeleton(const ImportState &state) {
 		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));
+		{
+			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
 		if (bone->valid_parent && state.fbx_bone_map.has(bone->parent_bone_id)) {
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
index e90eab522ff..879f2812928 100644
--- a/modules/fbx/editor_scene_importer_fbx.cpp
+++ b/modules/fbx/editor_scene_importer_fbx.cpp
@@ -1227,20 +1227,6 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
 										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) {
 								animation->position_track_insert_key(position_idx, time, pos);
 							}
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 32540e7a222..6fd542ca681 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -4319,6 +4319,9 @@ Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) {
 
 			skeleton->add_bone(node->get_name());
 			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) {
 				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
 		// 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)));
-		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->rotation = xform.basis.get_rotation_quaternion();
 		joint_node->position = xform.origin;
@@ -5958,38 +5961,16 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
 
 				if (position_idx >= 0) {
 					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) {
 					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) {
 					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);
 				}
 
@@ -6108,7 +6089,7 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
 			} else {
 				if (skin.is_null()) {
 					// 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->godot_skin = skin;
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index afd11482e33..8e89f4fc541 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -215,8 +215,6 @@ void BoneAttachment3D::_transform_changed() {
 			sk->set_bone_global_pose_override(bone_idx, our_trans, 1.0, true);
 		} 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);
-		} 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);
 			} else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
 				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();
@@ -294,8 +290,6 @@ void BoneAttachment3D::set_override_mode(int p_mode) {
 				sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false);
 			} else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
 				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;
diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h
index cf681cace8f..57b9854e0e4 100644
--- a/scene/3d/bone_attachment_3d.h
+++ b/scene/3d/bone_attachment_3d.h
@@ -47,7 +47,6 @@ class BoneAttachment3D : public Node3D {
 	enum OVERRIDE_MODES {
 		MODE_GLOBAL_POSE,
 		MODE_LOCAL_POSE,
-		MODE_CUSTOM_POSE
 	};
 
 	bool use_external_skeleton = false;
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index 67f4a882281..cfd90e5da06 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -146,11 +146,13 @@ void MeshInstance3D::_resolve_skeleton_path() {
 	if (!skeleton_path.is_empty()) {
 		Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(get_node(skeleton_path));
 		if (skeleton) {
-			new_skin_reference = skeleton->register_skin(skin_internal);
 			if (skin_internal.is_null()) {
+				new_skin_reference = skeleton->register_skin(skeleton->create_skin_from_rest_transforms());
 				//a skin was created for us
 				skin_internal = new_skin_reference->get_skin();
 				notify_property_list_changed();
+			} else {
+				new_skin_reference = skeleton->register_skin(skin_internal);
 			}
 		}
 	}
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 79504b10bb3..9b28d7aff83 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -557,18 +557,6 @@ void Skeleton3D::unparent_bone_and_rest(int p_bone) {
 	_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 {
 	const int bone_size = bones.size();
 	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;
 }
 
-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() {
 	if (dirty) {
 		return;
@@ -938,59 +909,57 @@ void Skeleton3D::_skin_changed() {
 	_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) {
+	ERR_FAIL_COND_V(p_skin.is_null(), Ref<SkinReference>());
+
 	for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
 		if (E->get()->skin == p_skin) {
 			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;
 	skin_ref.instantiate();
 
@@ -998,11 +967,11 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
 	skin_ref->bind_count = 0;
 	skin_ref->skeleton = RenderingServer::get_singleton()->skeleton_create();
 	skin_ref->skeleton_node = this;
-	skin_ref->skin = skin;
+	skin_ref->skin = p_skin;
 
 	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.
 
@@ -1038,61 +1007,33 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
 		Bone &b = bonesptr[current_bone_idx];
 		bool bone_enabled = b.enabled && !show_rest_only;
 
-		if (b.disable_rest) {
-			if (bone_enabled) {
-				b.update_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;
-				}
-			}
+		if (bone_enabled) {
+			b.update_pose_cache();
+			Transform3D pose = b.pose_cache;
 
-		} else {
-			if (bone_enabled) {
-				b.update_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 * (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;
-				}
+			if (b.parent >= 0) {
+				b.pose_global = bonesptr[b.parent].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.rest;
-					b.pose_global_no_override = b.pose_global;
-				} else {
-					b.pose_global = b.rest;
-					b.pose_global_no_override = b.pose_global;
-				}
+				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.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) {
 			Transform3D override_local_pose;
 			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 {
-				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);
 		}
@@ -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());
 	if (bones[p_bone_idx].parent >= 0) {
 		int parent_bone_idx = bones[p_bone_idx].parent;
-		Transform3D conversion_transform = (bones[parent_bone_idx].pose_global * bones[p_bone_idx].rest);
-		return conversion_transform.affine_inverse() * p_global_pose;
+		Transform3D conversion_transform = bones[parent_bone_idx].pose_global.affine_inverse();
+		return conversion_transform * p_global_pose;
 	} else {
 		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());
 	if (bones[p_bone_idx].parent >= 0) {
 		int parent_bone_idx = bones[p_bone_idx].parent;
-		Transform3D conversion_transform = (bones[parent_bone_idx].pose_global * bones[p_bone_idx].rest);
-		return conversion_transform * p_local_pose;
+		return bones[parent_bone_idx].pose_global * p_local_pose;
 	} else {
 		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("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("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("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("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_bone_child_transform", "bone_idx"), &Skeleton3D::force_update_bone_children_transforms);
 
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index aacee3da4ed..f3cf551af75 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -76,7 +76,6 @@ private:
 		bool enabled;
 		int parent;
 
-		bool disable_rest = false;
 		Transform3D rest;
 
 		_FORCE_INLINE_ void update_pose_cache() {
@@ -95,9 +94,6 @@ private:
 		Transform3D pose_global;
 		Transform3D pose_global_no_override;
 
-		bool custom_pose_enable = false;
-		Transform3D custom_pose;
-
 		real_t global_pose_override_amount = 0.0;
 		bool global_pose_override_reset = false;
 		Transform3D global_pose_override;
@@ -119,8 +115,6 @@ private:
 		Bone() {
 			parent = -1;
 			enabled = true;
-			disable_rest = false;
-			custom_pose_enable = false;
 			global_pose_override_amount = 0;
 			global_pose_override_reset = false;
 #ifndef _3D_DISABLED
@@ -199,9 +193,6 @@ public:
 	void remove_bone_child(int p_bone, int p_child);
 	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;
 
 	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;
 	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();
 	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);
@@ -241,6 +229,8 @@ public:
 
 	void localize_rests(); // used for loaders and tools
 
+	Ref<Skin> create_skin_from_rest_transforms();
+
 	Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
 
 	void force_update_all_dirty_bones();
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 2ed8268289e..dd5fe46223a 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -1360,9 +1360,6 @@ void AnimationTree::_process_graph(real_t p_delta) {
 
 						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) {
 						if (t->loc_used) {
 							t->skeleton->set_bone_pose_position(t->bone_idx, t->loc);
diff --git a/scene/resources/skeleton_modification_3d_fabrik.cpp b/scene/resources/skeleton_modification_3d_fabrik.cpp
index e6156159241..20ebbda2561 100644
--- a/scene/resources/skeleton_modification_3d_fabrik.cpp
+++ b/scene/resources/skeleton_modification_3d_fabrik.cpp
@@ -168,7 +168,7 @@ void SkeletonModification3DFABRIK::_execute(real_t p_delta) {
 		// Apply magnet positions:
 		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);
-			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);
 		} else {
 			local_pose_override.origin += fabrik_data_chain[i].magnet_position;
diff --git a/scene/resources/skeleton_modification_3d_twoboneik.cpp b/scene/resources/skeleton_modification_3d_twoboneik.cpp
index ae7a3bab7e6..c1a71148a74 100644
--- a/scene/resources/skeleton_modification_3d_twoboneik.cpp
+++ b/scene/resources/skeleton_modification_3d_twoboneik.cpp
@@ -455,7 +455,7 @@ void SkeletonModification3DTwoBoneIK::calculate_joint_lengths() {
 			joint_two_length = 0;
 			for (int i = 0; i < bone_two_children.size(); i++) {
 				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();
 		} else {