From 5ffda27ea9903eba5a0849633c8e049b77aeba76 Mon Sep 17 00:00:00 2001 From: Lyuma Date: Fri, 3 Sep 2021 18:00:59 -0700 Subject: gltf export: Fix export of skeletons, skins and blend shapes. Create GLTFSkeleton at the same time we create GLTFNode objects. Create GLTFSkin at the same time we export MeshInstance3D Fixes export of blend shape arrays for meshes with multiple surfaces. Fixes array indexing issues in export of glTF morph target animations. Converts BoneAttachment3D nodes during normal node creation: this avoids special cases during mesh export, and especially exporting skeletons or meshes which are children of BoneAttachment3D. Co-authored-by: K. S. Ernest (iFire) Lee --- modules/gltf/gltf_document.cpp | 631 +++++++++++++++++++++-------------------- modules/gltf/gltf_document.h | 63 ++-- modules/gltf/gltf_state.h | 5 + 3 files changed, 354 insertions(+), 345 deletions(-) (limited to 'modules/gltf') diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index a92eb88edb..5f2e8d4ba6 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -78,7 +78,10 @@ Error GLTFDocument::serialize(Ref state, Node *p_root, const String &p_path) { uint64_t begin_time = OS::get_singleton()->get_ticks_usec(); - _convert_scene_node(state, p_root, p_root, -1, -1); + state->skeleton3d_to_gltf_skeleton.clear(); + state->skin_and_skeleton3d_to_gltf_skin.clear(); + + _convert_scene_node(state, p_root, -1, -1); if (!state->buffers.size()) { state->buffers.push_back(Vector()); } @@ -97,11 +100,7 @@ Error GLTFDocument::serialize(Ref state, Node *p_root, const String & if (err != OK) { return Error::FAILED; } - /* STEP 4 CREATE BONE ATTACHMENTS */ - err = _serialize_bone_attachment(state); - if (err != OK) { - return Error::FAILED; - } + /* STEP 5 SERIALIZE MESHES (we have enough info now) */ err = _serialize_meshes(state); if (err != OK) { @@ -249,30 +248,6 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref state) { return OK; } -Error GLTFDocument::_serialize_bone_attachment(Ref state) { - for (int skeleton_i = 0; skeleton_i < state->skeletons.size(); skeleton_i++) { - for (int attachment_i = 0; attachment_i < state->skeletons[skeleton_i]->bone_attachments.size(); attachment_i++) { - BoneAttachment3D *bone_attachment = state->skeletons[skeleton_i]->bone_attachments[attachment_i]; - String bone_name = bone_attachment->get_bone_name(); - bone_name = _sanitize_bone_name(bone_name); - int32_t bone = state->skeletons[skeleton_i]->godot_skeleton->find_bone(bone_name); - ERR_CONTINUE(bone == -1); - for (int skin_i = 0; skin_i < state->skins.size(); skin_i++) { - if (state->skins[skin_i]->skeleton != skeleton_i) { - continue; - } - - for (int node_i = 0; node_i < bone_attachment->get_child_count(); node_i++) { - ERR_CONTINUE(bone >= state->skins[skin_i]->joints.size()); - _convert_scene_node(state, bone_attachment->get_child(node_i), bone_attachment->get_owner(), state->skins[skin_i]->joints[bone], 0); - } - break; - } - } - } - return OK; -} - Error GLTFDocument::_parse_glb(const String &p_path, Ref state) { Error err; FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); @@ -2131,11 +2106,14 @@ Error GLTFDocument::_serialize_meshes(Ref state) { continue; } Array primitives; - Array targets; Dictionary gltf_mesh; Array target_names; Array weights; + for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) { + target_names.push_back(import_mesh->get_blend_shape_name(morph_i)); + } for (int surface_i = 0; surface_i < import_mesh->get_surface_count(); surface_i++) { + Array targets; Dictionary primitive; Mesh::PrimitiveType primitive_type = import_mesh->get_surface_primitive_type(surface_i); switch (primitive_type) { @@ -2337,10 +2315,10 @@ Error GLTFDocument::_serialize_meshes(Ref state) { const Array &a = array[Mesh::ARRAY_WEIGHTS]; const Vector &vertex_array = array[Mesh::ARRAY_VERTEX]; if ((a.size() / JOINT_GROUP_SIZE) == vertex_array.size()) { - const int ret_size = a.size() / JOINT_GROUP_SIZE; + int32_t vertex_count = vertex_array.size(); Vector attribs; - attribs.resize(ret_size); - for (int i = 0; i < ret_size; i++) { + attribs.resize(vertex_count); + for (int i = 0; i < vertex_count; i++) { attribs.write[i] = Color(a[(i * JOINT_GROUP_SIZE) + 0], a[(i * JOINT_GROUP_SIZE) + 1], a[(i * JOINT_GROUP_SIZE) + 2], a[(i * JOINT_GROUP_SIZE) + 3]); } attributes["WEIGHTS_0"] = _encode_accessor_as_weights(state, attribs, true); @@ -2410,7 +2388,6 @@ Error GLTFDocument::_serialize_meshes(Ref state) { ArrayMesh::BlendShapeMode shape_mode = import_mesh->get_blend_shape_mode(); for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) { Array array_morph = import_mesh->get_surface_blend_shape_arrays(surface_i, morph_i); - target_names.push_back(import_mesh->get_blend_shape_name(morph_i)); Dictionary t; Vector varr = array_morph[Mesh::ARRAY_VERTEX]; Array mesh_arrays = import_mesh->get_surface_arrays(surface_i); @@ -2427,22 +2404,21 @@ Error GLTFDocument::_serialize_meshes(Ref state) { } Vector narr = array_morph[Mesh::ARRAY_NORMAL]; - if (varr.size()) { + if (narr.size()) { t["NORMAL"] = _encode_accessor_as_vec3(state, narr, true); } Vector tarr = array_morph[Mesh::ARRAY_TANGENT]; if (tarr.size()) { const int ret_size = tarr.size() / 4; - Vector attribs; + Vector attribs; attribs.resize(ret_size); for (int i = 0; i < ret_size; i++) { - Color tangent; - tangent.r = tarr[(i * 4) + 0]; - tangent.g = tarr[(i * 4) + 1]; - tangent.b = tarr[(i * 4) + 2]; - tangent.a = tarr[(i * 4) + 3]; + Vector3 vec3; + vec3.x = tarr[(i * 4) + 0]; + vec3.y = tarr[(i * 4) + 1]; + vec3.z = tarr[(i * 4) + 2]; } - t["TANGENT"] = _encode_accessor_as_color(state, attribs, true); + t["TANGENT"] = _encode_accessor_as_vec3(state, attribs, true); } targets.push_back(t); } @@ -2471,12 +2447,13 @@ Error GLTFDocument::_serialize_meshes(Ref state) { Dictionary e; e["targetNames"] = target_names; - for (int j = 0; j < target_names.size(); j++) { + weights.resize(target_names.size()); + for (int name_i = 0; name_i < target_names.size(); name_i++) { real_t weight = 0.0; - if (j < state->meshes.write[gltf_mesh_i]->get_blend_weights().size()) { - weight = state->meshes.write[gltf_mesh_i]->get_blend_weights()[j]; + if (name_i < state->meshes.write[gltf_mesh_i]->get_blend_weights().size()) { + weight = state->meshes.write[gltf_mesh_i]->get_blend_weights()[name_i]; } - weights.push_back(weight); + weights[name_i] = weight; } if (weights.size()) { gltf_mesh["weights"] = weights; @@ -4285,6 +4262,7 @@ Error GLTFDocument::_create_skeletons(Ref state) { Skeleton3D *skeleton = memnew(Skeleton3D); gltf_skeleton->godot_skeleton = skeleton; + state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skel_i; // Make a unique name, no gltf node represents this skeleton skeleton->set_name(_gen_unique_name(state, "Skeleton3D")); @@ -4370,6 +4348,16 @@ Error GLTFDocument::_map_skin_joints_indices_to_skeleton_bone_indices(Ref state) { _remove_duplicate_skins(state); + Array json_skins; + for (int skin_i = 0; skin_i < state->skins.size(); skin_i++) { + Ref gltf_skin = state->skins[skin_i]; + Dictionary json_skin; + json_skin["inverseBindMatrices"] = _encode_accessor_as_xform(state, gltf_skin->inverse_binds, false); + json_skin["joints"] = gltf_skin->get_joints(); + json_skin["name"] = gltf_skin->get_name(); + json_skins.push_back(json_skin); + } + state->json["skins"] = json_skins; return OK; } @@ -4748,30 +4736,74 @@ Error GLTFDocument::_serialize_animations(Ref state) { channels.push_back(t); } if (track.weight_tracks.size()) { + double length = 0.0f; + + for (int32_t track_idx = 0; track_idx < track.weight_tracks.size(); track_idx++) { + int32_t last_time_index = track.weight_tracks[track_idx].times.size() - 1; + length = MAX(length, track.weight_tracks[track_idx].times[last_time_index]); + } + Dictionary t; t["sampler"] = samplers.size(); Dictionary s; - Vector times; - Vector values; + const double increment = 1.0 / BAKE_FPS; + { + double time = 0.0; + bool last = false; + while (true) { + times.push_back(time); + if (last) { + break; + } + time += increment; + if (time >= length) { + last = true; + time = length; + } + } + } - for (int32_t times_i = 0; times_i < track.weight_tracks[0].times.size(); times_i++) { - real_t time = track.weight_tracks[0].times[times_i]; - times.push_back(time); + for (int32_t track_idx = 0; track_idx < track.weight_tracks.size(); track_idx++) { + double time = 0.0; + bool last = false; + Vector weight_track; + while (true) { + float weight = _interpolate_track(track.weight_tracks[track_idx].times, + track.weight_tracks[track_idx].values, + time, + track.weight_tracks[track_idx].interpolation); + weight_track.push_back(weight); + if (last) { + break; + } + time += increment; + if (time >= length) { + last = true; + time = length; + } + } + track.weight_tracks.write[track_idx].times = times; + track.weight_tracks.write[track_idx].values = weight_track; } - values.resize(times.size() * track.weight_tracks.size()); - // TODO Sort by order in blend shapes + Vector all_track_times = times; + Vector all_track_values; + int32_t values_size = track.weight_tracks[0].values.size(); + int32_t weight_tracks_size = track.weight_tracks.size(); + all_track_values.resize(weight_tracks_size * values_size); for (int k = 0; k < track.weight_tracks.size(); k++) { Vector wdata = track.weight_tracks[k].values; for (int l = 0; l < wdata.size(); l++) { - values.write[l * track.weight_tracks.size() + k] = wdata.write[l]; + int32_t index = l * weight_tracks_size + k; + ERR_BREAK(index >= all_track_values.size()); + all_track_values.write[index] = wdata.write[l]; } } s["interpolation"] = interpolation_to_string(track.weight_tracks[track.weight_tracks.size() - 1].interpolation); - s["input"] = _encode_accessor_as_floats(state, times, false); - s["output"] = _encode_accessor_as_floats(state, values, false); + s["input"] = _encode_accessor_as_floats(state, all_track_times, false); + s["output"] = _encode_accessor_as_floats(state, all_track_values, false); samplers.push_back(s); @@ -4905,7 +4937,7 @@ Error GLTFDocument::_parse_animations(Ref state) { track->weight_tracks.resize(wc); const int expected_value_count = times.size() * output_count * wc; - ERR_FAIL_COND_V_MSG(weights.size() != expected_value_count, ERR_PARSE_ERROR, "Invalid weight data, expected " + itos(expected_value_count) + " weight values, got " + itos(weights.size()) + " instead."); + ERR_CONTINUE_MSG(weights.size() != expected_value_count, "Invalid weight data, expected " + itos(expected_value_count) + " weight values, got " + itos(weights.size()) + " instead."); const int wlen = weights.size() / wc; for (int k = 0; k < wc; k++) { //separate tracks, having them together is not such a good idea @@ -4970,7 +5002,7 @@ BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref state, return bone_attachment; } -GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref state, MeshInstance3D *p_mesh_instance) { +GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref state, MeshInstance3D *p_mesh_instance) { ERR_FAIL_NULL_V(p_mesh_instance, -1); if (p_mesh_instance->get_mesh().is_null()) { return -1; @@ -5167,17 +5199,6 @@ GLTFLightIndex GLTFDocument::_convert_light(Ref state, Light3D *p_lig return light_index; } -GLTFSkeletonIndex GLTFDocument::_convert_skeleton(Ref state, Skeleton3D *p_skeleton) { - print_verbose("glTF: Converting skeleton: " + p_skeleton->get_name()); - Ref gltf_skeleton; - gltf_skeleton.instantiate(); - gltf_skeleton->set_name(_gen_unique_name(state, p_skeleton->get_name())); - gltf_skeleton->godot_skeleton = p_skeleton; - GLTFSkeletonIndex skeleton_i = state->skeletons.size(); - state->skeletons.push_back(gltf_skeleton); - return skeleton_i; -} - void GLTFDocument::_convert_spatial(Ref state, Node3D *p_spatial, Ref p_node) { Transform3D xform = p_spatial->get_transform(); p_node->scale = xform.basis.get_scale(); @@ -5193,7 +5214,7 @@ Node3D *GLTFDocument::_generate_spatial(Ref state, Node *scene_parent return spatial; } -void GLTFDocument::_convert_scene_node(Ref state, Node *p_current, Node *p_root, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) { +void GLTFDocument::_convert_scene_node(Ref state, Node *p_current, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) { bool retflag = true; _check_visibility(p_current, retflag); if (retflag) { @@ -5207,37 +5228,41 @@ void GLTFDocument::_convert_scene_node(Ref state, Node *p_current, No _convert_spatial(state, spatial, gltf_node); } if (cast_to(p_current)) { - Node3D *spatial = cast_to(p_current); - _convert_mesh_to_gltf(p_current, state, spatial, gltf_node); + MeshInstance3D *mi = cast_to(p_current); + _convert_mesh_instance_to_gltf(mi, state, gltf_node); } else if (cast_to(p_current)) { - _convert_bone_attachment_to_gltf(p_current, state, gltf_node, retflag); - // TODO 2020-12-21 iFire Handle the case of objects under the bone attachment. + BoneAttachment3D *bone = cast_to(p_current); + _convert_bone_attachment_to_gltf(bone, state, p_gltf_parent, p_gltf_root, gltf_node); return; } else if (cast_to(p_current)) { - _convert_skeleton_to_gltf(p_current, state, p_gltf_parent, p_gltf_root, gltf_node, p_root); + Skeleton3D *skel = cast_to(p_current); + _convert_skeleton_to_gltf(skel, state, p_gltf_parent, p_gltf_root, gltf_node); // We ignore the Godot Engine node that is the skeleton. return; } else if (cast_to(p_current)) { - _convert_mult_mesh_instance_to_gltf(p_current, p_gltf_parent, p_gltf_root, gltf_node, state, p_root); + MultiMeshInstance3D *multi = cast_to(p_current); + _convert_mult_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, state); #ifdef MODULE_CSG_ENABLED } else if (cast_to(p_current)) { - if (p_current->get_parent() && cast_to(p_current)->is_root_shape()) { - _convert_csg_shape_to_gltf(p_current, p_gltf_parent, gltf_node, state); + CSGShape3D *shape = cast_to(p_current); + if (shape->get_parent() && shape->is_root_shape()) { + _convert_csg_shape_to_gltf(shape, p_gltf_parent, gltf_node, state); } #endif // MODULE_CSG_ENABLED #ifdef MODULE_GRIDMAP_ENABLED } else if (cast_to(p_current)) { - _convert_grid_map_to_gltf(p_current, p_gltf_parent, p_gltf_root, gltf_node, state, p_root); + GridMap *gridmap = Object::cast_to(p_current); + _convert_grid_map_to_gltf(gridmap, p_gltf_parent, p_gltf_root, gltf_node, state); #endif // MODULE_GRIDMAP_ENABLED } else if (cast_to(p_current)) { Camera3D *camera = Object::cast_to(p_current); - _convert_camera_to_gltf(camera, state, camera, gltf_node); + _convert_camera_to_gltf(camera, state, gltf_node); } else if (cast_to(p_current)) { Light3D *light = Object::cast_to(p_current); - _convert_light_to_gltf(light, state, light, gltf_node); + _convert_light_to_gltf(light, state, gltf_node); } else if (cast_to(p_current)) { AnimationPlayer *animation_player = Object::cast_to(p_current); - _convert_animation_player_to_gltf(animation_player, state, p_gltf_parent, p_gltf_root, gltf_node, p_current, p_root); + _convert_animation_player_to_gltf(animation_player, state, p_gltf_parent, p_gltf_root, gltf_node, p_current); } GLTFNodeIndex current_node_i = state->nodes.size(); GLTFNodeIndex gltf_root = p_gltf_root; @@ -5249,13 +5274,13 @@ void GLTFDocument::_convert_scene_node(Ref state, Node *p_current, No } _create_gltf_node(state, p_current, current_node_i, p_gltf_parent, gltf_root, gltf_node); for (int node_i = 0; node_i < p_current->get_child_count(); node_i++) { - _convert_scene_node(state, p_current->get_child(node_i), p_root, current_node_i, gltf_root); + _convert_scene_node(state, p_current->get_child(node_i), current_node_i, gltf_root); } } #ifdef MODULE_CSG_ENABLED -void GLTFDocument::_convert_csg_shape_to_gltf(Node *p_current, GLTFNodeIndex p_gltf_parent, Ref gltf_node, Ref state) { - CSGShape3D *csg = Object::cast_to(p_current); +void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref gltf_node, Ref state) { + CSGShape3D *csg = p_current; csg->call("_update_shape"); Array meshes = csg->get_meshes(); if (meshes.size() != 2) { @@ -5286,16 +5311,15 @@ void GLTFDocument::_create_gltf_node(Ref state, Node *p_scene_parent, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_gltf_node, Ref gltf_node) { state->scene_nodes.insert(current_node_i, p_scene_parent); state->nodes.push_back(gltf_node); - if (current_node_i == p_parent_node_index) { - return; - } + ERR_FAIL_COND(current_node_i == p_parent_node_index); + state->nodes.write[current_node_i]->parent = p_parent_node_index; if (p_parent_node_index == -1) { return; } state->nodes.write[p_parent_node_index]->children.push_back(current_node_i); } -void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *animation_player, Ref state, const GLTFNodeIndex &p_gltf_current, const GLTFNodeIndex &p_gltf_root_index, Ref p_gltf_node, Node *p_scene_parent, Node *p_root) { +void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *animation_player, Ref state, GLTFNodeIndex p_gltf_current, GLTFNodeIndex p_gltf_root_index, Ref p_gltf_node, Node *p_scene_parent) { ERR_FAIL_COND(!animation_player); state->animation_players.push_back(animation_player); print_verbose(String("glTF: Converting animation player: ") + animation_player->get_name()); @@ -5314,7 +5338,7 @@ void GLTFDocument::_check_visibility(Node *p_node, bool &retflag) { retflag = false; } -void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref state, Node3D *spatial, Ref gltf_node) { +void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref state, Ref gltf_node) { ERR_FAIL_COND(!camera); GLTFCameraIndex camera_index = _convert_camera(state, camera); if (camera_index != -1) { @@ -5322,7 +5346,7 @@ void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref stat } } -void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref state, Node3D *spatial, Ref gltf_node) { +void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref state, Ref gltf_node) { ERR_FAIL_COND(!light); GLTFLightIndex light_index = _convert_light(state, light); if (light_index != -1) { @@ -5331,43 +5355,39 @@ void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref state, } #ifdef MODULE_GRIDMAP_ENABLED -void GLTFDocument::_convert_grid_map_to_gltf(Node *p_scene_parent, const GLTFNodeIndex &p_parent_node_index, const GLTFNodeIndex &p_root_node_index, Ref gltf_node, Ref state, Node *p_root_node) { - GridMap *grid_map = Object::cast_to(p_scene_parent); - ERR_FAIL_COND(!grid_map); - Array cells = grid_map->get_used_cells(); +void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref gltf_node, Ref state) { + Array cells = p_grid_map->get_used_cells(); for (int32_t k = 0; k < cells.size(); k++) { GLTFNode *new_gltf_node = memnew(GLTFNode); gltf_node->children.push_back(state->nodes.size()); state->nodes.push_back(new_gltf_node); Vector3 cell_location = cells[k]; - int32_t cell = grid_map->get_cell_item( + int32_t cell = p_grid_map->get_cell_item( Vector3(cell_location.x, cell_location.y, cell_location.z)); EditorSceneImporterMeshNode3D *import_mesh_node = memnew(EditorSceneImporterMeshNode3D); - import_mesh_node->set_mesh(grid_map->get_mesh_library()->get_item_mesh(cell)); + import_mesh_node->set_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell)); Transform3D cell_xform; cell_xform.basis.set_orthogonal_index( - grid_map->get_cell_item_orientation( + p_grid_map->get_cell_item_orientation( Vector3(cell_location.x, cell_location.y, cell_location.z))); - cell_xform.basis.scale(Vector3(grid_map->get_cell_scale(), - grid_map->get_cell_scale(), - grid_map->get_cell_scale())); - cell_xform.set_origin(grid_map->map_to_world( + cell_xform.basis.scale(Vector3(p_grid_map->get_cell_scale(), + p_grid_map->get_cell_scale(), + p_grid_map->get_cell_scale())); + cell_xform.set_origin(p_grid_map->map_to_world( Vector3(cell_location.x, cell_location.y, cell_location.z))); Ref gltf_mesh; gltf_mesh.instantiate(); gltf_mesh = import_mesh_node; new_gltf_node->mesh = state->meshes.size(); state->meshes.push_back(gltf_mesh); - new_gltf_node->xform = cell_xform * grid_map->get_transform(); - new_gltf_node->set_name(_gen_unique_name(state, grid_map->get_mesh_library()->get_item_name(cell))); + new_gltf_node->xform = cell_xform * p_grid_map->get_transform(); + new_gltf_node->set_name(_gen_unique_name(state, p_grid_map->get_mesh_library()->get_item_name(cell))); } } #endif // MODULE_GRIDMAP_ENABLED -void GLTFDocument::_convert_mult_mesh_instance_to_gltf(Node *p_scene_parent, const GLTFNodeIndex &p_parent_node_index, const GLTFNodeIndex &p_root_node_index, Ref gltf_node, Ref state, Node *p_root_node) { - MultiMeshInstance3D *multi_mesh_instance = Object::cast_to(p_scene_parent); - ERR_FAIL_COND(!multi_mesh_instance); - Ref multi_mesh = multi_mesh_instance->get_multimesh(); +void GLTFDocument::_convert_mult_mesh_instance_to_gltf(MultiMeshInstance3D *p_multi_mesh_instance, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref gltf_node, Ref state) { + Ref multi_mesh = p_multi_mesh_instance->get_multimesh(); if (multi_mesh.is_valid()) { for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count(); instance_i++) { @@ -5383,9 +5403,9 @@ void GLTFDocument::_convert_mult_mesh_instance_to_gltf(Node *p_scene_parent, con transform.basis.set_quaternion_scale(quaternion, Vector3(scale.x, 0, scale.y)); transform = - multi_mesh_instance->get_transform() * transform; + p_multi_mesh_instance->get_transform() * transform; } else if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_3D) { - transform = multi_mesh_instance->get_transform() * + transform = p_multi_mesh_instance->get_transform() * multi_mesh->get_instance_transform(instance_i); } Ref mm = multi_mesh->get_mesh(); @@ -5405,56 +5425,102 @@ void GLTFDocument::_convert_mult_mesh_instance_to_gltf(Node *p_scene_parent, con state->meshes.push_back(gltf_mesh); } new_gltf_node->xform = transform; - new_gltf_node->set_name(_gen_unique_name(state, multi_mesh_instance->get_name())); + new_gltf_node->set_name(_gen_unique_name(state, p_multi_mesh_instance->get_name())); gltf_node->children.push_back(state->nodes.size()); state->nodes.push_back(new_gltf_node); } } } -void GLTFDocument::_convert_skeleton_to_gltf(Node *p_scene_parent, Ref state, const GLTFNodeIndex &p_parent_node_index, const GLTFNodeIndex &p_root_node_index, Ref gltf_node, Node *p_root_node) { - Skeleton3D *skeleton = Object::cast_to(p_scene_parent); - if (skeleton) { - // Remove placeholder skeleton3d node by not creating the gltf node - // Skins are per mesh - for (int node_i = 0; node_i < skeleton->get_child_count(); node_i++) { - _convert_scene_node(state, skeleton->get_child(node_i), p_root_node, p_parent_node_index, p_root_node_index); +void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref gltf_node) { + Skeleton3D *skeleton = p_skeleton3d; + Ref gltf_skeleton; + gltf_skeleton.instantiate(); + // GLTFSkeleton is only used to hold internal state data. It will not be written to the document. + // + gltf_skeleton->godot_skeleton = skeleton; + GLTFSkeletonIndex skeleton_i = state->skeletons.size(); + state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skeleton_i; + state->skeletons.push_back(gltf_skeleton); + + BoneId bone_count = skeleton->get_bone_count(); + for (BoneId bone_i = 0; bone_i < bone_count; bone_i++) { + Ref joint_node; + joint_node.instantiate(); + // Note that we cannot use _gen_unique_bone_name here, because glTF spec requires all node + // names to be unique regardless of whether or not they are used as joints. + joint_node->set_name(_gen_unique_name(state, skeleton->get_bone_name(bone_i))); + Transform3D xform = skeleton->get_bone_rest(bone_i) * skeleton->get_bone_pose(bone_i); + joint_node->scale = xform.basis.get_scale(); + joint_node->rotation = xform.basis.get_rotation_quaternion(); + joint_node->position = xform.origin; + joint_node->joint = true; + GLTFNodeIndex current_node_i = state->nodes.size(); + state->scene_nodes.insert(current_node_i, skeleton); + state->nodes.push_back(joint_node); + + gltf_skeleton->joints.push_back(current_node_i); + if (skeleton->get_bone_parent(bone_i) == -1) { + gltf_skeleton->roots.push_back(current_node_i); + } + gltf_skeleton->godot_bone_node.insert(bone_i, current_node_i); + } + for (BoneId bone_i = 0; bone_i < bone_count; bone_i++) { + GLTFNodeIndex current_node_i = gltf_skeleton->godot_bone_node[bone_i]; + BoneId parent_bone_id = skeleton->get_bone_parent(bone_i); + if (parent_bone_id == -1) { + if (p_parent_node_index != -1) { + state->nodes.write[current_node_i]->parent = p_parent_node_index; + state->nodes.write[p_parent_node_index]->children.push_back(current_node_i); + } + } else { + GLTFNodeIndex parent_node_i = gltf_skeleton->godot_bone_node[parent_bone_id]; + state->nodes.write[current_node_i]->parent = parent_node_i; + state->nodes.write[parent_node_i]->children.push_back(current_node_i); } } + // Remove placeholder skeleton3d node by not creating the gltf node + // Skins are per mesh + for (int node_i = 0; node_i < skeleton->get_child_count(); node_i++) { + _convert_scene_node(state, skeleton->get_child(node_i), p_parent_node_index, p_root_node_index); + } } -void GLTFDocument::_convert_bone_attachment_to_gltf(Node *p_scene_parent, Ref state, Ref gltf_node, bool &retflag) { - retflag = true; - BoneAttachment3D *bone_attachment = Object::cast_to(p_scene_parent); - if (bone_attachment) { - Node *node = bone_attachment->get_parent(); - while (node) { - Skeleton3D *bone_attachment_skeleton = Object::cast_to(node); - if (bone_attachment_skeleton) { - for (GLTFSkeletonIndex skeleton_i = 0; skeleton_i < state->skeletons.size(); skeleton_i++) { - if (state->skeletons[skeleton_i]->godot_skeleton != bone_attachment_skeleton) { - continue; - } - state->skeletons.write[skeleton_i]->bone_attachments.push_back(bone_attachment); - break; - } - break; - } - node = node->get_parent(); +void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment, Ref state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref gltf_node) { + 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(p_bone_attachment->get_node_or_null(p_bone_attachment->get_external_skeleton())); + } else { + skeleton = cast_to(p_bone_attachment->get_parent()); + } + GLTFSkeletonIndex skel_gltf_i = -1; + if (skeleton != nullptr && state->skeleton3d_to_gltf_skeleton.has(skeleton->get_instance_id())) { + skel_gltf_i = state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()]; + } + int bone_idx = -1; + if (skeleton != nullptr) { + bone_idx = p_bone_attachment->get_bone_idx(); + if (bone_idx == -1) { + bone_idx = skeleton->find_bone(p_bone_attachment->get_bone_name()); } - gltf_node.unref(); - return; } - retflag = false; + GLTFNodeIndex par_node_index = p_parent_node_index; + if (skeleton != nullptr && bone_idx != -1 && skel_gltf_i != -1) { + Ref gltf_skeleton = state->skeletons.write[skel_gltf_i]; + gltf_skeleton->bone_attachments.push_back(p_bone_attachment); + par_node_index = gltf_skeleton->joints[bone_idx]; + } + + for (int node_i = 0; node_i < p_bone_attachment->get_child_count(); node_i++) { + _convert_scene_node(state, p_bone_attachment->get_child(node_i), par_node_index, p_root_node_index); + } } -void GLTFDocument::_convert_mesh_to_gltf(Node *p_scene_parent, Ref state, Node3D *spatial, Ref gltf_node) { - MeshInstance3D *mi = Object::cast_to(p_scene_parent); - if (mi) { - GLTFMeshIndex gltf_mesh_index = _convert_mesh_instance(state, mi); - if (gltf_mesh_index != -1) { - gltf_node->mesh = gltf_mesh_index; - } +void GLTFDocument::_convert_mesh_instance_to_gltf(MeshInstance3D *p_scene_parent, Ref state, Ref gltf_node) { + GLTFMeshIndex gltf_mesh_index = _convert_mesh_to_gltf(state, p_scene_parent); + if (gltf_mesh_index != -1) { + gltf_node->mesh = gltf_mesh_index; } } @@ -5908,10 +5974,6 @@ void GLTFDocument::_convert_mesh_instances(Ref state) { if (node->mesh < 0) { continue; } - Array json_skins; - if (state->json.has("skins")) { - json_skins = state->json["skins"]; - } Map::Element *mi_element = state->scene_nodes.find(mi_node_i); if (!mi_element) { continue; @@ -5923,7 +5985,6 @@ void GLTFDocument::_convert_mesh_instances(Ref state) { node->rotation = mi_xform.basis.get_rotation_quaternion(); node->position = mi_xform.origin; - Dictionary json_skin; Skeleton3D *skeleton = Object::cast_to(mi->get_node(mi->get_skeleton_path())); if (!skeleton) { continue; @@ -5932,121 +5993,75 @@ void GLTFDocument::_convert_mesh_instances(Ref state) { continue; } Ref skin = mi->get_skin(); - if (skin.is_null()) { - skin = skeleton->register_skin(nullptr)->get_skin(); - } Ref gltf_skin; gltf_skin.instantiate(); Array json_joints; - GLTFSkeletonIndex skeleton_gltf_i = -1; NodePath skeleton_path = mi->get_skeleton_path(); - bool is_unique = true; - for (int32_t skin_i = 0; skin_i < state->skins.size(); skin_i++) { - Ref prev_gltf_skin = state->skins.write[skin_i]; - if (gltf_skin.is_null()) { - continue; - } - GLTFSkeletonIndex prev_skeleton = prev_gltf_skin->get_skeleton(); - if (prev_skeleton == -1 || prev_skeleton >= state->skeletons.size()) { - continue; - } - if (prev_gltf_skin->get_godot_skin() == skin && state->skeletons[prev_skeleton]->godot_skeleton == skeleton) { - node->skin = skin_i; - node->skeleton = prev_skeleton; - is_unique = false; - break; - } - } - if (!is_unique) { - continue; - } - GLTFSkeletonIndex skeleton_i = _convert_skeleton(state, skeleton); - skeleton_gltf_i = skeleton_i; - ERR_CONTINUE(skeleton_gltf_i == -1); - gltf_skin->skeleton = skeleton_gltf_i; - Ref gltf_skeleton = state->skeletons.write[skeleton_gltf_i]; - for (int32_t bind_i = 0; bind_i < skin->get_bind_count(); bind_i++) { - String godot_bone_name = skin->get_bind_name(bind_i); - if (godot_bone_name.is_empty()) { - int32_t bone = skin->get_bind_bone(bind_i); - godot_bone_name = skeleton->get_bone_name(bone); - } - if (skeleton->find_bone(godot_bone_name) == -1) { - godot_bone_name = skeleton->get_bone_name(0); - } - BoneId bone_index = skeleton->find_bone(godot_bone_name); - ERR_CONTINUE(bone_index == -1); - Ref joint_node; - joint_node.instantiate(); - String gltf_bone_name = _gen_unique_bone_name(state, skeleton_gltf_i, godot_bone_name); - joint_node->set_name(gltf_bone_name); - - Transform3D bone_rest_xform = skeleton->get_bone_rest(bone_index); - joint_node->scale = bone_rest_xform.basis.get_scale(); - joint_node->rotation = bone_rest_xform.basis.get_rotation_quaternion(); - joint_node->position = bone_rest_xform.origin; - joint_node->joint = true; - - int32_t joint_node_i = state->nodes.size(); - state->nodes.push_back(joint_node); - gltf_skeleton->godot_bone_node.insert(bone_index, joint_node_i); - int32_t joint_index = gltf_skin->joints.size(); - gltf_skin->joint_i_to_bone_i.insert(joint_index, bone_index); - gltf_skin->joints.push_back(joint_node_i); - gltf_skin->joints_original.push_back(joint_node_i); - gltf_skin->inverse_binds.push_back(skin->get_bind_pose(bind_i)); - json_joints.push_back(joint_node_i); - for (Map::Element *skin_scene_node_i = state->scene_nodes.front(); skin_scene_node_i; skin_scene_node_i = skin_scene_node_i->next()) { - if (skin_scene_node_i->get() == skeleton) { - gltf_skin->skin_root = skin_scene_node_i->key(); - json_skin["skeleton"] = skin_scene_node_i->key(); - } - } - gltf_skin->godot_skin = skin; - gltf_skin->set_name(_gen_unique_name(state, skin->get_name())); - } - for (int32_t bind_i = 0; bind_i < skin->get_bind_count(); bind_i++) { - String bone_name = skeleton->get_bone_name(bind_i); - String godot_bone_name = skin->get_bind_name(bind_i); - int32_t bone = -1; - if (skin->get_bind_bone(bind_i) != -1) { - bone = skin->get_bind_bone(bind_i); - godot_bone_name = skeleton->get_bone_name(bone); - } - bone = skeleton->find_bone(godot_bone_name); - if (bone == -1) { - continue; - } - BoneId bone_parent = skeleton->get_bone_parent(bone); - GLTFNodeIndex joint_node_i = gltf_skeleton->godot_bone_node[bone]; - ERR_CONTINUE(joint_node_i >= state->nodes.size()); - if (bone_parent != -1) { - GLTFNodeIndex parent_joint_gltf_node = gltf_skin->joints[bone_parent]; - Ref parent_joint_node = state->nodes.write[parent_joint_gltf_node]; - parent_joint_node->children.push_back(joint_node_i); + Node *skel_node = mi->get_node_or_null(skeleton_path); + Skeleton3D *godot_skeleton = nullptr; + if (skel_node != nullptr) { + godot_skeleton = cast_to(skel_node); + } + if (godot_skeleton != nullptr && state->skeleton3d_to_gltf_skeleton.has(godot_skeleton->get_instance_id())) { + // This is a skinned mesh. If the mesh has no ARRAY_WEIGHTS or ARRAY_BONES, it will be invisible. + const GLTFSkeletonIndex skeleton_gltf_i = state->skeleton3d_to_gltf_skeleton[godot_skeleton->get_instance_id()]; + Ref gltf_skeleton = state->skeletons[skeleton_gltf_i]; + int bone_cnt = skeleton->get_bone_count(); + ERR_FAIL_COND(bone_cnt != gltf_skeleton->joints.size()); + + ObjectID gltf_skin_key = skin->get_instance_id(); + ObjectID gltf_skel_key = godot_skeleton->get_instance_id(); + GLTFSkinIndex skin_gltf_i = -1; + GLTFNodeIndex root_gltf_i = -1; + if (!gltf_skeleton->roots.is_empty()) { + root_gltf_i = gltf_skeleton->roots[0]; + } + if (state->skin_and_skeleton3d_to_gltf_skin.has(gltf_skin_key) && state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key].has(gltf_skel_key)) { + skin_gltf_i = state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key]; } else { - Node *node_parent = skeleton->get_parent(); - ERR_CONTINUE(!node_parent); - for (Map::Element *E = state->scene_nodes.front(); E; E = E->next()) { - if (E->get() == node_parent) { - GLTFNodeIndex gltf_node_i = E->key(); - Ref gltf_node = state->nodes.write[gltf_node_i]; - gltf_node->children.push_back(joint_node_i); - break; + if (skin.is_null()) { + // Note that gltf_skin_key should remain null, so these can share a reference. + skin = skeleton->register_skin(nullptr)->get_skin(); + } + gltf_skin.instantiate(); + gltf_skin->godot_skin = skin; + gltf_skin->set_name(skin->get_name()); + gltf_skin->skeleton = skeleton_gltf_i; + gltf_skin->skin_root = root_gltf_i; + //gltf_state->godot_to_gltf_node[skel_node] + HashMap bone_name_to_idx; + for (int bone_i = 0; bone_i < bone_cnt; bone_i++) { + bone_name_to_idx[skeleton->get_bone_name(bone_i)] = bone_i; + } + for (int bind_i = 0, cnt = skin->get_bind_count(); bind_i < cnt; bind_i++) { + int bone_i = skin->get_bind_bone(bind_i); + Transform3D bind_pose = skin->get_bind_pose(bind_i); + StringName bind_name = skin->get_bind_name(bind_i); + if (bind_name != StringName()) { + bone_i = bone_name_to_idx[bind_name]; } + ERR_CONTINUE(bone_i < 0 || bone_i >= bone_cnt); + if (bind_name == StringName()) { + bind_name = skeleton->get_bone_name(bone_i); + } + GLTFNodeIndex skeleton_bone_i = gltf_skeleton->joints[bone_i]; + gltf_skin->joints_original.push_back(skeleton_bone_i); + gltf_skin->joints.push_back(skeleton_bone_i); + gltf_skin->inverse_binds.push_back(bind_pose); + if (skeleton->get_bone_parent(bone_i) == -1) { + gltf_skin->roots.push_back(skeleton_bone_i); + } + gltf_skin->joint_i_to_bone_i[bind_i] = bone_i; + gltf_skin->joint_i_to_name[bind_i] = bind_name; } + skin_gltf_i = state->skins.size(); + state->skins.push_back(gltf_skin); + state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key] = skin_gltf_i; } + node->skin = skin_gltf_i; + node->skeleton = skeleton_gltf_i; } - _expand_skin(state, gltf_skin); - node->skin = state->skins.size(); - state->skins.push_back(gltf_skin); - - json_skin["inverseBindMatrices"] = _encode_accessor_as_xform(state, gltf_skin->inverse_binds, false); - json_skin["joints"] = json_joints; - json_skin["name"] = gltf_skin->get_name(); - json_skins.push_back(json_skin); - state->json["skins"] = json_skins; } } @@ -6129,7 +6144,6 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref state for (int32_t key_i = 0; key_i < key_count; key_i++) { times.write[key_i] = p_animation->track_get_key_time(p_track_i, key_i); } - const float BAKE_FPS = 30.0f; if (track_type == Animation::TYPE_TRANSFORM3D) { p_track.position_track.times = times; p_track.position_track.interpolation = gltf_interpolation; @@ -6367,69 +6381,58 @@ void GLTFDocument::_convert_animation(Ref state, AnimationPlayer *ap, const Vector node_suffix = String(orig_track_path).split(":blend_shapes/"); const NodePath path = node_suffix[0]; const String suffix = node_suffix[1]; - const Node *node = ap->get_parent()->get_node_or_null(path); - for (Map::Element *transform_track_i = state->scene_nodes.front(); transform_track_i; transform_track_i = transform_track_i->next()) { - if (transform_track_i->get() == node) { - const MeshInstance3D *mi = Object::cast_to(node); - if (!mi) { - continue; - } - Ref array_mesh = mi->get_mesh(); - if (array_mesh.is_null()) { + Node *node = ap->get_parent()->get_node_or_null(path); + MeshInstance3D *mi = cast_to(node); + Ref mesh = mi->get_mesh(); + ERR_CONTINUE(mesh.is_null()); + int32_t mesh_index = -1; + for (Map::Element *mesh_track_i = state->scene_nodes.front(); mesh_track_i; mesh_track_i = mesh_track_i->next()) { + if (mesh_track_i->get() == node) { + mesh_index = mesh_track_i->key(); + } + } + ERR_CONTINUE(mesh_index == -1); + Map &tracks = gltf_animation->get_tracks(); + GLTFAnimation::Track track = gltf_animation->get_tracks().has(mesh_index) ? gltf_animation->get_tracks()[mesh_index] : GLTFAnimation::Track(); + if (!tracks.has(mesh_index)) { + for (int32_t shape_i = 0; shape_i < mesh->get_blend_shape_count(); shape_i++) { + String shape_name = mesh->get_blend_shape_name(shape_i); + NodePath shape_path = String(path) + ":blend_shapes/" + shape_name; + int32_t shape_track_i = animation->find_track(shape_path); + if (shape_track_i == -1) { + GLTFAnimation::Channel weight; + weight.interpolation = GLTFAnimation::INTERP_LINEAR; + weight.times.push_back(0.0f); + weight.times.push_back(0.0f); + weight.values.push_back(0.0f); + weight.values.push_back(0.0f); + track.weight_tracks.push_back(weight); continue; } - if (node_suffix.size() != 2) { - continue; + Animation::InterpolationType interpolation = animation->track_get_interpolation_type(track_i); + GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR; + if (interpolation == Animation::InterpolationType::INTERPOLATION_LINEAR) { + gltf_interpolation = GLTFAnimation::INTERP_LINEAR; + } else if (interpolation == Animation::InterpolationType::INTERPOLATION_NEAREST) { + gltf_interpolation = GLTFAnimation::INTERP_STEP; + } else if (interpolation == Animation::InterpolationType::INTERPOLATION_CUBIC) { + gltf_interpolation = GLTFAnimation::INTERP_CUBIC_SPLINE; } - GLTFNodeIndex mesh_index = -1; - for (GLTFNodeIndex node_i = 0; node_i < state->scene_nodes.size(); node_i++) { - if (state->scene_nodes[node_i] == node) { - mesh_index = node_i; - break; - } + int32_t key_count = animation->track_get_key_count(shape_track_i); + GLTFAnimation::Channel weight; + weight.interpolation = gltf_interpolation; + weight.times.resize(key_count); + for (int32_t time_i = 0; time_i < key_count; time_i++) { + weight.times.write[time_i] = animation->track_get_key_time(shape_track_i, time_i); } - ERR_CONTINUE(mesh_index == -1); - Ref mesh = mi->get_mesh(); - ERR_CONTINUE(mesh.is_null()); - for (int32_t shape_i = 0; shape_i < mesh->get_blend_shape_count(); shape_i++) { - if (mesh->get_blend_shape_name(shape_i) != suffix) { - continue; - } - GLTFAnimation::Track track; - Map::Element *blend_shape_track_i = gltf_animation->get_tracks().find(mesh_index); - if (blend_shape_track_i) { - track = blend_shape_track_i->get(); - } - Animation::InterpolationType interpolation = animation->track_get_interpolation_type(track_i); - - GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR; - if (interpolation == Animation::InterpolationType::INTERPOLATION_LINEAR) { - gltf_interpolation = GLTFAnimation::INTERP_LINEAR; - } else if (interpolation == Animation::InterpolationType::INTERPOLATION_NEAREST) { - gltf_interpolation = GLTFAnimation::INTERP_STEP; - } else if (interpolation == Animation::InterpolationType::INTERPOLATION_CUBIC) { - gltf_interpolation = GLTFAnimation::INTERP_CUBIC_SPLINE; - } - Animation::TrackType track_type = animation->track_get_type(track_i); - if (track_type == Animation::TYPE_VALUE) { - int32_t key_count = animation->track_get_key_count(track_i); - GLTFAnimation::Channel weight; - weight.interpolation = gltf_interpolation; - weight.times.resize(key_count); - for (int32_t time_i = 0; time_i < key_count; time_i++) { - weight.times.write[time_i] = animation->track_get_key_time(track_i, time_i); - } - weight.values.resize(key_count); - for (int32_t value_i = 0; value_i < key_count; value_i++) { - weight.values.write[value_i] = animation->track_get_key_value(track_i, value_i); - } - track.weight_tracks.push_back(weight); - } - gltf_animation->get_tracks()[mesh_index] = track; + weight.values.resize(key_count); + for (int32_t value_i = 0; value_i < key_count; value_i++) { + weight.values.write[value_i] = animation->track_get_key_value(shape_track_i, value_i); } + track.weight_tracks.push_back(weight); } + tracks[mesh_index] = track; } - } else if (String(orig_track_path).find(":") != -1) { //Process skeleton const Vector node_suffix = String(orig_track_path).split(":"); diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index fb798a055a..18aeb81bc0 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -51,6 +51,9 @@ class GLTFSkin; class GLTFNode; class GLTFSpecGloss; class GLTFSkeleton; +class CSGShape3D; +class GridMap; +class MultiMeshInstance3D; using GLTFAccessorIndex = int; using GLTFAnimationIndex = int; @@ -72,6 +75,9 @@ class GLTFDocument : public Resource { friend class GLTFSkin; friend class GLTFSkeleton; +private: + const float BAKE_FPS = 30.0f; + public: const int32_t JOINT_GROUP_SIZE = 4; enum GLTFType { @@ -350,7 +356,6 @@ private: GLTFNodeIndex p_node_i); Error _encode_buffer_bins(Ref state, const String &p_path); Error _encode_buffer_glb(Ref state, const String &p_path); - Error _serialize_bone_attachment(Ref state); Dictionary _serialize_texture_transform_uv1(Ref p_material); Dictionary _serialize_texture_transform_uv2(Ref p_material); Error _serialize_version(Ref state); @@ -381,20 +386,17 @@ public: void _generate_skeleton_bone_node(Ref state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index); void _import_animation(Ref state, AnimationPlayer *ap, const GLTFAnimationIndex index, const int bake_fps); - GLTFMeshIndex _convert_mesh_instance(Ref state, - MeshInstance3D *p_mesh_instance); void _convert_mesh_instances(Ref state); GLTFCameraIndex _convert_camera(Ref state, Camera3D *p_camera); - void _convert_light_to_gltf(Light3D *light, Ref state, Node3D *spatial, Ref gltf_node); + void _convert_light_to_gltf(Light3D *light, Ref state, Ref gltf_node); GLTFLightIndex _convert_light(Ref state, Light3D *p_light); - GLTFSkeletonIndex _convert_skeleton(Ref state, Skeleton3D *p_skeleton); void _convert_spatial(Ref state, Node3D *p_spatial, Ref p_node); - void _convert_scene_node(Ref state, Node *p_current, Node *p_root, + void _convert_scene_node(Ref state, Node *p_current, const GLTFNodeIndex p_gltf_current, const GLTFNodeIndex p_gltf_root); #ifdef MODULE_CSG_ENABLED - void _convert_csg_shape_to_gltf(Node *p_current, GLTFNodeIndex p_gltf_parent, Ref gltf_node, Ref state); + void _convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref gltf_node, Ref state); #endif // MODULE_CSG_ENABLED void _create_gltf_node(Ref state, @@ -405,40 +407,39 @@ public: Ref gltf_node); void _convert_animation_player_to_gltf( AnimationPlayer *animation_player, Ref state, - const GLTFNodeIndex &p_gltf_current, - const GLTFNodeIndex &p_gltf_root_index, - Ref p_gltf_node, Node *p_scene_parent, - Node *p_root); + GLTFNodeIndex p_gltf_current, + GLTFNodeIndex p_gltf_root_index, + Ref p_gltf_node, Node *p_scene_parent); void _check_visibility(Node *p_node, bool &retflag); void _convert_camera_to_gltf(Camera3D *camera, Ref state, - Node3D *spatial, Ref gltf_node); #ifdef MODULE_GRIDMAP_ENABLED void _convert_grid_map_to_gltf( - Node *p_scene_parent, - const GLTFNodeIndex &p_parent_node_index, - const GLTFNodeIndex &p_root_node_index, - Ref gltf_node, Ref state, - Node *p_root_node); + GridMap *p_grid_map, + GLTFNodeIndex p_parent_node_index, + GLTFNodeIndex p_root_node_index, + Ref gltf_node, Ref state); #endif // MODULE_GRIDMAP_ENABLED void _convert_mult_mesh_instance_to_gltf( - Node *p_scene_parent, - const GLTFNodeIndex &p_parent_node_index, - const GLTFNodeIndex &p_root_node_index, - Ref gltf_node, Ref state, - Node *p_root_node); + MultiMeshInstance3D *p_scene_parent, + GLTFNodeIndex p_parent_node_index, + GLTFNodeIndex p_root_node_index, + Ref gltf_node, Ref state); void _convert_skeleton_to_gltf( - Node *p_scene_parent, Ref state, - const GLTFNodeIndex &p_parent_node_index, - const GLTFNodeIndex &p_root_node_index, - Ref gltf_node, Node *p_root_node); - void _convert_bone_attachment_to_gltf(Node *p_scene_parent, + Skeleton3D *p_scene_parent, Ref state, + GLTFNodeIndex p_parent_node_index, + GLTFNodeIndex p_root_node_index, + Ref gltf_node); + void _convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment, + Ref state, + GLTFNodeIndex p_parent_node_index, + GLTFNodeIndex p_root_node_index, + Ref gltf_node); + void _convert_mesh_instance_to_gltf(MeshInstance3D *p_mesh_instance, Ref state, - Ref gltf_node, - bool &retflag); - void _convert_mesh_to_gltf(Node *p_scene_parent, - Ref state, Node3D *spatial, Ref gltf_node); + GLTFMeshIndex _convert_mesh_to_gltf(Ref state, + MeshInstance3D *p_mesh_instance); void _convert_animation(Ref state, AnimationPlayer *ap, String p_animation_track_name); Error serialize(Ref state, Node *p_root, const String &p_path); diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index 896ea5fc56..d6614da804 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -44,6 +44,8 @@ #include "gltf_texture.h" #include "core/io/resource.h" +#include "core/templates/map.h" +#include "core/templates/pair.h" #include "core/templates/vector.h" #include "scene/animation/animation_player.h" #include "scene/resources/texture.h" @@ -87,6 +89,9 @@ class GLTFState : public Resource { Vector> animations; Map scene_nodes; + Map skeleton3d_to_gltf_skeleton; + Map> skin_and_skeleton3d_to_gltf_skin; + protected: static void _bind_methods(); -- cgit v1.2.3