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