// ==================================== // Helper Functions // ==================================== // Create component groups void createComp(MFnMeshData &dataCreator, MFn::Type compType, unsigned compId, MIntArray &compList) { MStatus returnStatus; MFnSingleIndexedComponent comp; MObject compObj = comp.create(compType,&returnStatus); MWARNERR(returnStatus, "cannot create MFnSingleIndexedComponent"); returnStatus = comp.addElements(compList); MWARNERR(returnStatus, "Error in addElements() for MFnSingleIndexedComponent"); returnStatus = dataCreator.addObjectGroup(compId); MWARNERR(returnStatus, "Error in addObjectGroup()"); returnStatus = dataCreator.setObjectGroupComponent(compId, compObj); MWARNERR(returnStatus, "Error in setObjectGroupComponent()"); }
//! Caller is expected to delete the returned value static OpenSubdiv::Far::TopologyRefiner * gatherTopology( MFnMesh & inMeshFn, MItMeshPolygon & inMeshItPolygon, OpenSubdiv::Sdc::SchemeType type, OpenSubdiv::Sdc::Options options, bool * hasUVs, bool * hasColors, std::vector<MFloatArray> & uvSet_uCoords, std::vector<MFloatArray> & uvSet_vCoords, std::vector<MColorArray> & colorSet_colors, float * maxCreaseSharpness=0 ) { MStatus returnStatus; // Gather FVarData MStringArray uvSetNames; MStringArray colorSetNames; std::vector<int> colorSetChannels; std::vector<MFnMesh::MColorRepresentation> colorSetReps; int totalColorSetChannels = 0; returnStatus = getMayaFvarFieldParams(inMeshFn, uvSetNames, colorSetNames, colorSetChannels, colorSetReps, totalColorSetChannels); MWARNERR(returnStatus, "Failed to retrieve Maya face-varying parameters"); // Storage for UVs and ColorSets for face-vertex MIntArray fvArray; // face vertex array uvSet_uCoords.clear(); uvSet_uCoords.resize(uvSetNames.length()); uvSet_vCoords.clear(); uvSet_vCoords.resize(uvSetNames.length()); colorSet_colors.clear();colorSet_colors.resize(colorSetNames.length()); // Put the data in the format needed for OSD Descriptor desc; int numFaceVertices = inMeshFn.numFaceVertices(); desc.numVertices = inMeshFn.numVertices(); desc.numFaces = inMeshItPolygon.count(); int * vertsPerFace = new int[desc.numFaces], * vertIndices = new int[numFaceVertices]; desc.numVertsPerFace = vertsPerFace; desc.vertIndicesPerFace = vertIndices; // Create Topology for (inMeshItPolygon.reset(); !inMeshItPolygon.isDone(); inMeshItPolygon.next()) { inMeshItPolygon.getVertices(fvArray); int nverts = fvArray.length(); vertsPerFace[inMeshItPolygon.index()] = nverts; for (int i=0; i<nverts; ++i) { *vertIndices++ = fvArray[i]; } } // Add Face-Varying data to the descriptor Descriptor::FVarChannel * channels = NULL; *hasUVs = uvSet_uCoords.size() > 0 && uvSet_vCoords.size() > 0; *hasColors = colorSet_colors.size() > 0; // Note : Only supports 1 channel of UVs and 1 channel of color if (*hasUVs || *hasColors) { // Create 2 face-varying channel descriptor that will hold UVs and color desc.numFVarChannels = 2; channels = new Descriptor::FVarChannel[desc.numFVarChannels]; desc.fvarChannels = channels; int * uvIndices = new int[numFaceVertices]; channels[CHANNELUV].valueIndices = uvIndices; channels[CHANNELUV].numValues = 0; int * colorIndices = new int[numFaceVertices]; channels[CHANNELCOLOR].valueIndices = colorIndices; channels[CHANNELCOLOR].numValues = 0; // Obtain UV information if (*hasUVs) { inMeshFn.getUVs(uvSet_uCoords[0], uvSet_vCoords[0], &uvSetNames[0]); assert( uvSet_uCoords[0].length() == uvSet_vCoords[0].length() ); int uvId = 0, nUVs = 0; for (int faceIndex = 0; faceIndex < inMeshFn.numPolygons(); ++faceIndex) { int numVertices = inMeshFn.polygonVertexCount(faceIndex); for (int v = 0; v < numVertices; v++) { inMeshFn.getPolygonUVid(faceIndex, v, uvId, &uvSetNames[0]); uvIndices[nUVs++] = uvId; } } channels[CHANNELUV].numValues = uvSet_uCoords[0].length(); } // Obtain color information if (*hasColors) { inMeshFn.getColors(colorSet_colors[0], &colorSetNames[0]); int colorId = 0, nColors = 0; bool addDefaultColor = true; for (int faceIndex = 0; faceIndex < inMeshFn.numPolygons(); ++faceIndex) { int numVertices = inMeshFn.polygonVertexCount(faceIndex); for ( int v = 0 ; v < numVertices; v++ ) { inMeshFn.getColorIndex(faceIndex, v, colorId, &colorSetNames[0]); if (colorId == -1) { if (addDefaultColor) { addDefaultColor = false; colorSet_colors[0].append(MColor(1.0, 1.0, 1.0, 1.0)); } colorId = colorSet_colors[0].length() - 1; } colorIndices[nColors ++] = colorId; } } channels[CHANNELCOLOR].numValues = colorSet_colors[0].length(); } } // Apply Creases float maxEdgeCrease = getCreaseEdges( inMeshFn, desc ); float maxVertexCrease = getCreaseVertices( inMeshFn, desc ); OpenSubdiv::Far::TopologyRefiner * refiner = OpenSubdiv::Far::TopologyRefinerFactory<Descriptor>::Create(desc, OpenSubdiv::Far::TopologyRefinerFactory<Descriptor>::Options(type, options)); delete [] desc.numVertsPerFace; delete [] desc.vertIndicesPerFace; delete [] desc.creaseVertexIndexPairs; delete [] desc.creaseWeights; delete [] desc.cornerVertexIndices; delete [] desc.cornerWeights; if (*hasUVs || *hasColors) { for(int i = 0 ; i < desc.numFVarChannels ; i ++) { delete [] channels[i].valueIndices; } delete [] channels; } if (maxCreaseSharpness) { *maxCreaseSharpness = std::max(maxEdgeCrease, maxVertexCrease); } return refiner; }
//! Create OSD HBR mesh. //! Caller is expected to delete the resulting hbrMesh returned HMesh * createOsdHbrFromPoly( MFnMesh const & inMeshFn, MItMeshPolygon & inMeshItPolygon, std::vector<int> & fvarIndices, std::vector<int> & fvarWidths) { MStatus returnStatus; // == Mesh Properties // Gather FVarData MStringArray uvSetNames; MStringArray colorSetNames; std::vector<int> colorSetChannels; std::vector<MFnMesh::MColorRepresentation> colorSetReps; int totalColorSetChannels = 0; returnStatus = getMayaFvarFieldParams(inMeshFn, uvSetNames, colorSetNames, colorSetChannels, colorSetReps, totalColorSetChannels); MWARNERR(returnStatus, "Failed to retrieve Maya face-varying parameters"); // Create face-varying data with independent float channels of dimension 1 // Note: This FVarData needs to be kept around for the duration of the HBR mesh int totalFvarWidth = 2*uvSetNames.length() + totalColorSetChannels; fvarIndices.resize(totalFvarWidth); fvarWidths.resize(totalFvarWidth); for (int i=0; i < totalFvarWidth; ++i) { fvarIndices[i] = i; fvarWidths[i] = 1; } // temp storage for UVs and ColorSets for a face MIntArray fvArray; // face vertex array std::vector<MFloatArray> uvSet_uCoords(uvSetNames.length()); std::vector<MFloatArray> uvSet_vCoords(uvSetNames.length()); std::vector<MColorArray> colorSet_colors(colorSetNames.length()); // ===================================== // Init HBR // ===================================== // Determine HBR Subdiv Method static HCatmark _catmark; // Create HBR mesh assert(fvarIndices.size() == fvarWidths.size()); HMesh * hbrMesh = new HMesh( &_catmark, (int)fvarIndices.size(), (fvarIndices.size() > 0) ? &fvarIndices[0] : NULL, (fvarWidths.size() > 0) ? &fvarWidths[0] : NULL, totalFvarWidth ); // Create Stub HBR Vertices int numVerts = inMeshFn.numVertices(); OpenSubdiv::OsdVertex v; for(int i=0; i<numVerts; i++ ) { hbrMesh->NewVertex( i, v ); } // =================================================== // Create HBR Topology // =================================================== assert(totalFvarWidth == hbrMesh->GetTotalFVarWidth()); unsigned int ptxidx = 0; for( inMeshItPolygon.reset(); !inMeshItPolygon.isDone(); inMeshItPolygon.next() ) { // Verts for this face inMeshItPolygon.getVertices(fvArray); unsigned int nv = fvArray.length(); bool valid = true; for(unsigned int j=0;j<fvArray.length(); j++) { HVertex const * origin = hbrMesh->GetVertex( fvArray[j] ), * destination = hbrMesh->GetVertex( fvArray[(j+1)%nv] ); HHalfedge const * opposite = destination->GetEdge(origin); if(origin==NULL || destination==NULL) { fprintf(stderr, "Skipping face: An edge was specified that connected a nonexistent vertex\n"); valid = false; break; } if(origin == destination) { fprintf(stderr, "Skipping face: An edge was specified that connected a vertex to itself\n"); valid = false; break; } if(opposite && opposite->GetOpposite() ) { fprintf(stderr, "Skipping face: A non-manifold edge incident to more than 2 faces was found\n"); valid = false; break; } if(origin->GetEdge(destination)) { fprintf(stderr, "Skipping face: An edge connecting two vertices was specified more than once." " It's likely that an incident face was flipped\n"); valid = false; break; } } // Update faces const int * fvArrayPtr = &(fvArray[0]); // get the raw int* array from std::vector<int> OpenSubdiv::HbrFace<OpenSubdiv::OsdVertex> * face = hbrMesh->NewFace(nv, fvArrayPtr, 0); // Increment ptex index face->SetPtexIndex(ptxidx); // Add FaceVaryingData (UVSets, ...) if (totalFvarWidth > 0) { // Retrieve all UV and ColorSet data MIntArray faceCounts; for (unsigned int i=0; i < uvSetNames.length(); ++i) { returnStatus = inMeshItPolygon.getUVs(uvSet_uCoords[i], uvSet_vCoords[i], &uvSetNames[i] ); MWARNERR(returnStatus, "Cannot get UVs"); } for (unsigned int i=0; i < colorSetNames.length(); ++i) { returnStatus = inMeshItPolygon.getColors (colorSet_colors[i], &colorSetNames[i]); MWARNERR(returnStatus, "Cannot get face vertex colors"); } std::vector<float> fvarItem(totalFvarWidth); // storage for all the face-varying channels for this face-vertex // loop over each uvSet and the uvs within for (unsigned int fvid=0; fvid < fvArray.length(); ++fvid) { int fvarItemIndex = 0; // Handle uvSets for( unsigned int uvSetIt=0; uvSetIt < uvSetNames.length(); ++uvSetIt ) { fvarItem[fvarItemIndex] = uvSet_uCoords[uvSetIt][fvid]; fvarItem[fvarItemIndex+1] = uvSet_vCoords[uvSetIt][fvid]; fvarItemIndex +=2; } // Handle colorSets for( unsigned int colorSetIt=0; colorSetIt < colorSetNames.length(); ++colorSetIt ) { if (colorSetChannels[colorSetIt] == 1) { fvarItem[fvarItemIndex] = colorSet_colors[colorSetIt][fvid].a; } else if (colorSetChannels[colorSetIt] == 3) { fvarItem[fvarItemIndex] = colorSet_colors[colorSetIt][fvid].r; fvarItem[fvarItemIndex+1] = colorSet_colors[colorSetIt][fvid].g; fvarItem[fvarItemIndex+2] = colorSet_colors[colorSetIt][fvid].b; } else { // colorSetChannels[colorSetIt] == 4 fvarItem[fvarItemIndex] = colorSet_colors[colorSetIt][fvid].r; fvarItem[fvarItemIndex+1] = colorSet_colors[colorSetIt][fvid].g; fvarItem[fvarItemIndex+2] = colorSet_colors[colorSetIt][fvid].b; fvarItem[fvarItemIndex+3] = colorSet_colors[colorSetIt][fvid].a; } fvarItemIndex += colorSetChannels[colorSetIt]; } assert((fvarItemIndex) == totalFvarWidth); // For UVs, sanity check the resulting value // Insert into the HBR structure for that face HVertex * hbrVertex = hbrMesh->GetVertex( fvArray[fvid] ); HFvarData & fvarData = hbrVertex->GetFVarData(face); if (not fvarData.IsInitialized()) { fvarData.SetAllData(totalFvarWidth, &fvarItem[0]); } else if (not fvarData.CompareAll(totalFvarWidth, &fvarItem[0])) { // If data exists for this face vertex, but is different // (e.g. we're on a UV seam) create another fvar datum OpenSubdiv::HbrFVarData<OpenSubdiv::OsdVertex> &fvarData_new = hbrVertex->NewFVarData(face); fvarData_new.SetAllData( totalFvarWidth, &fvarItem[0] ); } } } // Increment ptxidx and store off ptex index values // The number of ptexIds needed is 1 if a quad. Otherwise it is the number of // vertices for the face. int numPtexIdsForFace; if (valid) { numPtexIdsForFace = ( nv != 4 ) ? nv : 1 ; } else { numPtexIdsForFace = 0; } ptxidx += numPtexIdsForFace; } // Apply Creases applyCreaseEdges( inMeshFn, hbrMesh ); applyCreaseVertices( inMeshFn, hbrMesh ); // Return the resulting HBR Mesh // Note that boundaryMethods and hbrMesh->Finish() still need to be called return hbrMesh; }
//! Caller is expected to delete the returned value static OpenSubdiv::Far::TopologyRefiner * gatherTopology( MFnMesh const & inMeshFn, MItMeshPolygon & inMeshItPolygon, OpenSubdiv::Sdc::SchemeType type, OpenSubdiv::Sdc::Options options, float * maxCreaseSharpness=0 ) { MStatus returnStatus; // Gather FVarData MStringArray uvSetNames; MStringArray colorSetNames; std::vector<int> colorSetChannels; std::vector<MFnMesh::MColorRepresentation> colorSetReps; int totalColorSetChannels = 0; returnStatus = getMayaFvarFieldParams(inMeshFn, uvSetNames, colorSetNames, colorSetChannels, colorSetReps, totalColorSetChannels); MWARNERR(returnStatus, "Failed to retrieve Maya face-varying parameters"); // Create face-varying data with independent float channels of dimension 1 // Note: This FVarData needs to be kept around for the duration of the HBR mesh int totalFvarWidth = 2*uvSetNames.length() + totalColorSetChannels; // temp storage for UVs and ColorSets for a face MIntArray fvArray; // face vertex array std::vector<MFloatArray> uvSet_uCoords(uvSetNames.length()); std::vector<MFloatArray> uvSet_vCoords(uvSetNames.length()); std::vector<MColorArray> colorSet_colors(colorSetNames.length()); Descriptor desc; desc.numVertices = inMeshFn.numVertices(); desc.numFaces = inMeshItPolygon.count(); int * vertsPerFace = new int[desc.numFaces], * vertIndices = new int[inMeshFn.numFaceVertices()]; desc.numVertsPerFace = vertsPerFace; desc.vertIndicesPerFace = vertIndices; // Create Topology for( inMeshItPolygon.reset(); !inMeshItPolygon.isDone(); inMeshItPolygon.next() ) { inMeshItPolygon.getVertices(fvArray); int nverts = fvArray.length(); vertsPerFace[inMeshItPolygon.index()] = nverts; for (int i=0; i<nverts; ++i) { *vertIndices++ = fvArray[i]; } // Add FaceVaryingData (UVSets, ...) if (totalFvarWidth > 0) { // XXXX // Retrieve all UV and ColorSet topology for (unsigned int i=0; i < uvSetNames.length(); ++i) { inMeshItPolygon.getUVs(uvSet_uCoords[i], uvSet_vCoords[i], &uvSetNames[i] ); } for (unsigned int i=0; i < colorSetNames.length(); ++i) { inMeshItPolygon.getColors(colorSet_colors[i], &colorSetNames[i]); } // Handle uvSets for (unsigned int fvid=0; fvid < fvArray.length(); ++fvid) { } // Handle colorSets for( unsigned int colorSetIt=0; colorSetIt < colorSetNames.length(); ++colorSetIt ) { } } } // Apply Creases float maxEdgeCrease = getCreaseEdges( inMeshFn, desc ); float maxVertexCrease = getCreaseVertices( inMeshFn, desc ); OpenSubdiv::Far::TopologyRefiner * refiner = OpenSubdiv::Far::TopologyRefinerFactory<Descriptor>::Create(desc, OpenSubdiv::Far::TopologyRefinerFactory<Descriptor>::Options(type, options)); delete [] desc.numVertsPerFace; delete [] desc.vertIndicesPerFace; delete [] desc.creaseVertexIndexPairs; delete [] desc.creaseWeights; delete [] desc.cornerVertexIndices; delete [] desc.cornerWeights; if (maxCreaseSharpness) { *maxCreaseSharpness = std::max(maxEdgeCrease, maxVertexCrease); } return refiner; }