diff options
Diffstat (limited to 'modules/gltf/gltf_document.cpp')
-rw-r--r-- | modules/gltf/gltf_document.cpp | 311 |
1 files changed, 167 insertions, 144 deletions
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 4060f7f626..2acca5b856 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -405,6 +405,7 @@ static Vector<real_t> _xform_to_array(const Transform3D p_transform) { Error GLTFDocument::_serialize_nodes(Ref<GLTFState> p_state) { Array nodes; + const int scene_node_count = p_state->scene_nodes.size(); for (int i = 0; i < p_state->nodes.size(); i++) { Dictionary node; Ref<GLTFNode> gltf_node = p_state->nodes[i]; @@ -452,10 +453,13 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> p_state) { node["children"] = children; } + Node *scene_node = nullptr; + if (i < scene_node_count) { + scene_node = p_state->scene_nodes[i]; + } for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); - ERR_CONTINUE(!p_state->scene_nodes.find(i)); - Error err = ext->export_node(p_state, gltf_node, node, p_state->scene_nodes[i]); + Error err = ext->export_node(p_state, gltf_node, node, scene_node); ERR_CONTINUE(err != OK); } @@ -3218,7 +3222,7 @@ void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector< bool must_import = true; Vector<uint8_t> img_data = p_image->get_data(); Dictionary generator_parameters; - String file_path = p_state->get_base_path() + "/" + p_state->filename.get_basename() + "_" + p_image->get_name(); + String file_path = p_state->get_base_path().path_join(p_state->filename.get_basename() + "_" + p_image->get_name()); file_path += p_file_extension.is_empty() ? ".png" : p_file_extension; if (FileAccess::exists(file_path + ".import")) { Ref<ConfigFile> config; @@ -3230,6 +3234,8 @@ void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector< if (!generator_parameters.has("md5")) { must_import = false; // Didn't come from a gltf document; don't overwrite. } + } + if (must_import) { String existing_md5 = generator_parameters["md5"]; unsigned char md5_hash[16]; CryptoCore::md5(img_data.ptr(), img_data.size(), md5_hash); @@ -3658,141 +3664,143 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { mr["metallicFactor"] = base_material->get_metallic(); mr["roughnessFactor"] = base_material->get_roughness(); - bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); - bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); - bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); - if (has_ao || has_roughness || has_metalness) { - Dictionary mrt; - Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); - BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); - Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); - BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); - Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); - BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); - Ref<ImageTexture> orm_texture; - orm_texture.instantiate(); - Ref<Image> orm_image; - orm_image.instantiate(); - int32_t height = 0; - int32_t width = 0; - Ref<Image> ao_image; - if (has_ao) { - height = ao_texture->get_height(); - width = ao_texture->get_width(); - ao_image = ao_texture->get_image(); - Ref<ImageTexture> img_tex = ao_image; - if (img_tex.is_valid()) { - ao_image = img_tex->get_image(); - } - if (ao_image->is_compressed()) { - ao_image->decompress(); - } - } - Ref<Image> roughness_image; - if (has_roughness) { - height = roughness_texture->get_height(); - width = roughness_texture->get_width(); - roughness_image = roughness_texture->get_image(); - Ref<ImageTexture> img_tex = roughness_image; - if (img_tex.is_valid()) { - roughness_image = img_tex->get_image(); - } - if (roughness_image->is_compressed()) { - roughness_image->decompress(); - } - } - Ref<Image> metallness_image; - if (has_metalness) { - height = metallic_texture->get_height(); - width = metallic_texture->get_width(); - metallness_image = metallic_texture->get_image(); - Ref<ImageTexture> img_tex = metallness_image; - if (img_tex.is_valid()) { - metallness_image = img_tex->get_image(); - } - if (metallness_image->is_compressed()) { - metallness_image->decompress(); + if (_image_format != "None") { + bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); + bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); + bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); + if (has_ao || has_roughness || has_metalness) { + Dictionary mrt; + Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); + BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); + Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); + BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); + Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); + BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); + Ref<ImageTexture> orm_texture; + orm_texture.instantiate(); + Ref<Image> orm_image; + orm_image.instantiate(); + int32_t height = 0; + int32_t width = 0; + Ref<Image> ao_image; + if (has_ao) { + height = ao_texture->get_height(); + width = ao_texture->get_width(); + ao_image = ao_texture->get_image(); + Ref<ImageTexture> img_tex = ao_image; + if (img_tex.is_valid()) { + ao_image = img_tex->get_image(); + } + if (ao_image->is_compressed()) { + ao_image->decompress(); + } } - } - Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); - if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { - height = albedo_texture->get_height(); - width = albedo_texture->get_width(); - } - orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); - if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { - ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { - roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { - metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - for (int32_t h = 0; h < height; h++) { - for (int32_t w = 0; w < width; w++) { - Color c = Color(1.0f, 1.0f, 1.0f); - if (has_ao) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { - c.r = ao_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { - c.r = ao_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { - c.r = ao_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { - c.r = ao_image->get_pixel(w, h).a; - } + Ref<Image> roughness_image; + if (has_roughness) { + height = roughness_texture->get_height(); + width = roughness_texture->get_width(); + roughness_image = roughness_texture->get_image(); + Ref<ImageTexture> img_tex = roughness_image; + if (img_tex.is_valid()) { + roughness_image = img_tex->get_image(); } - if (has_roughness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).a; - } + if (roughness_image->is_compressed()) { + roughness_image->decompress(); + } + } + Ref<Image> metallness_image; + if (has_metalness) { + height = metallic_texture->get_height(); + width = metallic_texture->get_width(); + metallness_image = metallic_texture->get_image(); + Ref<ImageTexture> img_tex = metallness_image; + if (img_tex.is_valid()) { + metallness_image = img_tex->get_image(); + } + if (metallness_image->is_compressed()) { + metallness_image->decompress(); } - if (has_metalness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).a; + } + Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { + height = albedo_texture->get_height(); + width = albedo_texture->get_width(); + } + orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); + if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { + ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { + roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { + metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + for (int32_t h = 0; h < height; h++) { + for (int32_t w = 0; w < width; w++) { + Color c = Color(1.0f, 1.0f, 1.0f); + if (has_ao) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { + c.r = ao_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { + c.r = ao_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { + c.r = ao_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { + c.r = ao_image->get_pixel(w, h).a; + } + } + if (has_roughness) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).a; + } } + if (has_metalness) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).a; + } + } + orm_image->set_pixel(w, h, c); } - orm_image->set_pixel(w, h, c); } - } - orm_image->generate_mipmaps(); - orm_texture->set_image(orm_image); - GLTFTextureIndex orm_texture_index = -1; - if (has_ao || has_roughness || has_metalness) { - orm_texture->set_name(material->get_name() + "_orm"); - orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); - } - if (has_ao) { - Dictionary occt; - occt["index"] = orm_texture_index; - d["occlusionTexture"] = occt; - } - if (has_roughness || has_metalness) { - mrt["index"] = orm_texture_index; - Dictionary extensions = _serialize_texture_transform_uv1(material); - if (!extensions.is_empty()) { - mrt["extensions"] = extensions; - p_state->use_khr_texture_transform = true; + orm_image->generate_mipmaps(); + orm_texture->set_image(orm_image); + GLTFTextureIndex orm_texture_index = -1; + if (has_ao || has_roughness || has_metalness) { + orm_texture->set_name(material->get_name() + "_orm"); + orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + } + if (has_ao) { + Dictionary occt; + occt["index"] = orm_texture_index; + d["occlusionTexture"] = occt; + } + if (has_roughness || has_metalness) { + mrt["index"] = orm_texture_index; + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + mrt["extensions"] = extensions; + p_state->use_khr_texture_transform = true; + } + mr["metallicRoughnessTexture"] = mrt; } - mr["metallicRoughnessTexture"] = mrt; } } d["pbrMetallicRoughness"] = mr; - if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { + if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING) && _image_format != "None") { Dictionary nt; Ref<ImageTexture> tex; tex.instantiate(); @@ -3845,7 +3853,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { d["emissiveFactor"] = arr; } - if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { + if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION) && _image_format != "None") { Dictionary et; Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); GLTFTextureIndex gltf_texture_index = -1; @@ -5045,7 +5053,7 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> p_state) { AnimationPlayer *animation_player = p_state->animation_players[player_i]; List<StringName> animations; animation_player->get_animation_list(&animations); - for (StringName animation_name : animations) { + for (const StringName &animation_name : animations) { _convert_animation(p_state, animation_player, animation_name); } } @@ -6071,22 +6079,22 @@ struct SceneFormatImporterGLTFInterpolate { template <> struct SceneFormatImporterGLTFInterpolate<Quaternion> { Quaternion lerp(const Quaternion &a, const Quaternion &b, const float c) const { - ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quaternion(), "The quaternion \"a\" must be normalized."); - ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quaternion(), "The quaternion \"b\" must be normalized."); + ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quaternion(), vformat("The quaternion \"a\" %s must be normalized.", a)); + ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quaternion(), vformat("The quaternion \"b\" %s must be normalized.", b)); return a.slerp(b, c).normalized(); } Quaternion catmull_rom(const Quaternion &p0, const Quaternion &p1, const Quaternion &p2, const Quaternion &p3, const float c) { - ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quaternion(), "The quaternion \"p1\" must be normalized."); - ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quaternion(), "The quaternion \"p2\" must be normalized."); + ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quaternion(), vformat("The quaternion \"p1\" (%s) must be normalized.", p1)); + ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quaternion(), vformat("The quaternion \"p2\" (%s) must be normalized.", p2)); return p1.slerp(p2, c).normalized(); } Quaternion bezier(const Quaternion start, const Quaternion control_1, const Quaternion control_2, const Quaternion end, const float t) { - ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quaternion(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quaternion(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quaternion(), vformat("The start quaternion %s must be normalized.", start)); + ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quaternion(), vformat("The end quaternion %s must be normalized.", end)); return start.slerp(end, t).normalized(); } @@ -6151,9 +6159,9 @@ T GLTFDocument::_interpolate_track(const Vector<real_t> &p_times, const Vector<T const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); - const T from = p_values[idx * 3 + 1]; + const T &from = p_values[idx * 3 + 1]; const T c1 = from + p_values[idx * 3 + 2]; - const T to = p_values[idx * 3 + 4]; + const T &to = p_values[idx * 3 + 4]; const T c2 = to + p_values[idx * 3 + 3]; return interp.bezier(from, c1, c2, to, c); @@ -6284,6 +6292,9 @@ void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_ animation->add_track(Animation::TYPE_POSITION_3D); animation->track_set_path(position_idx, transform_node_path); animation->track_set_imported(position_idx, true); //helps merging later + if (track.position_track.interpolation == GLTFAnimation::INTERP_STEP) { + animation->track_set_interpolation_type(position_idx, Animation::InterpolationType::INTERPOLATION_NEAREST); + } base_idx++; } } @@ -6306,6 +6317,9 @@ void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_ animation->add_track(Animation::TYPE_ROTATION_3D); animation->track_set_path(rotation_idx, transform_node_path); animation->track_set_imported(rotation_idx, true); //helps merging later + if (track.rotation_track.interpolation == GLTFAnimation::INTERP_STEP) { + animation->track_set_interpolation_type(rotation_idx, Animation::InterpolationType::INTERPOLATION_NEAREST); + } base_idx++; } } @@ -6328,6 +6342,9 @@ void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_ animation->add_track(Animation::TYPE_SCALE_3D); animation->track_set_path(scale_idx, transform_node_path); animation->track_set_imported(scale_idx, true); //helps merging later + if (track.scale_track.interpolation == GLTFAnimation::INTERP_STEP) { + animation->track_set_interpolation_type(scale_idx, Animation::InterpolationType::INTERPOLATION_NEAREST); + } base_idx++; } } @@ -7052,9 +7069,9 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p } else if (String(final_track_path).contains(":")) { //Process skeleton const Vector<String> node_suffix = String(final_track_path).split(":"); - const String node = node_suffix[0]; + const String &node = node_suffix[0]; const NodePath node_path = node; - const String suffix = node_suffix[1]; + const String &suffix = node_suffix[1]; Node *godot_node = animation_base_node->get_node_or_null(node_path); if (!godot_node) { continue; @@ -7336,6 +7353,10 @@ void GLTFDocument::unregister_all_gltf_document_extensions() { all_document_extensions.clear(); } +Vector<Ref<GLTFDocumentExtension>> GLTFDocument::get_all_gltf_document_extensions() { + return all_document_extensions; +} + PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> p_state, Error *r_err) { Error err = _encode_buffer_glb(p_state, ""); if (r_err) { @@ -7454,11 +7475,13 @@ Node *GLTFDocument::generate_scene(Ref<GLTFState> p_state, float p_bake_fps, boo ERR_CONTINUE(!E.value); for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); - ERR_CONTINUE(!p_state->json.has("nodes")); - Array nodes = p_state->json["nodes"]; - ERR_CONTINUE(E.key >= nodes.size()); - ERR_CONTINUE(E.key < 0); - Dictionary node_json = nodes[E.key]; + Dictionary node_json; + if (p_state->json.has("nodes")) { + Array nodes = p_state->json["nodes"]; + if (0 <= E.key && E.key < nodes.size()) { + node_json = nodes[E.key]; + } + } Ref<GLTFNode> gltf_node = p_state->nodes[E.key]; err = ext->import_node(p_state, gltf_node, node_json, E.value); ERR_CONTINUE(err != OK); |