346 lines
20 KiB
C++
346 lines
20 KiB
C++
/****************************************************************************************
|
|
|
|
Copyright (C) 2015 Autodesk, Inc.
|
|
All rights reserved.
|
|
|
|
Use of this software is subject to the terms of the Autodesk license agreement
|
|
provided at the time of installation or download, or which otherwise accompanies
|
|
this software in either electronic or hard copy form.
|
|
|
|
****************************************************************************************/
|
|
|
|
//! \file fbxgeometryconverter.h
|
|
#ifndef _FBXSDK_UTILS_GEOMETRY_CONVERTER_H_
|
|
#define _FBXSDK_UTILS_GEOMETRY_CONVERTER_H_
|
|
|
|
#include <fbxsdk/fbxsdk_def.h>
|
|
|
|
#include <fbxsdk/core/base/fbxarray.h>
|
|
|
|
#include <fbxsdk/fbxsdk_nsbegin.h>
|
|
|
|
class FbxManager;
|
|
class FbxMesh;
|
|
class FbxPatch;
|
|
class FbxNurbs;
|
|
class FbxNurbsSurface;
|
|
class FbxNurbsCurve;
|
|
class FbxWeightedMapping;
|
|
class FbxSurfaceEvaluator;
|
|
class FbxScene;
|
|
class FbxNode;
|
|
class FbxNodeAttribute;
|
|
class FbxGeometry;
|
|
|
|
/**
|
|
* This class provides the functionality to convert geometry nodes
|
|
* attributes (FbxMesh, FbxNurbs and FbxPatch) and mainly focuses on the two
|
|
* major categories: Triangulation and conversion between NURBS and Patches surfaces.
|
|
* \nosubgrouping
|
|
*/
|
|
class FBXSDK_DLL FbxGeometryConverter
|
|
{
|
|
public:
|
|
/** \name Triangulation Utilities */
|
|
//@{
|
|
/** Triangulate all node attributes in the scene that can be triangulated.
|
|
* \param pScene The scene to iterate through to triangulate meshes.
|
|
* \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.
|
|
* \param pLegacy If \c true, use legacy triangulation method that does not support holes in geometry. Provided for backward compatibility.
|
|
* \return \c true if all node attributes that can be triangulated were triangulated successfully.
|
|
* \remark The function will still iterate through all meshes regardless if one fails to triangulate, but will return false in that case. This function
|
|
* currently only supports node attribute of type eMesh, ePatch, eNurbs or eNurbsSurface. */
|
|
bool Triangulate(FbxScene* pScene, bool pReplace, bool pLegacy=false);
|
|
|
|
/** Triangulate a node attribute, if supported, and preserve the skins and shapes animation channels.
|
|
* \param pNodeAttribute Pointer to the node containing the geometry to triangulate.
|
|
* \param pReplace If \c true, replace the original geometry with the new triangulated geometry on the nodes, and delete the original geometry.
|
|
* Otherwise, the original geometry is left untouched, the new one is added to the nodes, and becomes the default one.
|
|
* \param pLegacy If \c true, use legacy triangulation method that does not support holes in geometry. Provided for backward compatibility.
|
|
* \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.
|
|
* \remark This function currently only supports node attribute of type eMesh, ePatch, eNurbs or eNurbsSurface. If the node attribute does not support triangulation,
|
|
* or if it is already triangulated, this function will return pNodeAttribute. */
|
|
FbxNodeAttribute* Triangulate(FbxNodeAttribute* pNodeAttribute, bool pReplace, bool pLegacy=false);
|
|
|
|
/** Compute a "vertex-correspondence" table that helps passing from source to destination geometry.
|
|
* \param pSrcGeom Pointer to the source geometry.
|
|
* \param pDstGeom Pointer to the destination geometry.
|
|
* \param pSrcToDstWeightedMapping Pointer to the weighted mapping table.
|
|
* \param pSwapUV Set to \c true to swap UVs.
|
|
* \return \c true on success, \c false if the function fails to compute the correspondence.
|
|
* \remark Skins and shapes are also converted to fit the alternate geometry. */
|
|
bool ComputeGeometryControlPointsWeightedMapping(FbxGeometry* pSrcGeom, FbxGeometry* pDstGeom, FbxWeightedMapping* pSrcToDstWeightedMapping, bool pSwapUV=false);
|
|
//@}
|
|
|
|
/**
|
|
* \name Geometry Conversion
|
|
*/
|
|
//@{
|
|
/** Convert from patch to nurb.
|
|
* \param pPatch Pointer to the patch to convert.
|
|
* \return Created nurb or \c NULL if the conversion fails.
|
|
* \remarks The patch must be of type eBSpline, eBezier or eLinear.
|
|
*/
|
|
FbxNurbs* ConvertPatchToNurbs(FbxPatch *pPatch);
|
|
|
|
/** Convert a patch contained in a node to a nurb. Use this function to preserve the patch's
|
|
* skins and shapes animation channels.
|
|
* \param pNode Pointer to the node containing the patch.
|
|
* \return \c true on success, \c false if the node attribute is not a patch.
|
|
* \remarks The patch must be of type eBSpline, eBezier or eLinear.
|
|
*/
|
|
bool ConvertPatchToNurbsInPlace(FbxNode* pNode);
|
|
|
|
/** Convert a patch to nurb surface.
|
|
* \param pPatch Pointer to the patch to convert.
|
|
* \return Created nurb surface or \c NULL if conversion fails.
|
|
* \remarks The patch must be of type eBSpline, eBezier or eLinear.
|
|
*/
|
|
FbxNurbsSurface* ConvertPatchToNurbsSurface(FbxPatch *pPatch);
|
|
|
|
/** Convert a patch contained in a node to a nurb surface. Use this function to preserve
|
|
* the patch's skins and shapes animation channels.
|
|
* \param pNode Pointer to the node containing the patch.
|
|
* \return \c true on success, \c false if the node attribute is not a patch.
|
|
* \remarks The patch must be of type eBSpline, eBezier or eLinear.
|
|
*/
|
|
bool ConvertPatchToNurbsSurfaceInPlace(FbxNode* pNode);
|
|
|
|
/** Convert a FbxNurbs to a FbxNurbsSurface
|
|
* \param pNurbs Pointer to the original nurb
|
|
* \return A FbxNurbsSurface that is equivalent to the original nurb.
|
|
*/
|
|
FbxNurbsSurface* ConvertNurbsToNurbsSurface( FbxNurbs* pNurbs );
|
|
|
|
/** Convert a FbxNurbsSurface to a FbxNurbs
|
|
* \param pNurbs Pointer to the original nurbs surface
|
|
* \return A FbxNurbs that is equivalent to the original nurbs surface.
|
|
*/
|
|
FbxNurbs* ConvertNurbsSurfaceToNurbs( FbxNurbsSurface* pNurbs );
|
|
|
|
/** Convert a nurb, contained in a node, to a nurbs surface. Use this function to preserve
|
|
* the nurb's skins and shapes animation channels.
|
|
* \param pNode Pointer to the node containing the nurb.
|
|
* \return \c true on success, \c false otherwise
|
|
*/
|
|
bool ConvertNurbsToNurbsSurfaceInPlace(FbxNode* pNode);
|
|
|
|
/** Convert a nurb contained in a node to a nurbs surface. Use this function to preserve
|
|
* the nurb's skins and shapes animation channels.
|
|
* \param pNode Pointer to the node containing the nurbs surface.
|
|
* \return \c true on success, \c false otherwise
|
|
*/
|
|
bool ConvertNurbsSurfaceToNurbsInPlace(FbxNode* pNode);
|
|
//@}
|
|
|
|
/**
|
|
* \name Nurb UV and Links Swapping
|
|
*/
|
|
//@{
|
|
/** Flip UV and/or skin clusters of a nurb.
|
|
* \param pNurbs Pointer to the Source nurb.
|
|
* \param pSwapUV Set to \c true to swap the UVs.
|
|
* \param pSwapClusters Set to \c true to swap the control point indices of clusters.
|
|
* \return A flipped FbxNurbs, or \c NULL if the function fails.
|
|
*/
|
|
FbxNurbs* FlipNurbs(FbxNurbs* pNurbs, bool pSwapUV, bool pSwapClusters);
|
|
|
|
/** Flip UV and/or skin clusters of a nurb surface.
|
|
* \param pNurbs Pointer to the Source nurb surface.
|
|
* \param pSwapUV Set to \c true to swap the UVs.
|
|
* \param pSwapClusters Set to \c true to swap the control point indices of clusters.
|
|
* \return A flipped FbxNurbsSurface, or \c NULL if the function fails.
|
|
*/
|
|
FbxNurbsSurface* FlipNurbsSurface(FbxNurbsSurface* pNurbs, bool pSwapUV, bool pSwapClusters);
|
|
//@}
|
|
|
|
/**
|
|
* \name Normals By Polygon Vertex Emulation
|
|
*/
|
|
//@{
|
|
/** Emulate normals by polygon vertex mode for a mesh.
|
|
* \param pMesh Pointer to the mesh object.
|
|
* \return \c true on success, \c false if the number of normals in the
|
|
* mesh and in its associated shapes don't match the number of polygon
|
|
* vertices.
|
|
* \remarks For applications that only supports normals by control points,
|
|
* this function duplicates control points to equal the
|
|
* number of polygon vertices. skins and shapes are also converted.
|
|
* As preconditions:
|
|
* -# polygons must have been created
|
|
* -# the number of normals in the mesh and in its associated shapes must match the
|
|
* number of polygon vertices.
|
|
*/
|
|
bool EmulateNormalsByPolygonVertex(FbxMesh* pMesh);
|
|
|
|
/** Create edge smoothing information from polygon-vertex mapped normals.
|
|
* Existing smoothing information is removed and edge data is created if
|
|
* none exists on the mesh.
|
|
* \param pMesh The mesh used to generate edge smoothing.
|
|
* \return \c true on success, \c false otherwise.
|
|
* \remarks The edge smoothing data is placed on Layer 0 of the mesh.
|
|
* Normals do not need to be on Layer 0, since the first layer with
|
|
* per polygon vertex normals is used.
|
|
*/
|
|
bool ComputeEdgeSmoothingFromNormals( FbxMesh* pMesh ) const;
|
|
|
|
/** Convert edge smoothing to polygon smoothing group.
|
|
* Existing smoothing information is replaced.
|
|
*
|
|
* \param pMesh The mesh that contains the smoothing to be converted.
|
|
* \param pIndex The index of the layer smoothing to be converted.
|
|
* \return \c true on success, \c false otherwise.
|
|
* \remarks The smoothing group is bitwise. Each bit of the integer represents
|
|
* one smoothing group. Therefore, there is a maximum of 32 smoothing groups.
|
|
*/
|
|
bool ComputePolygonSmoothingFromEdgeSmoothing( FbxMesh* pMesh, int pIndex=0 ) const;
|
|
|
|
/** Convert polygon smoothing group to edge smoothing.
|
|
* Existing smoothing information is replaced.
|
|
*
|
|
* \param pMesh The mesh that contains the smoothing to be converted.
|
|
* \param pIndex The index of the layer smoothing to be converted
|
|
* \return \c true on success, \c false otherwise.
|
|
*/
|
|
bool ComputeEdgeSmoothingFromPolygonSmoothing( FbxMesh* pMesh, int pIndex=0 ) const;
|
|
//@}
|
|
|
|
/** \name Split Mesh Per Materials */
|
|
//@{
|
|
/** Split all the mesh in the scene per material.
|
|
* \param pScene The scene to iterate through to split meshes.
|
|
* \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.
|
|
* \return \c true if all splitable mesh were successfully split, \c false otherwise.
|
|
* \remark The function will still iterate through all meshes regardless if one fails to split, but will return false in that case. */
|
|
bool SplitMeshesPerMaterial(FbxScene* pScene, bool pReplace);
|
|
|
|
/** Split mesh per material.
|
|
* \param pMesh The mesh that will be split if it has multiple materials assigned.
|
|
* \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.
|
|
* \return \c true on success, \c false otherwise.
|
|
* \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
|
|
* 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
|
|
* 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
|
|
* be regenerated on the new meshes. */
|
|
bool SplitMeshPerMaterial(FbxMesh* pMesh, bool pReplace);
|
|
//@}
|
|
|
|
/** Re-parent nodes at root node level under a new node to re-center them at world center.
|
|
* Basically, this function calculates the scene bounding box in world coordinates, and test if the center of that bounding box distance from the
|
|
* 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.
|
|
* \param pScene The scene to process.
|
|
* \param pThreshold Threshold at which all nodes will be re-centered.
|
|
* \return \c true if any nodes were re-centered, otherwise \c false. */
|
|
bool RecenterSceneToWorldCenter(FbxScene* pScene, FbxDouble pThreshold);
|
|
|
|
/**
|
|
* Merge multiple meshes to one mesh.
|
|
* The method will merge:
|
|
* a) mesh vertex;
|
|
* b) mesh polygon;
|
|
* c) mesh edge;
|
|
* d) all mesh elements; only the layer 0 elements is merged.
|
|
* e) if there are skins for old mesh, merge these skins. The new skin clusters link to old skeletons.
|
|
*
|
|
* \param pMeshNodes FBX nodes that hold multiple meshes. These meshes will be merged.
|
|
* \param pNodeName Name of new mesh node.
|
|
* \param pScene The scene that will contain the new mesh node.
|
|
* \return The new mesh node if merge successfully, otherwise NULL is returned.
|
|
* \remarks This method creates a new mesh, leaving the source mesh unchanged.
|
|
* The transform of new mesh node is: translate (0, 0, 0), rotation (0, 0, 0), scale (1, 1, 1).
|
|
* For layer element material, normal, smoothing, UV set, vertex color, binormal, tangent and polygon group,
|
|
* if any mesh misses these element, the merge for this kind of element is skipped.
|
|
* For layer element crease, hole, visibility and user data, if any mesh has such element, the kind of element
|
|
* will be merged. The missing element will be filled with default values.
|
|
* For meshes with skin binding, if the pose of frame 0 is different with bind pose, the new mesh will be distorted.
|
|
*/
|
|
FbxNode* MergeMeshes(FbxArray<FbxNode*>& pMeshNodes, const char* pNodeName, FbxScene* pScene);
|
|
|
|
/**
|
|
* Cleanup or remove degenerated meshes.
|
|
* \param pScene The scene to process.
|
|
* \param pAffectedNodes The list of nodes that have been affected by this operation.
|
|
* \remarks If the cleaned-up mesh becomes invalid, it is removed entirely.
|
|
*/
|
|
void RemoveBadPolygonsFromMeshes(FbxScene* pScene, FbxArray<FbxNode*>* pAffectedNodes = NULL);
|
|
|
|
/*****************************************************************************************************************************
|
|
** WARNING! Anything beyond these lines is for internal use, may not be documented and is subject to change without notice! **
|
|
*****************************************************************************************************************************/
|
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
|
FbxGeometryConverter(FbxManager* pManager);
|
|
~FbxGeometryConverter();
|
|
|
|
private:
|
|
FbxMesh* TriangulateMeshInternal(const FbxMesh* pMesh);
|
|
FbxMesh* TriangulateMeshInternalLegacy(const FbxMesh* pMesh);
|
|
FbxMesh* TriangulatePatchInternal(const FbxPatch* pPatch);
|
|
FbxMesh* TriangulateNurbsInternal(const FbxNurbs* pNurbs);
|
|
|
|
bool AddAlternateGeometry(FbxNode* pNode, FbxGeometry* pSrcGeom, FbxGeometry* pAltGeom, FbxWeightedMapping* pSrcToAltWeightedMapping, bool pConvertDeformations);
|
|
bool ConvertGeometryAnimation(FbxNode* pNode, FbxGeometry* pSrcGeom, FbxGeometry* pDstGeom);
|
|
void ReplaceNodeAttribute(FbxNode* pNode, FbxNodeAttribute* pNewNodeAttr);
|
|
bool AddTriangulatedMeshGeometry(FbxNode* pNode, int pUVStepCoeff);
|
|
bool CreateAndCopyLayerElement(FbxMesh *pNewMesh, FbxMesh *pRefMesh);
|
|
bool SetLayerElements(FbxMesh *pNewMesh, FbxMesh *pMesh, int pPolygonIndex, int pPolyPointIndex, int pLoopIndex, bool pIsSearched, bool pIsEndPolygon);
|
|
|
|
/** FbxTriangulation
|
|
* \param Index Output array of triangle indices
|
|
* \param pNumSide Input number of sides of the polygon to triangulate
|
|
* -- Triangulation algorithm is strip, Sorting vertex index for strip in clockwise.
|
|
*
|
|
* 2 3 4
|
|
* 0----------0---------0
|
|
* / `
|
|
* / ` 5
|
|
* 1 / 0
|
|
* 0 /
|
|
* ` /
|
|
* ` /
|
|
* 0 0-----0-------------0 6
|
|
* 7
|
|
* 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}]
|
|
*/
|
|
static void FbxTriangulation(int *Index, int pNumSide);
|
|
|
|
bool ComputePatchToMeshControlPointsWeightedMapping(FbxPatch* pSrcPatch, FbxMesh* pDstMesh, FbxWeightedMapping* pMapping, bool pSwapUV=false);
|
|
bool ComputeNurbsToMeshControlPointsWeightedMapping(FbxNurbsSurface* pSrcNurbs, FbxMesh* pDstMesh, FbxWeightedMapping* pMapping, bool pRescaleUVs=false, bool pSwapUV=false);
|
|
|
|
void InitializeWeightInControlPoints(FbxGeometryBase* pGeometry);
|
|
void InitializeWeightInNormals(FbxLayerContainer* pLayerContainer);
|
|
void TriangulateContinuousSurface(FbxMesh* pMesh, FbxSurfaceEvaluator* pSurface, FbxUInt pPointCountX, FbxUInt pPointCountY, bool ClockWise=false);
|
|
void CheckForZeroWeightInShape(FbxGeometry *pGeometry);
|
|
FbxMesh* CreateMeshFromParametricSurface(const FbxGeometry* pGeometry);
|
|
FbxNurbs* CreateNurbsFromPatch(FbxPatch* pPatch);
|
|
FbxNurbsSurface* CreateNurbsSurfaceFromPatch(FbxPatch* pPatch);
|
|
|
|
void ConvertShapes(const FbxGeometry* pSource, FbxGeometry* pDestination, FbxSurfaceEvaluator* pEvaluator, int pUCount, int pVCount);
|
|
void ConvertShapes(const FbxGeometry* pSource, FbxGeometry* pDestination, FbxWeightedMapping* pSourceToDestinationMapping);
|
|
void ConvertClusters(const FbxGeometry* pSource, FbxGeometry* pDestination, FbxWeightedMapping* pSourceToDestinationMapping);
|
|
void ConvertClusters(FbxArray<FbxCluster*> const& pSourceClusters, int pSourceControlPointsCount, FbxArray<FbxCluster*>& pDestinationClusters, int pDestinationControlPointsCount, FbxWeightedMapping* pSourceToDestinationMapping);
|
|
void BuildClusterToSourceMapping(FbxArray<FbxCluster*> const& pSourceClusters, FbxWeightedMapping* pClusterToSourceMapping);
|
|
void CheckClusterToSourceMapping(FbxWeightedMapping* pClusterToSourceMapping);
|
|
void ConvertCluster(int pSourceClusterIndex, FbxWeightedMapping* pClusterToSourceMapping, FbxWeightedMapping* pSourceToDestinationMapping, FbxCluster* pDestinationCluster);
|
|
void DuplicateControlPoints(FbxArray<FbxVector4>& pControlPoints, FbxArray<int>& pPolygonVertices);
|
|
void UpdatePolygon(FbxMesh *pNewMesh, FbxMesh const *pRefMesh, int pPolygonIndex, int* pNewIndex, int &pVerticeIndexMeshTriangulated, int &pPolygonIndexMeshTriangulated);
|
|
void UpdatePolygon(FbxMesh *pNewMesh, FbxMesh const *pRefMesh, int pPolygonIndex, int* pNewIndex, int &pVerticeIndexMeshTriangulated, int &pPolygonIndexMeshTriangulated, int pTriangleNum);
|
|
void ResizePolygon(FbxMesh *pNewMesh, int pNewCountVertices = 0, int pNewCountPolygons =0, bool pClearFlag = true);
|
|
|
|
template <class T1, class T2> void ConvertNurbs(T1* pNewNurbs, T2* pOldNurb);
|
|
|
|
bool CopyAnimationCurves(FbxNode* pNode, FbxGeometry* pNewGeometry);
|
|
bool FlipNurbsCurve(FbxNurbsCurve* pCurve) const;
|
|
void FlipControlPoints(FbxGeometryBase* pPoints, int pUCount, int pVCount) const;
|
|
bool ConvertMaterialReferenceMode(FbxMesh* pMeshRef) const;
|
|
void RevertMaterialReferenceModeConversion(FbxMesh* pMeshRef) const;
|
|
|
|
FbxManager* mManager;
|
|
|
|
friend class FbxWriter3ds;
|
|
#endif /* !DOXYGEN_SHOULD_SKIP_THIS *****************************************************************************************/
|
|
};
|
|
|
|
#include <fbxsdk/fbxsdk_nsend.h>
|
|
|
|
#endif /* _FBXSDK_UTILS_GEOMETRY_CONVERTER_H_ */
|