1 /* 2 Open Asset Import Library (assimp) 3 ---------------------------------------------------------------------- 4 5 Copyright (c) 2006-2021, 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 is managed by the caller, via the PotentialNode struct. 175 */ 176 struct PotentialNode; 177 bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<PotentialNode>& output_nodes, std::vector<PotentialNode>& post_output_nodes); 178 179 // ------------------------------------------------------------------------------------------------ 180 void SetupNodeMetadata(const Model& model, aiNode& nd); 181 182 // ------------------------------------------------------------------------------------------------ 183 void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, 184 const aiMatrix4x4 &absolute_transform); 185 186 // ------------------------------------------------------------------------------------------------ 187 // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed 188 std::vector<unsigned int> 189 ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, 190 const aiMatrix4x4 &absolute_transform); 191 192 // ------------------------------------------------------------------------------------------------ 193 std::vector<unsigned int> ConvertLine(const LineGeometry& line, 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 MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, 224 aiNode *parent = nullptr, unsigned int materialIndex = NO_MATERIAL_SEPARATION, 225 std::vector<unsigned int> *outputVertStartIndices = nullptr); 226 227 // ------------------------------------------------------------------------------------------------ 228 void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl, 229 std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices, 230 std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform, 231 aiNode *parent ); 232 233 // ------------------------------------------------------------------------------------------------ 234 void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, 235 MatIndexArray::value_type materialIndex); 236 237 // ------------------------------------------------------------------------------------------------ 238 unsigned int GetDefaultMaterial(); 239 240 // ------------------------------------------------------------------------------------------------ 241 // Material -> aiMaterial 242 unsigned int ConvertMaterial(const Material& material, const MeshGeometry* const mesh); 243 244 // ------------------------------------------------------------------------------------------------ 245 // Video -> aiTexture 246 unsigned int ConvertVideo(const Video& video); 247 248 // ------------------------------------------------------------------------------------------------ 249 // convert embedded texture if necessary and return actual texture path 250 aiString GetTexturePath(const Texture* tex); 251 252 // ------------------------------------------------------------------------------------------------ 253 void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, 254 const std::string& propName, 255 aiTextureType target, const MeshGeometry* const mesh); 256 257 // ------------------------------------------------------------------------------------------------ 258 void TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, 259 const std::string& propName, 260 aiTextureType target, const MeshGeometry* const mesh); 261 262 // ------------------------------------------------------------------------------------------------ 263 void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh); 264 265 // ------------------------------------------------------------------------------------------------ 266 void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh); 267 268 // ------------------------------------------------------------------------------------------------ 269 aiColor3D GetColorPropertyFromMaterial(const PropertyTable& props, const std::string& baseName, 270 bool& result); 271 aiColor3D GetColorPropertyFactored(const PropertyTable& props, const std::string& colorName, 272 const std::string& factorName, bool& result, bool useTemplate = true); 273 aiColor3D GetColorProperty(const PropertyTable& props, const std::string& colorName, 274 bool& result, bool useTemplate = true); 275 276 // ------------------------------------------------------------------------------------------------ 277 void SetShadingPropertiesCommon(aiMaterial* out_mat, const PropertyTable& props); 278 void SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTable& props, const TextureMap& textures, const MeshGeometry* const mesh); 279 280 // ------------------------------------------------------------------------------------------------ 281 // get the number of fps for a FrameRate enumerated value 282 static double FrameRateToDouble(FileGlobalSettings::FrameRate fp, double customFPSVal = -1.0); 283 284 // ------------------------------------------------------------------------------------------------ 285 // convert animation data to aiAnimation et al 286 void ConvertAnimations(); 287 288 // ------------------------------------------------------------------------------------------------ 289 // takes a fbx node name and returns the identifier to be used in the assimp output scene. 290 // the function is guaranteed to provide consistent results over multiple invocations 291 // UNLESS RenameNode() is called for a particular node name. 292 std::string FixNodeName(const std::string& name); 293 std::string FixAnimMeshName(const std::string& name); 294 295 typedef std::map<const AnimationCurveNode*, const AnimationLayer*> LayerMap; 296 297 // XXX: better use multi_map .. 298 typedef std::map<std::string, std::vector<const AnimationCurveNode*> > NodeMap; 299 300 // ------------------------------------------------------------------------------------------------ 301 void ConvertAnimationStack(const AnimationStack& st); 302 303 // ------------------------------------------------------------------------------------------------ 304 void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node); 305 306 // ------------------------------------------------------------------------------------------------ 307 void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims, 308 const std::string& fixed_name, 309 const std::vector<const AnimationCurveNode*>& curves, 310 const LayerMap& layer_map, 311 int64_t start, int64_t stop, 312 double& max_time, 313 double& min_time); 314 315 // ------------------------------------------------------------------------------------------------ 316 bool IsRedundantAnimationData(const Model& target, 317 TransformationComp comp, 318 const std::vector<const AnimationCurveNode*>& curves); 319 320 // ------------------------------------------------------------------------------------------------ 321 aiNodeAnim* GenerateRotationNodeAnim(const std::string& name, 322 const Model& target, 323 const std::vector<const AnimationCurveNode*>& curves, 324 const LayerMap& layer_map, 325 int64_t start, int64_t stop, 326 double& max_time, 327 double& min_time); 328 329 // ------------------------------------------------------------------------------------------------ 330 aiNodeAnim* GenerateScalingNodeAnim(const std::string& name, 331 const Model& /*target*/, 332 const std::vector<const AnimationCurveNode*>& curves, 333 const LayerMap& layer_map, 334 int64_t start, int64_t stop, 335 double& max_time, 336 double& min_time); 337 338 // ------------------------------------------------------------------------------------------------ 339 aiNodeAnim* GenerateTranslationNodeAnim(const std::string& name, 340 const Model& /*target*/, 341 const std::vector<const AnimationCurveNode*>& curves, 342 const LayerMap& layer_map, 343 int64_t start, int64_t stop, 344 double& max_time, 345 double& min_time, 346 bool inverse = false); 347 348 // ------------------------------------------------------------------------------------------------ 349 // generate node anim, extracting only Rotation, Scaling and Translation from the given chain 350 aiNodeAnim* GenerateSimpleNodeAnim(const std::string& name, 351 const Model& target, 352 NodeMap::const_iterator chain[TransformationComp_MAXIMUM], 353 NodeMap::const_iterator iterEnd, 354 int64_t start, int64_t stop, 355 double& maxTime, 356 double& minTime); 357 358 // key (time), value, mapto (component index) 359 typedef std::tuple<std::shared_ptr<KeyTimeList>, std::shared_ptr<KeyValueList>, unsigned int > KeyFrameList; 360 typedef std::vector<KeyFrameList> KeyFrameListList; 361 362 // ------------------------------------------------------------------------------------------------ 363 KeyFrameListList GetKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop); 364 KeyFrameListList GetRotationKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop); 365 366 // ------------------------------------------------------------------------------------------------ 367 KeyTimeList GetKeyTimeList(const KeyFrameListList& inputs); 368 369 // ------------------------------------------------------------------------------------------------ 370 void InterpolateKeys(aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, 371 const aiVector3D& def_value, 372 double& max_time, 373 double& min_time); 374 375 // ------------------------------------------------------------------------------------------------ 376 void InterpolateKeys(aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, 377 const aiVector3D& def_value, 378 double& maxTime, 379 double& minTime, 380 Model::RotOrder order); 381 382 // ------------------------------------------------------------------------------------------------ 383 // euler xyz -> quat 384 aiQuaternion EulerToQuaternion(const aiVector3D& rot, Model::RotOrder order); 385 386 // ------------------------------------------------------------------------------------------------ 387 void ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/, 388 int64_t start, int64_t stop, 389 double& maxTime, 390 double& minTime); 391 392 // ------------------------------------------------------------------------------------------------ 393 void ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, 394 const LayerMap& /*layers*/, 395 int64_t start, int64_t stop, 396 double& maxTime, 397 double& minTime); 398 399 // ------------------------------------------------------------------------------------------------ 400 void ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, 401 const LayerMap& /*layers*/, 402 int64_t start, int64_t stop, 403 double& maxTime, 404 double& minTime, 405 Model::RotOrder order); 406 407 // ------------------------------------------------------------------------------------------------ 408 // Copy global geometric data and some information about the source asset into scene metadata. 409 void ConvertGlobalSettings(); 410 411 // ------------------------------------------------------------------------------------------------ 412 // copy generated meshes, animations, lights, cameras and textures to the output scene 413 void TransferDataToScene(); 414 415 // ------------------------------------------------------------------------------------------------ 416 // FBX file could have embedded textures not connected to anything 417 void ConvertOrphanedEmbeddedTextures(); 418 419 private: 420 // 0: not assigned yet, others: index is value - 1 421 unsigned int defaultMaterialIndex; 422 423 std::vector<aiMesh*> mMeshes; 424 std::vector<aiMaterial*> materials; 425 std::vector<aiAnimation*> animations; 426 std::vector<aiLight*> lights; 427 std::vector<aiCamera*> cameras; 428 std::vector<aiTexture*> textures; 429 430 using MaterialMap = std::fbx_unordered_map<const Material*, unsigned int>; 431 MaterialMap materials_converted; 432 433 using VideoMap = std::fbx_unordered_map<const Video*, unsigned int>; 434 VideoMap textures_converted; 435 436 using MeshMap = std::fbx_unordered_map<const Geometry*, std::vector<unsigned int> >; 437 MeshMap meshes_converted; 438 439 // fixed node name -> which trafo chain components have animations? 440 using NodeAnimBitMap = std::fbx_unordered_map<std::string, unsigned int> ; 441 NodeAnimBitMap node_anim_chain_bits; 442 443 // number of nodes with the same name 444 using NodeNameCache = std::fbx_unordered_map<std::string, unsigned int>; 445 NodeNameCache mNodeNames; 446 447 // Deformer name is not the same as a bone name - it does contain the bone name though :) 448 // Deformer names in FBX are always unique in an FBX file. 449 std::map<const std::string, aiBone *> bone_map; 450 451 double anim_fps; 452 453 aiScene* const mSceneOut; 454 const FBX::Document& doc; 455 bool mRemoveEmptyBones; 456 static void BuildBoneList(aiNode *current_node, const aiNode *root_node, const aiScene *scene, 457 std::vector<aiBone*>& bones); 458 459 void BuildBoneStack(aiNode *current_node, const aiNode *root_node, const aiScene *scene, 460 const std::vector<aiBone *> &bones, 461 std::map<aiBone *, aiNode *> &bone_stack, 462 std::vector<aiNode*> &node_stack ); 463 464 static void BuildNodeList(aiNode *current_node, std::vector<aiNode *> &nodes); 465 466 static aiNode *GetNodeFromStack(const aiString &node_name, std::vector<aiNode *> &nodes); 467 468 static aiNode *GetArmatureRoot(aiNode *bone_node, std::vector<aiBone*> &bone_list); 469 470 static bool IsBoneNode(const aiString &bone_name, std::vector<aiBone *> &bones); 471 }; 472 473 } 474 } 475 476 #endif // INCLUDED_AI_FBX_CONVERTER_H 477