diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index f4047094b66..482e5de4be9 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -565,7 +565,9 @@ String GLTFDocument::_gen_unique_bone_name(Ref p_state, const GLTFSke Error GLTFDocument::_parse_scenes(Ref p_state) { p_state->unique_names.insert("Skeleton3D"); // Reserve skeleton name. - ERR_FAIL_COND_V(!p_state->json.has("scenes"), ERR_FILE_CORRUPT); + if (!p_state->json.has("scenes")) { + return OK; // No scenes. + } const Array &scenes = p_state->json["scenes"]; int loaded_scene = 0; if (p_state->json.has("scene")) { @@ -577,10 +579,11 @@ Error GLTFDocument::_parse_scenes(Ref p_state) { if (scenes.size()) { ERR_FAIL_COND_V(loaded_scene >= scenes.size(), ERR_FILE_CORRUPT); const Dictionary &scene_dict = scenes[loaded_scene]; - ERR_FAIL_COND_V(!scene_dict.has("nodes"), ERR_UNAVAILABLE); - const Array &nodes = scene_dict["nodes"]; - for (int j = 0; j < nodes.size(); j++) { - p_state->root_nodes.push_back(nodes[j]); + if (scene_dict.has("nodes")) { + const Array &nodes = scene_dict["nodes"]; + for (const Variant &node : nodes) { + p_state->root_nodes.push_back(node); + } } // Determine what to use for the scene name. if (scene_dict.has("name") && !String(scene_dict["name"]).is_empty() && !((String)scene_dict["name"]).begins_with("Scene")) { @@ -597,7 +600,9 @@ Error GLTFDocument::_parse_scenes(Ref p_state) { } Error GLTFDocument::_parse_nodes(Ref p_state) { - ERR_FAIL_COND_V(!p_state->json.has("nodes"), ERR_FILE_CORRUPT); + if (!p_state->json.has("nodes")) { + return OK; // No nodes to parse. + } const Array &nodes = p_state->json["nodes"]; for (int i = 0; i < nodes.size(); i++) { Ref node; @@ -8676,6 +8681,7 @@ Node *GLTFDocument::_generate_scene_node_tree(Ref p_state) { // Generate the node tree. Node *single_root; if (p_state->extensions_used.has("GODOT_single_root")) { + ERR_FAIL_COND_V_MSG(p_state->nodes.is_empty(), nullptr, "glTF: Single root file has no nodes. This glTF file is invalid."); if (_naming_version < 2) { _generate_scene_node_compat_4pt4(p_state, 0, nullptr, nullptr); } else { @@ -8843,50 +8849,53 @@ Error GLTFDocument::write_to_filesystem(Ref p_state, const String &p_ } Node *GLTFDocument::generate_scene(Ref p_state, float p_bake_fps, bool p_trimming, bool p_remove_immutable_tracks) { - Ref state = p_state; - ERR_FAIL_COND_V(state.is_null(), nullptr); - ERR_FAIL_INDEX_V(0, state->root_nodes.size(), nullptr); + ERR_FAIL_COND_V(p_state.is_null(), nullptr); + // The glTF file must have nodes, and have some marked as root nodes, in order to generate a scene. + if (p_state->nodes.is_empty()) { + WARN_PRINT("glTF: This glTF file has no nodes, the generated Godot scene will be empty."); + } + // Now that we know that we have glTF nodes, we can begin generating a scene from the parsed glTF data. Error err = OK; p_state->set_bake_fps(p_bake_fps); - Node *root = _generate_scene_node_tree(state); - ERR_FAIL_NULL_V(root, nullptr); - _process_mesh_instances(state, root); - if (state->get_create_animations() && state->animations.size()) { - AnimationPlayer *ap = memnew(AnimationPlayer); - root->add_child(ap, true); - ap->set_owner(root); - for (int i = 0; i < state->animations.size(); i++) { - _import_animation(state, ap, i, p_trimming, p_remove_immutable_tracks); + Node *godot_root_node = _generate_scene_node_tree(p_state); + ERR_FAIL_NULL_V(godot_root_node, nullptr); + _process_mesh_instances(p_state, godot_root_node); + if (p_state->get_create_animations() && p_state->animations.size()) { + AnimationPlayer *anim_player = memnew(AnimationPlayer); + godot_root_node->add_child(anim_player, true); + anim_player->set_owner(godot_root_node); + for (int i = 0; i < p_state->animations.size(); i++) { + _import_animation(p_state, anim_player, i, p_trimming, p_remove_immutable_tracks); } } - for (KeyValue E : state->scene_nodes) { + for (KeyValue E : p_state->scene_nodes) { ERR_CONTINUE(!E.value); for (Ref ext : document_extensions) { ERR_CONTINUE(ext.is_null()); Dictionary node_json; - if (state->json.has("nodes")) { - Array nodes = state->json["nodes"]; + if (p_state->json.has("nodes")) { + Array nodes = p_state->json["nodes"]; if (0 <= E.key && E.key < nodes.size()) { node_json = nodes[E.key]; } } - Ref gltf_node = state->nodes[E.key]; + Ref gltf_node = p_state->nodes[E.key]; err = ext->import_node(p_state, gltf_node, node_json, E.value); ERR_CONTINUE(err != OK); } } - ImporterMeshInstance3D *root_importer_mesh = Object::cast_to(root); + ImporterMeshInstance3D *root_importer_mesh = Object::cast_to(godot_root_node); if (unlikely(root_importer_mesh)) { - root = GLTFDocumentExtensionConvertImporterMesh::convert_importer_mesh_instance_3d(root_importer_mesh); + godot_root_node = GLTFDocumentExtensionConvertImporterMesh::convert_importer_mesh_instance_3d(root_importer_mesh); memdelete(root_importer_mesh); } for (Ref ext : document_extensions) { ERR_CONTINUE(ext.is_null()); - err = ext->import_post(p_state, root); + err = ext->import_post(p_state, godot_root_node); ERR_CONTINUE(err != OK); } - ERR_FAIL_NULL_V(root, nullptr); - return root; + ERR_FAIL_NULL_V(godot_root_node, nullptr); + return godot_root_node; } Error GLTFDocument::append_from_scene(Node *p_node, Ref p_state, uint32_t p_flags) {