diff options
-rw-r--r-- | doc/classes/Skeleton3D.xml | 8 | ||||
-rw-r--r-- | editor/plugins/skeleton_3d_editor_plugin.cpp | 22 | ||||
-rw-r--r-- | scene/3d/skeleton_3d.cpp | 20 | ||||
-rw-r--r-- | scene/3d/skeleton_3d.h | 3 |
4 files changed, 37 insertions, 16 deletions
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml index 80a36acacc..f271220989 100644 --- a/doc/classes/Skeleton3D.xml +++ b/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"> diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 065683d632..d9274351ea 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/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; diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 783edf7fc6..9e403a6ecd 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/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); diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index 279c3e49a2..f8c9fa2c96 100644 --- a/scene/3d/skeleton_3d.h +++ b/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; |