Merge pull request #53448 from lyuma/backport_gltf_skin_export

This commit is contained in:
Rémi Verschelde 2021-10-06 08:26:18 +02:00 committed by GitHub
commit 0a1cd0c316
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 380 additions and 378 deletions

View file

@ -82,7 +82,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>());
}
@ -101,11 +104,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) {
@ -255,30 +254,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++) {
BoneAttachment *bone_attachment = state->skeletons[skeleton_i]->bone_attachments[attachment_i];
String bone_name = bone_attachment->get_bone_name();
bone_name = _sanitize_bone_name(state, 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);
@ -2313,11 +2288,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->surface_get_primitive_type(surface_i);
switch (primitive_type) {
@ -2443,10 +2421,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);
@ -2518,7 +2496,6 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
Array array_morphs = import_mesh->surface_get_blend_shape_arrays(surface_i);
for (int morph_i = 0; morph_i < array_morphs.size(); morph_i++) {
Array array_morph = array_morphs[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->surface_get_arrays(surface_i);
@ -2535,22 +2512,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);
}
@ -2579,12 +2555,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;
@ -4294,6 +4271,7 @@ Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) {
Skeleton *skeleton = memnew(Skeleton);
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, "Skeleton"));
@ -4379,6 +4357,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;
}
@ -4757,30 +4745,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;
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];
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;
}
}
}
values.resize(times.size() * track.weight_tracks.size());
// TODO Sort by order in blend shapes
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;
}
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);
@ -4918,7 +4950,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
@ -4987,7 +5019,7 @@ BoneAttachment *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> state, Sk
return bone_attachment;
}
GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshInstance *p_mesh_instance) {
GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInstance *p_mesh_instance) {
ERR_FAIL_NULL_V(p_mesh_instance, -1);
if (p_mesh_instance->get_mesh().is_null()) {
return -1;
@ -4998,20 +5030,16 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshIns
if (godot_mesh.is_null()) {
return -1;
}
Vector<float> blend_weights;
Vector<String> blend_names;
int32_t blend_count = godot_mesh->get_blend_shape_count();
blend_names.resize(blend_count);
Vector<float> blend_weights;
blend_weights.resize(blend_count);
for (int32_t blend_i = 0; blend_i < godot_mesh->get_blend_shape_count(); blend_i++) {
String blend_name = godot_mesh->get_blend_shape_name(blend_i);
blend_names.write[blend_i] = blend_name;
import_mesh->add_blend_shape(blend_name);
}
Ref<ArrayMesh> am = godot_mesh;
if (am != nullptr) {
import_mesh = am;
} else {
for (int32_t surface_i = 0; surface_i < godot_mesh->get_surface_count(); surface_i++) {
Mesh::PrimitiveType primitive_type = godot_mesh->surface_get_primitive_type(surface_i);
Array arrays = godot_mesh->surface_get_arrays(surface_i);
Array blend_shape_arrays = godot_mesh->surface_get_blend_shape_arrays(surface_i);
Ref<Material> mat = godot_mesh->surface_get_material(surface_i);
Ref<ArrayMesh> godot_array_mesh = godot_mesh;
String surface_name;
@ -5025,9 +5053,10 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshIns
mat = p_mesh_instance->get_material_override();
}
int32_t mat_idx = import_mesh->get_surface_count();
import_mesh->add_surface_from_arrays(primitive_type, arrays, blend_shape_arrays);
import_mesh->add_surface_from_arrays(primitive_type, arrays);
import_mesh->surface_set_material(mat_idx, mat);
}
}
for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) {
blend_weights.write[blend_i] = 0.0f;
}
@ -5190,17 +5219,6 @@ GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light *p_light
return light_index;
}
GLTFSkeletonIndex GLTFDocument::_convert_skeleton(Ref<GLTFState> state, Skeleton *p_skeleton) {
print_verbose("glTF: Converting skeleton: " + p_skeleton->get_name());
Ref<GLTFSkeleton> gltf_skeleton;
gltf_skeleton.instance();
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, Spatial *p_spatial, Ref<GLTFNode> p_node) {
Transform xform = p_spatial->get_transform();
p_node->scale = xform.basis.get_scale();
@ -5216,7 +5234,7 @@ Spatial *GLTFDocument::_generate_spatial(Ref<GLTFState> state, Node *scene_paren
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) {
@ -5230,37 +5248,41 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, No
_convert_spatial(state, spatial, gltf_node);
}
if (cast_to<MeshInstance>(p_current)) {
Spatial *spatial = cast_to<Spatial>(p_current);
_convert_mesh_to_gltf(p_current, state, spatial, gltf_node);
MeshInstance *mi = cast_to<MeshInstance>(p_current);
_convert_mesh_instance_to_gltf(mi, state, gltf_node);
} else if (cast_to<BoneAttachment>(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.
BoneAttachment *bone = cast_to<BoneAttachment>(p_current);
_convert_bone_attachment_to_gltf(bone, state, p_gltf_parent, p_gltf_root, gltf_node);
return;
} else if (cast_to<Skeleton>(p_current)) {
_convert_skeleton_to_gltf(p_current, state, p_gltf_parent, p_gltf_root, gltf_node, p_root);
Skeleton *skel = cast_to<Skeleton>(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<MultiMeshInstance>(p_current)) {
_convert_mult_mesh_instance_to_gltf(p_current, p_gltf_parent, p_gltf_root, gltf_node, state, p_root);
MultiMeshInstance *multi = cast_to<MultiMeshInstance>(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<CSGShape>(p_current)) {
if (p_current->get_parent() && cast_to<CSGShape>(p_current)->is_root_shape()) {
_convert_csg_shape_to_gltf(p_current, p_gltf_parent, gltf_node, state);
CSGShape *shape = cast_to<CSGShape>(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<Camera>(p_current)) {
Camera *camera = Object::cast_to<Camera>(p_current);
_convert_camera_to_gltf(camera, state, camera, gltf_node);
_convert_camera_to_gltf(camera, state, gltf_node);
} else if (cast_to<Light>(p_current)) {
Light *light = Object::cast_to<Light>(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;
@ -5272,13 +5294,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) {
CSGShape *csg = Object::cast_to<CSGShape>(p_current);
void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
CSGShape *csg = p_current;
csg->call("_update_shape");
Array meshes = csg->get_meshes();
if (meshes.size() != 2) {
@ -5309,16 +5331,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());
@ -5337,7 +5358,7 @@ void GLTFDocument::_check_visibility(Node *p_node, bool &retflag) {
retflag = false;
}
void GLTFDocument::_convert_camera_to_gltf(Camera *camera, Ref<GLTFState> state, Spatial *spatial, Ref<GLTFNode> gltf_node) {
void GLTFDocument::_convert_camera_to_gltf(Camera *camera, Ref<GLTFState> state, Ref<GLTFNode> gltf_node) {
ERR_FAIL_COND(!camera);
GLTFCameraIndex camera_index = _convert_camera(state, camera);
if (camera_index != -1) {
@ -5345,7 +5366,7 @@ void GLTFDocument::_convert_camera_to_gltf(Camera *camera, Ref<GLTFState> state,
}
}
void GLTFDocument::_convert_light_to_gltf(Light *light, Ref<GLTFState> state, Spatial *spatial, Ref<GLTFNode> gltf_node) {
void GLTFDocument::_convert_light_to_gltf(Light *light, Ref<GLTFState> state, Ref<GLTFNode> gltf_node) {
ERR_FAIL_COND(!light);
GLTFLightIndex light_index = _convert_light(state, light);
if (light_index != -1) {
@ -5354,43 +5375,39 @@ void GLTFDocument::_convert_light_to_gltf(Light *light, Ref<GLTFState> state, Sp
}
#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));
MeshInstance *import_mesh_node = memnew(MeshInstance);
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));
Transform 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.instance();
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) {
MultiMeshInstance *multi_mesh_instance = Object::cast_to<MultiMeshInstance>(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(MultiMeshInstance *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++) {
@ -5406,9 +5423,9 @@ void GLTFDocument::_convert_mult_mesh_instance_to_gltf(Node *p_scene_parent, con
transform.basis.set_quat_scale(quat,
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();
@ -5427,57 +5444,96 @@ 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) {
Skeleton *skeleton = Object::cast_to<Skeleton>(p_scene_parent);
if (skeleton) {
void GLTFDocument::_convert_skeleton_to_gltf(Skeleton *p_skeleton3d, Ref<GLTFState> state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node) {
Skeleton *skeleton = p_skeleton3d;
Ref<GLTFSkeleton> gltf_skeleton;
gltf_skeleton.instance();
// 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.instance();
// 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)));
Transform 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_quat();
joint_node->translation = 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_root_node, p_parent_node_index, p_root_node_index);
}
_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;
BoneAttachment *bone_attachment = Object::cast_to<BoneAttachment>(p_scene_parent);
if (bone_attachment) {
Node *node = bone_attachment->get_parent();
while (node) {
Skeleton *bone_attachment_skeleton = Object::cast_to<Skeleton>(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;
void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment *p_bone_attachment, Ref<GLTFState> state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node) {
Skeleton *skeleton;
// Note that relative transforms to external skeletons and pose overrides are not supported.
skeleton = cast_to<Skeleton>(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()];
}
state->skeletons.write[skeleton_i]->bone_attachments.push_back(bone_attachment);
break;
int bone_idx = -1;
if (skeleton != nullptr) {
bone_idx = skeleton->find_bone(p_bone_attachment->get_bone_name());
}
break;
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];
}
node = node->get_parent();
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);
}
gltf_node.unref();
return;
}
retflag = false;
}
void GLTFDocument::_convert_mesh_to_gltf(Node *p_scene_parent, Ref<GLTFState> state, Spatial *spatial, Ref<GLTFNode> gltf_node) {
MeshInstance *mi = Object::cast_to<MeshInstance>(p_scene_parent);
if (mi) {
GLTFMeshIndex gltf_mesh_index = _convert_mesh_instance(state, mi);
void GLTFDocument::_convert_mesh_instance_to_gltf(MeshInstance *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;
}
}
}
void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent, Spatial *scene_root, const GLTFNodeIndex node_index) {
@ -5933,10 +5989,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;
@ -5948,7 +6000,6 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
node->rotation = mi_xform.basis.get_rotation_quat();
node->translation = mi_xform.origin;
Dictionary json_skin;
Skeleton *skeleton = Object::cast_to<Skeleton>(mi->get_node(mi->get_skeleton_path()));
if (!skeleton) {
continue;
@ -5957,121 +6008,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.instance();
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;
Node *skel_node = mi->get_node_or_null(skeleton_path);
Skeleton *godot_skeleton = nullptr;
if (skel_node != nullptr) {
godot_skeleton = cast_to<Skeleton>(skel_node);
}
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.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.instance();
String gltf_bone_name = _gen_unique_bone_name(state, skeleton_gltf_i, godot_bone_name);
joint_node->set_name(gltf_bone_name);
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());
Transform 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_quat();
joint_node->translation = 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();
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.empty()) {
root_gltf_i = gltf_skeleton->roots[0];
}
}
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);
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.instance();
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);
Transform 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);
}
_expand_skin(state, gltf_skin);
node->skin = state->skins.size();
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);
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;
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;
}
}
}
@ -6154,7 +6159,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_TRANSFORM) {
p_track.translation_track.times = times;
p_track.translation_track.interpolation = gltf_interpolation;
@ -6396,41 +6400,35 @@ 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 MeshInstance *mi = Object::cast_to<MeshInstance>(node);
if (!mi) {
continue;
}
Ref<ArrayMesh> array_mesh = mi->get_mesh();
if (array_mesh.is_null()) {
continue;
}
if (node_suffix.size() != 2) {
continue;
}
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;
Node *node = ap->get_parent()->get_node_or_null(path);
MeshInstance *mi = cast_to<MeshInstance>(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);
Ref<Mesh> mesh = mi->get_mesh();
ERR_CONTINUE(mesh.is_null());
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++) {
if (mesh->get_blend_shape_name(shape_i) != suffix) {
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;
}
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;
@ -6439,26 +6437,21 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
} 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);
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(track_i, time_i);
weight.times.write[time_i] = animation->track_get_key_time(shape_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);
weight.values.write[value_i] = animation->track_get_key_value(shape_track_i, value_i);
}
track.weight_tracks.push_back(weight);
}
gltf_animation->get_tracks()[mesh_index] = track;
tracks[mesh_index] = track;
}
}
}
} else if (String(orig_track_path).find(":") != -1) {
//Process skeleton
const Vector<String> node_suffix = String(orig_track_path).split(":");

View file

@ -48,6 +48,9 @@ class GLTFSkin;
class GLTFNode;
class GLTFSpecGloss;
class GLTFSkeleton;
class CSGShape;
class GridMap;
class MultiMeshInstance;
using GLTFAccessorIndex = int;
using GLTFAnimationIndex = int;
@ -69,6 +72,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 {
@ -336,7 +342,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<SpatialMaterial> p_material);
Dictionary _serialize_texture_transform_uv2(Ref<SpatialMaterial> p_material);
Error _serialize_version(Ref<GLTFState> state);
@ -370,20 +375,17 @@ public:
void _generate_skeleton_bone_node(Ref<GLTFState> state, Node *scene_parent, Spatial *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,
MeshInstance *p_mesh_instance);
void _convert_mesh_instances(Ref<GLTFState> state);
GLTFCameraIndex _convert_camera(Ref<GLTFState> state, Camera *p_camera);
void _convert_light_to_gltf(Light *light, Ref<GLTFState> state, Spatial *spatial, Ref<GLTFNode> gltf_node);
void _convert_light_to_gltf(Light *light, Ref<GLTFState> state, Ref<GLTFNode> gltf_node);
GLTFLightIndex _convert_light(Ref<GLTFState> state, Light *p_light);
GLTFSkeletonIndex _convert_skeleton(Ref<GLTFState> state, Skeleton *p_skeleton);
void _convert_spatial(Ref<GLTFState> state, Spatial *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(CSGShape *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state);
#endif // MODULE_CSG_ENABLED
void _create_gltf_node(Ref<GLTFState> state,
@ -394,40 +396,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(Camera *camera, Ref<GLTFState> state,
Spatial *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);
MultiMeshInstance *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,
Ref<GLTFState> state,
Ref<GLTFNode> gltf_node,
bool &retflag);
void _convert_mesh_to_gltf(Node *p_scene_parent,
Ref<GLTFState> state, Spatial *spatial,
Skeleton *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(BoneAttachment *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(MeshInstance *p_mesh_instance,
Ref<GLTFState> state,
Ref<GLTFNode> gltf_node);
GLTFMeshIndex _convert_mesh_to_gltf(Ref<GLTFState> state,
MeshInstance *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);

View file

@ -45,6 +45,11 @@
#include "gltf_skeleton.h"
#include "gltf_skin.h"
#include "gltf_texture.h"
#include "core/map.h"
#include "core/pair.h"
#include "core/resource.h"
#include "core/vector.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/texture.h"
@ -89,6 +94,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();