diff options
-rw-r--r-- | modules/gltf/gltf_document.cpp | 631 | ||||
-rw-r--r-- | modules/gltf/gltf_document.h | 63 | ||||
-rw-r--r-- | modules/gltf/gltf_state.h | 5 |
3 files changed, 354 insertions, 345 deletions
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<GLTFState> 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<uint8_t>()); } @@ -97,11 +100,7 @@ Error GLTFDocument::serialize(Ref<GLTFState> 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<GLTFState> state) { return OK; } -Error GLTFDocument::_serialize_bone_attachment(Ref<GLTFState> 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<GLTFState> state) { Error err; FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); @@ -2131,11 +2106,14 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> 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<GLTFState> state) { const Array &a = array[Mesh::ARRAY_WEIGHTS]; const Vector<Vector3> &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<Color> 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<GLTFState> 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<Vector3> 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<GLTFState> state) { } Vector<Vector3> narr = array_morph[Mesh::ARRAY_NORMAL]; - if (varr.size()) { + if (narr.size()) { t["NORMAL"] = _encode_accessor_as_vec3(state, narr, true); } Vector<real_t> tarr = array_morph[Mesh::ARRAY_TANGENT]; if (tarr.size()) { const int ret_size = tarr.size() / 4; - Vector<Color> attribs; + Vector<Vector3> 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<GLTFState> 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<GLTFState> 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<GLTFSt Error GLTFDocument::_serialize_skins(Ref<GLTFState> state) { _remove_duplicate_skins(state); + Array json_skins; + for (int skin_i = 0; skin_i < state->skins.size(); skin_i++) { + Ref<GLTFSkin> 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<GLTFState> 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<real_t> times; - Vector<real_t> 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<real_t> weight_track; + while (true) { + float weight = _interpolate_track<float>(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<real_t> all_track_times = times; + Vector<real_t> 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<float> 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<GLTFState> 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<GLTFState> state, return bone_attachment; } -GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshInstance3D *p_mesh_instance) { +GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> 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<GLTFState> state, Light3D *p_lig return light_index; } -GLTFSkeletonIndex GLTFDocument::_convert_skeleton(Ref<GLTFState> state, Skeleton3D *p_skeleton) { - print_verbose("glTF: Converting skeleton: " + p_skeleton->get_name()); - Ref<GLTFSkeleton> 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<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node) { Transform3D xform = p_spatial->get_transform(); p_node->scale = xform.basis.get_scale(); @@ -5193,7 +5214,7 @@ Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, Node *scene_parent return spatial; } -void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, Node *p_root, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) { +void GLTFDocument::_convert_scene_node(Ref<GLTFState> 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<GLTFState> state, Node *p_current, No _convert_spatial(state, spatial, gltf_node); } if (cast_to<MeshInstance3D>(p_current)) { - Node3D *spatial = cast_to<Node3D>(p_current); - _convert_mesh_to_gltf(p_current, state, spatial, gltf_node); + MeshInstance3D *mi = cast_to<MeshInstance3D>(p_current); + _convert_mesh_instance_to_gltf(mi, state, gltf_node); } else if (cast_to<BoneAttachment3D>(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<BoneAttachment3D>(p_current); + _convert_bone_attachment_to_gltf(bone, state, p_gltf_parent, p_gltf_root, gltf_node); return; } else if (cast_to<Skeleton3D>(p_current)) { - _convert_skeleton_to_gltf(p_current, state, p_gltf_parent, p_gltf_root, gltf_node, p_root); + Skeleton3D *skel = cast_to<Skeleton3D>(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<MultiMeshInstance3D>(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<MultiMeshInstance3D>(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<CSGShape3D>(p_current)) { - if (p_current->get_parent() && cast_to<CSGShape3D>(p_current)->is_root_shape()) { - _convert_csg_shape_to_gltf(p_current, p_gltf_parent, gltf_node, state); + CSGShape3D *shape = cast_to<CSGShape3D>(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<GridMap>(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<GridMap>(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<Camera3D>(p_current)) { Camera3D *camera = Object::cast_to<Camera3D>(p_current); - _convert_camera_to_gltf(camera, state, camera, gltf_node); + _convert_camera_to_gltf(camera, state, gltf_node); } else if (cast_to<Light3D>(p_current)) { Light3D *light = Object::cast_to<Light3D>(p_current); - _convert_light_to_gltf(light, state, light, gltf_node); + _convert_light_to_gltf(light, state, gltf_node); } else if (cast_to<AnimationPlayer>(p_current)) { AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(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<GLTFState> 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<GLTFNode> gltf_node, Ref<GLTFState> state) { - CSGShape3D *csg = Object::cast_to<CSGShape3D>(p_current); +void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> 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<GLTFState> state, Node *p_scene_parent, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_gltf_node, Ref<GLTFNode> 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<GLTFState> state, const GLTFNodeIndex &p_gltf_current, const GLTFNodeIndex &p_gltf_root_index, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent, Node *p_root) { +void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *animation_player, Ref<GLTFState> state, GLTFNodeIndex p_gltf_current, GLTFNodeIndex p_gltf_root_index, Ref<GLTFNode> 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<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node) { +void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> state, Ref<GLTFNode> 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<GLTFState> stat } } -void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node) { +void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Ref<GLTFNode> 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<GLTFState> 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<GLTFNode> gltf_node, Ref<GLTFState> state, Node *p_root_node) { - GridMap *grid_map = Object::cast_to<GridMap>(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<GLTFNode> gltf_node, Ref<GLTFState> 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<GLTFMesh> 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<GLTFNode> gltf_node, Ref<GLTFState> state, Node *p_root_node) { - MultiMeshInstance3D *multi_mesh_instance = Object::cast_to<MultiMeshInstance3D>(p_scene_parent); - ERR_FAIL_COND(!multi_mesh_instance); - Ref<MultiMesh> 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<GLTFNode> gltf_node, Ref<GLTFState> state) { + Ref<MultiMesh> 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<ArrayMesh> 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<GLTFState> state, const GLTFNodeIndex &p_parent_node_index, const GLTFNodeIndex &p_root_node_index, Ref<GLTFNode> gltf_node, Node *p_root_node) { - Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(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<GLTFState> state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node) { + Skeleton3D *skeleton = p_skeleton3d; + Ref<GLTFSkeleton> 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<GLTFNode> 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<GLTFState> state, Ref<GLTFNode> gltf_node, bool &retflag) { - retflag = true; - BoneAttachment3D *bone_attachment = Object::cast_to<BoneAttachment3D>(p_scene_parent); - if (bone_attachment) { - Node *node = bone_attachment->get_parent(); - while (node) { - Skeleton3D *bone_attachment_skeleton = Object::cast_to<Skeleton3D>(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<GLTFState> state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> 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<Skeleton3D>(p_bone_attachment->get_node_or_null(p_bone_attachment->get_external_skeleton())); + } else { + skeleton = cast_to<Skeleton3D>(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<GLTFSkeleton> 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<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node) { - MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(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<GLTFState> state, Ref<GLTFNode> 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<GLTFState> state) { if (node->mesh < 0) { continue; } - Array json_skins; - if (state->json.has("skins")) { - json_skins = state->json["skins"]; - } Map<GLTFNodeIndex, Node *>::Element *mi_element = state->scene_nodes.find(mi_node_i); if (!mi_element) { continue; @@ -5923,7 +5985,6 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { node->rotation = mi_xform.basis.get_rotation_quaternion(); node->position = mi_xform.origin; - Dictionary json_skin; Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(mi->get_node(mi->get_skeleton_path())); if (!skeleton) { continue; @@ -5932,121 +5993,75 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { continue; } Ref<Skin> skin = mi->get_skin(); - if (skin.is_null()) { - skin = skeleton->register_skin(nullptr)->get_skin(); - } Ref<GLTFSkin> 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<GLTFSkin> 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<GLTFSkeleton> 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<GLTFNode> 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<GLTFNodeIndex, Node *>::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<GLTFNode> 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<Skeleton3D>(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<GLTFSkeleton> 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<GLTFNodeIndex, Node *>::Element *E = state->scene_nodes.front(); E; E = E->next()) { - if (E->get() == node_parent) { - GLTFNodeIndex gltf_node_i = E->key(); - Ref<GLTFNode> 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<StringName, int> 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<GLTFState> 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<GLTFState> state, AnimationPlayer *ap, const Vector<String> 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<GLTFNodeIndex, Node *>::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<MeshInstance3D>(node); - if (!mi) { - continue; - } - Ref<ArrayMesh> array_mesh = mi->get_mesh(); - if (array_mesh.is_null()) { + Node *node = ap->get_parent()->get_node_or_null(path); + MeshInstance3D *mi = cast_to<MeshInstance3D>(node); + Ref<Mesh> mesh = mi->get_mesh(); + ERR_CONTINUE(mesh.is_null()); + int32_t mesh_index = -1; + for (Map<GLTFNodeIndex, Node *>::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<int, GLTFAnimation::Track> &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<float> 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<float> 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> 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<int, GLTFAnimation::Track>::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<float> 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<String> 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<GLTFState> state, const String &p_path); Error _encode_buffer_glb(Ref<GLTFState> state, const String &p_path); - Error _serialize_bone_attachment(Ref<GLTFState> state); Dictionary _serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material); Dictionary _serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material); Error _serialize_version(Ref<GLTFState> state); @@ -381,20 +386,17 @@ public: void _generate_skeleton_bone_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index); void _import_animation(Ref<GLTFState> state, AnimationPlayer *ap, const GLTFAnimationIndex index, const int bake_fps); - GLTFMeshIndex _convert_mesh_instance(Ref<GLTFState> state, - MeshInstance3D *p_mesh_instance); void _convert_mesh_instances(Ref<GLTFState> state); GLTFCameraIndex _convert_camera(Ref<GLTFState> state, Camera3D *p_camera); - void _convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node); + void _convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Ref<GLTFNode> gltf_node); GLTFLightIndex _convert_light(Ref<GLTFState> state, Light3D *p_light); - GLTFSkeletonIndex _convert_skeleton(Ref<GLTFState> state, Skeleton3D *p_skeleton); void _convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node); - void _convert_scene_node(Ref<GLTFState> state, Node *p_current, Node *p_root, + void _convert_scene_node(Ref<GLTFState> 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<GLTFNode> gltf_node, Ref<GLTFState> state); + void _convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state); #endif // MODULE_CSG_ENABLED void _create_gltf_node(Ref<GLTFState> state, @@ -405,40 +407,39 @@ public: Ref<GLTFNode> gltf_node); void _convert_animation_player_to_gltf( AnimationPlayer *animation_player, Ref<GLTFState> state, - const GLTFNodeIndex &p_gltf_current, - const GLTFNodeIndex &p_gltf_root_index, - Ref<GLTFNode> p_gltf_node, Node *p_scene_parent, - Node *p_root); + GLTFNodeIndex p_gltf_current, + GLTFNodeIndex p_gltf_root_index, + Ref<GLTFNode> p_gltf_node, Node *p_scene_parent); void _check_visibility(Node *p_node, bool &retflag); void _convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> state, - Node3D *spatial, Ref<GLTFNode> 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<GLTFNode> gltf_node, Ref<GLTFState> state, - Node *p_root_node); + GridMap *p_grid_map, + GLTFNodeIndex p_parent_node_index, + GLTFNodeIndex p_root_node_index, + Ref<GLTFNode> gltf_node, Ref<GLTFState> 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<GLTFNode> gltf_node, Ref<GLTFState> state, - Node *p_root_node); + MultiMeshInstance3D *p_scene_parent, + GLTFNodeIndex p_parent_node_index, + GLTFNodeIndex p_root_node_index, + Ref<GLTFNode> gltf_node, Ref<GLTFState> state); void _convert_skeleton_to_gltf( - Node *p_scene_parent, Ref<GLTFState> state, - const GLTFNodeIndex &p_parent_node_index, - const GLTFNodeIndex &p_root_node_index, - Ref<GLTFNode> gltf_node, Node *p_root_node); - void _convert_bone_attachment_to_gltf(Node *p_scene_parent, + Skeleton3D *p_scene_parent, Ref<GLTFState> state, + GLTFNodeIndex p_parent_node_index, + GLTFNodeIndex p_root_node_index, + Ref<GLTFNode> gltf_node); + void _convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment, + Ref<GLTFState> state, + GLTFNodeIndex p_parent_node_index, + GLTFNodeIndex p_root_node_index, + Ref<GLTFNode> gltf_node); + void _convert_mesh_instance_to_gltf(MeshInstance3D *p_mesh_instance, Ref<GLTFState> state, - Ref<GLTFNode> gltf_node, - bool &retflag); - void _convert_mesh_to_gltf(Node *p_scene_parent, - Ref<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node); + GLTFMeshIndex _convert_mesh_to_gltf(Ref<GLTFState> state, + MeshInstance3D *p_mesh_instance); void _convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, String p_animation_track_name); Error serialize(Ref<GLTFState> 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<Ref<GLTFAnimation>> animations; Map<GLTFNodeIndex, Node *> scene_nodes; + Map<ObjectID, GLTFSkeletonIndex> skeleton3d_to_gltf_skeleton; + Map<ObjectID, Map<ObjectID, GLTFSkinIndex>> skin_and_skeleton3d_to_gltf_skin; + protected: static void _bind_methods(); |