2
0
Silc 'Tokage' Renew 3 жил өмнө
parent
commit
4d4ffa3a2c

+ 8 - 0
doc/classes/Skeleton3D.xml

@@ -111,6 +111,14 @@
 			<return type="Transform3D" />
 			<argument index="0" name="bone_idx" type="int" />
 			<description>
+				Returns the global pose override transform for [code]bone_idx[/code].
+			</description>
+		</method>
+		<method name="get_bone_global_rest" qualifiers="const">
+			<return type="Transform3D" />
+			<argument index="0" name="bone_idx" type="int" />
+			<description>
+				Returns the global rest transform for [code]bone_idx[/code].
 			</description>
 		</method>
 		<method name="get_bone_local_pose_override" qualifiers="const">

+ 6 - 16
editor/plugins/skeleton_3d_editor_plugin.cpp

@@ -1283,9 +1283,6 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 		surface_tool->set_material(unselected_mat);
 	}
 
-	Vector<Transform3D> grests;
-	grests.resize(skeleton->get_bone_count());
-
 	LocalVector<int> bones;
 	LocalVector<float> weights;
 	bones.resize(4);
@@ -1309,11 +1306,6 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 		child_bones_vector = skeleton->get_bone_children(current_bone_idx);
 		int child_bones_size = child_bones_vector.size();
 
