diff options
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/gltf/doc_classes/GLTFNode.xml | 9 | ||||
| -rw-r--r-- | modules/gltf/extensions/physics/gltf_physics_body.cpp | 3 | ||||
| -rw-r--r-- | modules/gltf/gltf_document.cpp | 83 | ||||
| -rw-r--r-- | modules/gltf/gltf_state.h | 1 | ||||
| -rw-r--r-- | modules/gltf/structures/gltf_node.cpp | 45 | ||||
| -rw-r--r-- | modules/gltf/structures/gltf_node.h | 3 |
6 files changed, 101 insertions, 43 deletions
diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml index a242a0d1d8..3ed357e828 100644 --- a/modules/gltf/doc_classes/GLTFNode.xml +++ b/modules/gltf/doc_classes/GLTFNode.xml @@ -27,6 +27,15 @@ The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the glTF file), and the return value can be anything you set. If nothing was set, the return value is null. </description> </method> + <method name="get_scene_node_path"> + <return type="NodePath" /> + <param index="0" name="gltf_state" type="GLTFState" /> + <param index="1" name="handle_skeletons" type="bool" default="true" /> + <description> + Returns the [NodePath] that this GLTF node will have in the Godot scene tree after being imported. + If [param handle_skeletons] is true, paths to skeleton bone glTF nodes will be resolved properly. For example, a path that would be [code]^"A/B/C/Bone1/Bone2/Bone3"[/code] if false will become [code]^"A/B/C/Skeleton3D:Bone3"[/code]. + </description> + </method> <method name="set_additional_data"> <return type="void" /> <param index="0" name="extension_name" type="StringName" /> diff --git a/modules/gltf/extensions/physics/gltf_physics_body.cpp b/modules/gltf/extensions/physics/gltf_physics_body.cpp index c11aa5d2ff..7c40f96e0a 100644 --- a/modules/gltf/extensions/physics/gltf_physics_body.cpp +++ b/modules/gltf/extensions/physics/gltf_physics_body.cpp @@ -193,9 +193,6 @@ Ref<GLTFPhysicsBody> GLTFPhysicsBody::from_node(const CollisionObject3D *p_body_ physics_body->angular_velocity = body->get_angular_velocity(); physics_body->center_of_mass = body->get_center_of_mass(); physics_body->inertia_diagonal = body->get_inertia(); - if (body->get_center_of_mass() != Vector3()) { - WARN_PRINT("GLTFPhysicsBody: This rigid body has a center of mass offset from the origin, which will be ignored when exporting to glTF."); - } if (cast_to<VehicleBody3D>(p_body_node)) { physics_body->body_type = PhysicsBodyType::VEHICLE; } else { diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index aeceae1be6..7da138ecf6 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -2894,41 +2894,42 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { Array meshes = p_state->json["meshes"]; for (GLTFMeshIndex i = 0; i < meshes.size(); i++) { print_verbose("glTF: Parsing mesh: " + itos(i)); - Dictionary d = meshes[i]; + Dictionary mesh_dict = meshes[i]; Ref<GLTFMesh> mesh; mesh.instantiate(); bool has_vertex_color = false; - ERR_FAIL_COND_V(!d.has("primitives"), ERR_PARSE_ERROR); + ERR_FAIL_COND_V(!mesh_dict.has("primitives"), ERR_PARSE_ERROR); - Array primitives = d["primitives"]; - const Dictionary &extras = d.has("extras") ? (Dictionary)d["extras"] : Dictionary(); + Array primitives = mesh_dict["primitives"]; + const Dictionary &extras = mesh_dict.has("extras") ? (Dictionary)mesh_dict["extras"] : Dictionary(); _attach_extras_to_meta(extras, mesh); Ref<ImporterMesh> import_mesh; import_mesh.instantiate(); String mesh_name = "mesh"; - if (d.has("name") && !String(d["name"]).is_empty()) { - mesh_name = d["name"]; + if (mesh_dict.has("name") && !String(mesh_dict["name"]).is_empty()) { + mesh_name = mesh_dict["name"]; mesh->set_original_name(mesh_name); } import_mesh->set_name(_gen_unique_name(p_state, vformat("%s_%s", p_state->scene_name, mesh_name))); mesh->set_name(import_mesh->get_name()); + TypedArray<Material> instance_materials; for (int j = 0; j < primitives.size(); j++) { uint64_t flags = RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES; - Dictionary p = primitives[j]; + Dictionary mesh_prim = primitives[j]; Array array; array.resize(Mesh::ARRAY_MAX); - ERR_FAIL_COND_V(!p.has("attributes"), ERR_PARSE_ERROR); + ERR_FAIL_COND_V(!mesh_prim.has("attributes"), ERR_PARSE_ERROR); - Dictionary a = p["attributes"]; + Dictionary a = mesh_prim["attributes"]; Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_TRIANGLES; - if (p.has("mode")) { - const int mode = p["mode"]; + if (mesh_prim.has("mode")) { + const int mode = mesh_prim["mode"]; ERR_FAIL_INDEX_V(mode, 7, ERR_FILE_CORRUPT); // Convert mesh.primitive.mode to Godot Mesh enum. See: // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode @@ -2959,8 +2960,8 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { Vector<int> indices_mapping; Vector<int> indices_rev_mapping; Vector<int> indices_vec4_mapping; - if (p.has("indices")) { - indices = _decode_accessor_as_ints(p_state, p["indices"], false); + if (mesh_prim.has("indices")) { + indices = _decode_accessor_as_ints(p_state, mesh_prim["indices"], false); const int is = indices.size(); if (primitive == Mesh::PRIMITIVE_TRIANGLES) { @@ -3218,7 +3219,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { } } - if (p_state->force_disable_compression || is_mesh_2d || !a.has("POSITION") || !a.has("NORMAL") || p.has("targets") || (a.has("JOINTS_0") || a.has("JOINTS_1"))) { + if (p_state->force_disable_compression || is_mesh_2d || !a.has("POSITION") || !a.has("NORMAL") || mesh_prim.has("targets") || (a.has("JOINTS_0") || a.has("JOINTS_1"))) { flags &= ~RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES; } @@ -3250,9 +3251,9 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { Array morphs; // Blend shapes - if (p.has("targets")) { + if (mesh_prim.has("targets")) { print_verbose("glTF: Mesh has targets"); - const Array &targets = p["targets"]; + const Array &targets = mesh_prim["targets"]; import_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); @@ -3383,8 +3384,8 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { Ref<Material> mat; String mat_name; if (!p_state->discard_meshes_and_materials) { - if (p.has("material")) { - const int material = p["material"]; + if (mesh_prim.has("material")) { + const int material = mesh_prim["material"]; ERR_FAIL_INDEX_V(material, p_state->materials.size(), ERR_FILE_CORRUPT); Ref<Material> mat3d = p_state->materials[material]; ERR_FAIL_COND_V(mat3d.is_null(), ERR_FILE_CORRUPT); @@ -3404,6 +3405,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { mat = mat3d; } ERR_FAIL_COND_V(mat.is_null(), ERR_FILE_CORRUPT); + instance_materials.append(mat); mat_name = mat->get_name(); } import_mesh->add_surface(primitive, array, morphs, @@ -3416,8 +3418,8 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { blend_weights.write[weight_i] = 0.0f; } - if (d.has("weights")) { - const Array &weights = d["weights"]; + if (mesh_dict.has("weights")) { + const Array &weights = mesh_dict["weights"]; for (int j = 0; j < weights.size(); j++) { if (j >= blend_weights.size()) { break; @@ -3426,6 +3428,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { } } mesh->set_blend_weights(blend_weights); + mesh->set_instance_materials(instance_materials); mesh->set_mesh(import_mesh); p_state->meshes.push_back(mesh); @@ -5366,44 +5369,44 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> p_state, Node *p_current, gltf_node->set_original_name(p_current->get_name()); gltf_node->set_name(_gen_unique_name(p_state, p_current->get_name())); gltf_node->merge_meta_from(p_current); - if (cast_to<Node3D>(p_current)) { - Node3D *spatial = cast_to<Node3D>(p_current); + if (Object::cast_to<Node3D>(p_current)) { + Node3D *spatial = Object::cast_to<Node3D>(p_current); _convert_spatial(p_state, spatial, gltf_node); } - if (cast_to<MeshInstance3D>(p_current)) { - MeshInstance3D *mi = cast_to<MeshInstance3D>(p_current); + if (Object::cast_to<MeshInstance3D>(p_current)) { + MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_current); _convert_mesh_instance_to_gltf(mi, p_state, gltf_node); - } else if (cast_to<BoneAttachment3D>(p_current)) { - BoneAttachment3D *bone = cast_to<BoneAttachment3D>(p_current); + } else if (Object::cast_to<BoneAttachment3D>(p_current)) { + BoneAttachment3D *bone = Object::cast_to<BoneAttachment3D>(p_current); _convert_bone_attachment_to_gltf(bone, p_state, p_gltf_parent, p_gltf_root, gltf_node); return; - } else if (cast_to<Skeleton3D>(p_current)) { - Skeleton3D *skel = cast_to<Skeleton3D>(p_current); + } else if (Object::cast_to<Skeleton3D>(p_current)) { + Skeleton3D *skel = Object::cast_to<Skeleton3D>(p_current); _convert_skeleton_to_gltf(skel, p_state, p_gltf_parent, p_gltf_root, gltf_node); // We ignore the Godot Engine node that is the skeleton. return; - } else if (cast_to<MultiMeshInstance3D>(p_current)) { - MultiMeshInstance3D *multi = cast_to<MultiMeshInstance3D>(p_current); + } else if (Object::cast_to<MultiMeshInstance3D>(p_current)) { + MultiMeshInstance3D *multi = Object::cast_to<MultiMeshInstance3D>(p_current); _convert_multi_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, p_state); #ifdef MODULE_CSG_ENABLED - } else if (cast_to<CSGShape3D>(p_current)) { - CSGShape3D *shape = cast_to<CSGShape3D>(p_current); + } else if (Object::cast_to<CSGShape3D>(p_current)) { + CSGShape3D *shape = Object::cast_to<CSGShape3D>(p_current); if (shape->get_parent() && shape->is_root_shape()) { _convert_csg_shape_to_gltf(shape, p_gltf_parent, gltf_node, p_state); } #endif // MODULE_CSG_ENABLED #ifdef MODULE_GRIDMAP_ENABLED - } else if (cast_to<GridMap>(p_current)) { + } else if (Object::cast_to<GridMap>(p_current)) { GridMap *gridmap = Object::cast_to<GridMap>(p_current); _convert_grid_map_to_gltf(gridmap, p_gltf_parent, p_gltf_root, gltf_node, p_state); #endif // MODULE_GRIDMAP_ENABLED - } else if (cast_to<Camera3D>(p_current)) { + } else if (Object::cast_to<Camera3D>(p_current)) { Camera3D *camera = Object::cast_to<Camera3D>(p_current); _convert_camera_to_gltf(camera, p_state, gltf_node); - } else if (cast_to<Light3D>(p_current)) { + } else if (Object::cast_to<Light3D>(p_current)) { Light3D *light = Object::cast_to<Light3D>(p_current); _convert_light_to_gltf(light, p_state, gltf_node); - } else if (cast_to<AnimationPlayer>(p_current)) { + } else if (Object::cast_to<AnimationPlayer>(p_current)) { AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_current); p_state->animation_players.push_back(animation_player); } @@ -5675,9 +5678,9 @@ void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_att Skeleton3D *skeleton; // Note that relative transforms to external skeletons and pose overrides are not supported. if (p_bone_attachment->get_use_external_skeleton()) { - skeleton = cast_to<Skeleton3D>(p_bone_attachment->get_node_or_null(p_bone_attachment->get_external_skeleton())); + skeleton = Object::cast_to<Skeleton3D>(p_bone_attachment->get_node_or_null(p_bone_attachment->get_external_skeleton())); } else { - skeleton = cast_to<Skeleton3D>(p_bone_attachment->get_parent()); + skeleton = Object::cast_to<Skeleton3D>(p_bone_attachment->get_parent()); } GLTFSkeletonIndex skel_gltf_i = -1; if (skeleton != nullptr && p_state->skeleton3d_to_gltf_skeleton.has(skeleton->get_instance_id())) { @@ -6478,7 +6481,7 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> p_state, Node *p_scene } GLTFNodeIndex GLTFDocument::_node_and_or_bone_to_gltf_node_index(Ref<GLTFState> p_state, const Vector<StringName> &p_node_subpath, const Node *p_godot_node) { - const Skeleton3D *skeleton = cast_to<Skeleton3D>(p_godot_node); + const Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_godot_node); if (skeleton && p_node_subpath.size() == 1) { // Special case: Handle skeleton bone TRS tracks. They use the format `A/B/C/Skeleton3D:bone_name`. // We have a Skeleton3D, check if it has a bone with the same name as this subpath. @@ -6909,7 +6912,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p const GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::godot_to_gltf_interpolation(animation, track_index); // First, check if it's a Blend Shape track. if (animation->track_get_type(track_index) == Animation::TYPE_BLEND_SHAPE) { - const MeshInstance3D *mesh_instance = cast_to<MeshInstance3D>(animated_node); + const MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(animated_node); ERR_CONTINUE_MSG(!mesh_instance, "glTF: Animation had a Blend Shape track, but the node wasn't a MeshInstance3D. Ignoring this track."); Ref<Mesh> mesh = mesh_instance->get_mesh(); ERR_CONTINUE(mesh.is_null()); diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index 7954049192..c2d3d49670 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -48,6 +48,7 @@ class GLTFState : public Resource { GDCLASS(GLTFState, Resource); friend class GLTFDocument; + friend class GLTFNode; protected: String base_path; diff --git a/modules/gltf/structures/gltf_node.cpp b/modules/gltf/structures/gltf_node.cpp index ccee5e8ca4..1626313551 100644 --- a/modules/gltf/structures/gltf_node.cpp +++ b/modules/gltf/structures/gltf_node.cpp @@ -30,6 +30,8 @@ #include "gltf_node.h" +#include "../gltf_state.h" + void GLTFNode::_bind_methods() { ClassDB::bind_method(D_METHOD("get_original_name"), &GLTFNode::get_original_name); ClassDB::bind_method(D_METHOD("set_original_name", "original_name"), &GLTFNode::set_original_name); @@ -60,6 +62,7 @@ void GLTFNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_light", "light"), &GLTFNode::set_light); ClassDB::bind_method(D_METHOD("get_additional_data", "extension_name"), &GLTFNode::get_additional_data); ClassDB::bind_method(D_METHOD("set_additional_data", "extension_name", "additional_data"), &GLTFNode::set_additional_data); + ClassDB::bind_method(D_METHOD("get_scene_node_path", "gltf_state", "handle_skeletons"), &GLTFNode::get_scene_node_path, DEFVAL(true)); ADD_PROPERTY(PropertyInfo(Variant::STRING, "original_name"), "set_original_name", "get_original_name"); // String ADD_PROPERTY(PropertyInfo(Variant::INT, "parent"), "set_parent", "get_parent"); // GLTFNodeIndex @@ -187,6 +190,48 @@ Variant GLTFNode::get_additional_data(const StringName &p_extension_name) { return additional_data[p_extension_name]; } +bool GLTFNode::has_additional_data(const StringName &p_extension_name) { + return additional_data.has(p_extension_name); +} + void GLTFNode::set_additional_data(const StringName &p_extension_name, Variant p_additional_data) { additional_data[p_extension_name] = p_additional_data; } + +NodePath GLTFNode::get_scene_node_path(Ref<GLTFState> p_state, bool p_handle_skeletons) { + Vector<StringName> path; + Vector<StringName> subpath; + Ref<GLTFNode> current_gltf_node = this; + const int gltf_node_count = p_state->nodes.size(); + if (p_handle_skeletons && skeleton != -1) { + // Special case for skeleton nodes, skip all bones so that the path is to the Skeleton3D node. + // A path that would otherwise be `A/B/C/Bone1/Bone2/Bone3` becomes `A/B/C/Skeleton3D:Bone3`. + subpath.append(get_name()); + // The generated Skeleton3D node will be named Skeleton3D, so add it to the path. + path.append("Skeleton3D"); + do { + const int parent_index = current_gltf_node->get_parent(); + ERR_FAIL_INDEX_V(parent_index, gltf_node_count, NodePath()); + current_gltf_node = p_state->nodes[parent_index]; + } while (current_gltf_node->skeleton != -1); + } + const bool is_godot_single_root = p_state->extensions_used.has("GODOT_single_root"); + while (true) { + const int parent_index = current_gltf_node->get_parent(); + if (is_godot_single_root && parent_index == -1) { + // For GODOT_single_root scenes, the root glTF node becomes the Godot scene root, so it + // should not be included in the path. Ex: A/B/C, A is single root, we want B/C only. + break; + } + path.insert(0, current_gltf_node->get_name()); + if (!is_godot_single_root && parent_index == -1) { + break; + } + ERR_FAIL_INDEX_V(parent_index, gltf_node_count, NodePath()); + current_gltf_node = p_state->nodes[parent_index]; + } + if (unlikely(path.is_empty())) { + path.append("."); + } + return NodePath(path, subpath, false); +} diff --git a/modules/gltf/structures/gltf_node.h b/modules/gltf/structures/gltf_node.h index f3f6bfa2f1..f72b65a003 100644 --- a/modules/gltf/structures/gltf_node.h +++ b/modules/gltf/structures/gltf_node.h @@ -103,7 +103,10 @@ public: void set_light(GLTFLightIndex p_light); Variant get_additional_data(const StringName &p_extension_name); + bool has_additional_data(const StringName &p_extension_name); void set_additional_data(const StringName &p_extension_name, Variant p_additional_data); + + NodePath get_scene_node_path(Ref<GLTFState> p_state, bool p_handle_skeletons = true); }; #endif // GLTF_NODE_H |
