Merge pull request #53448 from lyuma/backport_gltf_skin_export
This commit is contained in:
commit
0a1cd0c316
3 changed files with 380 additions and 378 deletions
|
@ -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(":");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in a new issue