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