import_utils.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*************************************************************************/
  2. /* import_utils.h */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #ifndef IMPORT_UTILS_FBX_IMPORTER_H
  31. #define IMPORT_UTILS_FBX_IMPORTER_H
  32. #include "core/io/image_loader.h"
  33. #include "data/import_state.h"
  34. #include "fbx_parser/FBXDocument.h"
  35. #include <string>
  36. #define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  37. /**
  38. * Import Utils
  39. * Conversion tools / glue code to convert from FBX to Godot
  40. */
  41. class ImportUtils {
  42. public:
  43. /// Convert a vector from degrees to radians.
  44. static Vector3 deg2rad(const Vector3 &p_rotation);
  45. /// Convert a vector from radians to degrees.
  46. static Vector3 rad2deg(const Vector3 &p_rotation);
  47. /// Converts rotation order vector (in rad) to quaternion.
  48. static Basis EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
  49. /// Converts rotation order vector (in rad) to quaternion.
  50. static Quat EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
  51. /// Converts basis into rotation order vector (in rad).
  52. static Vector3 BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation);
  53. /// Converts quaternion into rotation order vector (in rad).
  54. static Vector3 QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quat &p_rotation);
  55. static void debug_xform(String name, const Transform &t) {
  56. print_verbose(name + " " + t.origin + " rotation: " + (t.basis.get_euler() * (180 / Math_PI)));
  57. }
  58. static String FBXNodeToName(const std::string &name) {
  59. // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if
  60. // this causes ambiguities, well possible between empty identifiers,
  61. // such as "Model::" and ""). Make sure the behaviour is consistent
  62. // across multiple calls to FixNodeName().
  63. // We must remove this from the name
  64. // Some bones have this
  65. // SubDeformer::
  66. // Meshes, Joints have this, some other IK elements too.
  67. // Model::
  68. String node_name = String(name.c_str());
  69. if (node_name.substr(0, 7) == "Model::") {
  70. node_name = node_name.substr(7, node_name.length() - 7);
  71. return node_name.replace(":", "");
  72. }
  73. if (node_name.substr(0, 13) == "SubDeformer::") {
  74. node_name = node_name.substr(13, node_name.length() - 13);
  75. return node_name.replace(":", "");
  76. }
  77. if (node_name.substr(0, 11) == "AnimStack::") {
  78. node_name = node_name.substr(11, node_name.length() - 11);
  79. return node_name.replace(":", "");
  80. }
  81. if (node_name.substr(0, 15) == "AnimCurveNode::") {
  82. node_name = node_name.substr(15, node_name.length() - 15);
  83. return node_name.replace(":", "");
  84. }
  85. if (node_name.substr(0, 11) == "AnimCurve::") {
  86. node_name = node_name.substr(11, node_name.length() - 11);
  87. return node_name.replace(":", "");
  88. }
  89. if (node_name.substr(0, 10) == "Geometry::") {
  90. node_name = node_name.substr(10, node_name.length() - 10);
  91. return node_name.replace(":", "");
  92. }
  93. if (node_name.substr(0, 10) == "Material::") {
  94. node_name = node_name.substr(10, node_name.length() - 10);
  95. return node_name.replace(":", "");
  96. }
  97. if (node_name.substr(0, 9) == "Texture::") {
  98. node_name = node_name.substr(9, node_name.length() - 9);
  99. return node_name.replace(":", "");
  100. }
  101. return node_name.replace(":", "");
  102. }
  103. static std::string FBXAnimMeshName(const std::string &name) {
  104. if (name.length()) {
  105. size_t indexOf = name.find_first_of("::");
  106. if (indexOf != std::string::npos && indexOf < name.size() - 2) {
  107. return name.substr(indexOf + 2);
  108. }
  109. }
  110. return name.length() ? name : "AnimMesh";
  111. }
  112. static Vector3 safe_import_vector3(const Vector3 &p_vec) {
  113. Vector3 vector = p_vec;
  114. if (Math::is_equal_approx(0, vector.x)) {
  115. vector.x = 0;
  116. }
  117. if (Math::is_equal_approx(0, vector.y)) {
  118. vector.y = 0;
  119. }
  120. if (Math::is_equal_approx(0, vector.z)) {
  121. vector.z = 0;
  122. }
  123. return vector;
  124. }
  125. static void debug_xform(String name, const Basis &t) {
  126. //print_verbose(name + " rotation: " + (t.get_euler() * (180 / Math_PI)));
  127. }
  128. static Vector3 FixAxisConversions(Vector3 input) {
  129. return Vector3(input.x, input.y, input.z);
  130. }
  131. static void AlignMeshAxes(std::vector<Vector3> &vertex_data) {
  132. for (size_t x = 0; x < vertex_data.size(); x++) {
  133. vertex_data[x] = FixAxisConversions(vertex_data[x]);
  134. }
  135. }
  136. struct AssetImportFbx {
  137. enum ETimeMode {
  138. TIME_MODE_DEFAULT = 0,
  139. TIME_MODE_120 = 1,
  140. TIME_MODE_100 = 2,
  141. TIME_MODE_60 = 3,
  142. TIME_MODE_50 = 4,
  143. TIME_MODE_48 = 5,
  144. TIME_MODE_30 = 6,
  145. TIME_MODE_30_DROP = 7,
  146. TIME_MODE_NTSC_DROP_FRAME = 8,
  147. TIME_MODE_NTSC_FULL_FRAME = 9,
  148. TIME_MODE_PAL = 10,
  149. TIME_MODE_CINEMA = 11,
  150. TIME_MODE_1000 = 12,
  151. TIME_MODE_CINEMA_ND = 13,
  152. TIME_MODE_CUSTOM = 14,
  153. TIME_MODE_TIME_MODE_COUNT = 15
  154. };
  155. enum UpAxis {
  156. UP_VECTOR_AXIS_X = 1,
  157. UP_VECTOR_AXIS_Y = 2,
  158. UP_VECTOR_AXIS_Z = 3
  159. };
  160. enum FrontAxis {
  161. FRONT_PARITY_EVEN = 1,
  162. FRONT_PARITY_ODD = 2,
  163. };
  164. enum CoordAxis {
  165. COORD_RIGHT = 0,
  166. COORD_LEFT = 1
  167. };
  168. };
  169. /** Get fbx fps for time mode meta data
  170. */
  171. static float get_fbx_fps(int32_t time_mode) {
  172. switch (time_mode) {
  173. case AssetImportFbx::TIME_MODE_DEFAULT:
  174. return 24;
  175. case AssetImportFbx::TIME_MODE_120:
  176. return 120;
  177. case AssetImportFbx::TIME_MODE_100:
  178. return 100;
  179. case AssetImportFbx::TIME_MODE_60:
  180. return 60;
  181. case AssetImportFbx::TIME_MODE_50:
  182. return 50;
  183. case AssetImportFbx::TIME_MODE_48:
  184. return 48;
  185. case AssetImportFbx::TIME_MODE_30:
  186. return 30;
  187. case AssetImportFbx::TIME_MODE_30_DROP:
  188. return 30;
  189. case AssetImportFbx::TIME_MODE_NTSC_DROP_FRAME:
  190. return 29.9700262f;
  191. case AssetImportFbx::TIME_MODE_NTSC_FULL_FRAME:
  192. return 29.9700262f;
  193. case AssetImportFbx::TIME_MODE_PAL:
  194. return 25;
  195. case AssetImportFbx::TIME_MODE_CINEMA:
  196. return 24;
  197. case AssetImportFbx::TIME_MODE_1000:
  198. return 1000;
  199. case AssetImportFbx::TIME_MODE_CINEMA_ND:
  200. return 23.976f;
  201. case AssetImportFbx::TIME_MODE_CUSTOM:
  202. return -1;
  203. }
  204. return 0;
  205. }
  206. static float get_fbx_fps(const FBXDocParser::FileGlobalSettings *FBXSettings) {
  207. int time_mode = FBXSettings->TimeMode();
  208. // get the animation FPS
  209. float frames_per_second = get_fbx_fps(time_mode);
  210. // handle animation custom FPS time.
  211. if (time_mode == ImportUtils::AssetImportFbx::TIME_MODE_CUSTOM) {
  212. print_verbose("FBX Animation has custom FPS setting");
  213. frames_per_second = FBXSettings->CustomFrameRate();
  214. // not our problem this is the modeller, we can print as an error so they can fix the source.
  215. if (frames_per_second == 0) {
  216. print_error("Custom animation time in file is set to 0 value, animation won't play, please edit your file to correct the FPS value");
  217. }
  218. }
  219. return frames_per_second;
  220. }
  221. /**
  222. * Find hardcoded textures from assimp which could be in many different directories
  223. */
  224. /**
  225. * set_texture_mapping_mode
  226. * Helper to check the mapping mode of the texture (repeat, clamp and mirror)
  227. */
  228. // static void set_texture_mapping_mode(aiTextureMapMode *map_mode, Ref<ImageTexture> texture) {
  229. // ERR_FAIL_COND(texture.is_null());
  230. // ERR_FAIL_COND(map_mode == NULL);
  231. // aiTextureMapMode tex_mode = map_mode[0];
  232. // int32_t flags = Texture::FLAGS_DEFAULT;
  233. // if (tex_mode == aiTextureMapMode_Wrap) {
  234. // //Default
  235. // } else if (tex_mode == aiTextureMapMode_Clamp) {
  236. // flags = flags & ~Texture::FLAG_REPEAT;
  237. // } else if (tex_mode == aiTextureMapMode_Mirror) {
  238. // flags = flags | Texture::FLAG_MIRRORED_REPEAT;
  239. // }
  240. // texture->set_flags(flags);
  241. // }
  242. /**
  243. * Load or load from cache image :)
  244. * We need to upgrade this in the later version :) should not be hard
  245. */
  246. //static Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path){
  247. // Map<String, Ref<Image> >::Element *match = state.path_to_image_cache.find(p_path);
  248. // // if our cache contains this image then don't bother
  249. // if (match) {
  250. // return match->get();
  251. // }
  252. // Vector<String> split_path = p_path.get_basename().split("*");
  253. // if (split_path.size() == 2) {
  254. // size_t texture_idx = split_path[1].to_int();
  255. // ERR_FAIL_COND_V(texture_idx >= p_scene->mNumTextures, Ref<Image>());
  256. // aiTexture *tex = p_scene->mTextures[texture_idx];
  257. // String filename = AssimpUtils::get_raw_string_from_assimp(tex->mFilename);
  258. // filename = filename.get_file();
  259. // print_verbose("Open Asset Import: Loading embedded texture " + filename);
  260. // if (tex->mHeight == 0) {
  261. // if (tex->CheckFormat("png")) {
  262. // Ref<Image> img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
  263. // ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
  264. // state.path_to_image_cache.insert(p_path, img);
  265. // return img;
  266. // } else if (tex->CheckFormat("jpg")) {
  267. // Ref<Image> img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
  268. // ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
  269. // state.path_to_image_cache.insert(p_path, img);
  270. // return img;
  271. // } else if (tex->CheckFormat("dds")) {
  272. // ERR_FAIL_COND_V_MSG(true, Ref<Image>(), "Open Asset Import: Embedded dds not implemented");
  273. // }
  274. // } else {
  275. // Ref<Image> img;
  276. // img.instance();
  277. // PoolByteArray arr;
  278. // uint32_t size = tex->mWidth * tex->mHeight;
  279. // arr.resize(size);
  280. // memcpy(arr.write().ptr(), tex->pcData, size);
  281. // ERR_FAIL_COND_V(arr.size() % 4 != 0, Ref<Image>());
  282. // //ARGB8888 to RGBA8888
  283. // for (int32_t i = 0; i < arr.size() / 4; i++) {
  284. // arr.write().ptr()[(4 * i) + 3] = arr[(4 * i) + 0];
  285. // arr.write().ptr()[(4 * i) + 0] = arr[(4 * i) + 1];
  286. // arr.write().ptr()[(4 * i) + 1] = arr[(4 * i) + 2];
  287. // arr.write().ptr()[(4 * i) + 2] = arr[(4 * i) + 3];
  288. // }
  289. // img->create(tex->mWidth, tex->mHeight, true, Image::FORMAT_RGBA8, arr);
  290. // ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
  291. // state.path_to_image_cache.insert(p_path, img);
  292. // return img;
  293. // }
  294. // return Ref<Image>();
  295. // } else {
  296. // Ref<Texture> texture = ResourceLoader::load(p_path);
  297. // ERR_FAIL_COND_V(texture.is_null(), Ref<Image>());
  298. // Ref<Image> image = texture->get_data();
  299. // ERR_FAIL_COND_V(image.is_null(), Ref<Image>());
  300. // state.path_to_image_cache.insert(p_path, image);
  301. // return image;
  302. // }
  303. // return Ref<Image>();
  304. //}
  305. // /* create texture from assimp data, if found in path */
  306. // static bool CreateAssimpTexture(
  307. // AssimpImporter::ImportState &state,
  308. // aiString texture_path,
  309. // String &filename,
  310. // String &path,
  311. // AssimpImageData &image_state) {
  312. // filename = get_raw_string_from_assimp(texture_path);
  313. // path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
  314. // bool found = false;
  315. // find_texture_path(state.path, path, found);
  316. // if (found) {
  317. // image_state.raw_image = AssimpUtils::load_image(state, state.assimp_scene, path);
  318. // if (image_state.raw_image.is_valid()) {
  319. // image_state.texture.instance();
  320. // image_state.texture->create_from_image(image_state.raw_image);
  321. // image_state.texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
  322. // return true;
  323. // }
  324. // }
  325. // return false;
  326. // }
  327. // /** GetAssimpTexture
  328. // * Designed to retrieve textures for you
  329. // */
  330. // static bool GetAssimpTexture(
  331. // AssimpImporter::ImportState &state,
  332. // aiMaterial *ai_material,
  333. // aiTextureType texture_type,
  334. // String &filename,
  335. // String &path,
  336. // AssimpImageData &image_state) {
  337. // aiString ai_filename = aiString();
  338. // if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, NULL, NULL, NULL, NULL, image_state.map_mode)) {
  339. // return CreateAssimpTexture(state, ai_filename, filename, path, image_state);
  340. // }
  341. // return false;
  342. // }
  343. };
  344. // Apply the transforms so the basis will have scale 1.
  345. Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale);
  346. /// Uses the Newell's method to compute any polygon normal.
  347. /// The polygon must be at least size of 3 or bigger.
  348. Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices);
  349. #endif // IMPORT_UTILS_FBX_IMPORTER_H