Browse Source

More GLTF Fixes

1: Depth draw mode set for transparent materials (iFire)
2: Skeletons
  - Bone names now unique and seperate from scene names
  - Due to mixture of fake joints and joints, new bone sanitizing for names added
  - Fixed an issue where some disjoint skins were not being joined due to a logic error
  - Deterministic and Depth-first bone creation order
3: Skins
  - Removed duplicate skins when possible
4: Animations
  - Fixed invalid morph target names
Marios Staikopoulos 5 years ago
parent
commit
72d2468d68
2 changed files with 160 additions and 25 deletions
  1. 151 25
      editor/import/editor_scene_importer_gltf.cpp
  2. 9 0
      editor/import/editor_scene_importer_gltf.h

+ 151 - 25
editor/import/editor_scene_importer_gltf.cpp

@@ -35,6 +35,7 @@
 #include "core/math/math_defs.h"
 #include "core/os/file_access.h"
 #include "core/os/os.h"
+#include "modules/regex/regex.h"
 #include "scene/3d/bone_attachment.h"
 #include "scene/3d/camera.h"
 #include "scene/3d/mesh_instance.h"
@@ -154,14 +155,21 @@ static Transform _arr_to_xform(const Array &p_array) {
 	return xform;
 }
 
+String EditorSceneImporterGLTF::_sanitize_scene_name(const String &name) {
+	RegEx regex("([^a-zA-Z0-9_ ]+)");
+	String p_name = regex.sub(name, "", true);
+	return p_name;
+}
+
 String EditorSceneImporterGLTF::_gen_unique_name(GLTFState &state, const String &p_name) {
 
-	int index = 1;
+	const String s_name = _sanitize_scene_name(p_name);
 
 	String name;
+	int index = 1;
 	while (true) {
+		name = s_name;
 
-		name = p_name;
 		if (index > 1) {
 			name += " " + itos(index);
 		}
@@ -176,6 +184,47 @@ String EditorSceneImporterGLTF::_gen_unique_name(GLTFState &state, const String
 	return name;
 }
 
+String EditorSceneImporterGLTF::_sanitize_bone_name(const String &name) {
+	String p_name = name.camelcase_to_underscore(true);
+
+	RegEx pattern_del("([^a-zA-Z0-9_ ])+");
+	p_name = pattern_del.sub(p_name, "", true);
+
+	RegEx pattern_nospace(" +");
+	p_name = pattern_nospace.sub(p_name, "_", true);
+
+	RegEx pattern_multiple("_+");
+	p_name = pattern_multiple.sub(p_name, "_", true);
+
+	RegEx pattern_padded("0+(\\d+)");
+	p_name = pattern_padded.sub(p_name, "$1", true);
+
+	return p_name;
+}
+
+String EditorSceneImporterGLTF::_gen_unique_bone_name(GLTFState &state, const GLTFSkeletonIndex skel_i, const String &p_name) {
+
+	const String s_name = _sanitize_bone_name(p_name);
+
+	String name;
+	int index = 1;
+	while (true) {
+		name = s_name;
+
+		if (index > 1) {
+			name += "_" + itos(index);
+		}
+		if (!state.skeletons[skel_i].unique_names.has(name)) {
+			break;
+		}
+		index++;
+	}
+
+	state.skeletons.write[skel_i].unique_names.insert(name);
+
+	return name;
+}
+
 Error EditorSceneImporterGLTF::_parse_scenes(GLTFState &state) {
 
 	ERR_FAIL_COND_V(!state.json.has("scenes"), ERR_FILE_CORRUPT);
@@ -188,7 +237,7 @@ Error EditorSceneImporterGLTF::_parse_scenes(GLTFState &state) {
 			state.root_nodes.push_back(nodes[j]);
 		}
 
-		if (s.has("name")) {
+		if (s.has("name") && s["name"] != "") {
 			state.scene_name = _gen_unique_name(state, s["name"]);
 		} else {
 			state.scene_name = _gen_unique_name(state, "Scene");
@@ -1425,6 +1474,7 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
 			const String &am = d["alphaMode"];
 			if (am != "OPAQUE") {
 				material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+				material->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS);
 			}
 		}
 
@@ -1749,17 +1799,22 @@ Error EditorSceneImporterGLTF::_determine_skeletons(GLTFState &state) {
 		const GLTFNodeIndex skeleton_owner = skeleton_owners[skel_i];
 		GLTFSkeleton skeleton;
 
+		Vector<GLTFNodeIndex> skeleton_nodes;
+		skeleton_sets.get_members(skeleton_nodes, skeleton_owner);
+
 		for (GLTFSkinIndex skin_i = 0; skin_i < state.skins.size(); ++skin_i) {
 			GLTFSkin &skin = state.skins.write[skin_i];
 
-			if (skin.joints.find(skeleton_owner) >= 0 || skin.non_joints.find(skeleton_owner) >= 0) {
-				skin.skeleton = skel_i;
+			// If any of the the skeletons nodes exist in a skin, that skin now maps to the skeleton
+			for (int i = 0; i < skeleton_nodes.size(); ++i) {
+				GLTFNodeIndex skel_node_i = skeleton_nodes[i];
+				if (skin.joints.find(skel_node_i) >= 0 || skin.non_joints.find(skel_node_i) >= 0) {
+					skin.skeleton = skel_i;
+					continue;
+				}
 			}
 		}
 
-		Vector<GLTFNodeIndex> skeleton_nodes;
-		skeleton_sets.get_members(skeleton_nodes, skeleton_owner);
-
 		Vector<GLTFNodeIndex> non_joints;
 		for (int i = 0; i < skeleton_nodes.size(); ++i) {
 			const GLTFNodeIndex node_i = skeleton_nodes[i];
@@ -1864,8 +1919,8 @@ Error EditorSceneImporterGLTF::_reparent_to_fake_joint(GLTFState &state, GLTFSke
 	fake_joint->xform = node->xform;
 	fake_joint->joint = true;
 
-	// Create a new name
-	fake_joint->name = node->name + "_fake_joint";
+	// We can use the exact same name here, because the joint will be inside a skeleton and not the scene
+	fake_joint->name = node->name;
 
 	// Clear the nodes transforms, since it will be parented to the fake joint
 	node->translation = Vector3(0, 0, 0);
@@ -1971,7 +2026,7 @@ Error EditorSceneImporterGLTF::_create_skeletons(GLTFState &state) {
 		Skeleton *skeleton = memnew(Skeleton);
 		gltf_skeleton.godot_skeleton = skeleton;
 
-		//skeleton->set_use_bones_in_world_transform(true);
+		// Make a unique name, no gltf node represents this skeleton
 		skeleton->set_name(_gen_unique_name(state, "Skeleton"));
 
 		List<GLTFNodeIndex> bones;
@@ -1980,26 +2035,41 @@ Error EditorSceneImporterGLTF::_create_skeletons(GLTFState &state) {
 			bones.push_back(gltf_skeleton.roots[i]);
 		}
 
+		// Make the skeleton creation deterministic by going through the roots in
+		// a sorted order, and DEPTH FIRST
+		bones.sort();
+
 		while (!bones.empty()) {
 			const GLTFNodeIndex node_i = bones.front()->get();
 			bones.pop_front();
 
 			GLTFNode *node = state.nodes[node_i];
+			ERR_FAIL_COND_V(node->skeleton != skel_i, FAILED);
+
+			{ // Add all child nodes to the stack (deterministically)
+				Vector<GLTFNodeIndex> child_nodes;
+				for (int i = 0; i < node->children.size(); ++i) {
+					const GLTFNodeIndex child_i = node->children[i];
+					if (state.nodes[child_i]->skeleton == skel_i) {
+						child_nodes.push_back(child_i);
+					}
+				}
 
-			// Add all child nodes to the stack
-			for (int i = 0; i < node->children.size(); ++i) {
-				const GLTFNodeIndex child_i = node->children[i];
-				if (state.nodes[child_i]->skeleton == skel_i) {
-					bones.push_back(child_i);
+				// Depth first insertion
+				child_nodes.sort();
+				for (int i = child_nodes.size() - 1; i >= 0; --i) {
+					bones.push_front(child_nodes[i]);
 				}
 			}
 
 			const int bone_index = skeleton->get_bone_count();
 
 			if (node->name.empty()) {
-				node->name = "Bone " + itos(bone_index);
+				node->name = "bone";
 			}
 
+			node->name = _gen_unique_bone_name(state, skel_i, node->name);
+
 			skeleton->add_bone(node->name);
 			skeleton->set_bone_rest(bone_index, node->xform);
 			skeleton->set_bone_pose(bone_index, node->xform);
@@ -2087,8 +2157,6 @@ Error EditorSceneImporterGLTF::_create_skins(GLTFState &state) {
 		Ref<Skin> skin;
 		skin.instance();
 
-		skin->set_name(_gen_unique_name(state, "Skin"));
-
 		for (int joint_i = 0; joint_i < gltf_skin.joints_original.size(); ++joint_i) {
 			int bone_i = gltf_skin.joint_i_to_bone_i[joint_i];
 
@@ -2098,9 +2166,57 @@ Error EditorSceneImporterGLTF::_create_skins(GLTFState &state) {
 		gltf_skin.godot_skin = skin;
 	}
 
+	// Purge the duplicates!
+	_remove_duplicate_skins(state);
+
+	// Create unique names now, after removing duplicates
+	for (GLTFSkinIndex skin_i = 0; skin_i < state.skins.size(); ++skin_i) {
+		Ref<Skin> skin = state.skins[skin_i].godot_skin;
+		if (skin->get_name().empty()) {
+			// Make a unique name, no gltf node represents this skin
+			skin->set_name(_gen_unique_name(state, "Skin"));
+		}
+	}
+
 	return OK;
 }
 
+bool EditorSceneImporterGLTF::_skins_are_same(const Ref<Skin> &skin_a, const Ref<Skin> &skin_b) {
+	if (skin_a->get_bind_count() != skin_b->get_bind_count()) {
+		return false;
+	}
+
+	for (int i = 0; i < skin_a->get_bind_count(); ++i) {
+
+		if (skin_a->get_bind_bone(i) != skin_b->get_bind_bone(i)) {
+			return false;
+		}
+
+		Transform a_xform = skin_a->get_bind_pose(i);
+		Transform b_xform = skin_b->get_bind_pose(i);
+
+		if (a_xform != b_xform) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+void EditorSceneImporterGLTF::_remove_duplicate_skins(GLTFState &state) {
+	for (int i = 0; i < state.skins.size(); ++i) {
+		for (int j = i + 1; j < state.skins.size(); ++j) {
+			const Ref<Skin>& skin_i = state.skins[i].godot_skin;
+			const Ref<Skin>& skin_j = state.skins[j].godot_skin;
+
+			if (_skins_are_same(skin_i, skin_j)) {
+				// replace it and delete the old
+				state.skins.write[j].godot_skin = skin_i;
+			}
+		}
+	}
+}
+
 Error EditorSceneImporterGLTF::_parse_cameras(GLTFState &state) {
 
 	if (!state.json.has("cameras"))
@@ -2282,11 +2398,16 @@ void EditorSceneImporterGLTF::_assign_scene_names(GLTFState &state) {
 
 	for (int i = 0; i < state.nodes.size(); i++) {
 		GLTFNode *n = state.nodes[i];
-		if (n->name == "") {
+
+		// Any joints get unique names generated when the skeleton is made, unique to the skeleton
+		if (n->skeleton >= 0)
+			continue;
+
+		if (n->name.empty()) {
 			if (n->mesh >= 0) {
 				n->name = "Mesh";
-			} else if (n->joint) {
-				n->name = "Bone";
+			} else if (n->camera >= 0) {
+				n->name = "Camera";
 			} else {
 				n->name = "Node";
 			}
@@ -2378,7 +2499,8 @@ void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene
 			scene_parent->add_child(bone_attachment);
 			bone_attachment->set_owner(scene_root);
 
-			bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment " + gltf_node->name));
+			// There is no gltf_node that represent this, so just directly create a unique name
+			bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment"));
 
 			// We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node
 			// and attach it to the bone_attachment
@@ -2549,6 +2671,7 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
 
 	String name = anim.name;
 	if (name.empty()) {
+		// No node represent these, and they are not in the hierarchy, so just make a unique name
 		name = _gen_unique_name(state, "Animation");
 	}
 
@@ -2677,11 +2800,12 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
 			ERR_CONTINUE(node->mesh < 0 || node->mesh >= state.meshes.size());
 			const GLTFMesh &mesh = state.meshes[node->mesh];
 			const String prop = "blend_shapes/" + mesh.mesh->get_blend_shape_name(i);
-			node_path = String(node_path) + ":" + prop;
+
+			const String blend_path = String(node_path) + ":" + prop;
 
 			const int track_idx = animation->get_track_count();
 			animation->add_track(Animation::TYPE_VALUE);
-			animation->track_set_path(track_idx, node_path);
+			animation->track_set_path(track_idx, blend_path);
 
 			// Only LINEAR and STEP (NEAREST) can be supported out of the box by Godot's Animation,
 			// the other modes have to be baked.
@@ -2748,6 +2872,8 @@ void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Spatial
 Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, const int p_bake_fps) {
 
 	Spatial *root = memnew(Spatial);
+
+	// scene_name is already unique
 	root->set_name(state.scene_name);
 
 	for (int i = 0; i < state.root_nodes.size(); ++i) {

+ 9 - 0
editor/import/editor_scene_importer_gltf.h

@@ -191,6 +191,9 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
 		// The created Skeleton for the scene
 		Skeleton *godot_skeleton;
 
+		// Set of unique bone names for the skeleton
+		Set<String> unique_names;
+
 		GLTFSkeleton() :
 				godot_skeleton(nullptr) {
 		}
@@ -326,8 +329,12 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
 		}
 	};
 
+	String _sanitize_scene_name(const String &name);
 	String _gen_unique_name(GLTFState &state, const String &p_name);
 
+	String _sanitize_bone_name(const String &name);
+	String _gen_unique_bone_name(GLTFState &state, const GLTFSkeletonIndex skel_i, const String &p_name);
+
 	Ref<Texture> _get_texture(GLTFState &state, const GLTFTextureIndex p_texture);
 
 	Error _parse_json(const String &p_path, GLTFState &state);
@@ -381,6 +388,8 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
 	Transform _compute_skin_to_skeleton_transform(const GLTFState &state, const GLTFNodeIndex skin_parent, const GLTFNodeIndex skeleton_parent);
 	void _compute_skeleton_rooted_skin_inverse_binds(GLTFState &state, const GLTFSkinIndex skin_i);
 	Error _create_skins(GLTFState &state);
+	bool _skins_are_same(const Ref<Skin>& skin_a, const Ref<Skin>& skin_b);
+	void _remove_duplicate_skins(GLTFState& state);
 
 	Error _parse_cameras(GLTFState &state);