Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gltf: Fix mesh nodes which are also bones in 3.x #49119

Merged
merged 1 commit into from
May 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 119 additions & 114 deletions editor/import/editor_scene_importer_gltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}
}

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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<Skeleton>(scene_parent);

if (gltf_node->skeleton >= 0) {
Skeleton *skeleton = state.skeletons[gltf_node->skeleton].godot_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);
}
}
const bool non_bone_parented_to_skeleton = active_skeleton;

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);
Expand All @@ -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<Skeleton>(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 {
Expand All @@ -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]);
}
}

Expand Down Expand Up @@ -2976,26 +2975,30 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye

for (Map<int, GLTFAnimation::Track>::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<GLTFNodeIndex, Node *>::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<Skeleton>(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++) {
Expand All @@ -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

Expand Down
9 changes: 3 additions & 6 deletions editor/import/editor_scene_importer_gltf.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {

Vector<int> children;

GLTFNodeIndex fake_joint_parent;

GLTFLightIndex light;

GLTFNode() :
Expand All @@ -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) {}
};

Expand Down Expand Up @@ -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<GLTFNodeIndex> &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);
Expand All @@ -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);
Expand Down