Merge pull request #49119 from lyuma/gltf_mesh_nodes_bones_3.x
This commit is contained in:
commit
fb11927901
2 changed files with 122 additions and 120 deletions
|
@ -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<Skeleton>(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<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 {
|
||||
|
@ -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<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++) {
|
||||
|
@ -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
|
||||
|
||||
|
|
|
@ -113,8 +113,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
|
|||
|
||||
Vector<int> 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<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);
|
||||
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue