1 /* 2 Open Asset Import Library (assimp) 3 ---------------------------------------------------------------------- 4 5 Copyright (c) 2006-2019, assimp team 6 7 8 All rights reserved. 9 10 Redistribution and use of this software in source and binary forms, 11 with or without modification, are permitted provided that the 12 following conditions are met: 13 14 * Redistributions of source code must retain the above 15 copyright notice, this list of conditions and the 16 following disclaimer. 17 18 * Redistributions in binary form must reproduce the above 19 copyright notice, this list of conditions and the 20 following disclaimer in the documentation and/or other 21 materials provided with the distribution. 22 23 * Neither the name of the assimp team, nor the names of its 24 contributors may be used to endorse or promote products 25 derived from this software without specific prior 26 written permission of the assimp team. 27 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 40 ---------------------------------------------------------------------- 41 */ 42 43 /** @file FBXDConverter.h 44 * @brief FBX DOM to aiScene conversion 45 */ 46 #ifndef INCLUDED_AI_FBX_CONVERTER_H 47 #define INCLUDED_AI_FBX_CONVERTER_H 48 49 #include "FBXParser.h" 50 #include "FBXMeshGeometry.h" 51 #include "FBXDocument.h" 52 #include "FBXUtil.h" 53 #include "FBXProperties.h" 54 #include "FBXImporter.h" 55 56 #include <assimp/anim.h> 57 #include <assimp/material.h> 58 #include <assimp/light.h> 59 #include <assimp/texture.h> 60 #include <assimp/camera.h> 61 #include <assimp/StringComparison.h> 62 #include <unordered_map> 63 #include <unordered_set> 64 65 struct aiScene; 66 struct aiNode; 67 struct aiMaterial; 68 69 struct morphKeyData { 70 std::vector<unsigned int> values; 71 std::vector<float> weights; 72 }; 73 typedef std::map<int64_t, morphKeyData*> morphAnimData; 74 75 namespace Assimp { 76 namespace FBX { 77 78 class Document; 79 /** 80 * Convert a FBX #Document to #aiScene 81 * @param out Empty scene to be populated 82 * @param doc Parsed FBX document 83 * @param removeEmptyBones Will remove bones, which do not have any references to vertices. 84 */ 85 void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones); 86 87 /** Dummy class to encapsulate the conversion process */ 88 class FBXConverter { 89 public: 90 /** 91 * The different parts that make up the final local transformation of a fbx-node 92 */ 93 enum TransformationComp { 94 TransformationComp_GeometricScalingInverse = 0, 95 TransformationComp_GeometricRotationInverse, 96 TransformationComp_GeometricTranslationInverse, 97 TransformationComp_Translation, 98 TransformationComp_RotationOffset, 99 TransformationComp_RotationPivot, 100 TransformationComp_PreRotation, 101 TransformationComp_Rotation, 102 TransformationComp_PostRotation, 103 TransformationComp_RotationPivotInverse, 104 TransformationComp_ScalingOffset, 105 TransformationComp_ScalingPivot, 106 TransformationComp_Scaling, 107 TransformationComp_ScalingPivotInverse, 108 TransformationComp_GeometricTranslation, 109 TransformationComp_GeometricRotation, 110 TransformationComp_GeometricScaling, 111 112 TransformationComp_MAXIMUM 113 }; 114 115 public: 116 FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones); 117 ~FBXConverter(); 118 119 private: 120 // ------------------------------------------------------------------------------------------------ 121 // find scene root and trigger recursive scene conversion 122 void ConvertRootNode(); 123 124 // ------------------------------------------------------------------------------------------------ 125 // collect and assign child nodes 126 void ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node); 127 128 // ------------------------------------------------------------------------------------------------ 129 void ConvertLights(const Model& model, const std::string &orig_name ); 130 131 // ------------------------------------------------------------------------------------------------ 132 void ConvertCameras(const Model& model, const std::string &orig_name ); 133 134 // ------------------------------------------------------------------------------------------------ 135 void ConvertLight( const Light& light, const std::string &orig_name ); 136 137 // ------------------------------------------------------------------------------------------------ 138 void ConvertCamera( const Camera& cam, const std::string &orig_name ); 139 140 // ------------------------------------------------------------------------------------------------ 141 void GetUniqueName( const std::string &name, std::string& uniqueName ); 142 143 // ------------------------------------------------------------------------------------------------ 144 // this returns unified names usable within assimp identifiers (i.e. no space characters - 145 // while these would be allowed, they are a potential trouble spot so better not use them). 146 const char* NameTransformationComp(TransformationComp comp); 147 148 // ------------------------------------------------------------------------------------------------ 149 // Returns an unique name for a node or traverses up a hierarchy until a non-empty name is found and 150 // then makes this name unique 151 std::string MakeUniqueNodeName(const Model* const model, const aiNode& parent); 152 153 // ------------------------------------------------------------------------------------------------ 154 // note: this returns the REAL fbx property names 155 const char* NameTransformationCompProperty(TransformationComp comp); 156 157 // ------------------------------------------------------------------------------------------------ 158 aiVector3D TransformationCompDefaultValue(TransformationComp comp); 159 160 // ------------------------------------------------------------------------------------------------ 161 void GetRotationMatrix(Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out); 162 // ------------------------------------------------------------------------------------------------ 163 /** 164 * checks if a node has more than just scaling, rotation and translation components 165 */ 166 bool NeedsComplexTransformationChain(const Model& model); 167 168 // ------------------------------------------------------------------------------------------------ 169 // note: name must be a FixNodeName() result 170 std::string NameTransformationChainNode(const std::string& name, TransformationComp comp); 171 172 // ------------------------------------------------------------------------------------------------ 173 /** 174 * note: memory for output_nodes will be managed by the caller 175 */ 176 bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes); 177 178 // ------------------------------------------------------------------------------------------------ 179 void SetupNodeMetadata(const Model& model, aiNode& nd); 180 181 // ------------------------------------------------------------------------------------------------ 182 void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, 183 const aiMatrix4x4 &absolute_transform); 184 185 // ------------------------------------------------------------------------------------------------ 186 // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed 187 std::vector<unsigned int> 188 ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, 189 const aiMatrix4x4 &absolute_transform); 190 191 // ------------------------------------------------------------------------------------------------ 192 std::vector<unsigned int> ConvertLine(const LineGeometry& line, const Model& model, 193 aiNode *parent, aiNode *root_node); 194 195 // ------------------------------------------------------------------------------------------------ 196 aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent); 197 198 // ------------------------------------------------------------------------------------------------ 199 unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, 200 const aiMatrix4x4 &absolute_transform, aiNode *parent, 201 aiNode *root_node); 202 203 // ------------------------------------------------------------------------------------------------ 204 std::vector<unsigned int> 205 ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, 206 const aiMatrix4x4 &absolute_transform); 207 208 // ------------------------------------------------------------------------------------------------ 209 unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, MatIndexArray::value_type index, 210 aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform); 211 212 // ------------------------------------------------------------------------------------------------ 213 static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits<unsigned int>::max() */ 214 static_cast<unsigned int>(-1); 215 216 // ------------------------------------------------------------------------------------------------ 217 /** 218 * - if materialIndex == NO_MATERIAL_SEPARATION, materials are not taken into 219 * account when determining which weights to include. 220 * - outputVertStartIndices is only used when a material index is specified, it gives for 221 * each output vertex the DOM index it maps to. 222 */ 223 void ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, 224 aiNode *parent = NULL, aiNode *root_node = NULL, 225 unsigned int materialIndex = NO_MATERIAL_SEPARATION, 226 std::vector<unsigned int> *outputVertStartIndices = NULL); 227 // lookup 228 static const aiNode* GetNodeByName( const aiString& name, aiNode *current_node ); 229 // ------------------------------------------------------------------------------------------------ 230 void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl, 231 std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices, 232 std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform, 233 aiNode *parent, aiNode *root_node); 234 235 // ------------------------------------------------------------------------------------------------ 236 void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, 237 MatIndexArray::value_type materialIndex); 238 239 // ------------------------------------------------------------------------------------------------ 240 unsigned int GetDefaultMaterial(); 241 242 // ------------------------------------------------------------------------------------------------ 243 // Material -> aiMaterial 244 unsigned int ConvertMaterial(const Material& material, const MeshGeometry* const mesh); 245 246 // ------------------------------------------------------------------------------------------------ 247 // Video -> aiTexture 248 unsigned int ConvertVideo(const Video& video); 249 250 // ------------------------------------------------------------------------------------------------ 251 // convert embedded texture if necessary and return actual texture path 252 aiString GetTexturePath(const Texture* tex); 253 254 // ------------------------------------------------------------------------------------------------ 255 void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, 256 const std::string& propName, 257 aiTextureType target, const MeshGeometry* const mesh); 258 259 // ------------------------------------------------------------------------------------------------ 260 void TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, 261 const std::string& propName, 262 aiTextureType target, const MeshGeometry* const mesh); 263 264 // ------------------------------------------------------------------------------------------------ 265 void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh); 266 267 // ------------------------------------------------------------------------------------------------ 268 void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh); 269 270 // ------------------------------------------------------------------------------------------------ 271 aiColor3D GetColorPropertyFromMaterial(const PropertyTable& props, const std::string& baseName, 272 bool& result); 273 aiColor3D GetColorPropertyFactored(const PropertyTable& props, const std::string& colorName, 274 const std::string& factorName, bool& result, bool useTemplate = true); 275 aiColor3D GetColorProperty(const PropertyTable& props, const std::string& colorName, 276 bool& result, bool useTemplate = true); 277 278 // ------------------------------------------------------------------------------------------------ 279 void SetShadingPropertiesCommon(aiMaterial* out_mat, const PropertyTable& props); 280 void SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTable& props, const TextureMap& textures, const MeshGeometry* const mesh); 281 282 // ------------------------------------------------------------------------------------------------ 283 // get the number of fps for a FrameRate enumerated value 284 static double FrameRateToDouble(FileGlobalSettings::FrameRate fp, double customFPSVal = -1.0); 285 286 // ------------------------------------------------------------------------------------------------ 287 // convert animation data to aiAnimation et al 288 void ConvertAnimations(); 289 290 // ------------------------------------------------------------------------------------------------ 291 // takes a fbx node name and returns the identifier to be used in the assimp output scene. 292 // the function is guaranteed to provide consistent results over multiple invocations 293 // UNLESS RenameNode() is called for a particular node name. 294 std::string FixNodeName(const std::string& name); 295 std::string FixAnimMeshName(const std::string& name); 296 297 typedef std::map<const AnimationCurveNode*, const AnimationLayer*> LayerMap; 298 299 // XXX: better use multi_map .. 300 typedef std::map<std::string, std::vector<const AnimationCurveNode*> > NodeMap; 301 302 // ------------------------------------------------------------------------------------------------ 303 void ConvertAnimationStack(const AnimationStack& st); 304 305 // ------------------------------------------------------------------------------------------------ 306 void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node); 307 308 // ------------------------------------------------------------------------------------------------ 309 void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims, 310 const std::string& fixed_name, 311 const std::vector<const AnimationCurveNode*>& curves, 312 const LayerMap& layer_map, 313 int64_t start, int64_t stop, 314 double& max_time, 315 double& min_time); 316 317 // ------------------------------------------------------------------------------------------------ 318 bool IsRedundantAnimationData(const Model& target, 319 TransformationComp comp, 320 const std::vector<const AnimationCurveNode*>& curves); 321 322 // ------------------------------------------------------------------------------------------------ 323 aiNodeAnim* GenerateRotationNodeAnim(const std::string& name, 324 const Model& target, 325 const std::vector<const AnimationCurveNode*>& curves, 326 const LayerMap& layer_map, 327 int64_t start, int64_t stop, 328 double& max_time, 329 double& min_time); 330 331 // ------------------------------------------------------------------------------------------------ 332 aiNodeAnim* GenerateScalingNodeAnim(const std::string& name, 333 const Model& /*target*/, 334 const std::vector<const AnimationCurveNode*>& curves, 335 const LayerMap& layer_map, 336 int64_t start, int64_t stop, 337 double& max_time, 338 double& min_time); 339 340 // ------------------------------------------------------------------------------------------------ 341 aiNodeAnim* GenerateTranslationNodeAnim(const std::string& name, 342 const Model& /*target*/, 343 const std::vector<const AnimationCurveNode*>& curves, 344 const LayerMap& layer_map, 345 int64_t start, int64_t stop, 346 double& max_time, 347 double& min_time, 348 bool inverse = false); 349 350 // ------------------------------------------------------------------------------------------------ 351 // generate node anim, extracting only Rotation, Scaling and Translation from the given chain 352 aiNodeAnim* GenerateSimpleNodeAnim(const std::string& name, 353 const Model& target, 354 NodeMap::const_iterator chain[TransformationComp_MAXIMUM], 355 NodeMap::const_iterator iter_end, 356 const LayerMap& layer_map, 357 int64_t start, int64_t stop, 358 double& max_time, 359 double& min_time, 360 bool reverse_order = false); 361 362 // key (time), value, mapto (component index) 363 typedef std::tuple<std::shared_ptr<KeyTimeList>, std::shared_ptr<KeyValueList>, unsigned int > KeyFrameList; 364 typedef std::vector<KeyFrameList> KeyFrameListList; 365 366 // ------------------------------------------------------------------------------------------------ 367 KeyFrameListList GetKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop); 368 369 // ------------------------------------------------------------------------------------------------ 370 KeyTimeList GetKeyTimeList(const KeyFrameListList& inputs); 371 372 // ------------------------------------------------------------------------------------------------ 373 void InterpolateKeys(aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, 374 const aiVector3D& def_value, 375 double& max_time, 376 double& min_time); 377 378 // ------------------------------------------------------------------------------------------------ 379 void InterpolateKeys(aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, 380 const aiVector3D& def_value, 381 double& maxTime, 382 double& minTime, 383 Model::RotOrder order); 384 385 // ------------------------------------------------------------------------------------------------ 386 void ConvertTransformOrder_TRStoSRT(aiQuatKey* out_quat, aiVectorKey* out_scale, 387 aiVectorKey* out_translation, 388 const KeyFrameListList& scaling, 389 const KeyFrameListList& translation, 390 const KeyFrameListList& rotation, 391 const KeyTimeList& times, 392 double& maxTime, 393 double& minTime, 394 Model::RotOrder order, 395 const aiVector3D& def_scale, 396 const aiVector3D& def_translate, 397 const aiVector3D& def_rotation); 398 399 // ------------------------------------------------------------------------------------------------ 400 // euler xyz -> quat 401 aiQuaternion EulerToQuaternion(const aiVector3D& rot, Model::RotOrder order); 402 403 // ------------------------------------------------------------------------------------------------ 404 void ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/, 405 int64_t start, int64_t stop, 406 double& maxTime, 407 double& minTime); 408 409 // ------------------------------------------------------------------------------------------------ 410 void ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, 411 const LayerMap& /*layers*/, 412 int64_t start, int64_t stop, 413 double& maxTime, 414 double& minTime); 415 416 // ------------------------------------------------------------------------------------------------ 417 void ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, 418 const LayerMap& /*layers*/, 419 int64_t start, int64_t stop, 420 double& maxTime, 421 double& minTime, 422 Model::RotOrder order); 423 424 // ------------------------------------------------------------------------------------------------ 425 // Copy global geometric data and some information about the source asset into scene metadata. 426 void ConvertGlobalSettings(); 427 428 // ------------------------------------------------------------------------------------------------ 429 // copy generated meshes, animations, lights, cameras and textures to the output scene 430 void TransferDataToScene(); 431 432 // ------------------------------------------------------------------------------------------------ 433 // FBX file could have embedded textures not connected to anything 434 void ConvertOrphantEmbeddedTextures(); 435 436 private: 437 // 0: not assigned yet, others: index is value - 1 438 unsigned int defaultMaterialIndex; 439 440 std::vector<aiMesh*> meshes; 441 std::vector<aiMaterial*> materials; 442 std::vector<aiAnimation*> animations; 443 std::vector<aiLight*> lights; 444 std::vector<aiCamera*> cameras; 445 std::vector<aiTexture*> textures; 446 447 using MaterialMap = std::fbx_unordered_map<const Material*, unsigned int>; 448 MaterialMap materials_converted; 449 450 using VideoMap = std::fbx_unordered_map<const Video, unsigned int>; 451 VideoMap textures_converted; 452 453 using MeshMap = std::fbx_unordered_map<const Geometry*, std::vector<unsigned int> >; 454 MeshMap meshes_converted; 455 456 // fixed node name -> which trafo chain components have animations? 457 using NodeAnimBitMap = std::fbx_unordered_map<std::string, unsigned int> ; 458 NodeAnimBitMap node_anim_chain_bits; 459 460 // number of nodes with the same name 461 using NodeNameCache = std::fbx_unordered_map<std::string, unsigned int>; 462 NodeNameCache mNodeNames; 463 464 // Deformer name is not the same as a bone name - it does contain the bone name though :) 465 // Deformer names in FBX are always unique in an FBX file. 466 std::map<const std::string, aiBone *> bone_map; 467 468 double anim_fps; 469 470 aiScene* const out; 471 const FBX::Document& doc; 472 473 static void BuildBoneList(aiNode *current_node, const aiNode *root_node, const aiScene *scene, 474 std::vector<aiBone*>& bones); 475 476 void BuildBoneStack(aiNode *current_node, const aiNode *root_node, const aiScene *scene, 477 const std::vector<aiBone *> &bones, 478 std::map<aiBone *, aiNode *> &bone_stack, 479 std::vector<aiNode*> &node_stack ); 480 481 static void BuildNodeList(aiNode *current_node, std::vector<aiNode *> &nodes); 482 483 static aiNode *GetNodeFromStack(const aiString &node_name, std::vector<aiNode *> &nodes); 484 485 static aiNode *GetArmatureRoot(aiNode *bone_node, std::vector<aiBone*> &bone_list); 486 487 static bool IsBoneNode(const aiString &bone_name, std::vector<aiBone *> &bones); 488 }; 489 490 } 491 } 492 493 #endif // INCLUDED_AI_FBX_CONVERTER_H 494