-		// You have children but no parent, then you must be a root/parentless bone.
-		if (skeleton->get_bone_parent(current_bone_idx) < 0) {
-			grests.write[current_bone_idx] = skeleton->get_bone_rest(current_bone_idx);
-		}
-
 		for (int i = 0; i < child_bones_size; i++) {
 			// Something wrong.
 			if (child_bones_vector[i] < 0) {
@@ -1322,10 +1314,8 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 
 			int child_bone_idx = child_bones_vector[i];
 
-			grests.write[child_bone_idx] = grests[current_bone_idx] * skeleton->get_bone_rest(child_bone_idx);
-
-			Vector3 v0 = grests[current_bone_idx].origin;
-			Vector3 v1 = grests[child_bone_idx].origin;
+			Vector3 v0 = skeleton->get_bone_global_rest(current_bone_idx).origin;
+			Vector3 v1 = skeleton->get_bone_global_rest(child_bone_idx).origin;
 			Vector3 d = (v1 - v0).normalized();
 			real_t dist = v0.distance_to(v1);
 
@@ -1333,7 +1323,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 			int closest = -1;
 			real_t closest_d = 0.0;
 			for (int j = 0; j < 3; j++) {
-				real_t dp = Math::abs(grests[current_bone_idx].basis[j].normalized().dot(d));
+				real_t dp = Math::abs(skeleton->get_bone_global_rest(current_bone_idx).basis[j].normalized().dot(d));
 				if (j == 0 || dp > closest_d) {
 					closest = j;
 				}
@@ -1360,7 +1350,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 					for (int j = 0; j < 3; j++) {
 						Vector3 axis;
 						if (first == Vector3()) {
-							axis = d.cross(d.cross(grests[current_bone_idx].basis[j])).normalized();
+							axis = d.cross(d.cross(skeleton->get_bone_global_rest(current_bone_idx).basis[j])).normalized();
 							first = axis;
 						} else {
 							axis = d.cross(first).normalized();
@@ -1415,7 +1405,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 				surface_tool->add_vertex(v0);
 				surface_tool->set_bones(bones);
 				surface_tool->set_weights(weights);
-				surface_tool->add_vertex(v0 + (grests[current_bone_idx].basis.inverse())[j].normalized() * dist * bone_axis_length);
+				surface_tool->add_vertex(v0 + (skeleton->get_bone_global_rest(current_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
 
 				if (j == closest) {
 					continue;
@@ -1432,7 +1422,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 					surface_tool->add_vertex(v1);
 					surface_tool->set_bones(bones);
 					surface_tool->set_weights(weights);
-					surface_tool->add_vertex(v1 + (grests[child_bone_idx].basis.inverse())[j].normalized() * dist * bone_axis_length);
+					surface_tool->add_vertex(v1 + (skeleton->get_bone_global_rest(child_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
 
 					if (j == closest) {
 						continue;

+ 20 - 0
scene/3d/skeleton_3d.cpp

@@ -509,6 +509,7 @@ void Skeleton3D::add_bone(const String &p_name) {
 	bones.push_back(b);
 	process_order_dirty = true;
 	version++;
+	rest_dirty = true;
 	_make_dirty();
 	update_gizmos();
 }
@@ -567,6 +568,7 @@ void Skeleton3D::set_bone_parent(int p_bone, int p_parent) {
 
 	bones.write[p_bone].parent = p_parent;
 	process_order_dirty = true;
+	rest_dirty = true;
 	_make_dirty();
 }
 
@@ -585,6 +587,7 @@ void Skeleton3D::unparent_bone_and_rest(int p_bone) {
 	bones.write[p_bone].parent = -1;
 	process_order_dirty = true;
 
+	rest_dirty = true;
 	_make_dirty();
 }
 
@@ -607,6 +610,7 @@ void Skeleton3D::set_bone_children(int p_bone, Vector<int> p_children) {
 	bones.write[p_bone].child_bones = p_children;
 
 	process_order_dirty = true;
+	rest_dirty = true;
 	_make_dirty();
 }
 
@@ -616,6 +620,7 @@ void Skeleton3D::add_bone_child(int p_bone, int p_child) {
 	bones.write[p_bone].child_bones.push_back(p_child);
 
 	process_order_dirty = true;
+	rest_dirty = true;
 	_make_dirty();
 }
 
@@ -631,6 +636,7 @@ void Skeleton3D::remove_bone_child(int p_bone, int p_child) {
 	}
 
 	process_order_dirty = true;
+	rest_dirty = true;
 	_make_dirty();
 }
 
@@ -643,6 +649,7 @@ void Skeleton3D::set_bone_rest(int p_bone, const Transform3D &p_rest) {
 	ERR_FAIL_INDEX(p_bone, bone_size);
 
 	bones.write[p_bone].rest = p_rest;
+	rest_dirty = true;
 	_make_dirty();
 }
 Transform3D Skeleton3D::get_bone_rest(int p_bone) const {
@@ -651,6 +658,14 @@ Transform3D Skeleton3D::get_bone_rest(int p_bone) const {
 
 	return bones[p_bone].rest;
 }
+Transform3D Skeleton3D::get_bone_global_rest(int p_bone) const {
+	const int bone_size = bones.size();
+	ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
+	if (rest_dirty) {
+		const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
+	}
+	return bones[p_bone].global_rest;
+}
 
 void Skeleton3D::set_bone_enabled(int p_bone, bool p_enabled) {
 	const int bone_size = bones.size();
@@ -1058,6 +1073,9 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
 				b.pose_global_no_override = b.pose_global;
 			}
 		}
+		if (rest_dirty) {
+			b.global_rest = b.parent >= 0 ? bonesptr[b.parent].global_rest * b.rest : b.rest;
+		}
 
 		if (b.local_pose_override_amount >= CMP_EPSILON) {
 			Transform3D override_local_pose;
@@ -1088,6 +1106,7 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
 
 		emit_signal(SceneStringNames::get_singleton()->bone_pose_changed, current_bone_idx);
 	}
+	rest_dirty = false;
 }
 
 // Helper functions
@@ -1206,6 +1225,7 @@ 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("get_bone_global_rest", "bone_idx"), &Skeleton3D::get_bone_global_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);

+ 3 - 0
scene/3d/skeleton_3d.h

@@ -77,6 +77,7 @@ private:
 		int parent;
 
 		Transform3D rest;
+		Transform3D global_rest;
 
 		_FORCE_INLINE_ void update_pose_cache() {
 			if (pose_cache_dirty) {
@@ -142,6 +143,7 @@ private:
 
 	void _make_dirty();
 	bool dirty = false;
+	bool rest_dirty = false;
 
 	bool show_rest_only = false;
 
@@ -198,6 +200,7 @@ public:
 
 	void set_bone_rest(int p_bone, const Transform3D &p_rest);
 	Transform3D get_bone_rest(int p_bone) const;
+	Transform3D get_bone_global_rest(int p_bone) const;
 	Transform3D get_bone_global_pose(int p_bone) const;
 	Transform3D get_bone_global_pose_no_override(int p_bone) const;