1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsFBXPrerequisites.h"
6#include "Importer/BsSpecificImporter.h"
7#include "RenderAPI/BsSubMesh.h"
8#include "BsFBXImportData.h"
9
10#define FBX_IMPORT_MAX_UV_LAYERS 2
11
12namespace bs
13{
14 /** @addtogroup FBX
15 * @{
16 */
17
18 struct AnimationSplitInfo;
19 class MorphShapes;
20
21 /** Importer implementation that handles FBX/OBJ/DAE/3DS file import by using the FBX SDK. */
22 class FBXImporter : public SpecificImporter
23 {
24 public:
25 FBXImporter();
26 virtual ~FBXImporter() = default;
27
28 /** @copydoc SpecificImporter::isExtensionSupported */
29 bool isExtensionSupported(const String& ext) const override;
30
31 /** @copydoc SpecificImporter::isMagicNumberSupported */
32 bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const override;
33
34 /** @copydoc SpecificImporter::getAsyncMode */
35 ImporterAsyncMode getAsyncMode() const override { return ImporterAsyncMode::Single; }
36
37 /** @copydoc SpecificImporter::import */
38 SPtr<Resource> import(const Path& filePath, SPtr<const ImportOptions> importOptions) override;
39
40 /** @copydoc SpecificImporter::importAll */
41 Vector<SubResourceRaw> importAll(const Path& filePath, SPtr<const ImportOptions> importOptions) override;
42
43 /** @copydoc SpecificImporter::createImportOptions */
44 SPtr<ImportOptions> createImportOptions() const override;
45 private:
46 /**
47 * Starts up FBX SDK. Must be called before any other operations. Outputs an FBX manager and FBX scene instances
48 * you should use in further operations. Returns false if the SDK wasn't started properly.
49 */
50 bool startUpSdk(FbxScene*& scene);
51
52 /** Shuts down FBX SDK. Must be called after any other operations. */
53 void shutDownSdk();
54
55 /**
56 * Reads the FBX file and outputs mesh data from the read file. Sub-mesh information will be output in @p subMeshes.
57 */
58 SPtr<RendererMeshData> importMeshData(const Path& filePath, SPtr<const ImportOptions> importOptions,
59 Vector<SubMesh>& subMeshes, Vector<FBXAnimationClipData>& animationClips, SPtr<Skeleton>& skeleton,
60 SPtr<MorphShapes>& morphShapes);
61
62 /**
63 * Loads the data from the file at the provided path into the provided FBX scene. Returns false if the file
64 * couldn't be loaded.
65 */
66 bool loadFBXFile(FbxScene* scene, const Path& filePath);
67
68 /**
69 * Parses an FBX scene. Find all meshes in the scene and returns mesh data object containing all vertices, indexes
70 * and other mesh information. Also outputs a sub-mesh array that allows you locate specific sub-meshes within the
71 * returned mesh data object. If requested animation and blend shape data is output as well.
72 */
73 void parseScene(FbxScene* scene, const FBXImportOptions& options, FBXImportScene& outputScene);
74
75 /**
76 * Parses an FBX mesh. Converts it from FBX SDK format into a mesh data object containing one or multiple sub-meshes.
77 */
78 void parseMesh(FbxMesh* mesh, FBXImportNode* parentNode, const FBXImportOptions& options, FBXImportScene& outputScene);
79
80 /** Imports blend shapes for all the meshes that are part of the scene. */
81 void importBlendShapes(FBXImportScene& scene, const FBXImportOptions& options);
82
83 /**
84 * Parses a single FBX blend shape frame. Converts it from FBX SDK format into a shape data object containing
85 * position and tangent frame.
86 */
87 void importBlendShapeFrame(FbxShape* shape, const FBXImportMesh& mesh, const FBXImportOptions& options, FBXBlendShapeFrame& outFrame);
88
89 /** Imports skinning information and bones for all meshes. */
90 void importSkin(FBXImportScene& scene, const FBXImportOptions& options);
91
92 /** Imports skinning information and bones for the specified mesh. */
93 void importSkin(FBXImportScene& scene, FbxSkin* skin, FBXImportMesh& mesh, const FBXImportOptions& options);
94
95 /** Imports all bone and blend shape animations from the FBX. */
96 void importAnimations(FbxScene* scene, FBXImportOptions& importOptions, FBXImportScene& importScene);
97
98 /**
99 * Imports all animations for the specified animation layer and outputs them in the provided clip. Child nodes will
100 * be iterated recursively.
101 */
102 void importAnimations(FbxAnimLayer* layer, FbxNode* node, FBXImportOptions& importOptions,
103 FBXAnimationClip& clip, FBXImportScene& importScene);
104
105 /** Bakes all FBX node transforms into standard translation-rotation-scale transform components. */
106 void bakeTransforms(FbxScene* scene);
107
108 /** Converts a single FBX animation curve into an engine curve format, resampling it if necessary. */
109 template<class T, int C>
110 TAnimationCurve<T> importCurve(FbxAnimCurve*(&fbxCurve)[C], float(&defaultValues)[C],
111 FBXImportOptions& importOptions, float clipStart, float clipEnd);
112
113 /** Converts FBX animation clips into engine-ready animation curve format. */
114 void convertAnimations(const Vector<FBXAnimationClip>& clips, const Vector<AnimationSplitInfo>& splits,
115 const SPtr<Skeleton>& skeleton, bool importRootMotion, Vector<FBXAnimationClipData>& output);
116
117 /**
118 * Removes identical sequential keyframes for the provided set of curves. The keyframe must be identical over all
119 * the curves in order for it to be removed.
120 */
121 TAnimationCurve<Vector3> reduceKeyframes(TAnimationCurve<Vector3>& curve);
122
123 /**
124 * Converts all the meshes from per-index attributes to per-vertex attributes.
125 *
126 * @note
127 * This method will replace all meshes in the scene with new ones, and delete old ones so be sure not to keep any
128 * mesh references.
129 */
130 void splitMeshVertices(FBXImportScene& scene);
131
132 /**
133 * Traverses over all meshes in the scene and generates normals, tangents and bitangents if they're missing.
134 *
135 * @note This assumes vertices have already been split and shouldn't be called on pre-split meshes.
136 */
137 void generateMissingTangentSpace(FBXImportScene& scene, const FBXImportOptions& options);
138
139 /** Converts the mesh data from the imported FBX scene into mesh data that can be used for initializing a mesh. */
140 SPtr<RendererMeshData> generateMeshData(const FBXImportScene& scene, const FBXImportOptions& options,
141 Vector<SubMesh>& outputSubMeshes);
142
143 /**
144 * Parses the scene and outputs a skeleton for the imported meshes using the imported raw data.
145 *
146 * @param[in] scene Scene whose meshes to parse.
147 * @param[in] sharedRoot Determines should a shared root bone be created. Set this to true if the scene contains
148 * multiple sub-meshes (as there can't be multiple roots).
149 * @return Skeleton containing a set of bones, or null if meshes don't contain a skeleton.
150 */
151 SPtr<Skeleton> createSkeleton(const FBXImportScene& scene, bool sharedRoot);
152
153 /** Parses the scene and generates morph shapes for the imported meshes using the imported raw data. */
154 SPtr<MorphShapes> createMorphShapes(const FBXImportScene& scene);
155
156 /** Creates an internal representation of an FBX node from an FbxNode object. */
157 FBXImportNode* createImportNode(FBXImportScene& scene, FbxNode* fbxNode, FBXImportNode* parent);
158
159 private:
160 Vector<String> mExtensions;
161 FbxManager* mFBXManager = nullptr;
162 };
163
164 /** @} */
165}