// Reference: OSD shape_utils.h:: applyTags() "corner" static float getCreaseVertices( MFnMesh const & inMeshFn, Descriptor & outDesc) { MUintArray tVertexIds; MDoubleArray tCreaseData; float maxCreaseValue = 0.0f; if ( inMeshFn.getCreaseVertices(tVertexIds, tCreaseData) ) { assert( tVertexIds.length() == tCreaseData.length() ); int ncorners = tVertexIds.length(); int * verts = new int[ncorners*2]; float * weights = new float[ncorners]; // Has crease vertices for (unsigned int j=0; j < tVertexIds.length(); j++) { assert( tCreaseData[j] >= 0.0 ); verts[j] = tVertexIds[j]; weights[j] = float(tCreaseData[j]); maxCreaseValue = std::max(float(tCreaseData[j]), maxCreaseValue); } outDesc.numCorners = ncorners; outDesc.cornerVertexIndices = verts; outDesc.cornerWeights = weights; } return maxCreaseValue; }
// Reference: OSD shape_utils.h:: applyTags() "corner" float applyCreaseVertices( MFnMesh const & inMeshFn, HMesh * hbrMesh ) { MUintArray tVertexIds; MDoubleArray tCreaseData; float maxCreaseValue = 0.0f; if ( inMeshFn.getCreaseVertices(tVertexIds, tCreaseData) ) { assert( tVertexIds.length() == tCreaseData.length() ); // Has crease vertices for (unsigned int j=0; j < tVertexIds.length(); j++) { // Assumption: The OSD vert ids are identical to those of the Maya mesh HVertex * v = hbrMesh->GetVertex( tVertexIds[j] ); if(v) { assert( tCreaseData[j] >= 0.0 ); v->SetSharpness( (float)tCreaseData[j] ); maxCreaseValue = std::max(float(tCreaseData[j]), maxCreaseValue); } else { fprintf(stderr, "warning: cannot find vertex for corner tag (%d)\n", tVertexIds[j] ); } } } return maxCreaseValue; }
// Reference: OSD shape_utils.h:: applyTags() "crease" static float getCreaseEdges(MFnMesh const & inMeshFn, Descriptor & outDesc) { MUintArray tEdgeIds; MDoubleArray tCreaseData; float maxCreaseValue = 0.0f; if (inMeshFn.getCreaseEdges(tEdgeIds, tCreaseData)) { assert( tEdgeIds.length() == tCreaseData.length() ); int ncreases = tEdgeIds.length(); int * vertPairs = new int[ncreases*2]; float * weights = new float[ncreases]; int2 edgeVerts; for (unsigned int j=0; j < tEdgeIds.length(); j++) { assert( tCreaseData[j] >= 0.0 ); inMeshFn.getEdgeVertices(tEdgeIds[j], edgeVerts); vertPairs[j*2 ] = edgeVerts[0]; vertPairs[j*2+1] = edgeVerts[1]; weights[j] = float(tCreaseData[j]); maxCreaseValue = std::max(float(tCreaseData[j]), maxCreaseValue); } outDesc.numCreases = ncreases; outDesc.creaseVertexIndexPairs = vertPairs; outDesc.creaseWeights = weights; } return maxCreaseValue; }
// Reference: OSD shape_utils.h:: applyTags() "crease" float applyCreaseEdges(MFnMesh const & inMeshFn, HMesh * hbrMesh) { MStatus returnStatus; MUintArray tEdgeIds; MDoubleArray tCreaseData; float maxCreaseValue = 0.0f; if (inMeshFn.getCreaseEdges(tEdgeIds, tCreaseData)) { assert( tEdgeIds.length() == tCreaseData.length() ); // Has crease edges int2 edgeVerts; for (unsigned int j=0; j < tEdgeIds.length(); j++) { // Get vert ids from maya edge int edgeId = tEdgeIds[j]; returnStatus = inMeshFn.getEdgeVertices(edgeId, edgeVerts); // Assumption: The OSD vert ids are identical to those of the Maya mesh HVertex const * v = hbrMesh->GetVertex( edgeVerts[0] ), * w = hbrMesh->GetVertex( edgeVerts[1] ); HHalfedge * e = 0; if( v and w ) { if( (e = v->GetEdge(w)) == 0) { e = w->GetEdge(v); } if(e) { assert( tCreaseData[j] >= 0.0 ); e->SetSharpness( (float)tCreaseData[j] ); maxCreaseValue = std::max(float(tCreaseData[j]), maxCreaseValue); } else { fprintf(stderr, "warning: cannot find edge for crease tag (%d,%d)\n", edgeVerts[0], edgeVerts[1] ); } } } } return maxCreaseValue; }
void liqRibSubdivisionData::addExtraTags( MObject &mesh, SBD_EXTRA_TAG extraTag ) { CM_TRACE_FUNC("liqRibSubdivisionData::addExtraTags("<<MFnDagNode(mesh).fullPathName()<<","<<extraTag<<")"); MStatus status; MFnMesh fnMesh( mesh ); MUintArray ids; MDoubleArray creaseData; if( TAG_CREASE == extraTag ) { status = fnMesh.getCreaseEdges( ids, creaseData ); if( status == MS::kSuccess ) { MItMeshEdge itEdge( mesh ); int prevIndex; for( unsigned i( 0 ); i < ids.length(); i++ ) { v_tags.push_back( "crease" ); v_nargs.push_back( 2 ); v_nargs.push_back( 1 ); itEdge.setIndex( ids[i], prevIndex ); v_intargs.push_back( itEdge.index( 0 ) ); v_intargs.push_back( itEdge.index( 1 ) ); v_floatargs.push_back( creaseData[i] ); } } } if( TAG_CORNER == extraTag ) { status = fnMesh.getCreaseVertices( ids, creaseData ); if( status == MS::kSuccess ) { for( unsigned i( 0 ); i < ids.length(); i++ ) { v_tags.push_back( "corner" ); v_nargs.push_back( 1 ); v_nargs.push_back( 1 ); v_intargs.push_back( ids[i] ); v_floatargs.push_back( creaseData[i] ); } } } }
void userCB( MUintArray componentIds[], unsigned int count, void *clientData ) { cout << "poly component id modified"; cout << endl; if ( count != MPolyMessage::kLastErrorIndex ) return; unsigned int i, id; unsigned int kDeletedId = MPolyMessage::deletedId(); MUintArray vertexIds = componentIds[MPolyMessage::kVertexIndex]; for ( i = 0; i < vertexIds.length(); i++ ) { id = vertexIds[i]; if ( id == kDeletedId ) cout << "vertex " << i << " deleted" << endl; else if ( i != id ) cout << "vertex " << i << " " << id << endl; } MUintArray edgeIds = componentIds[MPolyMessage::kEdgeIndex]; for ( i = 0; i < edgeIds.length(); i++ ) { id = edgeIds[i]; if ( id == kDeletedId ) cout << "edge " << i << " deleted" << endl; else if ( i != id ) cout << "edge " << i << " " << id << endl; } MUintArray faceIds = componentIds[MPolyMessage::kFaceIndex]; for ( i = 0; i < faceIds.length(); i++ ) { id = faceIds[i]; if ( id == kDeletedId ) cout << "face " << i << " deleted" << endl; else if ( i != id ) cout << "face " << i << " " << id << endl; } }
void OsdPtexMeshData::rebuildHbrMeshIfNeeded(OpenSubdivPtexShader *shader) { MStatus status; if (!_meshTopoDirty && !shader->getHbrMeshDirty()) return; MFnMesh meshFn(_meshDagPath, &status); if (status != MS::kSuccess) return; int level = shader->getLevel(); if (level < 1) level =1; SchemeType scheme = shader->getScheme(); if (scheme == kLoop) scheme = kCatmark; // XXX: avoid loop for now // Get Maya vertex topology and crease data MIntArray vertexCount; MIntArray vertexList; meshFn.getVertices(vertexCount, vertexList); MUintArray edgeIds; MDoubleArray edgeCreaseData; meshFn.getCreaseEdges(edgeIds, edgeCreaseData); MUintArray vtxIds; MDoubleArray vtxCreaseData; meshFn.getCreaseVertices(vtxIds, vtxCreaseData); if (vertexCount.length() == 0) return; // Cache attribute values _level = shader->getLevel(); _scheme = shader->getScheme(); _kernel = shader->getKernel(); _adaptive = shader->isAdaptive(); _interpBoundary = shader->getInterpolateBoundary(); // Copy Maya vectors into std::vectors std::vector<int> numIndices(&vertexCount[0], &vertexCount[vertexCount.length()]); std::vector<int> faceIndices(&vertexList[0], &vertexList[vertexList.length()]); std::vector<int> vtxCreaseIndices(&vtxIds[0], &vtxIds[vtxIds.length()]); std::vector<double> vtxCreases(&vtxCreaseData[0], &vtxCreaseData[vtxCreaseData.length()]); std::vector<double> edgeCreases(&edgeCreaseData[0], &edgeCreaseData[edgeCreaseData.length()]); // Edge crease index is stored as pairs of vertex ids int nEdgeIds = edgeIds.length(); std::vector<int> edgeCreaseIndices; edgeCreaseIndices.resize(nEdgeIds*2); for (int i = 0; i < nEdgeIds; ++i) { int2 vertices; status = meshFn.getEdgeVertices(edgeIds[i], vertices); if (status.error()) { status.perror("ERROR can't get creased edge vertices"); continue; } edgeCreaseIndices[i*2] = vertices[0]; edgeCreaseIndices[i*2+1] = vertices[1]; } // Convert attribute enums to HBR enums (this is why the enums need to match) // XXX use some sort of built-in transmorgification avoid assumption? HbrMeshUtil::SchemeType hbrScheme = (HbrMeshUtil::SchemeType) _scheme; OsdHbrMesh::InterpolateBoundaryMethod hbrInterpBoundary = (OsdHbrMesh::InterpolateBoundaryMethod) _interpBoundary; // Convert Maya mesh to internal HBR representation _hbrmesh = ConvertToHBR(meshFn.numVertices(), numIndices, faceIndices, vtxCreaseIndices, vtxCreases, std::vector<int>(), std::vector<float>(), edgeCreaseIndices, edgeCreases, hbrInterpBoundary, hbrScheme, true ); // add ptex indices to HBR // note: GL function can't be used in prepareForDraw API. _needsInitializeMesh = true; // Mesh topology data is up to date _meshTopoDirty = false; shader->setHbrMeshDirty(false); }
// #### rebuildHbrMeshIfNeeded // // If the topology of the mesh changes, or any attributes that affect // how the mesh is computed the original HBR needs to be rebuilt // which will trigger a rebuild of the FAR mesh and subsequent buffers. // void OsdMeshData::rebuildHbrMeshIfNeeded(OpenSubdivShader *shader) { MStatus status = MS::kSuccess; if (!_meshTopoDirty && !shader->getHbrMeshDirty()) return; MFnMesh meshFn(_meshDagPath); // Cache attribute values _level = shader->getLevel(); _kernel = shader->getKernel(); _adaptive = shader->isAdaptive(); _uvSet = shader->getUVSet(); // Get Maya vertex topology and crease data MIntArray vertexCount; MIntArray vertexList; meshFn.getVertices(vertexCount, vertexList); MUintArray edgeIds; MDoubleArray edgeCreaseData; meshFn.getCreaseEdges(edgeIds, edgeCreaseData); MUintArray vtxIds; MDoubleArray vtxCreaseData; meshFn.getCreaseVertices(vtxIds, vtxCreaseData); if (vertexCount.length() == 0) return; // Copy Maya vectors into std::vectors std::vector<int> numIndices(&vertexCount[0], &vertexCount[vertexCount.length()]); std::vector<int> faceIndices(&vertexList[0], &vertexList[vertexList.length()]); std::vector<int> vtxCreaseIndices(&vtxIds[0], &vtxIds[vtxIds.length()]); std::vector<double> vtxCreases(&vtxCreaseData[0], &vtxCreaseData[vtxCreaseData.length()]); std::vector<double> edgeCreases(&edgeCreaseData[0], &edgeCreaseData[edgeCreaseData.length()]); // Edge crease index is stored as pairs of vertex ids int nEdgeIds = edgeIds.length(); std::vector<int> edgeCreaseIndices; edgeCreaseIndices.resize(nEdgeIds*2); for (int i = 0; i < nEdgeIds; ++i) { int2 vertices; status = meshFn.getEdgeVertices(edgeIds[i], vertices); if (status.error()) { MERROR(status, "OpenSubdivShader: Can't get edge vertices"); continue; } edgeCreaseIndices[i*2] = vertices[0]; edgeCreaseIndices[i*2+1] = vertices[1]; } // Convert attribute enums to HBR enums (this is why the enums need to match) HbrMeshUtil::SchemeType hbrScheme = (HbrMeshUtil::SchemeType) shader->getScheme(); OsdHbrMesh::InterpolateBoundaryMethod hbrInterpBoundary = (OsdHbrMesh::InterpolateBoundaryMethod) shader->getInterpolateBoundary(); OsdHbrMesh::InterpolateBoundaryMethod hbrInterpUVBoundary = (OsdHbrMesh::InterpolateBoundaryMethod) shader->getInterpolateUVBoundary(); // clear any existing face-varying descriptor if (_fvarDesc) { delete _fvarDesc; _fvarDesc = NULL; } // read UV data from maya and build per-face per-vert list of UVs for HBR face-varying data std::vector< float > uvList; status = buildUVList( meshFn, uvList ); if (! status.error()) { // Create face-varying data descriptor. The memory required for indices // and widths needs to stay alive as the HBR library only takes in the // pointers and assumes the client will maintain the memory so keep _fvarDesc // around as long as _hbrmesh is around. int fvarIndices[] = { 0, 1 }; int fvarWidths[] = { 1, 1 }; _fvarDesc = new FVarDataDesc( 2, fvarIndices, fvarWidths, 2, hbrInterpUVBoundary ); } if (_fvarDesc && hbrScheme != HbrMeshUtil::kCatmark) { MGlobal::displayWarning("Face-varying not yet supported for Loop/Bilinear, using Catmull-Clark"); hbrScheme = HbrMeshUtil::kCatmark; } // Convert Maya mesh to internal HBR representation _hbrmesh = ConvertToHBR(meshFn.numVertices(), numIndices, faceIndices, vtxCreaseIndices, vtxCreases, std::vector<int>(), std::vector<float>(), edgeCreaseIndices, edgeCreases, hbrInterpBoundary, hbrScheme, false, // no ptex _fvarDesc, _fvarDesc?&uvList:NULL); // yes fvar (if have UVs) // note: GL function can't be used in prepareForDraw API. _needsInitializeMesh = true; // Mesh topology data is up to date _meshTopoDirty = false; shader->setHbrMeshDirty(false); }
// virtual bool MayaMeshWriter::writeMeshAttrs(const UsdTimeCode &usdTime, UsdGeomMesh &primSchema) { MStatus status = MS::kSuccess; // Write parent class attrs writeTransformAttrs(usdTime, primSchema); // Return if usdTime does not match if shape is animated if (usdTime.IsDefault() == isShapeAnimated() ) { // skip shape as the usdTime does not match if shape isAnimated value return true; } MFnMesh lMesh( getDagPath(), &status ); if ( !status ) { MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" ); return false; } unsigned int numVertices = lMesh.numVertices(); unsigned int numPolygons = lMesh.numPolygons(); // Set mesh attrs ========== // Get points // TODO: Use memcpy() const float* mayaRawPoints = lMesh.getRawPoints(&status); VtArray<GfVec3f> points(numVertices); for (unsigned int i = 0; i < numVertices; i++) { unsigned int floatIndex = i*3; points[i].Set(mayaRawPoints[floatIndex], mayaRawPoints[floatIndex+1], mayaRawPoints[floatIndex+2]); } primSchema.GetPointsAttr().Set(points, usdTime); // ANIMATED // Compute the extent using the raw points VtArray<GfVec3f> extent(2); UsdGeomPointBased::ComputeExtent(points, &extent); primSchema.CreateExtentAttr().Set(extent, usdTime); // Get faceVertexIndices unsigned int numFaceVertices = lMesh.numFaceVertices(&status); VtArray<int> faceVertexCounts(numPolygons); VtArray<int> faceVertexIndices(numFaceVertices); MIntArray mayaFaceVertexIndices; // used in loop below unsigned int curFaceVertexIndex = 0; for (unsigned int i = 0; i < numPolygons; i++) { lMesh.getPolygonVertices(i, mayaFaceVertexIndices); faceVertexCounts[i] = mayaFaceVertexIndices.length(); for (unsigned int j=0; j < mayaFaceVertexIndices.length(); j++) { faceVertexIndices[ curFaceVertexIndex ] = mayaFaceVertexIndices[j]; // push_back curFaceVertexIndex++; } } primSchema.GetFaceVertexCountsAttr().Set(faceVertexCounts); // not animatable primSchema.GetFaceVertexIndicesAttr().Set(faceVertexIndices); // not animatable // Read usdSdScheme attribute. If not set, we default to defaultMeshScheme // flag that can be user defined and initialized to catmullClark TfToken sdScheme = PxrUsdMayaMeshUtil::getSubdivScheme(lMesh, getArgs().defaultMeshScheme); primSchema.CreateSubdivisionSchemeAttr(VtValue(sdScheme), true); // Polygonal Mesh Case if (sdScheme==UsdGeomTokens->none) { // Support for standard USD bool and with Mojito bool tag TfToken normalInterp=PxrUsdMayaMeshUtil::getEmitNormals(lMesh, UsdGeomTokens->none); if (normalInterp==UsdGeomTokens->faceVarying) { // Get References to members of meshData object MFloatVectorArray normalArray; MFloatVectorArray vertexNormalArray; lMesh.getNormals(normalArray, MSpace::kObject); // Iterate through each face in the mesh. vertexNormalArray.setLength(lMesh.numFaceVertices()); VtArray<GfVec3f> meshNormals(lMesh.numFaceVertices()); size_t faceVertIdx = 0; for (MItMeshPolygon faceIter(getDagPath()); !faceIter.isDone(); faceIter.next()) { // Iterate through each face-vertex. for (size_t locVertIdx = 0; locVertIdx < faceIter.polygonVertexCount(); ++locVertIdx, ++faceVertIdx) { int index=faceIter.normalIndex(locVertIdx); for (int j=0;j<3;j++) { meshNormals[faceVertIdx][j]=normalArray[index][j]; } } } primSchema.GetNormalsAttr().Set(meshNormals, usdTime); primSchema.SetNormalsInterpolation(normalInterp); } } else { TfToken sdInterpBound = PxrUsdMayaMeshUtil::getSubdivInterpBoundary( lMesh, UsdGeomTokens->edgeAndCorner); primSchema.CreateInterpolateBoundaryAttr(VtValue(sdInterpBound), true); TfToken sdFVInterpBound = PxrUsdMayaMeshUtil::getSubdivFVInterpBoundary( lMesh); primSchema.CreateFaceVaryingLinearInterpolationAttr( VtValue(sdFVInterpBound), true); assignSubDivTagsToUSDPrim( lMesh, primSchema); } // Holes - we treat InvisibleFaces as holes MUintArray mayaHoles = lMesh.getInvisibleFaces(); if (mayaHoles.length() > 0) { VtArray<int> subdHoles(mayaHoles.length()); for (unsigned int i=0; i < mayaHoles.length(); i++) { subdHoles[i] = mayaHoles[i]; } // not animatable in Maya, so we'll set default only primSchema.GetHoleIndicesAttr().Set(subdHoles); } // == Write UVSets as Vec2f Primvars MStringArray uvSetNames; if (getArgs().exportMeshUVs) { status = lMesh.getUVSetNames(uvSetNames); } for (unsigned int i=0; i < uvSetNames.length(); i++) { // Initialize the VtArray to the max possible size (facevarying) VtArray<GfVec2f> uvValues(numFaceVertices); TfToken interpolation=TfToken(); // Gather UV data and interpolation into a Vec2f VtArray and try to compress if possible if (_GetMeshUVSetData(lMesh, uvSetNames[i], &uvValues, &interpolation) == MS::kSuccess) { // XXX:bug 118447 // We should be able to configure the UV map name that triggers this // behavior, and the name to which it exports. // The UV Set "map1" is renamed st. This is a Pixar/USD convention TfToken setName(uvSetNames[i].asChar()); if (setName == "map1") setName=UsdUtilsGetPrimaryUVSetName(); // Create the primvar and set the values UsdGeomPrimvar uvSet = primSchema.CreatePrimvar(setName, SdfValueTypeNames->Float2Array, interpolation); uvSet.Set( uvValues ); // not animatable } } // == Gather ColorSets MStringArray colorSetNames; if (getArgs().exportColorSets) { status = lMesh.getColorSetNames(colorSetNames); } // shaderColor is used in our pipeline as displayColor. // shaderColor is used to fill faces where the colorset is not assigned MColorArray shaderColors; MObjectArray shaderObjs; VtArray<GfVec3f> shadersRGBData; TfToken shadersRGBInterp; VtArray<float> shadersAlphaData; TfToken shadersAlphaInterp; // If exportDisplayColor is set to true or we have color sets, // gather color & opacity from the shader including per face // assignment. Color set require this to initialize unauthored/unpainted faces if (getArgs().exportDisplayColor or colorSetNames.length()>0) { PxrUsdMayaUtil::GetLinearShaderColor(lMesh, numPolygons, &shadersRGBData, &shadersRGBInterp, &shadersAlphaData, &shadersAlphaInterp); } for (unsigned int i=0; i < colorSetNames.length(); i++) { bool isDisplayColor=false; if (colorSetNames[i]=="displayColor") { if (not getArgs().exportDisplayColor) continue; isDisplayColor=true; } if (colorSetNames[i]=="displayOpacity") { MGlobal::displayWarning("displayOpacity on mesh:" + lMesh.fullPathName() + " is a reserved PrimVar name in USD. Skipping..."); continue; } VtArray<GfVec3f> RGBData; TfToken RGBInterp; VtArray<GfVec4f> RGBAData; TfToken RGBAInterp; VtArray<float> AlphaData; TfToken AlphaInterp; MFnMesh::MColorRepresentation colorSetRep; bool clamped=false; // If displayColor uses shaderValues for non authored areas // and allow RGB and Alpha to have different interpolation // For all other colorSets the non authored values are set // to (1,1,1,1) and RGB and Alpha will have the same interplation // since they will be emitted as a Vec4f if (not _GetMeshColorSetData( lMesh, colorSetNames[i], isDisplayColor, shadersRGBData, shadersAlphaData, &RGBData, &RGBInterp, &RGBAData, &RGBAInterp, &AlphaData, &AlphaInterp, &colorSetRep, &clamped)) { MGlobal::displayWarning("Unable to retrieve colorSet data: " + colorSetNames[i] + " on mesh: "+ lMesh.fullPathName() + ". Skipping..."); continue; } if (isDisplayColor) { // We tag the resulting displayColor/displayOpacity primvar as // authored to make sure we reconstruct the colorset on import // The RGB is also convererted From DisplayToLinear _setDisplayPrimVar( primSchema, colorSetRep, RGBData, RGBInterp, AlphaData, AlphaInterp, clamped, true); } else { TfToken colorSetNameToken = TfToken( PxrUsdMayaUtil::SanitizeColorSetName( std::string(colorSetNames[i].asChar()))); if (colorSetRep == MFnMesh::kAlpha) { _createAlphaPrimVar(primSchema, colorSetNameToken, AlphaData, AlphaInterp, clamped); } else if (colorSetRep == MFnMesh::kRGB) { _createRGBPrimVar(primSchema, colorSetNameToken, RGBData, RGBInterp, clamped); } else if (colorSetRep == MFnMesh::kRGBA) { _createRGBAPrimVar(primSchema, colorSetNameToken, RGBAData, RGBAInterp, clamped); } } } // Set displayColor and displayOpacity only if they are NOT authored already // Since this primvar will come from the shader and not a colorset, // we are not adding the clamp attribute as custom data // If a displayColor/displayOpacity is added, it's not considered authored // we don't need to reconstruct this as a colorset since it orgininated // from bound shader[s], so the authored flag is set to false // Given that this RGB is for display, we do DisplayToLinear conversion if (getArgs().exportDisplayColor) { _setDisplayPrimVar( primSchema, MFnMesh::kRGBA, shadersRGBData, shadersRGBInterp, shadersAlphaData, shadersAlphaInterp, false, false); } return true; }
void MayaMeshWriter::writeSubD( const Alembic::AbcGeom::OV2fGeomParam::Sample & iUVs) { MStatus status = MS::kSuccess; MFnMesh lMesh( mDagPath, &status ); if ( !status ) { MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" ); } std::vector<float> points; std::vector<Alembic::Util::int32_t> facePoints; std::vector<Alembic::Util::int32_t> pointCounts; fillTopology(points, facePoints, pointCounts); Alembic::AbcGeom::OSubDSchema::Sample samp( Alembic::AbcGeom::V3fArraySample((const Imath::V3f *)&points.front(), points.size() / 3), Alembic::Abc::Int32ArraySample(facePoints), Alembic::Abc::Int32ArraySample(pointCounts)); samp.setUVs( iUVs ); MPlug plug = lMesh.findPlug("faceVaryingInterpolateBoundary"); if (!plug.isNull()) samp.setFaceVaryingInterpolateBoundary(plug.asInt()); plug = lMesh.findPlug("interpolateBoundary"); if (!plug.isNull()) samp.setInterpolateBoundary(plug.asInt()); plug = lMesh.findPlug("faceVaryingPropagateCorners"); if (!plug.isNull()) samp.setFaceVaryingPropagateCorners(plug.asInt()); std::vector <Alembic::Util::int32_t> creaseIndices; std::vector <Alembic::Util::int32_t> creaseLengths; std::vector <float> creaseSharpness; std::vector <Alembic::Util::int32_t> cornerIndices; std::vector <float> cornerSharpness; MUintArray edgeIds; MDoubleArray creaseData; if (lMesh.getCreaseEdges(edgeIds, creaseData) == MS::kSuccess) { unsigned int numCreases = creaseData.length(); creaseIndices.resize(numCreases * 2); creaseLengths.resize(numCreases, 2); creaseSharpness.resize(numCreases); for (unsigned int i = 0; i < numCreases; ++i) { int verts[2]; lMesh.getEdgeVertices(edgeIds[i], verts); creaseIndices[2 * i] = verts[0]; creaseIndices[2 * i + 1] = verts[1]; creaseSharpness[i] = static_cast<float>(creaseData[i]); } samp.setCreaseIndices(Alembic::Abc::Int32ArraySample(creaseIndices)); samp.setCreaseLengths(Alembic::Abc::Int32ArraySample(creaseLengths)); samp.setCreaseSharpnesses( Alembic::Abc::FloatArraySample(creaseSharpness)); } MUintArray cornerIds; MDoubleArray cornerData; if (lMesh.getCreaseVertices(cornerIds, cornerData) == MS::kSuccess) { unsigned int numCorners = cornerIds.length(); cornerIndices.resize(numCorners); cornerSharpness.resize(numCorners); for (unsigned int i = 0; i < numCorners; ++i) { cornerIndices[i] = cornerIds[i]; cornerSharpness[i] = static_cast<float>(cornerData[i]); } samp.setCornerSharpnesses( Alembic::Abc::FloatArraySample(cornerSharpness)); samp.setCornerIndices( Alembic::Abc::Int32ArraySample(cornerIndices)); } #if MAYA_API_VERSION >= 201100 MUintArray holes = lMesh.getInvisibleFaces(); unsigned int numHoles = holes.length(); std::vector <Alembic::Util::int32_t> holeIndices(numHoles); for (unsigned int i = 0; i < numHoles; ++i) { holeIndices[i] = holes[i]; } if (!holeIndices.empty()) { samp.setHoles(holeIndices); } #endif mSubDSchema.set(samp); writeColor(); writeUVSets(); }
void OsdMeshData::populateIfNeeded(int lv, int scheme, int kernel) { MStatus s; MFnMesh meshFn(_mesh, &s); if (s != MS::kSuccess) return; if (lv < 1) lv =1; MIntArray vertexCount, vertexList; meshFn.getVertices(vertexCount, vertexList); MUintArray edgeIds; MDoubleArray edgeCreaseData; meshFn.getCreaseEdges(edgeIds, edgeCreaseData); MUintArray vtxIds; MDoubleArray vtxCreaseData; meshFn.getCreaseVertices(vtxIds, vtxCreaseData ); if (vertexCount.length() == 0) return; short interpBoundary = 0; FindAttribute(meshFn, "boundaryRule", &interpBoundary); if(CompareArray(_vertexList, vertexList) && CompareArray(_edgeIds, edgeIds) && CompareArray(_edgeCreaseData, edgeCreaseData) && CompareArray(_vtxIds, vtxIds) && CompareArray(_vtxCreaseData, vtxCreaseData) && _interpBoundary == interpBoundary && _scheme == scheme && _kernel == kernel && _maxlevel >= lv) { if(_level != lv) { _level = lv; _needsInitializeIndexBuffer = true; } return; } // printf("Populate %s, level = %d < %d\n", meshFn.name().asChar(), lv, _level); // update topology _vertexList = vertexList; _edgeIds = edgeIds; _edgeCreaseData = edgeCreaseData; _vtxIds = vtxIds; _vtxCreaseData = vtxCreaseData; _maxlevel = lv; _level = lv; _interpBoundary = interpBoundary; _scheme = scheme; _kernel = kernel; std::vector<int> numIndices, faceIndices, edgeCreaseIndices, vtxCreaseIndices; std::vector<float> edgeCreases, vtxCreases; numIndices.resize(vertexCount.length()); faceIndices.resize(vertexList.length()); for(int i = 0; i < (int)vertexCount.length(); ++i) numIndices[i] = vertexCount[i]; for(int i = 0; i < (int)vertexList.length(); ++i) faceIndices[i] = vertexList[i]; vtxCreaseIndices.resize(vtxIds.length()); for(int i = 0; i < (int)vtxIds.length(); ++i) vtxCreaseIndices[i] = vtxIds[i]; vtxCreases.resize(vtxCreaseData.length()); for(int i = 0; i < (int)vtxCreaseData.length(); ++i) vtxCreases[i] = (float)vtxCreaseData[i]; edgeCreases.resize(edgeCreaseData.length()); for(int i = 0; i < (int)edgeCreaseData.length(); ++i) edgeCreases[i] = (float)edgeCreaseData[i]; // edge crease index is stored as pair of <face id> <edge localid> ... int nEdgeIds = edgeIds.length(); edgeCreaseIndices.resize(nEdgeIds*2); for(int i = 0; i < nEdgeIds; ++i){ int2 vertices; if (meshFn.getEdgeVertices(edgeIds[i], vertices) != MS::kSuccess) { s.perror("ERROR can't get creased edge vertices"); continue; } edgeCreaseIndices[i*2] = vertices[0]; edgeCreaseIndices[i*2+1] = vertices[1]; } _hbrmesh = ConvertToHBR(meshFn.numVertices(), numIndices, faceIndices, vtxCreaseIndices, vtxCreases, std::vector<int>(), std::vector<float>(), edgeCreaseIndices, edgeCreases, interpBoundary, scheme); // GL function can't be used in prepareForDraw API. _needsInitializeOsd = true; }
void SubdivUserData::Populate(MObject mesh) { MStatus s; MFnMesh meshFn(mesh); MIntArray vertexCount, vertexList; meshFn.getVertices(vertexCount, vertexList); MUintArray edgeIds; MDoubleArray edgeCreaseData; meshFn.getCreaseEdges(edgeIds, edgeCreaseData); MUintArray vtxIds; MDoubleArray vtxCreaseData; meshFn.getCreaseVertices(vtxIds, vtxCreaseData ); short level = 1; FindAttribute(meshFn, "smoothLevel", &level); if(level < 1) level = 1; short interpBoundary = 0; FindAttribute(meshFn, "boundaryRule", &interpBoundary); if(CompareArray(_vertexList, vertexList) && CompareArray(_edgeIds, edgeIds) && CompareArray(_edgeCreaseData, edgeCreaseData) && CompareArray(_vtxIds, vtxIds) && CompareArray(_vtxCreaseData, vtxCreaseData) && _level == level && _interpBoundary == interpBoundary) { return; } // update topology _vertexList = vertexList; _edgeIds = edgeIds; _edgeCreaseData = edgeCreaseData; _vtxIds = vtxIds; _vtxCreaseData = vtxCreaseData; _level = level; _interpBoundary = interpBoundary; if(_loop){ MIntArray triangleCounts; meshFn.getTriangles(triangleCounts, vertexList); int numTriangles = vertexList.length()/3; vertexCount.clear(); for(int i = 0; i < numTriangles; ++i){ vertexCount.append(3); } } // XXX redundant copy... replace _vertexList with numIndices, etc // create Osd mesh std::vector<int> numIndices, faceIndices, edgeCreaseIndices, vtxCreaseIndices; std::vector<float> edgeCreases, vtxCreases; numIndices.resize(vertexCount.length()); faceIndices.resize(vertexList.length()); for(int i = 0; i < (int)vertexCount.length(); ++i) numIndices[i] = vertexCount[i]; for(int i = 0; i < (int)vertexList.length(); ++i) faceIndices[i] = vertexList[i]; vtxCreaseIndices.resize(vtxIds.length()); for(int i = 0; i < (int)vtxIds.length(); ++i) vtxCreaseIndices[i] = vtxIds[i]; vtxCreases.resize(vtxCreaseData.length()); for(int i = 0; i < (int)vtxCreaseData.length(); ++i) vtxCreases[i] = (float)vtxCreaseData[i]; edgeCreases.resize(edgeCreaseData.length()); for(int i = 0; i < (int)edgeCreaseData.length(); ++i) edgeCreases[i] = (float)edgeCreaseData[i]; // edge crease index is stored as pair of <face id> <edge localid> ... int nEdgeIds = edgeIds.length(); edgeCreaseIndices.resize(nEdgeIds*2); for(int i = 0; i < nEdgeIds; ++i){ int2 vertices; if (meshFn.getEdgeVertices(edgeIds[i], vertices) != MS::kSuccess) { s.perror("ERROR can't get creased edge vertices"); continue; } edgeCreaseIndices[i*2] = vertices[0]; edgeCreaseIndices[i*2+1] = vertices[1]; } OpenSubdiv::OsdHbrMesh *hbrMesh = ConvertToHBR(meshFn.numVertices(), numIndices, faceIndices, vtxCreaseIndices, vtxCreases, std::vector<int>(), std::vector<float>(), edgeCreaseIndices, edgeCreases, interpBoundary, _loop); int kernel = OpenSubdiv::OsdKernelDispatcher::kCPU; if (OpenSubdiv::OsdKernelDispatcher::HasKernelType(OpenSubdiv::OsdKernelDispatcher::kOPENMP)) { kernel = OpenSubdiv::OsdKernelDispatcher::kOPENMP; } _osdmesh->Create(hbrMesh, level, kernel); delete hbrMesh; // create vertex buffer if (_vertexBuffer) { delete _vertexBuffer; } _vertexBuffer = _osdmesh->InitializeVertexBuffer(6 /* position + normal */); // create element array buffer if (_elementArrayBuffer) delete _elementArrayBuffer; _elementArrayBuffer = _osdmesh->CreateElementArrayBuffer(level); _cachedTotal = -1; UpdatePoints(mesh); }