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