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