| 1 | /**************************************************************************************** |
| 2 | |
| 3 | Copyright (C) 2015 Autodesk, Inc. |
| 4 | All rights reserved. |
| 5 | |
| 6 | Use of this software is subject to the terms of the Autodesk license agreement |
| 7 | provided at the time of installation or download, or which otherwise accompanies |
| 8 | this software in either electronic or hard copy form. |
| 9 | |
| 10 | ****************************************************************************************/ |
| 11 | |
| 12 | //! \file fbxgeometryconverter.h |
| 13 | #ifndef _FBXSDK_UTILS_GEOMETRY_CONVERTER_H_ |
| 14 | #define _FBXSDK_UTILS_GEOMETRY_CONVERTER_H_ |
| 15 | |
| 16 | #include <fbxsdk/fbxsdk_def.h> |
| 17 | |
| 18 | #include <fbxsdk/core/base/fbxarray.h> |
| 19 | |
| 20 | #include <fbxsdk/fbxsdk_nsbegin.h> |
| 21 | |
| 22 | class FbxManager; |
| 23 | class FbxMesh; |
| 24 | class FbxPatch; |
| 25 | class FbxNurbs; |
| 26 | class FbxNurbsSurface; |
| 27 | class FbxNurbsCurve; |
| 28 | class FbxWeightedMapping; |
| 29 | class FbxSurfaceEvaluator; |
| 30 | class FbxScene; |
| 31 | class FbxNode; |
| 32 | class FbxNodeAttribute; |
| 33 | class FbxGeometry; |
| 34 | |
| 35 | /** |
| 36 | * This class provides the functionality to convert geometry nodes |
| 37 | * attributes (FbxMesh, FbxNurbs and FbxPatch) and mainly focuses on the two |
| 38 | * major categories: Triangulation and conversion between NURBS and Patches surfaces. |
| 39 | * \nosubgrouping |
| 40 | */ |
| 41 | class FBXSDK_DLL FbxGeometryConverter |
| 42 | { |
| 43 | public: |
| 44 | /** \name Triangulation Utilities */ |
| 45 | //@{ |
| 46 | /** Triangulate all node attributes in the scene that can be triangulated. |
| 47 | * \param pScene The scene to iterate through to triangulate meshes. |
| 48 | * \param pReplace If \c true, replace the original meshes with the new triangulated meshes on all the nodes, and delete the original meshes. Otherwise, original meshes are left untouched. |
| 49 | * \param pLegacy If \c true, use legacy triangulation method that does not support holes in geometry. Provided for backward compatibility. |
| 50 | * \return \c true if all node attributes that can be triangulated were triangulated successfully. |
| 51 | * \remark The function will still iterate through all meshes regardless if one fails to triangulate, but will return false in that case. This function |
| 52 | * currently only supports node attribute of type eMesh, ePatch, eNurbs or eNurbsSurface. */ |
| 53 | bool Triangulate(FbxScene* pScene, bool pReplace, bool pLegacy=false); |
| 54 | |
| 55 | /** Triangulate a node attribute, if supported, and preserve the skins and shapes animation channels. |
| 56 | * \param pNodeAttribute Pointer to the node containing the geometry to triangulate. |
| 57 | * \param pReplace If \c true, replace the original geometry with the new triangulated geometry on the nodes, and delete the original geometry. |
| 58 | * Otherwise, the original geometry is left untouched, the new one is added to the nodes, and becomes the default one. |
| 59 | * \param pLegacy If \c true, use legacy triangulation method that does not support holes in geometry. Provided for backward compatibility. |
| 60 | * \return The newly created node attribute if successful, otherwise NULL. If node attribute type is not supported by triangulation, it returns the original node attribute. |
| 61 | * \remark This function currently only supports node attribute of type eMesh, ePatch, eNurbs or eNurbsSurface. If the node attribute does not support triangulation, |
| 62 | * or if it is already triangulated, this function will return pNodeAttribute. */ |
| 63 | FbxNodeAttribute* Triangulate(FbxNodeAttribute* pNodeAttribute, bool pReplace, bool pLegacy=false); |
| 64 | |
| 65 | /** Compute a "vertex-correspondence" table that helps passing from source to destination geometry. |
| 66 | * \param pSrcGeom Pointer to the source geometry. |
| 67 | * \param pDstGeom Pointer to the destination geometry. |
| 68 | * \param pSrcToDstWeightedMapping Pointer to the weighted mapping table. |
| 69 | * \param pSwapUV Set to \c true to swap UVs. |
| 70 | * \return \c true on success, \c false if the function fails to compute the correspondence. |
| 71 | * \remark Skins and shapes are also converted to fit the alternate geometry. */ |
| 72 | bool ComputeGeometryControlPointsWeightedMapping(FbxGeometry* pSrcGeom, FbxGeometry* pDstGeom, FbxWeightedMapping* pSrcToDstWeightedMapping, bool pSwapUV=false); |
| 73 | //@} |
| 74 | |
| 75 | /** |
| 76 | * \name Geometry Conversion |
| 77 | */ |
| 78 | //@{ |
| 79 | /** Convert from patch to nurb. |
| 80 | * \param pPatch Pointer to the patch to convert. |
| 81 | * \return Created nurb or \c NULL if the conversion fails. |
| 82 | * \remarks The patch must be of type eBSpline, eBezier or eLinear. |
| 83 | */ |
| 84 | FbxNurbs* ConvertPatchToNurbs(FbxPatch *pPatch); |
| 85 | |
| 86 | /** Convert a patch contained in a node to a nurb. Use this function to preserve the patch's |
| 87 | * skins and shapes animation channels. |
| 88 | * \param pNode Pointer to the node containing the patch. |
| 89 | * \return \c true on success, \c false if the node attribute is not a patch. |
| 90 | * \remarks The patch must be of type eBSpline, eBezier or eLinear. |
| 91 | */ |
| 92 | bool ConvertPatchToNurbsInPlace(FbxNode* pNode); |
| 93 | |
| 94 | /** Convert a patch to nurb surface. |
| 95 | * \param pPatch Pointer to the patch to convert. |
| 96 | * \return Created nurb surface or \c NULL if conversion fails. |
| 97 | * \remarks The patch must be of type eBSpline, eBezier or eLinear. |
| 98 | */ |
| 99 | FbxNurbsSurface* ConvertPatchToNurbsSurface(FbxPatch *pPatch); |
| 100 | |
| 101 | /** Convert a patch contained in a node to a nurb surface. Use this function to preserve |
| 102 | * the patch's skins and shapes animation channels. |
| 103 | * \param pNode Pointer to the node containing the patch. |
| 104 | * \return \c true on success, \c false if the node attribute is not a patch. |
| 105 | * \remarks The patch must be of type eBSpline, eBezier or eLinear. |
| 106 | */ |
| 107 | bool ConvertPatchToNurbsSurfaceInPlace(FbxNode* pNode); |
| 108 | |
| 109 | /** Convert a FbxNurbs to a FbxNurbsSurface |
| 110 | * \param pNurbs Pointer to the original nurb |
| 111 | * \return A FbxNurbsSurface that is equivalent to the original nurb. |
| 112 | */ |
| 113 | FbxNurbsSurface* ConvertNurbsToNurbsSurface( FbxNurbs* pNurbs ); |
| 114 | |
| 115 | /** Convert a FbxNurbsSurface to a FbxNurbs |
| 116 | * \param pNurbs Pointer to the original nurbs surface |
| 117 | * \return A FbxNurbs that is equivalent to the original nurbs surface. |
| 118 | */ |
| 119 | FbxNurbs* ConvertNurbsSurfaceToNurbs( FbxNurbsSurface* pNurbs ); |
| 120 | |
| 121 | /** Convert a nurb, contained in a node, to a nurbs surface. Use this function to preserve |
| 122 | * the nurb's skins and shapes animation channels. |
| 123 | * \param pNode Pointer to the node containing the nurb. |
| 124 | * \return \c true on success, \c false otherwise |
| 125 | */ |
| 126 | bool ConvertNurbsToNurbsSurfaceInPlace(FbxNode* pNode); |
| 127 | |
| 128 | /** Convert a nurb contained in a node to a nurbs surface. Use this function to preserve |
| 129 | * the nurb's skins and shapes animation channels. |
| 130 | * \param pNode Pointer to the node containing the nurbs surface. |
| 131 | * \return \c true on success, \c false otherwise |
| 132 | */ |
| 133 | bool ConvertNurbsSurfaceToNurbsInPlace(FbxNode* pNode); |
| 134 | //@} |
| 135 | |
| 136 | /** |
| 137 | * \name Nurb UV and Links Swapping |
| 138 | */ |
| 139 | //@{ |
| 140 | /** Flip UV and/or skin clusters of a nurb. |
| 141 | * \param pNurbs Pointer to the Source nurb. |
| 142 | * \param pSwapUV Set to \c true to swap the UVs. |
| 143 | * \param pSwapClusters Set to \c true to swap the control point indices of clusters. |
| 144 | * \return A flipped FbxNurbs, or \c NULL if the function fails. |
| 145 | */ |
| 146 | FbxNurbs* FlipNurbs(FbxNurbs* pNurbs, bool pSwapUV, bool pSwapClusters); |
| 147 | |
| 148 | /** Flip UV and/or skin clusters of a nurb surface. |
| 149 | * \param pNurbs Pointer to the Source nurb surface. |
| 150 | * \param pSwapUV Set to \c true to swap the UVs. |
| 151 | * \param pSwapClusters Set to \c true to swap the control point indices of clusters. |
| 152 | * \return A flipped FbxNurbsSurface, or \c NULL if the function fails. |
| 153 | */ |
| 154 | FbxNurbsSurface* FlipNurbsSurface(FbxNurbsSurface* pNurbs, bool pSwapUV, bool pSwapClusters); |
| 155 | //@} |
| 156 | |
| 157 | /** |
| 158 | * \name Normals By Polygon Vertex Emulation |
| 159 | */ |
| 160 | //@{ |
| 161 | /** Emulate normals by polygon vertex mode for a mesh. |
| 162 | * \param pMesh Pointer to the mesh object. |
| 163 | * \return \c true on success, \c false if the number of normals in the |
| 164 | * mesh and in its associated shapes don't match the number of polygon |
| 165 | * vertices. |
| 166 | * \remarks For applications that only supports normals by control points, |
| 167 | * this function duplicates control points to equal the |
| 168 | * number of polygon vertices. skins and shapes are also converted. |
| 169 | * As preconditions: |
| 170 | * -# polygons must have been created |
| 171 | * -# the number of normals in the mesh and in its associated shapes must match the |
| 172 | * number of polygon vertices. |
| 173 | */ |
| 174 | bool EmulateNormalsByPolygonVertex(FbxMesh* pMesh); |
| 175 | |
| 176 | /** Create edge smoothing information from polygon-vertex mapped normals. |
| 177 | * Existing smoothing information is removed and edge data is created if |
| 178 | * none exists on the mesh. |
| 179 | * \param pMesh The mesh used to generate edge smoothing. |
| 180 | * \return \c true on success, \c false otherwise. |
| 181 | * \remarks The edge smoothing data is placed on Layer 0 of the mesh. |
| 182 | * Normals do not need to be on Layer 0, since the first layer with |
| 183 | * per polygon vertex normals is used. |
| 184 | */ |
| 185 | bool ComputeEdgeSmoothingFromNormals( FbxMesh* pMesh ) const; |
| 186 | |
| 187 | /** Convert edge smoothing to polygon smoothing group. |
| 188 | * Existing smoothing information is replaced. |
| 189 | * |
| 190 | * \param pMesh The mesh that contains the smoothing to be converted. |
| 191 | * \param pIndex The index of the layer smoothing to be converted. |
| 192 | * \return \c true on success, \c false otherwise. |
| 193 | * \remarks The smoothing group is bitwise. Each bit of the integer represents |
| 194 | * one smoothing group. Therefore, there is a maximum of 32 smoothing groups. |
| 195 | */ |
| 196 | bool ComputePolygonSmoothingFromEdgeSmoothing( FbxMesh* pMesh, int pIndex=0 ) const; |
| 197 | |
| 198 | /** Convert polygon smoothing group to edge smoothing. |
| 199 | * Existing smoothing information is replaced. |
| 200 | * |
| 201 | * \param pMesh The mesh that contains the smoothing to be converted. |
| 202 | * \param pIndex The index of the layer smoothing to be converted |
| 203 | * \return \c true on success, \c false otherwise. |
| 204 | */ |
| 205 | bool ComputeEdgeSmoothingFromPolygonSmoothing( FbxMesh* pMesh, int pIndex=0 ) const; |
| 206 | //@} |
| 207 | |
| 208 | /** \name Split Mesh Per Materials */ |
| 209 | //@{ |
| 210 | /** Split all the mesh in the scene per material. |
| 211 | * \param pScene The scene to iterate through to split meshes. |
| 212 | * \param pReplace If \c true, replace the original mesh with new ones and delete the original meshes, but *only* if they got split into multiple meshes, otherwise they are left untouched. |
| 213 | * \return \c true if all splitable mesh were successfully split, \c false otherwise. |
| 214 | * \remark The function will still iterate through all meshes regardless if one fails to split, but will return false in that case. */ |
| 215 | bool SplitMeshesPerMaterial(FbxScene* pScene, bool pReplace); |
| 216 | |
| 217 | /** Split mesh per material. |
| 218 | * \param pMesh The mesh that will be split if it has multiple materials assigned. |
| 219 | * \param pReplace If \c true, replace the original mesh with new one and delete the original mesh, but *only* if they got split into multiple meshes, otherwise left untouched. |
| 220 | * \return \c true on success, \c false otherwise. |
| 221 | * \remark The function will fail if the mapped material is not per face (FbxLayerElement::eByPolygon) or if a material is multi-layered. It will create as many meshes as |
| 222 | * there are materials applied to it. If one mesh have some polygons with material A, some polygons with material B, and some polygons with NO material, 3 meshes distinct |
| 223 | * will be created. The newly created meshes will be automatically attached to the same FbxNode that holds the original FbxMesh. If the original mesh have tangents, they will |
| 224 | * be regenerated on the new meshes. */ |
| 225 | bool SplitMeshPerMaterial(FbxMesh* pMesh, bool pReplace); |
| 226 | //@} |
| 227 | |
| 228 | /** Re-parent nodes at root node level under a new node to re-center them at world center. |
| 229 | * Basically, this function calculates the scene bounding box in world coordinates, and test if the center of that bounding box distance from the |
| 230 | * world center is larger or equal than the threshold. If true, a new node with the proper negative offset position will become the new parent of all nodes at root node level. |
| 231 | * \param pScene The scene to process. |
| 232 | * \param pThreshold Threshold at which all nodes will be re-centered. |
| 233 | * \return \c true if any nodes were re-centered, otherwise \c false. */ |
| 234 | bool RecenterSceneToWorldCenter(FbxScene* pScene, FbxDouble pThreshold); |
| 235 | |
| 236 | /** |
| 237 | * Merge multiple meshes to one mesh. |
| 238 | * The method will merge: |
| 239 | * a) mesh vertex; |
| 240 | * b) mesh polygon; |
| 241 | * c) mesh edge; |
| 242 | * d) all mesh elements; only the layer 0 elements is merged. |
| 243 | * e) if there are skins for old mesh, merge these skins. The new skin clusters link to old skeletons. |
| 244 | * |
| 245 | * \param pMeshNodes FBX nodes that hold multiple meshes. These meshes will be merged. |
| 246 | * \param pNodeName Name of new mesh node. |
| 247 | * \param pScene The scene that will contain the new mesh node. |
| 248 | * \return The new mesh node if merge successfully, otherwise NULL is returned. |
| 249 | * \remarks This method creates a new mesh, leaving the source mesh unchanged. |
| 250 | * The transform of new mesh node is: translate (0, 0, 0), rotation (0, 0, 0), scale (1, 1, 1). |
| 251 | * For layer element material, normal, smoothing, UV set, vertex color, binormal, tangent and polygon group, |
| 252 | * if any mesh misses these element, the merge for this kind of element is skipped. |
| 253 | * For layer element crease, hole, visibility and user data, if any mesh has such element, the kind of element |
| 254 | * will be merged. The missing element will be filled with default values. |
| 255 | * For meshes with skin binding, if the pose of frame 0 is different with bind pose, the new mesh will be distorted. |
| 256 | */ |
| 257 | FbxNode* MergeMeshes(FbxArray<FbxNode*>& pMeshNodes, const char* pNodeName, FbxScene* pScene); |
| 258 | |
| 259 | /** |
| 260 | * Cleanup or remove degenerated meshes. |
| 261 | * \param pScene The scene to process. |
| 262 | * \param pAffectedNodes The list of nodes that have been affected by this operation. |
| 263 | * \remarks If the cleaned-up mesh becomes invalid, it is removed entirely. |
| 264 | */ |
| 265 | void RemoveBadPolygonsFromMeshes(FbxScene* pScene, FbxArray<FbxNode*>* pAffectedNodes = NULL); |
| 266 | |
| 267 | /***************************************************************************************************************************** |
| 268 | ** WARNING! Anything beyond these lines is for internal use, may not be documented and is subject to change without notice! ** |
| 269 | *****************************************************************************************************************************/ |
| 270 | #ifndef DOXYGEN_SHOULD_SKIP_THIS |
| 271 | FbxGeometryConverter(FbxManager* pManager); |
| 272 | ~FbxGeometryConverter(); |
| 273 | |
| 274 | private: |
| 275 | FbxMesh* TriangulateMeshInternal(const FbxMesh* pMesh); |
| 276 | FbxMesh* TriangulateMeshInternalLegacy(const FbxMesh* pMesh); |
| 277 | FbxMesh* TriangulatePatchInternal(const FbxPatch* pPatch); |
| 278 | FbxMesh* TriangulateNurbsInternal(const FbxNurbs* pNurbs); |
| 279 | |
| 280 | bool AddAlternateGeometry(FbxNode* pNode, FbxGeometry* pSrcGeom, FbxGeometry* pAltGeom, FbxWeightedMapping* pSrcToAltWeightedMapping, bool pConvertDeformations); |
| 281 | bool ConvertGeometryAnimation(FbxNode* pNode, FbxGeometry* pSrcGeom, FbxGeometry* pDstGeom); |
| 282 | void ReplaceNodeAttribute(FbxNode* pNode, FbxNodeAttribute* pNewNodeAttr); |
| 283 | bool AddTriangulatedMeshGeometry(FbxNode* pNode, int pUVStepCoeff); |
| 284 | bool CreateAndCopyLayerElement(FbxMesh *pNewMesh, FbxMesh *pRefMesh); |
| 285 | bool SetLayerElements(FbxMesh *pNewMesh, FbxMesh *pMesh, int pPolygonIndex, int pPolyPointIndex, int pLoopIndex, bool pIsSearched, bool pIsEndPolygon); |
| 286 | |
| 287 | /** FbxTriangulation |
| 288 | * \param Index Output array of triangle indices |
| 289 | * \param pNumSide Input number of sides of the polygon to triangulate |
| 290 | * -- Triangulation algorithm is strip, Sorting vertex index for strip in clockwise. |
| 291 | * |
| 292 | * 2 3 4 |
| 293 | * 0----------0---------0 |
| 294 | * / ` |
| 295 | * / ` 5 |
| 296 | * 1 / 0 |
| 297 | * 0 / |
| 298 | * ` / |
| 299 | * ` / |
| 300 | * 0 0-----0-------------0 6 |
| 301 | * 7 |
| 302 | * The result of this one will be [{0,1,2},{2,3,0},{0,3,7},{3,4,7},{7,4,6},{4,5,6}] |
| 303 | */ |
| 304 | static void FbxTriangulation(int *Index, int pNumSide); |
| 305 | |
| 306 | bool ComputePatchToMeshControlPointsWeightedMapping(FbxPatch* pSrcPatch, FbxMesh* pDstMesh, FbxWeightedMapping* pMapping, bool pSwapUV=false); |
| 307 | bool ComputeNurbsToMeshControlPointsWeightedMapping(FbxNurbsSurface* pSrcNurbs, FbxMesh* pDstMesh, FbxWeightedMapping* pMapping, bool pRescaleUVs=false, bool pSwapUV=false); |
| 308 | |
| 309 | void InitializeWeightInControlPoints(FbxGeometryBase* pGeometry); |
| 310 | void InitializeWeightInNormals(FbxLayerContainer* pLayerContainer); |
| 311 | void TriangulateContinuousSurface(FbxMesh* pMesh, FbxSurfaceEvaluator* pSurface, FbxUInt pPointCountX, FbxUInt pPointCountY, bool ClockWise=false); |
| 312 | void CheckForZeroWeightInShape(FbxGeometry *pGeometry); |
| 313 | FbxMesh* CreateMeshFromParametricSurface(const FbxGeometry* pGeometry); |
| 314 | FbxNurbs* CreateNurbsFromPatch(FbxPatch* pPatch); |
| 315 | FbxNurbsSurface* CreateNurbsSurfaceFromPatch(FbxPatch* pPatch); |
| 316 | |
| 317 | void ConvertShapes(const FbxGeometry* pSource, FbxGeometry* pDestination, FbxSurfaceEvaluator* pEvaluator, int pUCount, int pVCount); |
| 318 | void ConvertShapes(const FbxGeometry* pSource, FbxGeometry* pDestination, FbxWeightedMapping* pSourceToDestinationMapping); |
| 319 | void ConvertClusters(const FbxGeometry* pSource, FbxGeometry* pDestination, FbxWeightedMapping* pSourceToDestinationMapping); |
| 320 | void ConvertClusters(FbxArray<FbxCluster*> const& pSourceClusters, int pSourceControlPointsCount, FbxArray<FbxCluster*>& pDestinationClusters, int pDestinationControlPointsCount, FbxWeightedMapping* pSourceToDestinationMapping); |
| 321 | void BuildClusterToSourceMapping(FbxArray<FbxCluster*> const& pSourceClusters, FbxWeightedMapping* pClusterToSourceMapping); |
| 322 | void CheckClusterToSourceMapping(FbxWeightedMapping* pClusterToSourceMapping); |
| 323 | void ConvertCluster(int pSourceClusterIndex, FbxWeightedMapping* pClusterToSourceMapping, FbxWeightedMapping* pSourceToDestinationMapping, FbxCluster* pDestinationCluster); |
| 324 | void DuplicateControlPoints(FbxArray<FbxVector4>& pControlPoints, FbxArray<int>& pPolygonVertices); |
| 325 | void UpdatePolygon(FbxMesh *pNewMesh, FbxMesh const *pRefMesh, int pPolygonIndex, int* pNewIndex, int &pVerticeIndexMeshTriangulated, int &pPolygonIndexMeshTriangulated); |
| 326 | void UpdatePolygon(FbxMesh *pNewMesh, FbxMesh const *pRefMesh, int pPolygonIndex, int* pNewIndex, int &pVerticeIndexMeshTriangulated, int &pPolygonIndexMeshTriangulated, int pTriangleNum); |
| 327 | void ResizePolygon(FbxMesh *pNewMesh, int pNewCountVertices = 0, int pNewCountPolygons =0, bool pClearFlag = true); |
| 328 | |
| 329 | template <class T1, class T2> void ConvertNurbs(T1* pNewNurbs, T2* pOldNurb); |
| 330 | |
| 331 | bool CopyAnimationCurves(FbxNode* pNode, FbxGeometry* pNewGeometry); |
| 332 | bool FlipNurbsCurve(FbxNurbsCurve* pCurve) const; |
| 333 | void FlipControlPoints(FbxGeometryBase* pPoints, int pUCount, int pVCount) const; |
| 334 | bool ConvertMaterialReferenceMode(FbxMesh* pMeshRef) const; |
| 335 | void RevertMaterialReferenceModeConversion(FbxMesh* pMeshRef) const; |
| 336 | |
| 337 | FbxManager* mManager; |
| 338 | |
| 339 | friend class FbxWriter3ds; |
| 340 | #endif /* !DOXYGEN_SHOULD_SKIP_THIS *****************************************************************************************/ |
| 341 | }; |
| 342 | |
| 343 | #include <fbxsdk/fbxsdk_nsend.h> |
| 344 | |
| 345 | #endif /* _FBXSDK_UTILS_GEOMETRY_CONVERTER_H_ */ |
| 346 | |