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
This commit is contained in:
Marios Staikopoulos 2019-09-21 21:45:38 -07:00
parent 6fc5647bc3
commit 72d2468d68
2 changed files with 160 additions and 25 deletions

View File

@ -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,16 +1799,21 @@ 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) {
// 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) {
@ -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
{ // 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) {
bones.push_back(child_i);
child_nodes.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) {

View File

@ -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);