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 | |
12 | namespace 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 | } |