#ifndef _SHAVEOBJEXPORTER_H_ #define _SHAVEOBJEXPORTER_H_ // Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 #include #include #include #include #include #include #include #include #include #include #include #include #include #include // We used to use MDagPaths to initialize function sets to access // the input surfacs. That was always dangerous given that this // code gets called during shaveHairShape::compute(). In Maya 8.0 // that started to cause problems when it turned out that polygon // smooth proxy meshes were not in an internally consistent state // in the middle of a compute(): they could have verts but not yet // any faces. // // Here we get around this by pulling the geometry from the mesh's // plug to ensure that it updates correctly. The proper approach // GET_GEOM_FROM_DATABLOCK represents the correct approach which is to // avoid the MDagPaths altogether and get all input geometry from the // compute's datablock. // // Unfortunately that's not finished yet (shaveTextureStore still uses // the DAG paths for the surfaces) so GET_GEOM_FROM_PLUGS represents a // temporary workaround in which we continue to use MDagPaths to access // the nodes, but make sure to pull the geometry from the node's plugs // beforehand to ensure that it is up to date. // // Since the old approach worked prior to Maya 8.0, I'm only enabling this // new stuff in 8.0. #define GET_GEOM_FROM_DATABLOCK 0 #define GET_GEOM_FROM_PLUGS 1 #if MAYA_API_VERSION < 20180000 class MDataBlock; class MFloatPointArray; #endif typedef struct { WFTYPE* theObj; WFTYPE* uvs; MDagPathArray meshes; // The exported meshes, in the order exported MIntArray startFaces; // Face ID of first face of each mesh MIntArray startVerts; // Vertex ID of first vert of each mesh bool newtopo; int uSubdivs; int vSubdivs; int lastUSubdiv; int lastVSubdiv; int subdDepth; int subdSamples; int lastSubdDepth; int lastSubdSamples; MObject shaveHairShape; MString objFileName; }ShaveExportData; class shaveObjTranslator { public: shaveObjTranslator (); virtual ~shaveObjTranslator (){} static void* creator(); // called from shaveHairShape in order to export .obj file for the // current node. MStatus exportThis(MDataBlock& block, ShaveExportData& data); MStatus exportOcclusion(MDagPathArray&, WFTYPE *); void exportInstanceObj(MObject instanceMesh, MObject shader, MString filename); private: enum GeomType { kGrowthGeom, kCollisionGeom, kOcclusionGeom }; bool newtopo; #if GET_GEOM_FROM_DATABLOCK MObjectArray hairObjects; MObjectArray hairComponents; MObjectArray fullHairObjects; MObjectArray partialHairObjects; MObjectArray partialHairComponents; MObjectArray skullObjects; MObjectArray skullComponents; MObjectArray fullSkullObjects; MObjectArray partialSkullObjects; MObjectArray partialSkullComponents; #else MSelectionList hairSelections; MSelectionList skullSelections; MDagPathArray fullHairObjects; MSelectionList partialHairObjects; MDagPathArray fullSkullObjects; MSelectionList partialSkullObjects; #endif //! the total number of verts we'll write to the WFType. int totalverts; //! the total number of faces we'll write to the WFType. int totalfaces; //! the total number of fverts we'll write to the WFType. int totalfverts; MSpace::Space space; MStatus objListInit(); MStatus separateOutPartialMeshes( #if GET_GEOM_FROM_DATABLOCK MObjectArray& objects, MObjectArray& components, MObjectArray& fullObjects, MObjectArray& partialMeshes, MObjectArray& partialMeshComponents #else MSelectionList& objectList, MDagPathArray& fullObjects, MSelectionList& partialMeshes #endif ); MStatus mtlLookupInit(bool**& growthFaces, bool**& collisionFaces); void mtlLookupCleanup(bool**& growthFaces, bool**& collisionFaces); MStatus createMtlLookup(MSelectionList& objectList, bool**& lookupTbl); void deleteMtlLookup(MSelectionList& objectList, bool**& lookupTbl); void exportFullObjects( FILE* exportFile, #if GET_GEOM_FROM_DATABLOCK MObjectArray& objects, #else MDagPathArray& objects, #endif MObjectArray tesselations, const char* surfaceMaterial, const char* curveMaterial, int& objectIndex, int& vtxOffset, int& faceOffset ); void exportPartialMeshes( FILE* exportFile, #if GET_GEOM_FROM_DATABLOCK MObjectArray& meshList, #else MSelectionList& meshList, #endif bool** activeFaceMap, const char* activeFaceMaterial, int& objectIndex, int& vertexOffset, int& faceOffset ); MStatus doExport( MString fileName, MObjectArray tesselations, bool** growthFaces, bool** collisionFaces ); void storeMeshInWFTYPE( WFTYPE* wf, WFTYPE* uvs, MItMeshVertex& vertexIter, MItMeshPolygon& faceIter, int& vertexIndex, int& faceIndex, int& faceVertexIndex ); void storeObjectInWFTYPE( WFTYPE* wf, WFTYPE* uvs, #if GET_GEOM_FROM_DATABLOCK MObject& object, #else MDagPath& object, #endif MObject tempMesh, int& vertexIndex, int& faceIndex, int& faceVertexIndex ); void getObjectCounts( #if GET_GEOM_FROM_DATABLOCK MObject& object, #else MDagPath& object, #endif GeomType geomType, int& numVertices, int& numFaces, int& numFaceVertices, int uTess, int vTess, int sDept, int sSamp, ShaveExportData* exportData, MObjectArray& tesselations, bool includeDisplacements = false ); MStatus wfInit( int uTess, int vTess, int sDept, int sSamp, ShaveExportData& exportData, MObjectArray& tesselations ); bool checkExported(); MStatus doWFType(WFTYPE* wf, WFTYPE* uvs, MObjectArray tesselations); MObject getConnectedShader(MFnMesh); void getCurveSamples( #if GET_GEOM_FROM_DATABLOCK MObject curve, MFloatPointArray& samples #else MDagPath curve, MFloatPointArray& samples #endif ); MString getShaderTexture(MObject shadingGroup); }; #endif