//! 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; }