Browse Source

GLTF: Make skeleton bone names unique per-skeleton instead of scene-wide

Aaron Franke 3 months ago
parent
commit
8350919575

+ 1 - 1
modules/fbx/fbx_document.cpp

@@ -2221,7 +2221,7 @@ Error FBXDocument::_parse_fbx_state(Ref<FBXState> p_state, const String &p_searc
 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
 
 	/* CREATE SKELETONS */
-	err = SkinTool::_create_skeletons(p_state->unique_names, p_state->skins, p_state->nodes, p_state->skeleton3d_to_fbx_skeleton, p_state->skeletons, p_state->scene_nodes);
+	err = SkinTool::_create_skeletons(p_state->unique_names, p_state->skins, p_state->nodes, p_state->skeleton3d_to_fbx_skeleton, p_state->skeletons, p_state->scene_nodes, _naming_version);
 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
 
 	/* CREATE SKINS */

+ 2 - 0
modules/fbx/fbx_document.h

@@ -40,6 +40,8 @@
 class FBXDocument : public GLTFDocument {
 	GDCLASS(FBXDocument, GLTFDocument);
 
+	int _naming_version = 2;
+
 public:
 	enum {
 		TEXTURE_TYPE_GENERIC = 0,

+ 1 - 1
modules/gltf/gltf_document.cpp

@@ -8622,7 +8622,7 @@ Node *GLTFDocument::_generate_scene_node_tree(Ref<GLTFState> p_state) {
 	// Generate the skeletons and skins (if any).
 	HashMap<ObjectID, SkinSkeletonIndex> skeleton_map;
 	Error err = SkinTool::_create_skeletons(p_state->unique_names, p_state->skins, p_state->nodes,
-			skeleton_map, p_state->skeletons, p_state->scene_nodes);
+			skeleton_map, p_state->skeletons, p_state->scene_nodes, _naming_version);
 	ERR_FAIL_COND_V_MSG(err != OK, nullptr, "glTF: Failed to create skeletons.");
 	err = _create_skins(p_state);
 	ERR_FAIL_COND_V_MSG(err != OK, nullptr, "glTF: Failed to create skins.");

+ 15 - 2
modules/gltf/skin_tool.cpp

@@ -563,9 +563,13 @@ Error SkinTool::_create_skeletons(
 		Vector<Ref<GLTFNode>> &nodes,
 		HashMap<ObjectID, GLTFSkeletonIndex> &skeleton3d_to_gltf_skeleton,
 		Vector<Ref<GLTFSkeleton>> &skeletons,
-		HashMap<GLTFNodeIndex, Node *> &scene_nodes) {
+		HashMap<GLTFNodeIndex, Node *> &scene_nodes,
+		int p_naming_version) {
+	// This is the syntax to duplicate a Godot HashSet.
+	HashSet<String> unique_node_names(unique_names);
 	for (SkinSkeletonIndex skel_i = 0; skel_i < skeletons.size(); ++skel_i) {
 		Ref<GLTFSkeleton> gltf_skeleton = skeletons.write[skel_i];
+		HashSet<String> skel_unique_names(unique_node_names);
 
 		Skeleton3D *skeleton = memnew(Skeleton3D);
 		gltf_skeleton->godot_skeleton = skeleton;
@@ -613,7 +617,16 @@ Error SkinTool::_create_skeletons(
 				node->set_name("bone");
 			}
 
-			node->set_name(_gen_unique_bone_name(unique_names, node->get_name()));
+			if (p_naming_version < 2) {
+				node->set_name(_gen_unique_bone_name(unique_names, node->get_name()));
+			} else {
+				// Make sure the bone name is unique in the skeleton and unique compared
+				// to scene nodes, but bone names may be duplicated between skeletons.
+				// Example: Two skeletons with a "Head" bone should not have one become "Head_2".
+				const String unique_bone_name = _gen_unique_bone_name(skel_unique_names, node->get_name());
+				unique_names.insert(unique_bone_name);
+				node->set_name(unique_bone_name);
+			}
 
 			skeleton->add_bone(node->get_name());
 			Transform3D rest_transform = node->get_additional_data("GODOT_rest_transform");

+ 2 - 1
modules/gltf/skin_tool.h

@@ -97,6 +97,7 @@ public:
 			Vector<Ref<GLTFNode>> &r_nodes,
 			HashMap<ObjectID, GLTFSkeletonIndex> &r_skeleton3d_to_fbx_skeleton,
 			Vector<Ref<GLTFSkeleton>> &r_skeletons,
-			HashMap<GLTFNodeIndex, Node *> &r_scene_nodes);
+			HashMap<GLTFNodeIndex, Node *> &r_scene_nodes,
+			int p_naming_version);
 	static Error _create_skins(Vector<Ref<GLTFSkin>> &skins, Vector<Ref<GLTFNode>> &nodes, bool use_named_skin_binds, HashSet<String> &unique_names);
 };