From a330b6829f3c726387ce3a5bb27a8c098498c57d Mon Sep 17 00:00:00 2001 From: Lyuma Date: Fri, 21 May 2021 00:03:06 -0700 Subject: [PATCH] gltf: Fix mesh nodes which are also bones for 3.x Fix issue when two skeletons end up directly parented. Prevent animating TRS for skinned Mesh node. Fix animating weights on meshes with targets but no weights. --- editor/import/editor_scene_importer_gltf.cpp | 233 ++++++++++--------- editor/import/editor_scene_importer_gltf.h | 9 +- 2 files changed, 122 insertions(+), 120 deletions(-) diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index 1398be5980d..404875e7c7f 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -2082,81 +2082,10 @@ Error EditorSceneImporterGLTF::_reparent_non_joint_skeleton_subtrees(GLTFState & subtree_set.get_members(subtree_nodes, subtree_root); for (int subtree_i = 0; subtree_i < subtree_nodes.size(); ++subtree_i) { - ERR_FAIL_COND_V(_reparent_to_fake_joint(state, skeleton, subtree_nodes[subtree_i]), FAILED); - - // We modified the tree, recompute all the heights - _compute_node_heights(state); - } - } - - return OK; -} - -Error EditorSceneImporterGLTF::_reparent_to_fake_joint(GLTFState &state, GLTFSkeleton &skeleton, const GLTFNodeIndex node_index) { - GLTFNode *node = state.nodes[node_index]; - - // Can we just "steal" this joint if it is just a spatial node? - if (node->skin < 0 && node->mesh < 0 && node->camera < 0) { - node->joint = true; - // Add the joint to the skeletons joints - skeleton.joints.push_back(node_index); - return OK; - } - - GLTFNode *fake_joint = memnew(GLTFNode); - const GLTFNodeIndex fake_joint_index = state.nodes.size(); - state.nodes.push_back(fake_joint); - - // We better not be a joint, or we messed up in our logic - if (node->joint) { - return FAILED; - } - - fake_joint->translation = node->translation; - fake_joint->rotation = node->rotation; - fake_joint->scale = node->scale; - fake_joint->xform = node->xform; - fake_joint->joint = true; - - // 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); - node->rotation = Quat(); - node->scale = Vector3(1, 1, 1); - node->xform = Transform(); - - // Transfer the node children to the fake joint - for (int child_i = 0; child_i < node->children.size(); ++child_i) { - GLTFNode *child = state.nodes[node->children[child_i]]; - child->parent = fake_joint_index; - } - - fake_joint->children = node->children; - node->children.clear(); - - // add the fake joint to the parent and remove the original joint - if (node->parent >= 0) { - GLTFNode *parent = state.nodes[node->parent]; - parent->children.erase(node_index); - parent->children.push_back(fake_joint_index); - fake_joint->parent = node->parent; - } - - // Add the node to the fake joint - fake_joint->children.push_back(node_index); - node->parent = fake_joint_index; - node->fake_joint_parent = fake_joint_index; - - // Add the fake joint to the skeletons joints - skeleton.joints.push_back(fake_joint_index); - - // Replace skin_skeletons with fake joints if we must. - for (GLTFSkinIndex skin_i = 0; skin_i < state.skins.size(); ++skin_i) { - GLTFSkin &skin = state.skins.write[skin_i]; - if (skin.skin_root == node_index) { - skin.skin_root = fake_joint_index; + GLTFNode *node = state.nodes[subtree_nodes[subtree_i]]; + node->joint = true; + // Add the joint to the skeletons joints + skeleton.joints.push_back(subtree_nodes[subtree_i]); } } @@ -2651,10 +2580,9 @@ void EditorSceneImporterGLTF::_assign_scene_names(GLTFState &state) { } } -BoneAttachment *EditorSceneImporterGLTF::_generate_bone_attachment(GLTFState &state, Skeleton *skeleton, const GLTFNodeIndex node_index) { +BoneAttachment *EditorSceneImporterGLTF::_generate_bone_attachment(GLTFState &state, Skeleton *skeleton, const GLTFNodeIndex node_index, const GLTFNodeIndex bone_index) { const GLTFNode *gltf_node = state.nodes[node_index]; - const GLTFNode *bone_node = state.nodes[gltf_node->parent]; - + const GLTFNode *bone_node = state.nodes[bone_index]; BoneAttachment *bone_attachment = memnew(BoneAttachment); print_verbose("glTF: Creating bone attachment for: " + gltf_node->name); @@ -2687,7 +2615,7 @@ MeshInstance *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state, return mi; } -Light *EditorSceneImporterGLTF::_generate_light(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) { +Spatial *EditorSceneImporterGLTF::_generate_light(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) { const GLTFNode *gltf_node = state.nodes[node_index]; ERR_FAIL_INDEX_V(gltf_node->light, state.lights.size(), nullptr); @@ -2736,7 +2664,7 @@ Light *EditorSceneImporterGLTF::_generate_light(GLTFState &state, Node *scene_pa light->set_param(SpotLight::PARAM_SPOT_ATTENUATION, angle_attenuation); return light; } - return nullptr; + return memnew(Spatial); } Camera *EditorSceneImporterGLTF::_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) { @@ -2769,31 +2697,22 @@ Spatial *EditorSceneImporterGLTF::_generate_spatial(GLTFState &state, Node *scen void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene_parent, Spatial *scene_root, const GLTFNodeIndex node_index) { const GLTFNode *gltf_node = state.nodes[node_index]; + if (gltf_node->skeleton >= 0) { + _generate_skeleton_bone_node(state, scene_parent, scene_root, node_index); + return; + } + Spatial *current_node = nullptr; // Is our parent a skeleton Skeleton *active_skeleton = Object::cast_to(scene_parent); - if (gltf_node->skeleton >= 0) { - Skeleton *skeleton = state.skeletons[gltf_node->skeleton].godot_skeleton; + const bool non_bone_parented_to_skeleton = active_skeleton; - if (active_skeleton != skeleton) { - ERR_FAIL_COND_MSG(active_skeleton != nullptr, "glTF: Generating scene detected direct parented Skeletons"); - - // Add it to the scene if it has not already been added - if (skeleton->get_parent() == nullptr) { - scene_parent->add_child(skeleton); - skeleton->set_owner(scene_root); - } - } - - active_skeleton = skeleton; - current_node = skeleton; - } - - // If we have an active skeleton, and the node is node skinned, we need to create a bone attachment - if (current_node == nullptr && active_skeleton != nullptr && gltf_node->skin < 0) { - BoneAttachment *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index); + // skinned meshes must not be placed in a bone attachment. + if (non_bone_parented_to_skeleton && gltf_node->skin < 0) { + // Bone Attachment - Parent Case + BoneAttachment *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, gltf_node->parent); scene_parent->add_child(bone_attachment); bone_attachment->set_owner(scene_root); @@ -2807,20 +2726,100 @@ void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene } // We still have not managed to make a node - if (current_node == nullptr) { + if (gltf_node->mesh >= 0) { + current_node = _generate_mesh_instance(state, scene_parent, node_index); + } else if (gltf_node->camera >= 0) { + current_node = _generate_camera(state, scene_parent, node_index); + } else if (gltf_node->light >= 0) { + current_node = _generate_light(state, scene_parent, node_index); + } else { + current_node = _generate_spatial(state, scene_parent, node_index); + } + + scene_parent->add_child(current_node); + current_node->set_owner(scene_root); + current_node->set_transform(gltf_node->xform); + if (state.use_legacy_names) { + current_node->set_name(_legacy_validate_node_name(gltf_node->name)); + } else { + current_node->set_name(gltf_node->name); + } + + state.scene_nodes.insert(node_index, current_node); + + for (int i = 0; i < gltf_node->children.size(); ++i) { + _generate_scene_node(state, current_node, scene_root, gltf_node->children[i]); + } +} + +void EditorSceneImporterGLTF::_generate_skeleton_bone_node(GLTFState &state, Node *scene_parent, Spatial *scene_root, const GLTFNodeIndex node_index) { + const GLTFNode *gltf_node = state.nodes[node_index]; + + Spatial *current_node = nullptr; + + Skeleton *skeleton = state.skeletons[gltf_node->skeleton].godot_skeleton; + // In this case, this node is already a bone in skeleton. + const bool is_skinned_mesh = (gltf_node->skin >= 0 && gltf_node->mesh >= 0); + const bool requires_extra_node = (gltf_node->mesh >= 0 || gltf_node->camera >= 0 || gltf_node->light >= 0); + + Skeleton *active_skeleton = Object::cast_to(scene_parent); + if (active_skeleton != skeleton) { + if (active_skeleton) { + // Bone Attachment - Direct Parented Skeleton Case + BoneAttachment *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, gltf_node->parent); + + scene_parent->add_child(bone_attachment); + bone_attachment->set_owner(scene_root); + + // 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 + scene_parent = bone_attachment; + WARN_PRINT(vformat("glTF: Generating scene detected direct parented Skeletons at node %d", node_index)); + } + + // Add it to the scene if it has not already been added + if (skeleton->get_parent() == nullptr) { + scene_parent->add_child(skeleton); + skeleton->set_owner(scene_root); + } + } + + active_skeleton = skeleton; + current_node = skeleton; + + // If we have an active skeleton, and the node is node skinned, we need to create a bone attachment + if (requires_extra_node) { + // skinned meshes must not be placed in a bone attachment. + if (!is_skinned_mesh) { + BoneAttachment *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, node_index); + + scene_parent->add_child(bone_attachment); + bone_attachment->set_owner(scene_root); + + // 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 + scene_parent = bone_attachment; + current_node = nullptr; + } + + // We still have not managed to make a node if (gltf_node->mesh >= 0) { current_node = _generate_mesh_instance(state, scene_parent, node_index); } else if (gltf_node->camera >= 0) { current_node = _generate_camera(state, scene_parent, node_index); } else if (gltf_node->light >= 0) { current_node = _generate_light(state, scene_parent, node_index); - } else { - current_node = _generate_spatial(state, scene_parent, node_index); } scene_parent->add_child(current_node); current_node->set_owner(scene_root); - current_node->set_transform(gltf_node->xform); + // Do not set transform here. Transform is already applied to our bone. if (state.use_legacy_names) { current_node->set_name(_legacy_validate_node_name(gltf_node->name)); } else { @@ -2831,7 +2830,7 @@ void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene state.scene_nodes.insert(node_index, current_node); for (int i = 0; i < gltf_node->children.size(); ++i) { - _generate_scene_node(state, current_node, scene_root, gltf_node->children[i]); + _generate_scene_node(state, active_skeleton, scene_root, gltf_node->children[i]); } } @@ -2976,26 +2975,30 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye for (Map::Element *E = anim.tracks.front(); E; E = E->next()) { const GLTFAnimation::Track &track = E->get(); - //need to find the path + //need to find the path: for skeletons, weight tracks will affect the mesh NodePath node_path; + //for skeletons, transform tracks always affect bones + NodePath transform_node_path; GLTFNodeIndex node_index = E->key(); - if (state.nodes[node_index]->fake_joint_parent >= 0) { - // Should be same as parent - node_index = state.nodes[node_index]->fake_joint_parent; - } const GLTFNode *node = state.nodes[E->key()]; + Node *root = ap->get_parent(); + ERR_FAIL_COND(root == nullptr); + Map::Element *node_element = state.scene_nodes.find(node_index); + ERR_CONTINUE_MSG(node_element == nullptr, vformat("Unable to find node %d for animation", node_index)); + node_path = root->get_path_to(node_element->get()); + if (node->skeleton >= 0) { - const Skeleton *sk = Object::cast_to(state.scene_nodes.find(node_index)->get()); + const Skeleton *sk = state.skeletons[node->skeleton].godot_skeleton; ERR_FAIL_COND(sk == nullptr); const String path = ap->get_parent()->get_path_to(sk); const String bone = node->name; - node_path = path + ":" + bone; + transform_node_path = path + ":" + bone; } else { - node_path = ap->get_parent()->get_path_to(state.scene_nodes.find(node_index)->get()); + transform_node_path = node_path; } for (int i = 0; i < track.rotation_track.times.size(); i++) { @@ -3014,11 +3017,13 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye } } - if (track.rotation_track.values.size() || track.translation_track.values.size() || track.scale_track.values.size()) { + // Animated TRS properties will not affect a skinned mesh. + const bool transform_affects_skinned_mesh_instance = node->skeleton < 0 && node->skin >= 0; + if ((track.rotation_track.values.size() || track.translation_track.values.size() || track.scale_track.values.size()) && !transform_affects_skinned_mesh_instance) { //make transform track int track_idx = animation->get_track_count(); animation->add_track(Animation::TYPE_TRANSFORM); - animation->track_set_path(track_idx, node_path); + animation->track_set_path(track_idx, transform_node_path); animation->track_set_imported(track_idx, true); //first determine animation length diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h index 33192aefad7..ca04f622a64 100644 --- a/editor/import/editor_scene_importer_gltf.h +++ b/editor/import/editor_scene_importer_gltf.h @@ -113,8 +113,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { Vector children; - GLTFNodeIndex fake_joint_parent; - GLTFLightIndex light; GLTFNode() : @@ -127,7 +125,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { joint(false), translation(0, 0, 0), scale(Vector3(1, 1, 1)), - fake_joint_parent(-1), light(-1) {} }; @@ -406,7 +403,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { Error _determine_skeletons(GLTFState &state); Error _reparent_non_joint_skeleton_subtrees(GLTFState &state, GLTFSkeleton &skeleton, const Vector &non_joints); - Error _reparent_to_fake_joint(GLTFState &state, GLTFSkeleton &skeleton, const GLTFNodeIndex node_index); Error _determine_skeleton_roots(GLTFState &state, const GLTFSkeletonIndex skel_i); Error _create_skeletons(GLTFState &state); @@ -420,13 +416,14 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { Error _parse_lights(GLTFState &state); Error _parse_animations(GLTFState &state); - BoneAttachment *_generate_bone_attachment(GLTFState &state, Skeleton *skeleton, const GLTFNodeIndex node_index); + BoneAttachment *_generate_bone_attachment(GLTFState &state, Skeleton *skeleton, const GLTFNodeIndex node_index, const GLTFNodeIndex bone_index); MeshInstance *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); Camera *_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); - Light *_generate_light(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); + Spatial *_generate_light(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); Spatial *_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); void _generate_scene_node(GLTFState &state, Node *scene_parent, Spatial *scene_root, const GLTFNodeIndex node_index); + void _generate_skeleton_bone_node(GLTFState &state, Node *scene_parent, Spatial *scene_root, const GLTFNodeIndex node_index); Spatial *_generate_scene(GLTFState &state, const int p_bake_fps); void _process_mesh_instances(GLTFState &state, Spatial *scene_root);