diff options
Diffstat (limited to 'modules/fbx/data')
-rw-r--r-- | modules/fbx/data/fbx_anim_container.h | 46 | ||||
-rw-r--r-- | modules/fbx/data/fbx_bone.cpp | 56 | ||||
-rw-r--r-- | modules/fbx/data/fbx_bone.h | 90 | ||||
-rw-r--r-- | modules/fbx/data/fbx_material.cpp | 468 | ||||
-rw-r--r-- | modules/fbx/data/fbx_material.h | 285 | ||||
-rw-r--r-- | modules/fbx/data/fbx_mesh_data.cpp | 1446 | ||||
-rw-r--r-- | modules/fbx/data/fbx_mesh_data.h | 200 | ||||
-rw-r--r-- | modules/fbx/data/fbx_node.h | 63 | ||||
-rw-r--r-- | modules/fbx/data/fbx_skeleton.cpp | 130 | ||||
-rw-r--r-- | modules/fbx/data/fbx_skeleton.h | 53 | ||||
-rw-r--r-- | modules/fbx/data/import_state.h | 112 | ||||
-rw-r--r-- | modules/fbx/data/model_abstraction.h | 52 | ||||
-rw-r--r-- | modules/fbx/data/pivot_transform.cpp | 307 | ||||
-rw-r--r-- | modules/fbx/data/pivot_transform.h | 115 |
14 files changed, 0 insertions, 3423 deletions
diff --git a/modules/fbx/data/fbx_anim_container.h b/modules/fbx/data/fbx_anim_container.h deleted file mode 100644 index 6559add858..0000000000 --- a/modules/fbx/data/fbx_anim_container.h +++ /dev/null @@ -1,46 +0,0 @@ -/*************************************************************************/ -/* fbx_anim_container.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef FBX_ANIM_CONTAINER_H -#define FBX_ANIM_CONTAINER_H - -#include "core/math/vector3.h" - -// Generic keyframes 99.99 percent of files will be vector3, except if quat interp is used, or visibility tracks -// FBXTrack is used in a map in the implementation in fbx/editor_scene_importer_fbx.cpp -// to avoid having to rewrite the entire logic I refactored this into the code instead. -// once it works I can rewrite so we can add the fun misc features / small features -struct FBXTrack { - bool has_default = false; - Vector3 default_value; - std::map<int64_t, Vector3> keyframes; -}; - -#endif //MODEL_ABSTRACTION_ANIM_CONTAINER_H diff --git a/modules/fbx/data/fbx_bone.cpp b/modules/fbx/data/fbx_bone.cpp deleted file mode 100644 index 72aba20fd4..0000000000 --- a/modules/fbx/data/fbx_bone.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/*************************************************************************/ -/* fbx_bone.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "fbx_bone.h" - -#include "fbx_node.h" -#include "import_state.h" - -Ref<FBXNode> FBXSkinDeformer::get_link(const ImportState &state) const { - print_verbose("bone name: " + bone->bone_name); - - // safe for when deformers must be polyfilled when skin has different count of binds to bones in the scene ;) - if (!cluster) { - return nullptr; - } - - ERR_FAIL_COND_V_MSG(cluster->TargetNode() == nullptr, nullptr, "bone has invalid target node"); - - Ref<FBXNode> link_node; - uint64_t id = cluster->TargetNode()->ID(); - if (state.fbx_target_map.has(id)) { - link_node = state.fbx_target_map[id]; - } else { - print_error("link node not found for " + itos(id)); - } - - // the node in space this is for, like if it's FOR a target. - return link_node; -} diff --git a/modules/fbx/data/fbx_bone.h b/modules/fbx/data/fbx_bone.h deleted file mode 100644 index 6c8f7f7cae..0000000000 --- a/modules/fbx/data/fbx_bone.h +++ /dev/null @@ -1,90 +0,0 @@ -/*************************************************************************/ -/* fbx_bone.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef FBX_BONE_H -#define FBX_BONE_H - -#include "fbx_node.h" -#include "import_state.h" - -#include "fbx_parser/FBXDocument.h" - -struct PivotTransform; - -struct FBXBone : public RefCounted { - uint64_t parent_bone_id = 0; - uint64_t bone_id = 0; - - bool valid_parent = false; // if the parent bone id is set up. - String bone_name = String(); // bone name - - bool is_root_bone() const { - return !valid_parent; - } - - // Godot specific data - int godot_bone_id = -2; // godot internal bone id assigned after import - - // if a bone / armature is the root then FBX skeleton will contain the bone not any other skeleton. - // this is to support joints by themselves in scenes - bool valid_armature_id = false; - uint64_t armature_id = 0; - - /* link node is the parent bone */ - mutable const FBXDocParser::Geometry *geometry = nullptr; - mutable const FBXDocParser::ModelLimbNode *limb_node = nullptr; - - void set_node(Ref<FBXNode> p_node) { - node = p_node; - } - - // Stores the pivot xform for this bone - - Ref<FBXNode> node = nullptr; - Ref<FBXBone> parent_bone = nullptr; - Ref<FBXSkeleton> fbx_skeleton = nullptr; -}; - -struct FBXSkinDeformer { - FBXSkinDeformer(Ref<FBXBone> p_bone, const FBXDocParser::Cluster *p_cluster) : - cluster(p_cluster), bone(p_bone) {} - ~FBXSkinDeformer() {} - const FBXDocParser::Cluster *cluster; - Ref<FBXBone> bone; - - /* get associate model - the model can be invalid sometimes */ - Ref<FBXBone> get_associate_model() const { - return bone->parent_bone; - } - - Ref<FBXNode> get_link(const ImportState &state) const; -}; - -#endif // FBX_BONE_H diff --git a/modules/fbx/data/fbx_material.cpp b/modules/fbx/data/fbx_material.cpp deleted file mode 100644 index 36e20df3a9..0000000000 --- a/modules/fbx/data/fbx_material.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/*************************************************************************/ -/* fbx_material.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "fbx_material.h" - -// FIXME: Shouldn't depend on core_bind.h! Use DirAccessRef like the rest of -// the engine instead of core_bind::Directory. -#include "core/core_bind.h" -#include "scene/resources/material.h" -#include "scene/resources/texture.h" -#include "tools/validation_tools.h" - -String FBXMaterial::get_material_name() const { - return material_name; -} - -void FBXMaterial::set_imported_material(FBXDocParser::Material *p_material) { - material = p_material; -} - -void FBXMaterial::add_search_string(String p_filename, String p_current_directory, String search_directory, Vector<String> &texture_search_paths) { - if (search_directory.is_empty()) { - texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file(p_filename)); - } else { - texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file(search_directory + "/" + p_filename)); - texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file("../" + search_directory + "/" + p_filename)); - } -} - -String find_file(const String &p_base, const String &p_file_to_find) { - core_bind::Directory dir; - dir.open(p_base); - - dir.list_dir_begin(); - String n = dir.get_next(); - while (!n.is_empty()) { - if (n == "." || n == "..") { - n = dir.get_next(); - continue; - } - if (dir.current_is_dir()) { - // Don't use `path_to` or the returned path will be wrong. - const String f = find_file(p_base + "/" + n, p_file_to_find); - if (!f.is_empty()) { - return f; - } - } else if (n == p_file_to_find) { - return p_base + "/" + n; - } - n = dir.get_next(); - } - dir.list_dir_end(); - - return String(); -} - -// fbx will not give us good path information and let's not regex them to fix them -// no relative paths are in fbx generally they have a rel field but it's populated incorrectly by the SDK. -String FBXMaterial::find_texture_path_by_filename(const String p_filename, const String p_current_directory) { - core_bind::Directory dir; - Vector<String> paths; - add_search_string(p_filename, p_current_directory, "", paths); - add_search_string(p_filename, p_current_directory, "texture", paths); - add_search_string(p_filename, p_current_directory, "textures", paths); - add_search_string(p_filename, p_current_directory, "Textures", paths); - add_search_string(p_filename, p_current_directory, "materials", paths); - add_search_string(p_filename, p_current_directory, "mats", paths); - add_search_string(p_filename, p_current_directory, "pictures", paths); - add_search_string(p_filename, p_current_directory, "images", paths); - - for (int i = 0; i < paths.size(); i++) { - if (dir.file_exists(paths[i])) { - return paths[i]; - } - } - - // We were not able to find the texture in the common locations, - // try to find it into the project globally. - // The common textures can be stored into one of those folders: - // res://asset - // res://texture - // res://material - // res://mat - // res://image - // res://picture - // - // Note the folders can also be called with custom names, like: - // res://my_assets - // since the keyword `asset` is into the directory name the textures will be - // searched there too. - - dir.open("res://"); - dir.list_dir_begin(); - String n = dir.get_next(); - while (!n.is_empty()) { - if (n == "." || n == "..") { - n = dir.get_next(); - continue; - } - if (dir.current_is_dir()) { - const String lower_n = n.to_lower(); - if ( - // Don't need to use plural. - lower_n.find("asset") >= 0 || - lower_n.find("texture") >= 0 || - lower_n.find("material") >= 0 || - lower_n.find("mat") >= 0 || - lower_n.find("image") >= 0 || - lower_n.find("picture") >= 0) { - // Don't use `path_to` or the returned path will be wrong. - const String f = find_file(String("res://") + n, p_filename); - if (!f.is_empty()) { - return f; - } - } - } - n = dir.get_next(); - } - dir.list_dir_end(); - - return ""; -} - -template <class T> -T extract_from_prop(FBXDocParser::PropertyPtr prop, const T &p_default, const std::string &p_name, const String &p_type) { - ERR_FAIL_COND_V_MSG(prop == nullptr, p_default, "invalid property passed to extractor"); - const FBXDocParser::TypedProperty<T> *val = dynamic_cast<const FBXDocParser::TypedProperty<T> *>(prop); - - ERR_FAIL_COND_V_MSG(val == nullptr, p_default, "The FBX is corrupted, the property `" + String(p_name.c_str()) + "` is a `" + String(typeid(*prop).name()) + "` but should be a " + p_type); - // Make sure to not lost any eventual opacity. - return val->Value(); -} - -Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { - ERR_FAIL_COND_V(material == nullptr, nullptr); - - const String p_fbx_current_directory = state.path; - - Ref<StandardMaterial3D> spatial_material; - spatial_material.instantiate(); - - // read the material file - // is material two sided - // read material name - print_verbose("[material] material name: " + ImportUtils::FBXNodeToName(material->Name())); - - material_name = ImportUtils::FBXNodeToName(material->Name()); - - for (const std::pair<std::string, const FBXDocParser::Texture *> iter : material->Textures()) { - const uint64_t texture_id = iter.second->ID(); - const std::string &fbx_mapping_name = iter.first; - const FBXDocParser::Texture *fbx_texture_data = iter.second; - const String absolute_texture_path = iter.second->FileName().c_str(); - const String texture_name = absolute_texture_path.get_file(); - const String file_extension = absolute_texture_path.get_extension().to_upper(); - - const String debug_string = "texture id: " + itos(texture_id) + " texture name: " + String(iter.second->Name().c_str()) + " mapping name: " + String(fbx_mapping_name.c_str()); - // remember errors STILL need this string at the end for when you aren't in verbose debug mode :) they need context for when you're not verbose-ing. - print_verbose(debug_string); - - const String file_extension_uppercase = file_extension.to_upper(); - - if (fbx_transparency_flags.count(fbx_mapping_name) > 0) { - // just enable it later let's make this fine-tuned. - spatial_material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA); - } - - ERR_CONTINUE_MSG(file_extension.is_empty(), "your texture has no file extension so we had to ignore it, let us know if you think this is wrong file an issue on github! " + debug_string); - ERR_CONTINUE_MSG(fbx_texture_map.count(fbx_mapping_name) <= 0, "This material has a texture with mapping name: " + String(fbx_mapping_name.c_str()) + " which is not yet supported by this importer. Consider opening an issue so we can support it."); - ERR_CONTINUE_MSG( - file_extension_uppercase != "PNG" && - file_extension_uppercase != "JPEG" && - file_extension_uppercase != "JPG" && - file_extension_uppercase != "TGA" && - file_extension_uppercase != "WEBP" && - file_extension_uppercase != "DDS", - "The FBX file contains a texture with an unrecognized extension: " + file_extension_uppercase); - - print_verbose("Getting FBX mapping mode for " + String(fbx_mapping_name.c_str())); - // get the texture map type - const StandardMaterial3D::TextureParam mapping_mode = fbx_texture_map.at(fbx_mapping_name); - print_verbose("Set FBX mapping mode to " + get_texture_param_name(mapping_mode)); - - Ref<Texture> texture; - print_verbose("texture mapping name: " + texture_name); - - if (state.cached_image_searches.has(texture_name)) { - texture = state.cached_image_searches[texture_name]; - } else { - String path = find_texture_path_by_filename(texture_name, p_fbx_current_directory); - if (!path.is_empty()) { - Ref<Texture2D> image_texture = ResourceLoader::load(path); - - ERR_CONTINUE(image_texture.is_null()); - - texture = image_texture; - state.cached_image_searches.insert(texture_name, texture); - print_verbose("Created texture from loaded image file."); - - } else if (fbx_texture_data != nullptr && fbx_texture_data->Media() != nullptr && fbx_texture_data->Media()->IsEmbedded()) { - // This is an embedded texture. Extract it. - Ref<Image> image; - //image.instantiate(); // oooo double instance bug? why make Image::_png_blah call - - const String extension = texture_name.get_extension().to_upper(); - if (extension == "PNG") { - // The stored file is a PNG. - image = Image::_png_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength()); - ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded PNG image load fail."); - - } else if ( - extension == "JPEG" || - extension == "JPG") { - // The stored file is a JPEG. - image = Image::_jpg_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength()); - ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded JPEG image load fail."); - - } else if (extension == "TGA") { - // The stored file is a TGA. - image = Image::_tga_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength()); - ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded TGA image load fail."); - - } else if (extension == "WEBP") { - // The stored file is a WEBP. - image = Image::_webp_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength()); - ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded WEBP image load fail."); - - // } else if (extension == "DDS") { - // // In this moment is not possible to extract a DDS from a buffer, TODO consider add it to godot. See `textureloader_dds.cpp::load(). - // // The stored file is a DDS. - } else { - ERR_CONTINUE_MSG(true, "The embedded image with extension: " + extension + " is not yet supported. Open an issue please."); - } - - Ref<ImageTexture> image_texture; - image_texture.instantiate(); - image_texture->create_from_image(image); - - texture = image_texture; - - // TODO: this is potentially making something with the same name have a match incorrectly USE FBX ID as Hash. #fuck it later. - state.cached_image_searches[texture_name] = texture; - print_verbose("Created texture from embedded image."); - } else { - ERR_CONTINUE_MSG(true, "The FBX texture, with name: `" + texture_name + "`, is not found into the project nor is stored as embedded file. Make sure to insert the texture as embedded file or into the project, then reimport."); - } - } - - spatial_material->set_texture(mapping_mode, texture); - } - - if (spatial_material.is_valid()) { - spatial_material->set_name(material_name); - } - - /// ALL below is related to properties - for (FBXDocParser::LazyPropertyMap::value_type iter : material->GetLazyProperties()) { - const std::string name = iter.first; - - if (name.empty()) { - continue; - } - - PropertyDesc desc = PROPERTY_DESC_NOT_FOUND; - if (fbx_properties_desc.count(name) > 0) { - desc = fbx_properties_desc.at(name); - } - - // check if we can ignore this it will be done at the next phase - if (desc == PROPERTY_DESC_NOT_FOUND || desc == PROPERTY_DESC_IGNORE) { - // count the texture mapping references. Skip this one if it's found and we can't look up a property value. - if (fbx_texture_map.count(name) > 0) { - continue; // safe to ignore it's a texture mapping. - } - } - - if (desc == PROPERTY_DESC_IGNORE) { - //WARN_PRINT("[Ignored] The FBX material parameter: `" + String(name.c_str()) + "` is ignored."); - continue; - } else { - print_verbose("FBX Material parameter: " + String(name.c_str())); - - // Check for Diffuse material system / lambert materials / legacy basically - if (name == "Diffuse" && !warning_non_pbr_material) { - ValidationTracker::get_singleton()->add_validation_error(state.path, "Invalid material settings change to Ai Standard Surface shader, mat name: " + material_name.c_escape()); - warning_non_pbr_material = true; - } - } - - // DISABLE when adding support for all weird and wonderful material formats - if (desc == PROPERTY_DESC_NOT_FOUND) { - continue; - } - - ERR_CONTINUE_MSG(desc == PROPERTY_DESC_NOT_FOUND, "The FBX material parameter: `" + String(name.c_str()) + "` was not recognized. Please open an issue so we can add the support to it."); - - const FBXDocParser::PropertyTable *tbl = material; - FBXDocParser::PropertyPtr prop = tbl->Get(name); - - ERR_CONTINUE_MSG(prop == nullptr, "This file may be corrupted because is not possible to extract the material parameter: " + String(name.c_str())); - - if (spatial_material.is_null()) { - // Done here so if no data no material is created. - spatial_material.instantiate(); - } - - const FBXDocParser::TypedProperty<real_t> *real_value = dynamic_cast<const FBXDocParser::TypedProperty<real_t> *>(prop); - const FBXDocParser::TypedProperty<Vector3> *vector_value = dynamic_cast<const FBXDocParser::TypedProperty<Vector3> *>(prop); - - if (!real_value && !vector_value) { - //WARN_PRINT("unsupported datatype in property: " + String(name.c_str())); - continue; - } - - if (vector_value && !real_value) { - if (vector_value->Value() == Vector3(0, 0, 0) && !real_value) { - continue; - } - } - - switch (desc) { - case PROPERTY_DESC_ALBEDO_COLOR: { - if (vector_value) { - const Vector3 &color = vector_value->Value(); - // Make sure to not lost any eventual opacity. - if (color != Vector3(0, 0, 0)) { - Color c = Color(); - c[0] = color[0]; - c[1] = color[1]; - c[2] = color[2]; - spatial_material->set_albedo(c); - } - - } else if (real_value) { - print_error("albedo is unsupported format?"); - } - } break; - case PROPERTY_DESC_TRANSPARENT: { - if (real_value) { - const real_t opacity = real_value->Value(); - if (opacity < (1.0 - CMP_EPSILON)) { - Color c = spatial_material->get_albedo(); - c.a = opacity; - spatial_material->set_albedo(c); - - spatial_material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA); - spatial_material->set_depth_draw_mode(BaseMaterial3D::DEPTH_DRAW_OPAQUE_ONLY); - } - } else if (vector_value) { - print_error("unsupported transparent desc type vector!"); - } - } break; - case PROPERTY_DESC_SPECULAR: { - if (real_value) { - print_verbose("specular real value: " + rtos(real_value->Value())); - spatial_material->set_specular(MIN(1.0, real_value->Value())); - } - - if (vector_value) { - print_error("unsupported specular vector value: " + vector_value->Value()); - } - } break; - - case PROPERTY_DESC_SPECULAR_COLOR: { - if (vector_value) { - print_error("unsupported specular color: " + vector_value->Value()); - } - } break; - case PROPERTY_DESC_SHINYNESS: { - if (real_value) { - print_error("unsupported shinyness:" + rtos(real_value->Value())); - } - } break; - case PROPERTY_DESC_METALLIC: { - if (real_value) { - print_verbose("metallic real value: " + rtos(real_value->Value())); - spatial_material->set_metallic(MIN(1.0f, real_value->Value())); - } else { - print_error("unsupported value type for metallic"); - } - } break; - case PROPERTY_DESC_ROUGHNESS: { - if (real_value) { - print_verbose("roughness real value: " + rtos(real_value->Value())); - spatial_material->set_roughness(MIN(1.0f, real_value->Value())); - } else { - print_error("unsupported value type for roughness"); - } - } break; - case PROPERTY_DESC_COAT: { - if (real_value) { - print_verbose("clearcoat real value: " + rtos(real_value->Value())); - spatial_material->set_clearcoat(MIN(1.0f, real_value->Value())); - } else { - print_error("unsupported value type for clearcoat"); - } - } break; - case PROPERTY_DESC_COAT_ROUGHNESS: { - // meaning is that approx equal to zero is disabled not actually zero. ;) - if (real_value && Math::is_zero_approx(real_value->Value())) { - print_verbose("clearcoat real value: " + rtos(real_value->Value())); - spatial_material->set_clearcoat_roughness(real_value->Value()); - } else { - print_error("unsupported value type for clearcoat gloss"); - } - } break; - case PROPERTY_DESC_EMISSIVE: { - if (real_value && Math::is_zero_approx(real_value->Value())) { - print_verbose("Emissive real value: " + rtos(real_value->Value())); - spatial_material->set_emission_energy(real_value->Value()); - } else if (vector_value && !vector_value->Value().is_equal_approx(Vector3(0, 0, 0))) { - const Vector3 &color = vector_value->Value(); - Color c; - c[0] = color[0]; - c[1] = color[1]; - c[2] = color[2]; - spatial_material->set_emission(c); - } - } break; - case PROPERTY_DESC_EMISSIVE_COLOR: { - if (vector_value && !vector_value->Value().is_equal_approx(Vector3(0, 0, 0))) { - const Vector3 &color = vector_value->Value(); - Color c; - c[0] = color[0]; - c[1] = color[1]; - c[2] = color[2]; - spatial_material->set_emission(c); - } else { - print_error("unsupported value type for emissive color"); - } - } break; - case PROPERTY_DESC_NOT_FOUND: - case PROPERTY_DESC_IGNORE: - break; - default: - break; - } - } - - return spatial_material; -} diff --git a/modules/fbx/data/fbx_material.h b/modules/fbx/data/fbx_material.h deleted file mode 100644 index e20b43561b..0000000000 --- a/modules/fbx/data/fbx_material.h +++ /dev/null @@ -1,285 +0,0 @@ -/*************************************************************************/ -/* fbx_material.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef FBX_MATERIAL_H -#define FBX_MATERIAL_H - -#include "tools/import_utils.h" - -#include "core/object/ref_counted.h" -#include "core/string/ustring.h" - -struct FBXMaterial : public RefCounted { - String material_name = String(); - bool warning_non_pbr_material = false; - FBXDocParser::Material *material = nullptr; - - /* Godot materials - *** Texture Maps: - * Albedo - color, texture - * Metallic - specular, metallic, texture - * Roughness - roughness, texture - * Emission - color, texture - * Normal Map - scale, texture - * Ambient Occlusion - texture - * Refraction - scale, texture - *** Has Settings for: - * UV1 - SCALE, OFFSET - * UV2 - SCALE, OFFSET - *** Flags for - * Transparent - * Cull Mode - */ - - enum class MapMode { - AlbedoM = 0, - MetallicM, - SpecularM, - EmissionM, - RoughnessM, - NormalM, - AmbientOcclusionM, - RefractionM, - ReflectionM, - }; - - /* Returns the string representation of the TextureParam enum */ - static String get_texture_param_name(StandardMaterial3D::TextureParam param) { - switch (param) { - case StandardMaterial3D::TEXTURE_ALBEDO: - return "TEXTURE_ALBEDO"; - case StandardMaterial3D::TEXTURE_METALLIC: - return "TEXTURE_METALLIC"; - case StandardMaterial3D::TEXTURE_ROUGHNESS: - return "TEXTURE_ROUGHNESS"; - case StandardMaterial3D::TEXTURE_EMISSION: - return "TEXTURE_EMISSION"; - case StandardMaterial3D::TEXTURE_NORMAL: - return "TEXTURE_NORMAL"; - case StandardMaterial3D::TEXTURE_RIM: - return "TEXTURE_RIM"; - case StandardMaterial3D::TEXTURE_CLEARCOAT: - return "TEXTURE_CLEARCOAT"; - case StandardMaterial3D::TEXTURE_FLOWMAP: - return "TEXTURE_FLOWMAP"; - case StandardMaterial3D::TEXTURE_AMBIENT_OCCLUSION: - return "TEXTURE_AMBIENT_OCCLUSION"; - // case StandardMaterial3D::TEXTURE_DEPTH: // TODO: work out how to make this function again! - // return "TEXTURE_DEPTH"; - case StandardMaterial3D::TEXTURE_SUBSURFACE_SCATTERING: - return "TEXTURE_SUBSURFACE_SCATTERING"; - // case StandardMaterial3D::TEXTURE_TRANSMISSION: // TODO: work out how to make this function again! - // return "TEXTURE_TRANSMISSION"; - case StandardMaterial3D::TEXTURE_REFRACTION: - return "TEXTURE_REFRACTION"; - case StandardMaterial3D::TEXTURE_DETAIL_MASK: - return "TEXTURE_DETAIL_MASK"; - case StandardMaterial3D::TEXTURE_DETAIL_ALBEDO: - return "TEXTURE_DETAIL_ALBEDO"; - case StandardMaterial3D::TEXTURE_DETAIL_NORMAL: - return "TEXTURE_DETAIL_NORMAL"; - case StandardMaterial3D::TEXTURE_MAX: - return "TEXTURE_MAX"; - default: - return "broken horribly"; - } - }; - - // TODO make this static? - const std::map<std::string, bool> fbx_transparency_flags = { - /* Transparent */ - { "TransparentColor", true }, - { "Maya|opacity", true } - }; - - // TODO make this static? - const std::map<std::string, StandardMaterial3D::TextureParam> fbx_texture_map = { - /* Diffuse */ - { "Maya|base", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "DiffuseColor", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "Maya|DiffuseTexture", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "Maya|baseColor", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "Maya|baseColor|file", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "3dsMax|Parameters|base_color_map", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "Maya|TEX_color_map|file", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - { "Maya|TEX_color_map", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO }, - /* Emission */ - { "EmissiveColor", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - { "EmissiveFactor", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - { "Maya|emissionColor", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - { "Maya|emissionColor|file", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - { "3dsMax|Parameters|emission_map", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - { "Maya|TEX_emissive_map", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - { "Maya|TEX_emissive_map|file", StandardMaterial3D::TextureParam::TEXTURE_EMISSION }, - /* Metallic */ - { "Maya|metalness", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - { "Maya|metalness|file", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - { "3dsMax|Parameters|metalness_map", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - { "Maya|TEX_metallic_map", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - { "Maya|TEX_metallic_map|file", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - - /* Roughness */ - // Arnold Roughness Map - { "Maya|specularRoughness", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS }, - - { "3dsMax|Parameters|roughness_map", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS }, - { "Maya|TEX_roughness_map", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS }, - { "Maya|TEX_roughness_map|file", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS }, - - /* Normal */ - { "NormalMap", StandardMaterial3D::TextureParam::TEXTURE_NORMAL }, - //{ "Bump", Material::TextureParam::TEXTURE_NORMAL }, - //{ "3dsMax|Parameters|bump_map", Material::TextureParam::TEXTURE_NORMAL }, - { "Maya|NormalTexture", StandardMaterial3D::TextureParam::TEXTURE_NORMAL }, - //{ "Maya|normalCamera", Material::TextureParam::TEXTURE_NORMAL }, - //{ "Maya|normalCamera|file", Material::TextureParam::TEXTURE_NORMAL }, - { "Maya|TEX_normal_map", StandardMaterial3D::TextureParam::TEXTURE_NORMAL }, - { "Maya|TEX_normal_map|file", StandardMaterial3D::TextureParam::TEXTURE_NORMAL }, - /* AO */ - { "Maya|TEX_ao_map", StandardMaterial3D::TextureParam::TEXTURE_AMBIENT_OCCLUSION }, - { "Maya|TEX_ao_map|file", StandardMaterial3D::TextureParam::TEXTURE_AMBIENT_OCCLUSION }, - - // TODO: specular workflow conversion - // { "SpecularColor", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - // { "Maya|specularColor", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - // { "Maya|SpecularTexture", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - // { "Maya|SpecularTexture|file", StandardMaterial3D::TextureParam::TEXTURE_METALLIC }, - // { "ShininessExponent", SpatialMaterial::TextureParam::UNSUPPORTED }, - // { "ReflectionFactor", SpatialMaterial::TextureParam::UNSUPPORTED }, - - //{ "TransparentColor",SpatialMaterial::TextureParam::TEXTURE_CHANNEL_ALPHA }, - //{ "TransparencyFactor",SpatialMaterial::TextureParam::TEXTURE_CHANNEL_ALPHA } - - // TODO: diffuse roughness - //{ "Maya|diffuseRoughness", SpatialMaterial::TextureParam::UNSUPPORTED }, - //{ "Maya|diffuseRoughness|file", SpatialMaterial::TextureParam::UNSUPPORTED }, - - }; - - // TODO make this static? - enum PropertyDesc { - PROPERTY_DESC_NOT_FOUND, - PROPERTY_DESC_ALBEDO_COLOR, - PROPERTY_DESC_TRANSPARENT, - PROPERTY_DESC_METALLIC, - PROPERTY_DESC_ROUGHNESS, - PROPERTY_DESC_SPECULAR, - PROPERTY_DESC_SPECULAR_COLOR, - PROPERTY_DESC_SHINYNESS, - PROPERTY_DESC_COAT, - PROPERTY_DESC_COAT_ROUGHNESS, - PROPERTY_DESC_EMISSIVE, - PROPERTY_DESC_EMISSIVE_COLOR, - PROPERTY_DESC_IGNORE - }; - - const std::map<std::string, PropertyDesc> fbx_properties_desc = { - /* Albedo */ - { "DiffuseColor", PROPERTY_DESC_ALBEDO_COLOR }, - { "Maya|baseColor", PROPERTY_DESC_ALBEDO_COLOR }, - - /* Specular */ - { "Maya|specular", PROPERTY_DESC_SPECULAR }, - { "Maya|specularColor", PROPERTY_DESC_SPECULAR_COLOR }, - - /* Specular roughness - arnold roughness map */ - { "Maya|specularRoughness", PROPERTY_DESC_ROUGHNESS }, - - /* Transparent */ - { "Opacity", PROPERTY_DESC_TRANSPARENT }, - { "TransparencyFactor", PROPERTY_DESC_TRANSPARENT }, - { "Maya|opacity", PROPERTY_DESC_TRANSPARENT }, - - { "Maya|metalness", PROPERTY_DESC_METALLIC }, - { "Maya|metallic", PROPERTY_DESC_METALLIC }, - - /* Roughness */ - { "Maya|roughness", PROPERTY_DESC_ROUGHNESS }, - - /* Coat */ - //{ "Maya|coat", PROPERTY_DESC_COAT }, - - /* Coat roughness */ - //{ "Maya|coatRoughness", PROPERTY_DESC_COAT_ROUGHNESS }, - - /* Emissive */ - { "Maya|emission", PROPERTY_DESC_EMISSIVE }, - { "Maya|emissive", PROPERTY_DESC_EMISSIVE }, - - /* Emissive color */ - { "EmissiveColor", PROPERTY_DESC_EMISSIVE_COLOR }, - { "Maya|emissionColor", PROPERTY_DESC_EMISSIVE_COLOR }, - - /* Ignore */ - { "Shininess", PROPERTY_DESC_IGNORE }, - { "Reflectivity", PROPERTY_DESC_IGNORE }, - { "Maya|diffuseRoughness", PROPERTY_DESC_IGNORE }, - { "Maya", PROPERTY_DESC_IGNORE }, - { "Diffuse", PROPERTY_DESC_ALBEDO_COLOR }, - { "Maya|TypeId", PROPERTY_DESC_IGNORE }, - { "Ambient", PROPERTY_DESC_IGNORE }, - { "AmbientColor", PROPERTY_DESC_IGNORE }, - { "ShininessExponent", PROPERTY_DESC_IGNORE }, - { "Specular", PROPERTY_DESC_IGNORE }, - { "SpecularColor", PROPERTY_DESC_IGNORE }, - { "SpecularFactor", PROPERTY_DESC_IGNORE }, - //{ "BumpFactor", PROPERTY_DESC_IGNORE }, - { "Maya|exitToBackground", PROPERTY_DESC_IGNORE }, - { "Maya|indirectDiffuse", PROPERTY_DESC_IGNORE }, - { "Maya|indirectSpecular", PROPERTY_DESC_IGNORE }, - { "Maya|internalReflections", PROPERTY_DESC_IGNORE }, - { "DiffuseFactor", PROPERTY_DESC_IGNORE }, - { "AmbientFactor", PROPERTY_DESC_IGNORE }, - { "ReflectionColor", PROPERTY_DESC_IGNORE }, - { "Emissive", PROPERTY_DESC_IGNORE }, - { "Maya|coatColor", PROPERTY_DESC_IGNORE }, - { "Maya|coatNormal", PROPERTY_DESC_IGNORE }, - { "Maya|coatIOR", PROPERTY_DESC_IGNORE }, - }; - - /* storing the texture properties like color */ - template <class T> - struct TexturePropertyMapping : RefCounted { - StandardMaterial3D::TextureParam map_mode = StandardMaterial3D::TextureParam::TEXTURE_ALBEDO; - const T property = T(); - }; - - static void add_search_string(String p_filename, String p_current_directory, String search_directory, Vector<String> &texture_search_paths); - - static String find_texture_path_by_filename(const String p_filename, const String p_current_directory); - - String get_material_name() const; - - void set_imported_material(FBXDocParser::Material *p_material); - - Ref<StandardMaterial3D> import_material(ImportState &state); -}; - -#endif // FBX_MATERIAL_H diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp deleted file mode 100644 index 1d59851778..0000000000 --- a/modules/fbx/data/fbx_mesh_data.cpp +++ /dev/null @@ -1,1446 +0,0 @@ -/*************************************************************************/ -/* fbx_mesh_data.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "fbx_mesh_data.h" - -#include "core/templates/local_vector.h" -#include "scene/resources/importer_mesh.h" -#include "scene/resources/mesh.h" -#include "scene/resources/surface_tool.h" - -#include "thirdparty/misc/polypartition.h" - -template <class T> -T collect_first(const Vector<VertexData<T>> *p_data, T p_fall_back) { - if (p_data->is_empty()) { - return p_fall_back; - } - - return (*p_data)[0].data; -} - -template <class T> -HashMap<int, T> collect_all(const Vector<VertexData<T>> *p_data, HashMap<int, T> p_fall_back) { - if (p_data->is_empty()) { - return p_fall_back; - } - - HashMap<int, T> collection; - for (int i = 0; i < p_data->size(); i += 1) { - const VertexData<T> &vd = (*p_data)[i]; - collection[vd.polygon_index] = vd.data; - } - return collection; -} - -template <class T> -T collect_average(const Vector<VertexData<T>> *p_data, T p_fall_back) { - if (p_data->is_empty()) { - return p_fall_back; - } - - T combined = (*p_data)[0].data; // Make sure the data is always correctly initialized. - print_verbose("size of data: " + itos(p_data->size())); - for (int i = 1; i < p_data->size(); i += 1) { - combined += (*p_data)[i].data; - } - combined = combined / real_t(p_data->size()); - - return combined.normalized(); -} - -HashMap<int, Vector3> collect_normal(const Vector<VertexData<Vector3>> *p_data, HashMap<int, Vector3> p_fall_back) { - if (p_data->is_empty()) { - return p_fall_back; - } - - HashMap<int, Vector3> collection; - for (int i = 0; i < p_data->size(); i += 1) { - const VertexData<Vector3> &vd = (*p_data)[i]; - collection[vd.polygon_index] = vd.data; - } - return collection; -} - -HashMap<int, Vector2> collect_uv(const Vector<VertexData<Vector2>> *p_data, HashMap<int, Vector2> p_fall_back) { - if (p_data->is_empty()) { - return p_fall_back; - } - - HashMap<int, Vector2> collection; - for (int i = 0; i < p_data->size(); i += 1) { - const VertexData<Vector2> &vd = (*p_data)[i]; - collection[vd.polygon_index] = vd.data; - } - return collection; -} - -ImporterMeshInstance3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) { - mesh_geometry = p_mesh_geometry; - // todo: make this just use a uint64_t FBX ID this is a copy of our original materials unfortunately. - const std::vector<const FBXDocParser::Material *> &material_lookup = model->GetMaterials(); - - // TODO: perf hotspot on large files - // this can be a very large copy - std::vector<int> polygon_indices = mesh_geometry->get_polygon_indices(); - std::vector<Vector3> vertices = mesh_geometry->get_vertices(); - - // Phase 1. Parse all FBX data. - HashMap<int, Vector3> normals; - HashMap<int, HashMap<int, Vector3>> normals_raw = extract_per_vertex_data( - vertices.size(), - mesh_geometry->get_edge_map(), - polygon_indices, - mesh_geometry->get_normals(), - &collect_all, - HashMap<int, Vector3>()); - - HashMap<int, Vector2> uvs_0; - HashMap<int, HashMap<int, Vector2>> uvs_0_raw = extract_per_vertex_data( - vertices.size(), - mesh_geometry->get_edge_map(), - polygon_indices, - mesh_geometry->get_uv_0(), - &collect_all, - HashMap<int, Vector2>()); - - HashMap<int, Vector2> uvs_1; - HashMap<int, HashMap<int, Vector2>> uvs_1_raw = extract_per_vertex_data( - vertices.size(), - mesh_geometry->get_edge_map(), - polygon_indices, - mesh_geometry->get_uv_1(), - &collect_all, - HashMap<int, Vector2>()); - - HashMap<int, Color> colors; - HashMap<int, HashMap<int, Color>> colors_raw = extract_per_vertex_data( - vertices.size(), - mesh_geometry->get_edge_map(), - polygon_indices, - mesh_geometry->get_colors(), - &collect_all, - HashMap<int, Color>()); - - // TODO what about tangents? - // TODO what about bi-nomials? - // TODO there is other? - - HashMap<int, SurfaceId> polygon_surfaces = extract_per_polygon( - vertices.size(), - polygon_indices, - mesh_geometry->get_material_allocation_id(), - -1); - - HashMap<String, MorphVertexData> morphs; - extract_morphs(mesh_geometry, morphs); - - // TODO please add skinning. - //mesh_id = mesh_geometry->ID(); - - sanitize_vertex_weights(state); - - // Reorganize polygon vertices to correctly take into account strange - // UVs. - reorganize_vertices( - polygon_indices, - vertices, - normals, - uvs_0, - uvs_1, - colors, - morphs, - normals_raw, - colors_raw, - uvs_0_raw, - uvs_1_raw); - - const int color_count = colors.size(); - print_verbose("Vertex color count: " + itos(color_count)); - - // Make sure that from this moment on the mesh_geometry is no used anymore. - // This is a safety step, because the mesh_geometry data are no more valid - // at this point. - - const int vertex_count = vertices.size(); - - print_verbose("Vertex count: " + itos(vertex_count)); - - // The map key is the material allocator id that is also used as surface id. - HashMap<SurfaceId, SurfaceData> surfaces; - - // Phase 2. For each material create a surface tool (So a different mesh). - { - if (polygon_surfaces.is_empty()) { - // No material, just use the default one with index -1. - // Set -1 to all polygons. - const int polygon_count = count_polygons(polygon_indices); - for (int p = 0; p < polygon_count; p += 1) { - polygon_surfaces[p] = -1; - } - } - - // Create the surface now. - for (const int *polygon_id = polygon_surfaces.next(nullptr); polygon_id != nullptr; polygon_id = polygon_surfaces.next(polygon_id)) { - const int surface_id = polygon_surfaces[*polygon_id]; - if (surfaces.has(surface_id) == false) { - SurfaceData sd; - sd.surface_tool.instantiate(); - sd.surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES); - - if (surface_id < 0) { - // nothing to do - } else if (surface_id < (int)material_lookup.size()) { - const FBXDocParser::Material *mat_mapping = material_lookup.at(surface_id); - const uint64_t mapping_id = mat_mapping->ID(); - if (state.cached_materials.has(mapping_id)) { - sd.material = state.cached_materials[mapping_id]; - } - } else { - WARN_PRINT("out of bounds surface detected, FBX file has corrupt material data"); - } - - surfaces.set(surface_id, sd); - } - } - } - - // Phase 3. Map the vertices relative to each surface, in this way we can - // just insert the vertices that we need per each surface. - { - PolygonId polygon_index = -1; - SurfaceId surface_id = -1; - SurfaceData *surface_data = nullptr; - - for (size_t polygon_vertex = 0; polygon_vertex < polygon_indices.size(); polygon_vertex += 1) { - if (is_start_of_polygon(polygon_indices, polygon_vertex)) { - polygon_index += 1; - ERR_FAIL_COND_V_MSG(polygon_surfaces.has(polygon_index) == false, nullptr, "The FBX file is corrupted, This surface_index is not expected."); - surface_id = polygon_surfaces[polygon_index]; - surface_data = surfaces.getptr(surface_id); - CRASH_COND(surface_data == nullptr); // Can't be null. - } - - const int vertex = get_vertex_from_polygon_vertex(polygon_indices, polygon_vertex); - - // The vertex position in the surface - // Uses a lookup table for speed with large scenes - bool has_polygon_vertex_index = surface_data->lookup_table.has(vertex); - int surface_polygon_vertex_index = -1; - - if (has_polygon_vertex_index) { - surface_polygon_vertex_index = surface_data->lookup_table[vertex]; - } else { - surface_polygon_vertex_index = surface_data->vertices_map.size(); - surface_data->lookup_table[vertex] = surface_polygon_vertex_index; - surface_data->vertices_map.push_back(vertex); - } - - surface_data->surface_polygon_vertex[polygon_index].push_back(surface_polygon_vertex_index); - } - } - - //print_verbose("[debug UV 1] UV1: " + itos(uvs_0.size())); - //print_verbose("[debug UV 2] UV2: " + itos(uvs_1.size())); - - // Phase 4. Per each surface just insert the vertices and add the indices. - for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) { - SurfaceData *surface = surfaces.getptr(*surface_id); - - // Just add the vertices data. - for (unsigned int i = 0; i < surface->vertices_map.size(); i += 1) { - const Vertex vertex = surface->vertices_map[i]; - - // This must be done before add_vertex because the surface tool is - // expecting this before the st->add_vertex() call - add_vertex(state, - surface->surface_tool, - state.scale, - vertex, - vertices, - normals, - uvs_0, - uvs_1, - colors); - } - - // Triangulate the various polygons and add the indices. - for (const PolygonId *polygon_id = surface->surface_polygon_vertex.next(nullptr); polygon_id != nullptr; polygon_id = surface->surface_polygon_vertex.next(polygon_id)) { - const Vector<DataIndex> *indices = surface->surface_polygon_vertex.getptr(*polygon_id); - triangulate_polygon( - surface, - *indices, - vertices); - } - } - - // Phase 5. Compose the morphs if any. - for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) { - SurfaceData *surface = surfaces.getptr(*surface_id); - - for (const String *morph_name = morphs.next(nullptr); morph_name != nullptr; morph_name = morphs.next(morph_name)) { - MorphVertexData *morph_data = morphs.getptr(*morph_name); - - // As said by the docs, this is not supposed to be different than - // vertex_count. - CRASH_COND(morph_data->vertices.size() != vertex_count); - CRASH_COND(morph_data->normals.size() != vertex_count); - - Vector3 *vertices_ptr = morph_data->vertices.ptrw(); - Vector3 *normals_ptr = morph_data->normals.ptrw(); - - Ref<SurfaceTool> morph_st; - morph_st.instantiate(); - morph_st->begin(Mesh::PRIMITIVE_TRIANGLES); - - for (unsigned int vi = 0; vi < surface->vertices_map.size(); vi += 1) { - const Vertex &vertex = surface->vertices_map[vi]; - add_vertex( - state, - morph_st, - state.scale, - vertex, - vertices, - normals, - uvs_0, - uvs_1, - colors, - vertices_ptr[vertex], - normals_ptr[vertex]); - } - - if (state.is_blender_fbx) { - morph_st->generate_normals(); - } - morph_st->generate_tangents(); - surface->morphs.push_back(morph_st->commit_to_arrays()); - } - } - - // Phase 6. Compose the mesh and return it. - Ref<ImporterMesh> mesh; - mesh.instantiate(); - - // Add blend shape info. - for (const String *morph_name = morphs.next(nullptr); morph_name != nullptr; morph_name = morphs.next(morph_name)) { - mesh->add_blend_shape(*morph_name); - } - - // TODO always normalized, Why? - mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); - - // Add surfaces. - for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) { - SurfaceData *surface = surfaces.getptr(*surface_id); - - if (state.is_blender_fbx) { - surface->surface_tool->generate_normals(); - } - // you can't generate them without a valid uv map. - if (uvs_0_raw.size() > 0) { - surface->surface_tool->generate_tangents(); - } - - Array mesh_array = surface->surface_tool->commit_to_arrays(); - Array blend_shapes = surface->morphs; - - // Enforce blend shape mask array format - for (int i = 0; i < blend_shapes.size(); i++) { - Array bsdata = blend_shapes[i]; - - for (int j = 0; j < Mesh::ARRAY_MAX; j++) { - if (!(Mesh::ARRAY_FORMAT_BLEND_SHAPE_MASK & (1 << j))) { - bsdata[j] = Variant(); - } - } - } - - if (surface->material.is_valid()) { - mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, mesh_array, blend_shapes, Dictionary(), surface->material, surface->material->get_name()); - } else { - mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, mesh_array, blend_shapes); - } - } - - ImporterMeshInstance3D *godot_mesh = memnew(ImporterMeshInstance3D); - godot_mesh->set_mesh(mesh); - const String name = ImportUtils::FBXNodeToName(model->Name()); - godot_mesh->set_name(name); // hurry up compiling >.< - mesh->set_name("mesh3d-" + name); - return godot_mesh; -} - -void FBXMeshData::sanitize_vertex_weights(const ImportState &state) { - const int max_vertex_influence_count = RS::ARRAY_WEIGHTS_SIZE; - Map<int, int> skeleton_to_skin_bind_id; - // TODO: error's need added - const FBXDocParser::Skin *fbx_skin = mesh_geometry->DeformerSkin(); - - if (fbx_skin == nullptr || fbx_skin->Clusters().size() == 0) { - return; // do nothing - } - - // - // Precalculate the skin cluster mapping - // - - int bind_id = 0; - for (const FBXDocParser::Cluster *cluster : fbx_skin->Clusters()) { - ERR_CONTINUE_MSG(!state.fbx_bone_map.has(cluster->TargetNode()->ID()), "Missing bone map for cluster target node with id " + uitos(cluster->TargetNode()->ID()) + "."); - Ref<FBXBone> bone = state.fbx_bone_map[cluster->TargetNode()->ID()]; - skeleton_to_skin_bind_id.insert(bone->godot_bone_id, bind_id); - bind_id++; - } - - for (const Vertex *v = vertex_weights.next(nullptr); v != nullptr; v = vertex_weights.next(v)) { - VertexWeightMapping *vm = vertex_weights.getptr(*v); - ERR_CONTINUE(vm->bones.size() != vm->weights.size()); // No message, already checked. - ERR_CONTINUE(vm->bones_ref.size() != vm->weights.size()); // No message, already checked. - - const int initial_size = vm->weights.size(); - { - // Init bone id - int *bones_ptr = vm->bones.ptrw(); - Ref<FBXBone> *bones_ref_ptr = vm->bones_ref.ptrw(); - - for (int i = 0; i < vm->weights.size(); i += 1) { - // At this point this is not possible because the skeleton is already initialized. - CRASH_COND(bones_ref_ptr[i]->godot_bone_id == -2); - bones_ptr[i] = skeleton_to_skin_bind_id[bones_ref_ptr[i]->godot_bone_id]; - } - - // From this point on the data is no more valid. - vm->bones_ref.clear(); - } - - { - // Sort - float *weights_ptr = vm->weights.ptrw(); - int *bones_ptr = vm->bones.ptrw(); - for (int i = 0; i < vm->weights.size(); i += 1) { - for (int x = i + 1; x < vm->weights.size(); x += 1) { - if (weights_ptr[i] < weights_ptr[x]) { - SWAP(weights_ptr[i], weights_ptr[x]); - SWAP(bones_ptr[i], bones_ptr[x]); - } - } - } - } - - { - // Resize - vm->weights.resize(max_vertex_influence_count); - vm->bones.resize(max_vertex_influence_count); - float *weights_ptr = vm->weights.ptrw(); - int *bones_ptr = vm->bones.ptrw(); - for (int i = initial_size; i < max_vertex_influence_count; i += 1) { - weights_ptr[i] = 0.0; - bones_ptr[i] = 0; - } - - // Normalize - real_t sum = 0.0; - for (int i = 0; i < max_vertex_influence_count; i += 1) { - sum += weights_ptr[i]; - } - if (sum > 0.0) { - for (int i = 0; i < vm->weights.size(); i += 1) { - weights_ptr[i] = weights_ptr[i] / sum; - } - } - } - } -} - -void FBXMeshData::reorganize_vertices( - // TODO: perf hotspot on insane files - std::vector<int> &r_polygon_indices, - std::vector<Vector3> &r_vertices, - HashMap<int, Vector3> &r_normals, - HashMap<int, Vector2> &r_uv_1, - HashMap<int, Vector2> &r_uv_2, - HashMap<int, Color> &r_color, - HashMap<String, MorphVertexData> &r_morphs, - HashMap<int, HashMap<int, Vector3>> &r_normals_raw, - HashMap<int, HashMap<int, Color>> &r_colors_raw, - HashMap<int, HashMap<int, Vector2>> &r_uv_1_raw, - HashMap<int, HashMap<int, Vector2>> &r_uv_2_raw) { - // Key: OldVertex; Value: [New vertices]; - HashMap<int, Vector<int>> duplicated_vertices; - - PolygonId polygon_index = -1; - for (int pv = 0; pv < (int)r_polygon_indices.size(); pv += 1) { - if (is_start_of_polygon(r_polygon_indices, pv)) { - polygon_index += 1; - } - const Vertex index = get_vertex_from_polygon_vertex(r_polygon_indices, pv); - - bool need_duplication = false; - Vector2 this_vert_poly_uv1 = Vector2(); - Vector2 this_vert_poly_uv2 = Vector2(); - Vector3 this_vert_poly_normal = Vector3(); - Color this_vert_poly_color = Color(); - - // Take the normal and see if we need to duplicate this polygon. - if (r_normals_raw.has(index)) { - const HashMap<PolygonId, Vector3> *nrml_arr = r_normals_raw.getptr(index); - - if (nrml_arr->has(polygon_index)) { - this_vert_poly_normal = nrml_arr->get(polygon_index); - } else if (nrml_arr->has(-1)) { - this_vert_poly_normal = nrml_arr->get(-1); - } else { - print_error("invalid normal detected: " + itos(index) + " polygon index: " + itos(polygon_index)); - for (const PolygonId *pid = nrml_arr->next(nullptr); pid != nullptr; pid = nrml_arr->next(pid)) { - print_verbose("debug contents key: " + itos(*pid)); - - if (nrml_arr->has(*pid)) { - print_verbose("contents valid: " + nrml_arr->get(*pid)); - } - } - } - - // Now, check if we need to duplicate it. - for (const PolygonId *pid = nrml_arr->next(nullptr); pid != nullptr; pid = nrml_arr->next(pid)) { - if (*pid == polygon_index) { - continue; - } - - const Vector3 vert_poly_normal = *nrml_arr->getptr(*pid); - if (!vert_poly_normal.is_equal_approx(this_vert_poly_normal)) { - // Yes this polygon need duplication. - need_duplication = true; - break; - } - } - } - - // TODO: make me vertex color - // Take the normal and see if we need to duplicate this polygon. - if (r_colors_raw.has(index)) { - const HashMap<PolygonId, Color> *color_arr = r_colors_raw.getptr(index); - - if (color_arr->has(polygon_index)) { - this_vert_poly_color = color_arr->get(polygon_index); - } else if (color_arr->has(-1)) { - this_vert_poly_color = color_arr->get(-1); - } else { - print_error("invalid color detected: " + itos(index) + " polygon index: " + itos(polygon_index)); - for (const PolygonId *pid = color_arr->next(nullptr); pid != nullptr; pid = color_arr->next(pid)) { - print_verbose("debug contents key: " + itos(*pid)); - - if (color_arr->has(*pid)) { - print_verbose("contents valid: " + color_arr->get(*pid)); - } - } - } - - // Now, check if we need to duplicate it. - for (const PolygonId *pid = color_arr->next(nullptr); pid != nullptr; pid = color_arr->next(pid)) { - if (*pid == polygon_index) { - continue; - } - - const Color vert_poly_color = *color_arr->getptr(*pid); - if (!this_vert_poly_color.is_equal_approx(vert_poly_color)) { - // Yes this polygon need duplication. - need_duplication = true; - break; - } - } - } - - // Take the UV1 and UV2 and see if we need to duplicate this polygon. - { - HashMap<int, HashMap<int, Vector2>> *uv_raw = &r_uv_1_raw; - Vector2 *this_vert_poly_uv = &this_vert_poly_uv1; - for (int kk = 0; kk < 2; kk++) { - if (uv_raw->has(index)) { - const HashMap<PolygonId, Vector2> *uvs = uv_raw->getptr(index); - - if (uvs->has(polygon_index)) { - // This Polygon has its own uv. - (*this_vert_poly_uv) = *uvs->getptr(polygon_index); - - // Check if we need to duplicate it. - for (const PolygonId *pid = uvs->next(nullptr); pid != nullptr; pid = uvs->next(pid)) { - if (*pid == polygon_index) { - continue; - } - const Vector2 vert_poly_uv = *uvs->getptr(*pid); - if (!vert_poly_uv.is_equal_approx(*this_vert_poly_uv)) { - // Yes this polygon need duplication. - need_duplication = true; - break; - } - } - } else if (uvs->has(-1)) { - // It has the default UV. - (*this_vert_poly_uv) = *uvs->getptr(-1); - } else if (uvs->size() > 0) { - // No uv, this is strange, just take the first and duplicate. - (*this_vert_poly_uv) = *uvs->getptr(*uvs->next(nullptr)); - WARN_PRINT("No UVs for this polygon, while there is no default and some other polygons have it. This FBX file may be corrupted."); - } - } - uv_raw = &r_uv_2_raw; - this_vert_poly_uv = &this_vert_poly_uv2; - } - } - - // If we want to duplicate it, Let's see if we already duplicated this - // vertex. - if (need_duplication) { - if (duplicated_vertices.has(index)) { - Vertex similar_vertex = -1; - // Let's see if one of the new vertices has the same data of this. - const Vector<int> *new_vertices = duplicated_vertices.getptr(index); - for (int j = 0; j < new_vertices->size(); j += 1) { - const Vertex new_vertex = (*new_vertices)[j]; - bool same_uv1 = false; - bool same_uv2 = false; - bool same_normal = false; - bool same_color = false; - - if (r_uv_1.has(new_vertex)) { - if ((this_vert_poly_uv1 - (*r_uv_1.getptr(new_vertex))).length_squared() <= CMP_EPSILON) { - same_uv1 = true; - } - } - - if (r_uv_2.has(new_vertex)) { - if ((this_vert_poly_uv2 - (*r_uv_2.getptr(new_vertex))).length_squared() <= CMP_EPSILON) { - same_uv2 = true; - } - } - - if (r_color.has(new_vertex)) { - if (this_vert_poly_color.is_equal_approx((*r_color.getptr(new_vertex)))) { - same_color = true; - } - } - - if (r_normals.has(new_vertex)) { - if ((this_vert_poly_normal - (*r_normals.getptr(new_vertex))).length_squared() <= CMP_EPSILON) { - same_uv2 = true; - } - } - - if (same_uv1 && same_uv2 && same_normal && same_color) { - similar_vertex = new_vertex; - break; - } - } - - if (similar_vertex != -1) { - // Update polygon. - if (is_end_of_polygon(r_polygon_indices, pv)) { - r_polygon_indices[pv] = ~similar_vertex; - } else { - r_polygon_indices[pv] = similar_vertex; - } - need_duplication = false; - } - } - } - - if (need_duplication) { - const Vertex old_index = index; - const Vertex new_index = r_vertices.size(); - - // Polygon index. - if (is_end_of_polygon(r_polygon_indices, pv)) { - r_polygon_indices[pv] = ~new_index; - } else { - r_polygon_indices[pv] = new_index; - } - - // Vertex position. - r_vertices.push_back(r_vertices[old_index]); - - // Normals - if (r_normals_raw.has(old_index)) { - r_normals.set(new_index, this_vert_poly_normal); - r_normals_raw.getptr(old_index)->erase(polygon_index); - r_normals_raw[new_index][polygon_index] = this_vert_poly_normal; - } - - // Vertex Color - if (r_colors_raw.has(old_index)) { - r_color.set(new_index, this_vert_poly_color); - r_colors_raw.getptr(old_index)->erase(polygon_index); - r_colors_raw[new_index][polygon_index] = this_vert_poly_color; - } - - // UV 0 - if (r_uv_1_raw.has(old_index)) { - r_uv_1.set(new_index, this_vert_poly_uv1); - r_uv_1_raw.getptr(old_index)->erase(polygon_index); - r_uv_1_raw[new_index][polygon_index] = this_vert_poly_uv1; - } - - // UV 1 - if (r_uv_2_raw.has(old_index)) { - r_uv_2.set(new_index, this_vert_poly_uv2); - r_uv_2_raw.getptr(old_index)->erase(polygon_index); - r_uv_2_raw[new_index][polygon_index] = this_vert_poly_uv2; - } - - // Morphs - for (const String *mname = r_morphs.next(nullptr); mname != nullptr; mname = r_morphs.next(mname)) { - MorphVertexData *d = r_morphs.getptr(*mname); - // This can't never happen. - CRASH_COND(d == nullptr); - if (d->vertices.size() > old_index) { - d->vertices.push_back(d->vertices[old_index]); - } - if (d->normals.size() > old_index) { - d->normals.push_back(d->normals[old_index]); - } - } - - if (vertex_weights.has(old_index)) { - vertex_weights.set(new_index, vertex_weights[old_index]); - } - - duplicated_vertices[old_index].push_back(new_index); - } else { - if (r_normals_raw.has(index) && - r_normals.has(index) == false) { - r_normals.set(index, this_vert_poly_normal); - } - - if (r_colors_raw.has(index) && r_color.has(index) == false) { - r_color.set(index, this_vert_poly_color); - } - - if (r_uv_1_raw.has(index) && - r_uv_1.has(index) == false) { - r_uv_1.set(index, this_vert_poly_uv1); - } - - if (r_uv_2_raw.has(index) && - r_uv_2.has(index) == false) { - r_uv_2.set(index, this_vert_poly_uv2); - } - } - } -} - -void FBXMeshData::add_vertex( - const ImportState &state, - Ref<SurfaceTool> p_surface_tool, - real_t p_scale, - Vertex p_vertex, - const std::vector<Vector3> &p_vertices_position, - const HashMap<int, Vector3> &p_normals, - const HashMap<int, Vector2> &p_uvs_0, - const HashMap<int, Vector2> &p_uvs_1, - const HashMap<int, Color> &p_colors, - const Vector3 &p_morph_value, - const Vector3 &p_morph_normal) { - ERR_FAIL_INDEX_MSG(p_vertex, (Vertex)p_vertices_position.size(), "FBX file is corrupted, the position of the vertex can't be retrieved."); - - if (p_normals.has(p_vertex) && !state.is_blender_fbx) { - p_surface_tool->set_normal(p_normals[p_vertex] + p_morph_normal); - } - - if (p_uvs_0.has(p_vertex)) { - //print_verbose("uv1: [" + itos(p_vertex) + "] " + p_uvs_0[p_vertex]); - // Inverts Y UV. - p_surface_tool->set_uv(Vector2(p_uvs_0[p_vertex].x, 1 - p_uvs_0[p_vertex].y)); - } - - if (p_uvs_1.has(p_vertex)) { - //print_verbose("uv2: [" + itos(p_vertex) + "] " + p_uvs_1[p_vertex]); - // Inverts Y UV. - p_surface_tool->set_uv2(Vector2(p_uvs_1[p_vertex].x, 1 - p_uvs_1[p_vertex].y)); - } - - if (p_colors.has(p_vertex)) { - p_surface_tool->set_color(p_colors[p_vertex]); - } - - // TODO what about binormals? - // TODO there is other? - - if (vertex_weights.has(p_vertex)) { - // Let's extract the weight info. - const VertexWeightMapping *vm = vertex_weights.getptr(p_vertex); - const Vector<int> &bones = vm->bones; - - // the bug is that the bone idx is wrong because it is not ref'ing the skin. - - if (bones.size() > RS::ARRAY_WEIGHTS_SIZE) { - print_error("[weight overflow detected]"); - } - - p_surface_tool->set_weights(vm->weights); - // 0 1 2 3 4 5 6 7 < local skeleton / skin for mesh - // 0 1 2 3 4 5 6 7 8 9 10 < actual skeleton with all joints - p_surface_tool->set_bones(bones); - } - - // The surface tool want the vertex position as last thing. - p_surface_tool->add_vertex((p_vertices_position[p_vertex] + p_morph_value) * p_scale); -} - -void FBXMeshData::triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const { - Ref<SurfaceTool> st(surface->surface_tool); - const int polygon_vertex_count = p_polygon_vertex.size(); - //const Vector<Vertex>& p_surface_vertex_map - if (polygon_vertex_count == 1) { - // point to triangle - st->add_index(p_polygon_vertex[0]); - st->add_index(p_polygon_vertex[0]); - st->add_index(p_polygon_vertex[0]); - return; - } else if (polygon_vertex_count == 2) { - // line to triangle - st->add_index(p_polygon_vertex[1]); - st->add_index(p_polygon_vertex[1]); - st->add_index(p_polygon_vertex[0]); - return; - } else if (polygon_vertex_count == 3) { - // triangle to triangle - st->add_index(p_polygon_vertex[0]); - st->add_index(p_polygon_vertex[2]); - st->add_index(p_polygon_vertex[1]); - return; - } else if (polygon_vertex_count == 4) { - // quad to triangle - this code is awesome for import times - // it prevents triangles being generated slowly - st->add_index(p_polygon_vertex[0]); - st->add_index(p_polygon_vertex[2]); - st->add_index(p_polygon_vertex[1]); - st->add_index(p_polygon_vertex[2]); - st->add_index(p_polygon_vertex[0]); - st->add_index(p_polygon_vertex[3]); - return; - } else { - // non triangulated - we must run the triangulation algorithm - bool is_simple_convex = false; - // this code is 'slow' but required it triangulates all the unsupported geometry. - // Doesn't allow for bigger polygons because those are unlikely be convex - if (polygon_vertex_count <= 6) { - // Start from true, check if it's false. - is_simple_convex = true; - Vector3 first_vec; - for (int i = 0; i < polygon_vertex_count; i += 1) { - const Vector3 p1 = p_vertices[surface->vertices_map[p_polygon_vertex[i]]]; - const Vector3 p2 = p_vertices[surface->vertices_map[p_polygon_vertex[(i + 1) % polygon_vertex_count]]]; - const Vector3 p3 = p_vertices[surface->vertices_map[p_polygon_vertex[(i + 2) % polygon_vertex_count]]]; - - const Vector3 edge1 = p1 - p2; - const Vector3 edge2 = p3 - p2; - - const Vector3 res = edge1.normalized().cross(edge2.normalized()).normalized(); - if (i == 0) { - first_vec = res; - } else { - if (first_vec.dot(res) < 0.0) { - // Ok we found an angle that is not the same dir of the - // others. - is_simple_convex = false; - break; - } - } - } - } - - if (is_simple_convex) { - // This is a convex polygon, so just triangulate it. - for (int i = 0; i < (polygon_vertex_count - 2); i += 1) { - st->add_index(p_polygon_vertex[2 + i]); - st->add_index(p_polygon_vertex[1 + i]); - st->add_index(p_polygon_vertex[0]); - } - return; - } - } - - { - // This is a concave polygon. - - std::vector<Vector3> poly_vertices(polygon_vertex_count); - for (int i = 0; i < polygon_vertex_count; i += 1) { - poly_vertices[i] = p_vertices[surface->vertices_map[p_polygon_vertex[i]]]; - } - - const Vector3 poly_norm = get_poly_normal(poly_vertices); - if (poly_norm.length_squared() <= CMP_EPSILON) { - ERR_FAIL_COND_MSG(poly_norm.length_squared() <= CMP_EPSILON, "The normal of this poly was not computed. Is this FBX file corrupted."); - } - - // Select the plan coordinate. - int axis_1_coord = 0; - int axis_2_coord = 1; - { - real_t inv = poly_norm.z; - - const real_t axis_x = ABS(poly_norm.x); - const real_t axis_y = ABS(poly_norm.y); - const real_t axis_z = ABS(poly_norm.z); - - if (axis_x > axis_y) { - if (axis_x > axis_z) { - // For the most part the normal point toward X. - axis_1_coord = 1; - axis_2_coord = 2; - inv = poly_norm.x; - } - } else if (axis_y > axis_z) { - // For the most part the normal point toward Y. - axis_1_coord = 2; - axis_2_coord = 0; - inv = poly_norm.y; - } - - // Swap projection axes to take the negated projection vector into account - if (inv < 0.0f) { - SWAP(axis_1_coord, axis_2_coord); - } - } - - TPPLPoly tppl_poly; - tppl_poly.Init(polygon_vertex_count); - std::vector<Vector2> projected_vertices(polygon_vertex_count); - for (int i = 0; i < polygon_vertex_count; i += 1) { - const Vector2 pv(poly_vertices[i][axis_1_coord], poly_vertices[i][axis_2_coord]); - projected_vertices[i] = pv; - tppl_poly.GetPoint(i) = pv; - } - tppl_poly.SetOrientation(TPPL_ORIENTATION_CCW); - - List<TPPLPoly> out_poly; - - TPPLPartition tppl_partition; - if (tppl_partition.Triangulate_OPT(&tppl_poly, &out_poly) == 0) { // Good result. - if (tppl_partition.Triangulate_EC(&tppl_poly, &out_poly) == 0) { // Medium result. - if (tppl_partition.Triangulate_MONO(&tppl_poly, &out_poly) == 0) { // Really poor result. - ERR_FAIL_MSG("The triangulation of this polygon failed, please try to triangulate your mesh or check if it has broken polygons."); - } - } - } - - std::vector<Vector2> tris(out_poly.size()); - for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) { - TPPLPoly &tp = I->get(); - - ERR_FAIL_COND_MSG(tp.GetNumPoints() != 3, "The triangulator returned more points, how this is possible?"); - // Find Index - for (int i = 2; i >= 0; i -= 1) { - const Vector2 vertex = tp.GetPoint(i); - bool done = false; - // Find Index - for (int y = 0; y < polygon_vertex_count; y += 1) { - if ((projected_vertices[y] - vertex).length_squared() <= CMP_EPSILON) { - // This seems the right vertex - st->add_index(p_polygon_vertex[y]); - done = true; - break; - } - } - ERR_FAIL_COND(done == false); - } - } - } -} - -void FBXMeshData::gen_weight_info(Ref<SurfaceTool> st, Vertex vertex_id) const { - if (vertex_weights.is_empty()) { - return; - } - - if (vertex_weights.has(vertex_id)) { - // Let's extract the weight info. - const VertexWeightMapping *vm = vertex_weights.getptr(vertex_id); - st->set_weights(vm->weights); - st->set_bones(vm->bones); - } -} - -int FBXMeshData::get_vertex_from_polygon_vertex(const std::vector<int> &p_polygon_indices, int p_index) const { - if (p_index < 0 || p_index >= (int)p_polygon_indices.size()) { - return -1; - } - - const int vertex = p_polygon_indices[p_index]; - if (vertex >= 0) { - return vertex; - } else { - // Negative numbers are the end of the face, reversing the bits is - // possible to obtain the positive correct vertex number. - return ~vertex; - } -} - -bool FBXMeshData::is_end_of_polygon(const std::vector<int> &p_polygon_indices, int p_index) const { - if (p_index < 0 || p_index >= (int)p_polygon_indices.size()) { - return false; - } - - const int vertex = p_polygon_indices[p_index]; - - // If the index is negative this is the end of the Polygon. - return vertex < 0; -} - -bool FBXMeshData::is_start_of_polygon(const std::vector<int> &p_polygon_indices, int p_index) const { - if (p_index < 0 || p_index >= (int)p_polygon_indices.size()) { - return false; - } - - if (p_index == 0) { - return true; - } - - // If the previous indices is negative this is the begin of a new Polygon. - return p_polygon_indices[p_index - 1] < 0; -} - -int FBXMeshData::count_polygons(const std::vector<int> &p_polygon_indices) const { - // The negative numbers define the end of the polygon. Counting the amount of - // negatives the numbers of polygons are obtained. - int count = 0; - for (size_t i = 0; i < p_polygon_indices.size(); i += 1) { - if (p_polygon_indices[i] < 0) { - count += 1; - } - } - return count; -} - -template <class R, class T> -HashMap<int, R> FBXMeshData::extract_per_vertex_data( - int p_vertex_count, - const std::vector<FBXDocParser::MeshGeometry::Edge> &p_edge_map, - const std::vector<int> &p_mesh_indices, - const FBXDocParser::MeshGeometry::MappingData<T> &p_mapping_data, - R (*collector_function)(const Vector<VertexData<T>> *p_vertex_data, R p_fall_back), - R p_fall_back) const { - /* When index_to_direct is set - * index size is 184 ( contains index for the data array [values 0, 96] ) - * data size is 96 (contains uv coordinates) - * this means index is simple data reduction basically - */ - //// - if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct && p_mapping_data.index.size() == 0) { - print_verbose("debug count: index size: " + itos(p_mapping_data.index.size()) + ", data size: " + itos(p_mapping_data.data.size())); - print_verbose("vertex indices count: " + itos(p_mesh_indices.size())); - print_verbose("Edge map size: " + itos(p_edge_map.size())); - } - - ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct && p_mapping_data.index.size() == 0, (HashMap<int, R>()), "FBX importer needs to map correctly to this field, please specify the override index name to fix this problem!"); - ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index && p_mapping_data.index.size() == 0, (HashMap<int, R>()), "The FBX seems corrupted"); - - // Aggregate vertex data. - HashMap<Vertex, Vector<VertexData<T>>> aggregate_vertex_data; - - switch (p_mapping_data.map_type) { - case FBXDocParser::MeshGeometry::MapType::none: { - // No data nothing to do. - return (HashMap<int, R>()); - } - case FBXDocParser::MeshGeometry::MapType::vertex: { - ERR_FAIL_COND_V_MSG(p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct, (HashMap<int, R>()), "We will support in future"); - - if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) { - // The data is mapped per vertex directly. - ERR_FAIL_COND_V_MSG((int)p_mapping_data.data.size() != p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR01"); - for (size_t vertex_index = 0; vertex_index < p_mapping_data.data.size(); vertex_index += 1) { - aggregate_vertex_data[vertex_index].push_back({ -1, p_mapping_data.data[vertex_index] }); - } - } else { - // The data is mapped per vertex using a reference. - // The indices array, contains a *reference_id for each vertex. - // * Note that the reference_id is the id of data into the data array. - // - // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - ERR_FAIL_COND_V_MSG((int)p_mapping_data.index.size() != p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR02"); - for (size_t vertex_index = 0; vertex_index < p_mapping_data.index.size(); vertex_index += 1) { - ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[vertex_index], (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR03."); - aggregate_vertex_data[vertex_index].push_back({ -1, p_mapping_data.data[p_mapping_data.index[vertex_index]] }); - } - } - } break; - case FBXDocParser::MeshGeometry::MapType::polygon_vertex: { - if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct) { - // The data is mapped using each index from the indexes array then direct to the data (data reduction algorithm) - ERR_FAIL_COND_V_MSG((int)p_mesh_indices.size() != (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR04"); - int polygon_id = -1; - for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_mapping_data.index.size(); polygon_vertex_index += 1) { - if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { - polygon_id += 1; - } - const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); - ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap<int, R>()), "FBX file corrupted: #ERR05"); - ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR06"); - const int index_to_direct = get_vertex_from_polygon_vertex(p_mapping_data.index, polygon_vertex_index); - T value = p_mapping_data.data[index_to_direct]; - aggregate_vertex_data[vertex_index].push_back({ polygon_id, value }); - } - } else if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) { - // The data are mapped per polygon vertex directly. - ERR_FAIL_COND_V_MSG((int)p_mesh_indices.size() != (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR04"); - int polygon_id = -1; - for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_mapping_data.data.size(); polygon_vertex_index += 1) { - if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { - polygon_id += 1; - } - const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); - ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap<int, R>()), "FBX file corrupted: #ERR05"); - ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR06"); - - aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_mapping_data.data[polygon_vertex_index] }); - } - } else { - // The data is mapped per polygon_vertex using a reference. - // The indices array, contains a *reference_id for each polygon_vertex. - // * Note that the reference_id is the id of data into the data array. - // - // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - ERR_FAIL_COND_V_MSG(p_mesh_indices.size() != p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR7"); - int polygon_id = -1; - for (size_t polygon_vertex_index = 0; polygon_vertex_index < p_mapping_data.index.size(); polygon_vertex_index += 1) { - if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { - polygon_id += 1; - } - const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); - ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap<int, R>()), "FBX file corrupted: #ERR8"); - ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR9."); - ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] < 0, (HashMap<int, R>()), "FBX file seems corrupted: #ERR10."); - ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] >= (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR11."); - aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_mapping_data.data[p_mapping_data.index[polygon_vertex_index]] }); - } - } - } break; - case FBXDocParser::MeshGeometry::MapType::polygon: { - if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) { - // The data are mapped per polygon directly. - const int polygon_count = count_polygons(p_mesh_indices); - ERR_FAIL_COND_V_MSG(polygon_count != (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR12"); - - // Advance each polygon vertex, each new polygon advance the polygon index. - int polygon_index = -1; - for (size_t polygon_vertex_index = 0; - polygon_vertex_index < p_mesh_indices.size(); - polygon_vertex_index += 1) { - if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { - polygon_index += 1; - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR13"); - } - - const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); - ERR_FAIL_INDEX_V_MSG(vertex_index, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR14"); - - aggregate_vertex_data[vertex_index].push_back({ polygon_index, p_mapping_data.data[polygon_index] }); - } - ERR_FAIL_COND_V_MSG((polygon_index + 1) != polygon_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR16. Not all Polygons are present in the file."); - } else { - // The data is mapped per polygon using a reference. - // The indices array, contains a *reference_id for each polygon. - // * Note that the reference_id is the id of data into the data array. - // - // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - const int polygon_count = count_polygons(p_mesh_indices); - ERR_FAIL_COND_V_MSG(polygon_count != (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR17"); - - // Advance each polygon vertex, each new polygon advance the polygon index. - int polygon_index = -1; - for (size_t polygon_vertex_index = 0; - polygon_vertex_index < p_mesh_indices.size(); - polygon_vertex_index += 1) { - if (is_start_of_polygon(p_mesh_indices, polygon_vertex_index)) { - polygon_index += 1; - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR18"); - ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[polygon_index], (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR19"); - } - - const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); - ERR_FAIL_INDEX_V_MSG(vertex_index, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR20"); - - aggregate_vertex_data[vertex_index].push_back({ polygon_index, p_mapping_data.data[p_mapping_data.index[polygon_index]] }); - } - ERR_FAIL_COND_V_MSG((polygon_index + 1) != polygon_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR22. Not all Polygons are present in the file."); - } - } break; - case FBXDocParser::MeshGeometry::MapType::edge: { - if (p_mapping_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) { - // The data are mapped per edge directly. - ERR_FAIL_COND_V_MSG(p_edge_map.size() != p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR23"); - for (size_t edge_index = 0; edge_index < p_mapping_data.data.size(); edge_index += 1) { - const FBXDocParser::MeshGeometry::Edge edge = FBXDocParser::MeshGeometry::get_edge(p_edge_map, edge_index); - ERR_FAIL_INDEX_V_MSG(edge.vertex_0, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR24"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_1, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR25"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_0, (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR26"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_1, (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR27"); - aggregate_vertex_data[edge.vertex_0].push_back({ -1, p_mapping_data.data[edge_index] }); - aggregate_vertex_data[edge.vertex_1].push_back({ -1, p_mapping_data.data[edge_index] }); - } - } else { - // The data is mapped per edge using a reference. - // The indices array, contains a *reference_id for each polygon. - // * Note that the reference_id is the id of data into the data array. - // - // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - ERR_FAIL_COND_V_MSG(p_edge_map.size() != p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR28"); - for (size_t edge_index = 0; edge_index < p_mapping_data.data.size(); edge_index += 1) { - const FBXDocParser::MeshGeometry::Edge edge = FBXDocParser::MeshGeometry::get_edge(p_edge_map, edge_index); - ERR_FAIL_INDEX_V_MSG(edge.vertex_0, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR29"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_1, p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR30"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_0, (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR31"); - ERR_FAIL_INDEX_V_MSG(edge.vertex_1, (int)p_mapping_data.index.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR32"); - ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[edge.vertex_0], (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR33"); - ERR_FAIL_INDEX_V_MSG(p_mapping_data.index[edge.vertex_1], (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file corrupted: #ERR34"); - aggregate_vertex_data[edge.vertex_0].push_back({ -1, p_mapping_data.data[p_mapping_data.index[edge_index]] }); - aggregate_vertex_data[edge.vertex_1].push_back({ -1, p_mapping_data.data[p_mapping_data.index[edge_index]] }); - } - } - } break; - case FBXDocParser::MeshGeometry::MapType::all_the_same: { - // No matter the mode, no matter the data size; The first always win - // and is set to all the vertices. - ERR_FAIL_COND_V_MSG(p_mapping_data.data.size() <= 0, (HashMap<int, R>()), "FBX file seems corrupted: #ERR35"); - if (p_mapping_data.data.size() > 0) { - for (int vertex_index = 0; vertex_index < p_vertex_count; vertex_index += 1) { - aggregate_vertex_data[vertex_index].push_back({ -1, p_mapping_data.data[0] }); - } - } - } break; - } - - if (aggregate_vertex_data.size() == 0) { - return (HashMap<int, R>()); - } - - // A map is used because turns out that the some FBX file are not well organized - // with vertices well compacted. Using a map allows avoid those issues. - HashMap<Vertex, R> result; - - // Aggregate the collected data. - for (const Vertex *index = aggregate_vertex_data.next(nullptr); index != nullptr; index = aggregate_vertex_data.next(index)) { - Vector<VertexData<T>> *aggregated_vertex = aggregate_vertex_data.getptr(*index); - // This can't be null because we are just iterating. - CRASH_COND(aggregated_vertex == nullptr); - - ERR_FAIL_INDEX_V_MSG(0, aggregated_vertex->size(), (HashMap<int, R>()), "The FBX file is corrupted, No valid data for this vertex index."); - result[*index] = collector_function(aggregated_vertex, p_fall_back); - } - - // Sanitize the data now, if the file is broken we can try import it anyway. - bool problem_found = false; - for (size_t i = 0; i < p_mesh_indices.size(); i += 1) { - const Vertex vertex = get_vertex_from_polygon_vertex(p_mesh_indices, i); - if (result.has(vertex) == false) { - result[vertex] = p_fall_back; - problem_found = true; - } - } - if (problem_found) { - WARN_PRINT("Some data is missing, this FBX file may be corrupted: #WARN0."); - } - - return result; -} - -template <class T> -HashMap<int, T> FBXMeshData::extract_per_polygon( - int p_vertex_count, - const std::vector<int> &p_polygon_indices, - const FBXDocParser::MeshGeometry::MappingData<T> &p_fbx_data, - T p_fallback_value) const { - ERR_FAIL_COND_V_MSG(p_fbx_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct && p_fbx_data.data.size() == 0, (HashMap<int, T>()), "invalid index to direct array"); - ERR_FAIL_COND_V_MSG(p_fbx_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index && p_fbx_data.index.size() == 0, (HashMap<int, T>()), "The FBX seems corrupted"); - - const int polygon_count = count_polygons(p_polygon_indices); - - // Aggregate vertex data. - HashMap<int, Vector<T>> aggregate_polygon_data; - - switch (p_fbx_data.map_type) { - case FBXDocParser::MeshGeometry::MapType::none: { - // No data nothing to do. - return (HashMap<int, T>()); - } - case FBXDocParser::MeshGeometry::MapType::vertex: { - ERR_FAIL_V_MSG((HashMap<int, T>()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per vertex. This should not happen."); - } break; - case FBXDocParser::MeshGeometry::MapType::polygon_vertex: { - ERR_FAIL_V_MSG((HashMap<int, T>()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per polygon vertex. This should not happen."); - } break; - case FBXDocParser::MeshGeometry::MapType::polygon: { - if (p_fbx_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::index_to_direct) { - // The data is stored efficiently index_to_direct allows less data in the FBX file. - for (int polygon_index = 0; - polygon_index < polygon_count; - polygon_index += 1) { - if (p_fbx_data.index.size() == 0) { - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.data.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR62"); - aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[polygon_index]); - } else { - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.index.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR62"); - - const int index_to_direct = get_vertex_from_polygon_vertex(p_fbx_data.index, polygon_index); - T value = p_fbx_data.data[index_to_direct]; - aggregate_polygon_data[polygon_index].push_back(value); - } - } - } else if (p_fbx_data.ref_type == FBXDocParser::MeshGeometry::ReferenceType::direct) { - // The data are mapped per polygon directly. - ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.data.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR51"); - - // Advance each polygon vertex, each new polygon advance the polygon index. - for (int polygon_index = 0; - polygon_index < polygon_count; - polygon_index += 1) { - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.data.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR52"); - aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[polygon_index]); - } - } else { - // The data is mapped per polygon using a reference. - // The indices array, contains a *reference_id for each polygon. - // * Note that the reference_id is the id of data into the data array. - // - // https://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_layer_element_html - ERR_FAIL_COND_V_MSG(polygon_count != (int)p_fbx_data.index.size(), (HashMap<int, T>()), "FBX file seems corrupted: #ERR52"); - - // Advance each polygon vertex, each new polygon advance the polygon index. - for (int polygon_index = 0; - polygon_index < polygon_count; - polygon_index += 1) { - ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.index.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR53"); - ERR_FAIL_INDEX_V_MSG(p_fbx_data.index[polygon_index], (int)p_fbx_data.data.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR54"); - aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[p_fbx_data.index[polygon_index]]); - } - } - } break; - case FBXDocParser::MeshGeometry::MapType::edge: { - ERR_FAIL_V_MSG((HashMap<int, T>()), "This data can't be extracted and organized per polygon, since into the FBX is mapped per edge. This should not happen."); - } break; - case FBXDocParser::MeshGeometry::MapType::all_the_same: { - // No matter the mode, no matter the data size; The first always win - // and is set to all the vertices. - ERR_FAIL_COND_V_MSG(p_fbx_data.data.size() <= 0, (HashMap<int, T>()), "FBX file seems corrupted: #ERR55"); - if (p_fbx_data.data.size() > 0) { - for (int polygon_index = 0; polygon_index < polygon_count; polygon_index += 1) { - aggregate_polygon_data[polygon_index].push_back(p_fbx_data.data[0]); - } - } - } break; - } - - if (aggregate_polygon_data.size() == 0) { - return (HashMap<int, T>()); - } - - // A map is used because turns out that the some FBX file are not well organized - // with vertices well compacted. Using a map allows avoid those issues. - HashMap<int, T> polygons; - - // Take the first value for each vertex. - for (const Vertex *index = aggregate_polygon_data.next(nullptr); index != nullptr; index = aggregate_polygon_data.next(index)) { - Vector<T> *aggregated_polygon = aggregate_polygon_data.getptr(*index); - // This can't be null because we are just iterating. - CRASH_COND(aggregated_polygon == nullptr); - - ERR_FAIL_INDEX_V_MSG(0, (int)aggregated_polygon->size(), (HashMap<int, T>()), "The FBX file is corrupted, No valid data for this polygon index."); - - // Validate the final value. - polygons[*index] = (*aggregated_polygon)[0]; - } - - // Sanitize the data now, if the file is broken we can try import it anyway. - bool problem_found = false; - for (int polygon_i = 0; polygon_i < polygon_count; polygon_i += 1) { - if (polygons.has(polygon_i) == false) { - polygons[polygon_i] = p_fallback_value; - problem_found = true; - } - } - if (problem_found) { - WARN_PRINT("Some data is missing, this FBX file may be corrupted: #WARN1."); - } - - return polygons; -} - -void FBXMeshData::extract_morphs(const FBXDocParser::MeshGeometry *mesh_geometry, HashMap<String, MorphVertexData> &r_data) { - r_data.clear(); - - const int vertex_count = mesh_geometry->get_vertices().size(); - - for (const FBXDocParser::BlendShape *blend_shape : mesh_geometry->get_blend_shapes()) { - for (const FBXDocParser::BlendShapeChannel *blend_shape_channel : blend_shape->BlendShapeChannels()) { - const std::vector<const FBXDocParser::ShapeGeometry *> &shape_geometries = blend_shape_channel->GetShapeGeometries(); - for (const FBXDocParser::ShapeGeometry *shape_geometry : shape_geometries) { - String morph_name = ImportUtils::FBXAnimMeshName(shape_geometry->Name()).c_str(); - if (morph_name.is_empty()) { - morph_name = "morph"; - } - - // TODO we have only these?? - const std::vector<unsigned int> &morphs_vertex_indices = shape_geometry->GetIndices(); - const std::vector<Vector3> &morphs_vertices = shape_geometry->GetVertices(); - const std::vector<Vector3> &morphs_normals = shape_geometry->GetNormals(); - - ERR_FAIL_COND_MSG((int)morphs_vertex_indices.size() > vertex_count, "The FBX file is corrupted: #ERR103"); - ERR_FAIL_COND_MSG(morphs_vertex_indices.size() != morphs_vertices.size(), "The FBX file is corrupted: #ERR104"); - ERR_FAIL_COND_MSG((int)morphs_vertices.size() > vertex_count, "The FBX file is corrupted: #ERR105"); - ERR_FAIL_COND_MSG(morphs_normals.size() != 0 && morphs_normals.size() != morphs_vertices.size(), "The FBX file is corrupted: #ERR106"); - - if (r_data.has(morph_name) == false) { - // This morph doesn't exist yet. - // Create it. - MorphVertexData md; - md.vertices.resize(vertex_count); - md.normals.resize(vertex_count); - r_data.set(morph_name, md); - } - - MorphVertexData *data = r_data.getptr(morph_name); - Vector3 *data_vertices_ptr = data->vertices.ptrw(); - Vector3 *data_normals_ptr = data->normals.ptrw(); - - for (int i = 0; i < (int)morphs_vertex_indices.size(); i += 1) { - const Vertex vertex = morphs_vertex_indices[i]; - - ERR_FAIL_INDEX_MSG(vertex, vertex_count, "The blend shapes of this FBX file are corrupted. It has a not valid vertex."); - - data_vertices_ptr[vertex] = morphs_vertices[i]; - - if (morphs_normals.size() != 0) { - data_normals_ptr[vertex] = morphs_normals[i]; - } - } - } - } - } -} diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h deleted file mode 100644 index 358d0c2cb6..0000000000 --- a/modules/fbx/data/fbx_mesh_data.h +++ /dev/null @@ -1,200 +0,0 @@ -/*************************************************************************/ -/* fbx_mesh_data.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef FBX_MESH_DATA_H -#define FBX_MESH_DATA_H - -#include "core/templates/hash_map.h" -#include "core/templates/local_vector.h" -#include "core/templates/ordered_hash_map.h" -#include "editor/import/resource_importer_scene.h" -#include "scene/3d/importer_mesh_instance_3d.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/resources/surface_tool.h" - -#include "fbx_bone.h" -#include "fbx_parser/FBXMeshGeometry.h" -#include "import_state.h" -#include "tools/import_utils.h" - -struct FBXNode; -struct FBXMeshData; -struct FBXBone; -struct ImportState; - -typedef int Vertex; -typedef int SurfaceId; -typedef int PolygonId; -typedef int DataIndex; - -struct SurfaceData { - Ref<SurfaceTool> surface_tool; - OrderedHashMap<Vertex, int> lookup_table; // proposed fix is to replace lookup_table[vertex_id] to give the position of the vertices_map[int] index. - LocalVector<Vertex> vertices_map; // this must be ordered the same as insertion <-- slow to do find() operation. - Ref<Material> material; - HashMap<PolygonId, Vector<DataIndex>> surface_polygon_vertex; - Array morphs; -}; - -struct VertexWeightMapping { - Vector<float> weights; - Vector<int> bones; - // This extra vector is used because the bone id is computed in a second step. - // TODO Get rid of this extra step is a good idea. - Vector<Ref<FBXBone>> bones_ref; -}; - -template <class T> -struct VertexData { - int polygon_index; - T data; -}; - -// Caches mesh information and instantiates meshes for you using helper functions. -struct FBXMeshData : RefCounted { - struct MorphVertexData { - // TODO we have only these?? - /// Each element is a vertex. Not supposed to be void. - Vector<Vector3> vertices; - /// Each element is a vertex. Not supposed to be void. - Vector<Vector3> normals; - }; - - // FIXME: remove this is a hack for testing only - mutable const FBXDocParser::MeshGeometry *mesh_geometry = nullptr; - - Ref<FBXNode> mesh_node = nullptr; - /// vertex id, Weight Info - /// later: perf we can use array here - HashMap<int, VertexWeightMapping> vertex_weights; - - // translate fbx mesh data from document context to FBX Mesh Geometry Context - bool valid_weight_indexes = false; - - ImporterMeshInstance3D *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression); - - void gen_weight_info(Ref<SurfaceTool> st, int vertex_id) const; - - /* mesh maximum weight count */ - bool valid_weight_count = false; - int max_weight_count = 0; - uint64_t armature_id = 0; - bool valid_armature_id = false; - ImporterMeshInstance3D *godot_mesh_instance = nullptr; - -private: - void sanitize_vertex_weights(const ImportState &state); - - /// Make sure to reorganize the vertices so that the correct UV is taken. - /// This step is needed because differently from the normal, that can be - /// combined, the UV may need its own triangle because sometimes they have - /// really different UV for the same vertex but different polygon. - /// This function make sure to add another vertex for those UVS. - void reorganize_vertices( - std::vector<int> &r_polygon_indices, - std::vector<Vector3> &r_vertices, - HashMap<int, Vector3> &r_normals, - HashMap<int, Vector2> &r_uv_1, - HashMap<int, Vector2> &r_uv_2, - HashMap<int, Color> &r_color, - HashMap<String, MorphVertexData> &r_morphs, - HashMap<int, HashMap<int, Vector3>> &r_normals_raw, - HashMap<int, HashMap<int, Color>> &r_colors_raw, - HashMap<int, HashMap<int, Vector2>> &r_uv_1_raw, - HashMap<int, HashMap<int, Vector2>> &r_uv_2_raw); - - void add_vertex( - const ImportState &state, - Ref<SurfaceTool> p_surface_tool, - real_t p_scale, - int p_vertex, - const std::vector<Vector3> &p_vertices_position, - const HashMap<int, Vector3> &p_normals, - const HashMap<int, Vector2> &p_uvs_0, - const HashMap<int, Vector2> &p_uvs_1, - const HashMap<int, Color> &p_colors, - const Vector3 &p_morph_value = Vector3(), - const Vector3 &p_morph_normal = Vector3()); - - void triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const; - - /// This function is responsible to convert the FBX polygon vertex to - /// vertex index. - /// The polygon vertices are stored in an array with some negative - /// values. The negative values define the last face index. - /// For example the following `face_array` contains two faces, the former - /// with 3 vertices and the latter with a line: - /// [0,2,-2,3,-5] - /// Parsed as: - /// [0, 2, 1, 3, 4] - /// The negative values are computed using this formula: `(-value) - 1` - /// - /// Returns the vertex index from the polygon vertex. - /// Returns -1 if `p_index` is invalid. - int get_vertex_from_polygon_vertex(const std::vector<int> &p_face_indices, int p_index) const; - - /// Returns true if this polygon_vertex_index is the end of a new polygon. - bool is_end_of_polygon(const std::vector<int> &p_face_indices, int p_index) const; - - /// Returns true if this polygon_vertex_index is the begin of a new polygon. - bool is_start_of_polygon(const std::vector<int> &p_face_indices, int p_index) const; - - /// Returns the number of polygons. - int count_polygons(const std::vector<int> &p_face_indices) const; - - /// Used to extract data from the `MappingData` aligned with vertex. - /// Useful to extract normal/uvs/colors/tangents/etc... - /// If the function fails somehow, it returns an hollow vector and print an error. - template <class R, class T> - HashMap<int, R> extract_per_vertex_data( - int p_vertex_count, - const std::vector<FBXDocParser::MeshGeometry::Edge> &p_edges, - const std::vector<int> &p_mesh_indices, - const FBXDocParser::MeshGeometry::MappingData<T> &p_mapping_data, - R (*collector_function)(const Vector<VertexData<T>> *p_vertex_data, R p_fall_back), - R p_fall_back) const; - - /// Used to extract data from the `MappingData` organized per polygon. - /// Useful to extract the material - /// If the function fails somehow, it returns an hollow vector and print an error. - template <class T> - HashMap<int, T> extract_per_polygon( - int p_vertex_count, - const std::vector<int> &p_face_indices, - const FBXDocParser::MeshGeometry::MappingData<T> &p_fbx_data, - T p_fallback_value) const; - - /// Extracts the morph data and organizes it per vertices. - /// The returned `MorphVertexData` arrays are never something different - /// then the `vertex_count`. - void extract_morphs(const FBXDocParser::MeshGeometry *mesh_geometry, HashMap<String, MorphVertexData> &r_data); -}; - -#endif // FBX_MESH_DATA_H diff --git a/modules/fbx/data/fbx_node.h b/modules/fbx/data/fbx_node.h deleted file mode 100644 index 7a4139dcdf..0000000000 --- a/modules/fbx/data/fbx_node.h +++ /dev/null @@ -1,63 +0,0 @@ -/*************************************************************************/ -/* fbx_node.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef FBX_NODE_H -#define FBX_NODE_H - -#include "fbx_skeleton.h" -#include "model_abstraction.h" -#include "pivot_transform.h" - -#include "fbx_parser/FBXDocument.h" - -class Node3D; -struct PivotTransform; - -struct FBXNode : RefCounted, ModelAbstraction { - uint64_t current_node_id = 0; - String node_name = String(); - Node3D *godot_node = nullptr; - - // used to parent the skeleton once the tree is built. - Ref<FBXSkeleton> skeleton_node = Ref<FBXSkeleton>(); - - void set_parent(Ref<FBXNode> p_parent) { - fbx_parent = p_parent; - } - - void set_pivot_transform(Ref<PivotTransform> p_pivot_transform) { - pivot_transform = p_pivot_transform; - } - - Ref<PivotTransform> pivot_transform = Ref<PivotTransform>(); // local and global xform data - Ref<FBXNode> fbx_parent = Ref<FBXNode>(); // parent node -}; - -#endif // FBX_NODE_H diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp deleted file mode 100644 index 0225df16af..0000000000 --- a/modules/fbx/data/fbx_skeleton.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/*************************************************************************/ -/* fbx_skeleton.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "fbx_skeleton.h" - -#include "import_state.h" - -#include "tools/import_utils.h" - -void FBXSkeleton::init_skeleton(const ImportState &state) { - int skeleton_bone_count = skeleton_bones.size(); - - if (skeleton == nullptr && skeleton_bone_count > 0) { - skeleton = memnew(Skeleton3D); - - if (fbx_node.is_valid()) { - // cache skeleton attachment for later during node creation - // can't be done until after node hierarchy is built - if (fbx_node->godot_node != state.root) { - fbx_node->skeleton_node = Ref<FBXSkeleton>(this); - print_verbose("cached armature skeleton attachment for node " + fbx_node->node_name); - } else { - // root node must never be a skeleton to prevent cyclic skeletons from being allowed (skeleton in a skeleton) - fbx_node->godot_node->add_child(skeleton); - skeleton->set_owner(state.root_owner); - skeleton->set_name("Skeleton3D"); - print_verbose("created armature skeleton for root"); - } - } else { - memfree(skeleton); - skeleton = nullptr; - print_error("[doc] skeleton has no valid node to parent nodes to - erasing"); - skeleton_bones.clear(); - return; - } - } - - // Make the bone name uniques. - for (int x = 0; x < skeleton_bone_count; x++) { - Ref<FBXBone> bone = skeleton_bones[x]; - if (bone.is_valid()) { - // Make sure the bone name is unique. - const String bone_name = bone->bone_name; - int same_name_count = 0; - for (int y = x + 1; y < skeleton_bone_count; y++) { - Ref<FBXBone> other_bone = skeleton_bones[y]; - if (other_bone.is_valid()) { - if (other_bone->bone_name == bone_name) { - same_name_count += 1; - other_bone->bone_name += "_" + itos(same_name_count); - } - } - } - } - } - - Map<int, Ref<FBXBone>> bone_map; - // implement fbx cluster skin logic here this is where it goes - int bone_count = 0; - for (int x = 0; x < skeleton_bone_count; x++) { - Ref<FBXBone> bone = skeleton_bones[x]; - if (bone.is_valid()) { - skeleton->add_bone(bone->bone_name); - bone->godot_bone_id = bone_count; - bone->fbx_skeleton = Ref<FBXSkeleton>(this); - bone_map.insert(bone_count, bone); - print_verbose("added bone " + itos(bone->bone_id) + " " + bone->bone_name); - bone_count++; - } - } - - ERR_FAIL_COND_MSG(skeleton->get_bone_count() != bone_count, "Not all bones got added, is the file corrupted?"); - - for (const KeyValue<int, Ref<FBXBone>> &bone_element : bone_map) { - const Ref<FBXBone> bone = bone_element.value; - int bone_index = bone_element.key; - print_verbose("working on bone: " + itos(bone_index) + " bone name:" + bone->bone_name); - - skeleton->set_bone_rest(bone->godot_bone_id, get_unscaled_transform(bone->node->pivot_transform->LocalTransform, state.scale)); - { - Transform3D base_xform = bone->node->pivot_transform->LocalTransform; - - skeleton->set_bone_pose_position(bone_index, base_xform.origin); - skeleton->set_bone_pose_rotation(bone_index, base_xform.basis.get_rotation_quaternion()); - skeleton->set_bone_pose_scale(bone_index, base_xform.basis.get_scale()); - } - - // lookup parent ID - if (bone->valid_parent && state.fbx_bone_map.has(bone->parent_bone_id)) { - Ref<FBXBone> parent_bone = state.fbx_bone_map[bone->parent_bone_id]; - int bone_id = skeleton->find_bone(parent_bone->bone_name); - if (bone_id != -1) { - skeleton->set_bone_parent(bone_index, bone_id); - } else { - print_error("invalid bone parent: " + parent_bone->bone_name); - } - } else { - if (bone->godot_bone_id != -1) { - skeleton->set_bone_parent(bone_index, -1); // no parent for this bone - } - } - } -} diff --git a/modules/fbx/data/fbx_skeleton.h b/modules/fbx/data/fbx_skeleton.h deleted file mode 100644 index e615d0f5e3..0000000000 --- a/modules/fbx/data/fbx_skeleton.h +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************/ -/* fbx_skeleton.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef FBX_SKELETON_H -#define FBX_SKELETON_H - -#include "fbx_bone.h" -#include "fbx_node.h" -#include "model_abstraction.h" - -#include "core/object/ref_counted.h" -#include "scene/3d/skeleton_3d.h" - -struct FBXNode; -struct ImportState; -struct FBXBone; - -struct FBXSkeleton : RefCounted { - Ref<FBXNode> fbx_node = Ref<FBXNode>(); - Vector<Ref<FBXBone>> skeleton_bones = Vector<Ref<FBXBone>>(); - Skeleton3D *skeleton = nullptr; - - void init_skeleton(const ImportState &state); -}; - -#endif // FBX_SKELETON_H diff --git a/modules/fbx/data/import_state.h b/modules/fbx/data/import_state.h deleted file mode 100644 index eff11e3bb8..0000000000 --- a/modules/fbx/data/import_state.h +++ /dev/null @@ -1,112 +0,0 @@ -/*************************************************************************/ -/* import_state.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef IMPORT_STATE_H -#define IMPORT_STATE_H - -#include "fbx_mesh_data.h" -#include "tools/import_utils.h" -#include "tools/validation_tools.h" - -#include "pivot_transform.h" - -#include "core/io/resource_importer.h" -#include "core/templates/vector.h" -#include "editor/import/resource_importer_scene.h" -#include "editor/project_settings_editor.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/3d/node_3d.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/animation/animation_player.h" -#include "scene/resources/animation.h" -#include "scene/resources/surface_tool.h" - -#include "modules/fbx/fbx_parser/FBXDocument.h" -#include "modules/fbx/fbx_parser/FBXImportSettings.h" -#include "modules/fbx/fbx_parser/FBXMeshGeometry.h" -#include "modules/fbx/fbx_parser/FBXParser.h" -#include "modules/fbx/fbx_parser/FBXTokenizer.h" -#include "modules/fbx/fbx_parser/FBXUtil.h" - -struct FBXBone; -struct FBXMeshData; -struct FBXNode; -struct FBXSkeleton; - -struct ImportState { - bool enable_material_import = true; - bool enable_animation_import = true; - bool is_blender_fbx = false; - - Map<StringName, Ref<Texture>> cached_image_searches; - Map<uint64_t, Ref<Material>> cached_materials; - - String path = String(); - Node3D *root_owner = nullptr; - Node3D *root = nullptr; - real_t scale = 0.01; - Ref<FBXNode> fbx_root_node = Ref<FBXNode>(); - // skeleton map - merged automatically when they are on the same x node in the tree so we can merge them automatically. - Map<uint64_t, Ref<FBXSkeleton>> skeleton_map = Map<uint64_t, Ref<FBXSkeleton>>(); - - // nodes on the same level get merged automatically. - //Map<uint64_t, Skeleton3D *> armature_map; - AnimationPlayer *animation_player = nullptr; - - // Generation 4 - Raw document accessing for bone/skin/joint/kLocators - // joints are not necessarily bones but must be merged into the skeleton - // (bone id), bone - Map<uint64_t, Ref<FBXBone>> fbx_bone_map = Map<uint64_t, Ref<FBXBone>>(); // this is the bone name and setup information required for joints - // this will never contain joints only bones attached to a mesh. - - // Generation 4 - Raw document for creating the nodes transforms in the scene - // this is a list of the nodes in the scene - // (id, node) - List<Ref<FBXNode>> fbx_node_list = List<Ref<FBXNode>>(); - - // All nodes which have been created in the scene - // this will not contain the root node of the scene - Map<uint64_t, Ref<FBXNode>> fbx_target_map = Map<uint64_t, Ref<FBXNode>>(); - - // mesh nodes which are created in node / mesh step - used for populating skin poses in MeshSkins - Map<uint64_t, Ref<FBXNode>> MeshNodes = Map<uint64_t, Ref<FBXNode>>(); - // mesh skin map - Map<uint64_t, Ref<Skin>> MeshSkins = Map<uint64_t, Ref<Skin>>(); - - // this is the container for the mesh weight information and eventually - // any mesh data - // but not the skin, just stuff important for rendering - // skin is applied to mesh instance so not really required to be in here yet. - // maybe later - // fbx mesh id, FBXMeshData - Map<uint64_t, Ref<FBXMeshData>> renderer_mesh_data = Map<uint64_t, Ref<FBXMeshData>>(); -}; - -#endif // IMPORT_STATE_H diff --git a/modules/fbx/data/model_abstraction.h b/modules/fbx/data/model_abstraction.h deleted file mode 100644 index 4c3f81b163..0000000000 --- a/modules/fbx/data/model_abstraction.h +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* model_abstraction.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef MODEL_ABSTRACTION_H -#define MODEL_ABSTRACTION_H - -#include "modules/fbx/fbx_parser/FBXDocument.h" - -struct ModelAbstraction { - mutable const FBXDocParser::Model *fbx_model = nullptr; - - void set_model(const FBXDocParser::Model *p_model) { - fbx_model = p_model; - } - - bool has_model() const { - return fbx_model != nullptr; - } - - const FBXDocParser::Model *get_model() const { - return fbx_model; - } -}; - -#endif // MODEL_ABSTRACTION_H diff --git a/modules/fbx/data/pivot_transform.cpp b/modules/fbx/data/pivot_transform.cpp deleted file mode 100644 index 9457b19a7f..0000000000 --- a/modules/fbx/data/pivot_transform.cpp +++ /dev/null @@ -1,307 +0,0 @@ -/*************************************************************************/ -/* pivot_transform.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "pivot_transform.h" - -#include "tools/import_utils.h" - -void PivotTransform::ReadTransformChain() { - const FBXDocParser::PropertyTable *props = fbx_model; - const FBXDocParser::Model::RotOrder &rot = fbx_model->RotationOrder(); - const FBXDocParser::TransformInheritance &inheritType = fbx_model->InheritType(); - inherit_type = inheritType; // copy the inherit type we need it in the second step. - print_verbose("Model: " + String(fbx_model->Name().c_str()) + " Has inherit type: " + itos(fbx_model->InheritType())); - bool ok = false; - raw_pre_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "PreRotation", ok)); - if (ok) { - pre_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_pre_rotation)); - print_verbose("valid pre_rotation: " + raw_pre_rotation + " euler conversion: " + (pre_rotation.get_euler() * (180 / Math_PI))); - } - raw_post_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "PostRotation", ok)); - if (ok) { - post_rotation = ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder_EulerXYZ, ImportUtils::deg2rad(raw_post_rotation)); - print_verbose("valid post_rotation: " + raw_post_rotation + " euler conversion: " + (pre_rotation.get_euler() * (180 / Math_PI))); - } - const Vector3 &RotationPivot = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "RotationPivot", ok)); - if (ok) { - rotation_pivot = ImportUtils::FixAxisConversions(RotationPivot); - } - const Vector3 &RotationOffset = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "RotationOffset", ok)); - if (ok) { - rotation_offset = ImportUtils::FixAxisConversions(RotationOffset); - } - const Vector3 &ScalingOffset = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "ScalingOffset", ok)); - if (ok) { - scaling_offset = ImportUtils::FixAxisConversions(ScalingOffset); - } - const Vector3 &ScalingPivot = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "ScalingPivot", ok)); - if (ok) { - scaling_pivot = ImportUtils::FixAxisConversions(ScalingPivot); - } - const Vector3 &Translation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Translation", ok)); - if (ok) { - translation = ImportUtils::FixAxisConversions(Translation); - } - raw_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Rotation", ok)); - if (ok) { - rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_rotation)); - } - const Vector3 &Scaling = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Scaling", ok)); - if (ok) { - scaling = Scaling; - } else { - scaling = Vector3(1, 1, 1); - } - const Vector3 &GeometricScaling = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricScaling", ok)); - if (ok) { - geometric_scaling = GeometricScaling; - } else { - geometric_scaling = Vector3(1, 1, 1); - } - - const Vector3 &GeometricRotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricRotation", ok)); - if (ok) { - geometric_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(GeometricRotation)); - } else { - geometric_rotation = Quaternion(); - } - - const Vector3 &GeometricTranslation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricTranslation", ok)); - if (ok) { - geometric_translation = ImportUtils::FixAxisConversions(GeometricTranslation); - } else { - geometric_translation = Vector3(0, 0, 0); - } - - if (geometric_rotation != Quaternion()) { - print_error("geometric rotation is unsupported!"); - //CRASH_COND(true); - } - - if (!geometric_scaling.is_equal_approx(Vector3(1, 1, 1))) { - print_error("geometric scaling is unsupported!"); - //CRASH_COND(true); - } - - if (!geometric_translation.is_equal_approx(Vector3(0, 0, 0))) { - print_error("geometric translation is unsupported."); - //CRASH_COND(true); - } -} - -Transform3D PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const { - Transform3D T, Roff, Rp, Soff, Sp, S; - - // Here I assume this is the operation which needs done. - // Its WorldTransform * V - - // Origin pivots - T.set_origin(p_translation); - Roff.set_origin(rotation_offset); - Rp.set_origin(rotation_pivot); - Soff.set_origin(scaling_offset); - Sp.set_origin(scaling_pivot); - - // Scaling node - S.scale(p_scaling); - // Rotation pivots - Transform3D Rpre = Transform3D(pre_rotation); - Transform3D R = Transform3D(p_rotation); - Transform3D Rpost = Transform3D(post_rotation); - - return T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse(); -} - -Transform3D PivotTransform::ComputeGlobalTransform(Transform3D t) const { - Vector3 pos = t.origin; - Vector3 scale = t.basis.get_scale(); - Quaternion rot = t.basis.get_rotation_quaternion(); - return ComputeGlobalTransform(pos, rot, scale); -} - -Transform3D PivotTransform::ComputeLocalTransform(Transform3D t) const { - Vector3 pos = t.origin; - Vector3 scale = t.basis.get_scale(); - Quaternion rot = t.basis.get_rotation_quaternion(); - return ComputeLocalTransform(pos, rot, scale); -} - -Transform3D PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const { - Transform3D T, Roff, Rp, Soff, Sp, S; - - // Here I assume this is the operation which needs done. - // Its WorldTransform * V - - // Origin pivots - T.set_origin(p_translation); - Roff.set_origin(rotation_offset); - Rp.set_origin(rotation_pivot); - Soff.set_origin(scaling_offset); - Sp.set_origin(scaling_pivot); - - // Scaling node - S.scale(p_scaling); - - // Rotation pivots - Transform3D Rpre = Transform3D(pre_rotation); - Transform3D R = Transform3D(p_rotation); - Transform3D Rpost = Transform3D(post_rotation); - - Transform3D parent_global_xform; - Transform3D parent_local_scaling_m; - - if (parent_transform.is_valid()) { - parent_global_xform = parent_transform->GlobalTransform; - parent_local_scaling_m = parent_transform->Local_Scaling_Matrix; - } - - Transform3D local_rotation_m, parent_global_rotation_m; - Quaternion parent_global_rotation = parent_global_xform.basis.get_rotation_quaternion(); - parent_global_rotation_m.basis.set_quaternion(parent_global_rotation); - local_rotation_m = Rpre * R * Rpost; - - //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quaternion().normalized()); - - Transform3D local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation; - Vector3 parent_translation = parent_global_xform.get_origin(); - parent_shear_translation.origin = parent_translation; - parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform; - parent_shear_scaling = parent_global_rotation_m.affine_inverse() * parent_shear_rotation; - local_shear_scaling = S; - - // Inherit type handler - we don't care about T here, just reordering RSrs etc. - Transform3D global_rotation_scale; - if (inherit_type == FBXDocParser::Transform_RrSs) { - global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling; - } else if (inherit_type == FBXDocParser::Transform_RSrs) { - global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling; - } else if (inherit_type == FBXDocParser::Transform_Rrs) { - Transform3D parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.affine_inverse(); - global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling; - } - Transform3D local_transform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse(); - //Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin); - - ERR_FAIL_COND_V_MSG(local_transform.basis.determinant() == 0, Transform3D(), "Det == 0 prevented in scene file"); - - // manual hack to force SSC not to be compensated for - until we can handle it properly with tests - return parent_global_xform * local_transform; -} - -void PivotTransform::ComputePivotTransform() { - Transform3D T, Roff, Rp, Soff, Sp, S; - - // Here I assume this is the operation which needs done. - // Its WorldTransform * V - - // Origin pivots - T.set_origin(translation); - Roff.set_origin(rotation_offset); - Rp.set_origin(rotation_pivot); - Soff.set_origin(scaling_offset); - Sp.set_origin(scaling_pivot); - - // Scaling node - if (!scaling.is_equal_approx(Vector3())) { - S.scale(scaling); - } else { - S.scale(Vector3(1, 1, 1)); - } - Local_Scaling_Matrix = S; // copy for when node / child is looking for the value of this. - - // Rotation pivots - Transform3D Rpre = Transform3D(pre_rotation); - Transform3D R = Transform3D(rotation); - Transform3D Rpost = Transform3D(post_rotation); - - Transform3D parent_global_xform; - Transform3D parent_local_scaling_m; - - if (parent_transform.is_valid()) { - parent_global_xform = parent_transform->GlobalTransform; - parent_local_scaling_m = parent_transform->Local_Scaling_Matrix; - } - - Transform3D local_rotation_m, parent_global_rotation_m; - Quaternion parent_global_rotation = parent_global_xform.basis.get_rotation_quaternion(); - parent_global_rotation_m.basis.set_quaternion(parent_global_rotation); - local_rotation_m = Rpre * R * Rpost; - - //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quaternion().normalized()); - - Transform3D local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation; - Vector3 parent_translation = parent_global_xform.get_origin(); - parent_shear_translation.origin = parent_translation; - parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform; - parent_shear_scaling = parent_global_rotation_m.affine_inverse() * parent_shear_rotation; - local_shear_scaling = S; - - // Inherit type handler - we don't care about T here, just reordering RSrs etc. - Transform3D global_rotation_scale; - if (inherit_type == FBXDocParser::Transform_RrSs) { - global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling; - } else if (inherit_type == FBXDocParser::Transform_RSrs) { - global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling; - } else if (inherit_type == FBXDocParser::Transform_Rrs) { - Transform3D parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.inverse(); - global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling; - } - LocalTransform = Transform3D(); - LocalTransform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse(); - - ERR_FAIL_COND_MSG(LocalTransform.basis.determinant() == 0, "invalid scale reset"); - - Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin); - GlobalTransform = Transform3D(); - //GlobalTransform = parent_global_xform * LocalTransform; - Transform3D global_origin = Transform3D(Basis(), parent_translation); - GlobalTransform = (global_origin * local_translation_pivoted) * global_rotation_scale; - - ImportUtils::debug_xform("local xform calculation", LocalTransform); - print_verbose("scale of node: " + S.basis.get_scale_local()); - print_verbose("---------------------------------------------------------------"); -} - -void PivotTransform::Execute() { - ReadTransformChain(); - ComputePivotTransform(); - - ImportUtils::debug_xform("global xform: ", GlobalTransform); - - if (LocalTransform.basis.determinant() == 0) { - print_error("Serious det == 0!"); - } - - if (GlobalTransform.basis.determinant() == 0) { - print_error("Serious! node has det == 0!"); - } - - computed_global_xform = true; -} diff --git a/modules/fbx/data/pivot_transform.h b/modules/fbx/data/pivot_transform.h deleted file mode 100644 index df97c8db57..0000000000 --- a/modules/fbx/data/pivot_transform.h +++ /dev/null @@ -1,115 +0,0 @@ -/*************************************************************************/ -/* pivot_transform.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef PIVOT_TRANSFORM_H -#define PIVOT_TRANSFORM_H - -#include "core/math/transform_3d.h" -#include "core/object/ref_counted.h" - -#include "model_abstraction.h" - -#include "fbx_parser/FBXDocument.h" -#include "tools/import_utils.h" - -enum TransformationComp { - TransformationComp_Translation, - TransformationComp_Scaling, - TransformationComp_Rotation, - TransformationComp_RotationOffset, - TransformationComp_RotationPivot, - TransformationComp_PreRotation, - TransformationComp_PostRotation, - TransformationComp_ScalingOffset, - TransformationComp_ScalingPivot, - TransformationComp_GeometricTranslation, - TransformationComp_GeometricRotation, - TransformationComp_GeometricScaling, - TransformationComp_MAXIMUM -}; -// Abstract away pivot data so its simpler to handle -struct PivotTransform : RefCounted, ModelAbstraction { - // at the end we want to keep geometric_ everything, post and pre rotation - // these are used during animation data processing / keyframe ingestion the rest can be simplified down / out. - Quaternion pre_rotation = Quaternion(); - Quaternion post_rotation = Quaternion(); - Quaternion rotation = Quaternion(); - Quaternion geometric_rotation = Quaternion(); - Vector3 rotation_pivot = Vector3(); - Vector3 rotation_offset = Vector3(); - Vector3 scaling_offset = Vector3(1.0, 1.0, 1.0); - Vector3 scaling_pivot = Vector3(1.0, 1.0, 1.0); - Vector3 translation = Vector3(); - Vector3 scaling = Vector3(1.0, 1.0, 1.0); - Vector3 geometric_scaling = Vector3(1.0, 1.0, 1.0); - Vector3 geometric_translation = Vector3(); - - Vector3 raw_rotation = Vector3(); - Vector3 raw_post_rotation = Vector3(); - Vector3 raw_pre_rotation = Vector3(); - - /* Read pivots from the document */ - void ReadTransformChain(); - - void debug_pivot_xform(String p_name) { - print_verbose("debugging node name: " + p_name); - print_verbose("raw rotation: " + raw_rotation * (180 / Math_PI)); - print_verbose("raw pre_rotation " + raw_pre_rotation * (180 / Math_PI)); - print_verbose("raw post_rotation " + raw_post_rotation * (180 / Math_PI)); - } - - Transform3D ComputeGlobalTransform(Transform3D t) const; - Transform3D ComputeLocalTransform(Transform3D t) const; - Transform3D ComputeGlobalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const; - Transform3D ComputeLocalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const; - - /* Extract into xforms and calculate once */ - void ComputePivotTransform(); - - /* Execute the command for the pivot generation */ - void Execute(); - - void set_parent(Ref<PivotTransform> p_parent) { - parent_transform = p_parent; - } - - bool computed_global_xform = false; - Ref<PivotTransform> parent_transform = Ref<PivotTransform>(); - //Transform chain[TransformationComp_MAXIMUM]; - - // cached for later use - Transform3D GlobalTransform = Transform3D(); - Transform3D LocalTransform = Transform3D(); - Transform3D Local_Scaling_Matrix = Transform3D(); // used for inherit type. - Transform3D GeometricTransform = Transform3D(); // 3DS max only - FBXDocParser::TransformInheritance inherit_type = FBXDocParser::TransformInheritance_MAX; // maya fbx requires this - sorry <3 -}; - -#endif // PIVOT_TRANSFORM_H |