// 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() "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" 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; } }
PXR_NAMESPACE_OPEN_SCOPE /* static */ bool PxrUsdMayaTranslatorMesh::Create( const UsdGeomMesh& mesh, MObject parentNode, const PxrUsdMayaPrimReaderArgs& args, PxrUsdMayaPrimReaderContext* context) { if (!mesh) { return false; } const UsdPrim& prim = mesh.GetPrim(); MStatus status; // Create node (transform) MObject mayaNodeTransformObj; if (!PxrUsdMayaTranslatorUtil::CreateTransformNode(prim, parentNode, args, context, &status, &mayaNodeTransformObj)) { return false; } VtArray<GfVec3f> points; VtArray<GfVec3f> normals; VtArray<int> faceVertexCounts; VtArray<int> faceVertexIndices; UsdAttribute fvc = mesh.GetFaceVertexCountsAttr(); if (fvc.ValueMightBeTimeVarying()){ // at some point, it would be great, instead of failing, to create a usd/hydra proxy node // for the mesh, perhaps? For now, better to give a more specific error MGlobal::displayError( TfStringPrintf("<%s> is a topologically varying Mesh (animated faceVertexCounts). Skipping...", prim.GetPath().GetText()).c_str()); return false; } else { // for any non-topo-varying mesh, sampling at zero will get us the right answer fvc.Get(&faceVertexCounts, 0); } UsdAttribute fvi = mesh.GetFaceVertexIndicesAttr(); if (fvi.ValueMightBeTimeVarying()){ // at some point, it would be great, instead of failing, to create a usd/hydra proxy node // for the mesh, perhaps? For now, better to give a more specific error MGlobal::displayError( TfStringPrintf("<%s> is a topologically varying Mesh (animated faceVertexIndices). Skipping...", prim.GetPath().GetText()).c_str()); return false; } else { // for any non-topo-varying mesh, sampling at zero will get us the right answer fvi.Get(&faceVertexIndices, 0); } // Sanity Checks. If the vertex arrays are empty, skip this mesh if (faceVertexCounts.size() == 0 || faceVertexIndices.size() == 0) { MGlobal::displayError( TfStringPrintf("FaceVertex arrays are empty [Count:%zu Indices:%zu] on Mesh <%s>. Skipping...", faceVertexCounts.size(), faceVertexIndices.size(), prim.GetPath().GetText()).c_str()); return false; // invalid mesh, so exit } // Gather points and normals // If args.GetReadAnimData() is TRUE, // pick the first avaiable sample or default UsdTimeCode pointsTimeSample=UsdTimeCode::EarliestTime(); UsdTimeCode normalsTimeSample=UsdTimeCode::EarliestTime(); std::vector<double> pointsTimeSamples; size_t pointsNumTimeSamples = 0; if (args.GetReadAnimData()) { PxrUsdMayaTranslatorUtil::GetTimeSamples(mesh.GetPointsAttr(), args, &pointsTimeSamples); pointsNumTimeSamples = pointsTimeSamples.size(); if (pointsNumTimeSamples>0) { pointsTimeSample = pointsTimeSamples[0]; } std::vector<double> normalsTimeSamples; PxrUsdMayaTranslatorUtil::GetTimeSamples(mesh.GetNormalsAttr(), args, &normalsTimeSamples); if (normalsTimeSamples.size()) { normalsTimeSample = normalsTimeSamples[0]; } } mesh.GetPointsAttr().Get(&points, pointsTimeSample); mesh.GetNormalsAttr().Get(&normals, normalsTimeSample); if (points.size() == 0) { MGlobal::displayError( TfStringPrintf("Points arrays is empty on Mesh <%s>. Skipping...", prim.GetPath().GetText()).c_str()); return false; // invalid mesh, so exit } // == Convert data size_t mayaNumVertices = points.size(); MPointArray mayaPoints(mayaNumVertices); for (size_t i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } MIntArray polygonCounts( faceVertexCounts.cdata(), faceVertexCounts.size() ); MIntArray polygonConnects( faceVertexIndices.cdata(), faceVertexIndices.size() ); // == Create Mesh Shape Node MFnMesh meshFn; MObject meshObj = meshFn.create(mayaPoints.length(), polygonCounts.length(), mayaPoints, polygonCounts, polygonConnects, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { return false; } // Since we are "decollapsing", we will create a xform and a shape node for each USD prim std::string usdPrimName(prim.GetName().GetText()); std::string shapeName(usdPrimName); shapeName += "Shape"; // Set mesh name and register meshFn.setName(MString(shapeName.c_str()), false, &status); if (context) { std::string usdPrimPath(prim.GetPath().GetText()); std::string shapePath(usdPrimPath); shapePath += "/"; shapePath += shapeName; context->RegisterNewMayaNode( shapePath, meshObj ); // used for undo/redo } // If a material is bound, create (or reuse if already present) and assign it // If no binding is present, assign the mesh to the default shader const TfToken& shadingMode = args.GetShadingMode(); PxrUsdMayaTranslatorMaterial::AssignMaterial(shadingMode, mesh, meshObj, context); // Mesh is a shape, so read Gprim properties PxrUsdMayaTranslatorGprim::Read(mesh, meshObj, context); // Set normals if supplied MIntArray normalsFaceIds; if (normals.size() == static_cast<size_t>(meshFn.numFaceVertices())) { for (size_t i=0; i < polygonCounts.length(); i++) { for (int j=0; j < polygonCounts[i]; j++) { normalsFaceIds.append(i); } } if (normalsFaceIds.length() == static_cast<size_t>(meshFn.numFaceVertices())) { MVectorArray mayaNormals(normals.size()); for (size_t i=0; i < normals.size(); i++) { mayaNormals.set( MVector(normals[i][0], normals[i][1], normals[i][2]), i); } if (meshFn.setFaceVertexNormals(mayaNormals, normalsFaceIds, polygonConnects) != MS::kSuccess) { } } } // Determine if PolyMesh or SubdivMesh TfToken subdScheme = PxrUsdMayaMeshUtil::setSubdivScheme(mesh, meshFn, args.GetDefaultMeshScheme()); // If we are dealing with polys, check if there are normals // If we are dealing with SubdivMesh, read additional attributes and SubdivMesh properties if (subdScheme == UsdGeomTokens->none) { if (normals.size() == static_cast<size_t>(meshFn.numFaceVertices())) { PxrUsdMayaMeshUtil::setEmitNormals(mesh, meshFn, UsdGeomTokens->none); } } else { PxrUsdMayaMeshUtil::setSubdivInterpBoundary(mesh, meshFn, UsdGeomTokens->edgeAndCorner); PxrUsdMayaMeshUtil::setSubdivFVLinearInterpolation(mesh, meshFn); _AssignSubDivTagsToMesh(mesh, meshObj, meshFn); } // Set Holes VtArray<int> holeIndices; mesh.GetHoleIndicesAttr().Get(&holeIndices); // not animatable if ( holeIndices.size() != 0 ) { MUintArray mayaHoleIndices; mayaHoleIndices.setLength( holeIndices.size() ); for (size_t i=0; i < holeIndices.size(); i++) { mayaHoleIndices[i] = holeIndices[i]; } if (meshFn.setInvisibleFaces(mayaHoleIndices) == MS::kFailure) { MGlobal::displayError(TfStringPrintf("Unable to set Invisible Faces on <%s>", meshFn.fullPathName().asChar()).c_str()); } } // GETTING PRIMVARS std::vector<UsdGeomPrimvar> primvars = mesh.GetPrimvars(); TF_FOR_ALL(iter, primvars) { const UsdGeomPrimvar& primvar = *iter; const TfToken& name = primvar.GetBaseName(); const SdfValueTypeName& typeName = primvar.GetTypeName(); // If the primvar is called either displayColor or displayOpacity check // if it was really authored from the user. It may not have been // authored by the user, for example if it was generated by shader // values and not an authored colorset/entity. // If it was not really authored, we skip the primvar. if (name == PxrUsdMayaMeshColorSetTokens->DisplayColorColorSetName || name == PxrUsdMayaMeshColorSetTokens->DisplayOpacityColorSetName) { if (!PxrUsdMayaRoundTripUtil::IsAttributeUserAuthored(primvar)) { continue; } } // XXX: Maya stores UVs in MFloatArrays and color set data in MColors // which store floats, so we currently only import primvars holding // float-typed arrays. Should we still consider other precisions // (double, half, ...) and/or numeric types (int)? if (typeName == SdfValueTypeNames->Float2Array) { // We assume that Float2Array primvars are UV sets. if (!_AssignUVSetPrimvarToMesh(primvar, meshFn)) { MGlobal::displayWarning( TfStringPrintf("Unable to retrieve and assign data for UV set <%s> on mesh <%s>", name.GetText(), mesh.GetPrim().GetPath().GetText()).c_str()); } } else if (typeName == SdfValueTypeNames->FloatArray || typeName == SdfValueTypeNames->Float3Array || typeName == SdfValueTypeNames->Color3fArray || typeName == SdfValueTypeNames->Float4Array || typeName == SdfValueTypeNames->Color4fArray) { if (!_AssignColorSetPrimvarToMesh(mesh, primvar, meshFn)) { MGlobal::displayWarning( TfStringPrintf("Unable to retrieve and assign data for color set <%s> on mesh <%s>", name.GetText(), mesh.GetPrim().GetPath().GetText()).c_str()); } } } // We only vizualize the colorset by default if it is "displayColor". MStringArray colorSetNames; if (meshFn.getColorSetNames(colorSetNames)==MS::kSuccess) { for (unsigned int i=0; i < colorSetNames.length(); i++) { const MString colorSetName = colorSetNames[i]; if (std::string(colorSetName.asChar()) == PxrUsdMayaMeshColorSetTokens->DisplayColorColorSetName.GetString()) { MFnMesh::MColorRepresentation csRep= meshFn.getColorRepresentation(colorSetName); if (csRep==MFnMesh::kRGB || csRep==MFnMesh::kRGBA) { // both of these are needed to show the colorset. MPlug plg=meshFn.findPlug("displayColors"); if ( !plg.isNull() ) { plg.setBool(true); } meshFn.setCurrentColorSetName(colorSetName); } break; } } } // == Animate points == // Use blendShapeDeformer so that all the points for a frame are contained in a single node // if (pointsNumTimeSamples > 0) { MPointArray mayaPoints(mayaNumVertices); MObject meshAnimObj; MFnBlendShapeDeformer blendFn; MObject blendObj = blendFn.create(meshObj); if (context) { context->RegisterNewMayaNode( blendFn.name().asChar(), blendObj ); // used for undo/redo } for (unsigned int ti=0; ti < pointsNumTimeSamples; ++ti) { mesh.GetPointsAttr().Get(&points, pointsTimeSamples[ti]); for (unsigned int i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } // == Create Mesh Shape Node MFnMesh meshFn; if ( meshAnimObj.isNull() ) { meshAnimObj = meshFn.create(mayaPoints.length(), polygonCounts.length(), mayaPoints, polygonCounts, polygonConnects, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { continue; } } else { // Reuse the already created mesh by copying it and then setting the points meshAnimObj = meshFn.copy(meshAnimObj, mayaNodeTransformObj, &status); meshFn.setPoints(mayaPoints); } // Set normals if supplied // // NOTE: This normal information is not propagated through the blendShapes, only the controlPoints. // mesh.GetNormalsAttr().Get(&normals, pointsTimeSamples[ti]); if (normals.size() == static_cast<size_t>(meshFn.numFaceVertices()) && normalsFaceIds.length() == static_cast<size_t>(meshFn.numFaceVertices())) { MVectorArray mayaNormals(normals.size()); for (size_t i=0; i < normals.size(); i++) { mayaNormals.set( MVector(normals[i][0], normals[i][1], normals[i][2]), i); } if (meshFn.setFaceVertexNormals(mayaNormals, normalsFaceIds, polygonConnects) != MS::kSuccess) { } } // Add as target and set as an intermediate object blendFn.addTarget(meshObj, ti, meshAnimObj, 1.0); meshFn.setIntermediateObject(true); if (context) { context->RegisterNewMayaNode( meshFn.fullPathName().asChar(), meshAnimObj ); // used for undo/redo } } // Animate the weights so that mesh0 has a weight of 1 at frame 0, etc. MFnAnimCurve animFn; // Construct the time array to be used for all the keys MTimeArray timeArray; timeArray.setLength(pointsNumTimeSamples); for (unsigned int ti=0; ti < pointsNumTimeSamples; ++ti) { timeArray.set( MTime(pointsTimeSamples[ti]), ti); } // Key/Animate the weights MPlug plgAry = blendFn.findPlug( "weight" ); if ( !plgAry.isNull() && plgAry.isArray() ) { for (unsigned int ti=0; ti < pointsNumTimeSamples; ++ti) { MPlug plg = plgAry.elementByLogicalIndex(ti, &status); MDoubleArray valueArray(pointsNumTimeSamples, 0.0); valueArray[ti] = 1.0; // Set the time value where this mesh's weight should be 1.0 MObject animObj = animFn.create(plg, NULL, &status); animFn.addKeys(&timeArray, &valueArray); if (context) { context->RegisterNewMayaNode(animFn.name().asChar(), animObj ); // used for undo/redo } } } } return true; }
MObject createSubD(double iFrame, SubDAndColors & iNode, MObject & iParent) { Alembic::AbcGeom::ISubDSchema schema = iNode.mMesh.getSchema(); Alembic::AbcCoreAbstract::index_t index, ceilIndex; getWeightAndIndex(iFrame, schema.getTimeSampling(), schema.getNumSamples(), index, ceilIndex); Alembic::AbcGeom::ISubDSchema::Sample samp; schema.get(samp, Alembic::Abc::ISampleSelector(index)); MString name(iNode.mMesh.getName().c_str()); MFnMesh fnMesh; MFloatPointArray pointArray; Alembic::Abc::P3fArraySamplePtr emptyPtr; fillPoints(pointArray, samp.getPositions(), emptyPtr, 0.0); fillTopology(fnMesh, iParent, pointArray, samp.getFaceIndices(), samp.getFaceCounts()); fnMesh.setName(iNode.mMesh.getName().c_str()); setInitialShadingGroup(fnMesh.partialPathName()); MObject obj = fnMesh.object(); setUVs(iFrame, fnMesh, schema.getUVsParam()); setColors(iFrame, fnMesh, iNode.mC3s, iNode.mC4s, true); // add the mFn-specific attributes to fnMesh node MFnNumericAttribute numAttr; MString attrName("SubDivisionMesh"); MObject attrObj = numAttr.create(attrName, attrName, MFnNumericData::kBoolean, 1); numAttr.setKeyable(true); numAttr.setHidden(false); fnMesh.addAttribute(attrObj, MFnDependencyNode::kLocalDynamicAttr); if (samp.getInterpolateBoundary() > 0) { attrName = MString("interpolateBoundary"); attrObj = numAttr.create(attrName, attrName, MFnNumericData::kBoolean, samp.getInterpolateBoundary()); numAttr.setKeyable(true); numAttr.setHidden(false); fnMesh.addAttribute(attrObj, MFnDependencyNode::kLocalDynamicAttr); } if (samp.getFaceVaryingInterpolateBoundary() > 0) { attrName = MString("faceVaryingInterpolateBoundary"); attrObj = numAttr.create(attrName, attrName, MFnNumericData::kBoolean, samp.getFaceVaryingInterpolateBoundary()); numAttr.setKeyable(true); numAttr.setHidden(false); fnMesh.addAttribute(attrObj, MFnDependencyNode::kLocalDynamicAttr); } if (samp.getFaceVaryingPropagateCorners() > 0) { attrName = MString("faceVaryingPropagateCorners"); attrObj = numAttr.create(attrName, attrName, MFnNumericData::kBoolean, samp.getFaceVaryingPropagateCorners()); numAttr.setKeyable(true); numAttr.setHidden(false); fnMesh.addAttribute(attrObj, MFnDependencyNode::kLocalDynamicAttr); } #if MAYA_API_VERSION >= 201100 Alembic::Abc::Int32ArraySamplePtr holes = samp.getHoles(); if (holes && !holes->size() == 0) { unsigned int numHoles = (unsigned int)holes->size(); MUintArray holeData(numHoles); for (unsigned int i = 0; i < numHoles; ++i) { holeData[i] = (*holes)[i]; } if (fnMesh.setInvisibleFaces(holeData) != MS::kSuccess) { MString warn = "Failed to set holes on: "; warn += iNode.mMesh.getName().c_str(); printWarning(warn); } } #endif Alembic::Abc::FloatArraySamplePtr creases = samp.getCreaseSharpnesses(); if (creases && !creases->size() == 0) { Alembic::Abc::Int32ArraySamplePtr indices = samp.getCreaseIndices(); Alembic::Abc::Int32ArraySamplePtr lengths = samp.getCreaseLengths(); std::size_t numLengths = lengths->size(); MUintArray edgeIds; MDoubleArray creaseData; std::size_t curIndex = 0; // curIndex incremented here to move on to the next crease length for (std::size_t i = 0; i < numLengths; ++i, ++curIndex) { std::size_t len = (*lengths)[i] - 1; float creaseSharpness = (*creases)[i]; // curIndex incremented here to go between all the edges that make // up a given length for (std::size_t j = 0; j < len; ++j, ++curIndex) { Alembic::Util::int32_t vertA = (*indices)[curIndex]; Alembic::Util::int32_t vertB = (*indices)[curIndex+1]; MItMeshVertex itv(obj); int prev; itv.setIndex(vertA, prev); MIntArray edges; itv.getConnectedEdges(edges); std::size_t numEdges = edges.length(); for (unsigned int k = 0; k < numEdges; ++k) { int oppVert = -1; itv.getOppositeVertex(oppVert, edges[k]); if (oppVert == vertB) { creaseData.append(creaseSharpness); edgeIds.append(edges[k]); break; } } } } if (fnMesh.setCreaseEdges(edgeIds, creaseData) != MS::kSuccess) { MString warn = "Failed to set creases on: "; warn += iNode.mMesh.getName().c_str(); printWarning(warn); } } Alembic::Abc::FloatArraySamplePtr corners = samp.getCornerSharpnesses(); if (corners && !corners->size() == 0) { Alembic::Abc::Int32ArraySamplePtr cornerVerts = samp.getCornerIndices(); unsigned int numCorners = static_cast<unsigned int>(corners->size()); MUintArray vertIds(numCorners); MDoubleArray cornerData(numCorners); for (unsigned int i = 0; i < numCorners; ++i) { cornerData[i] = (*corners)[i]; vertIds[i] = (*cornerVerts)[i]; } if (fnMesh.setCreaseVertices(vertIds, cornerData) != MS::kSuccess) { MString warn = "Failed to set corners on: "; warn += iNode.mMesh.getName().c_str(); printWarning(warn); } } return obj; }
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 uiDrawManagerDrawOverride::addUIDrawables( const MDagPath& objPath, MHWRender::MUIDrawManager& drawManager, const MHWRender::MFrameContext& frameContext, const MUserData* data) { const uiDrawManagerData* thisdata = dynamic_cast<const uiDrawManagerData*>(data); if (!thisdata) { return; } switch (thisdata->fUIType) { case uiDrawManager::kText: { // Draw a text "uiDrawManager" // All drawing operations must take place between calls to beginDrawable() // and endDrawable(). drawManager.beginDrawable(); drawManager.setColor(thisdata->fColor); drawManager.setFontSize(thisdata->fTextFontSize); drawManager.setFontIncline(thisdata->fTextIncline); drawManager.setFontWeight(thisdata->fTextWeight); drawManager.setFontStretch(thisdata->fTextStretch); drawManager.setFontLine(thisdata->fTextLine); MString faceName = uiDrawManagerData::fFontList[thisdata->fFontFaceIndex]; drawManager.setFontName(faceName); int boxSize[] = { thisdata->fTextBoxWidth, thisdata->fTextBoxHeight }; if (thisdata->fDraw2D) { // uiDrawManagerData::fPosition gives a screen space position // where 2D UI item is located. drawManager.text2d(thisdata->fPosition, thisdata->fText, thisdata->fTextAlignment, boxSize[0]+boxSize[1] == 0 ? NULL : boxSize, &thisdata->fTextBoxColor, false); } else { // for 3D items, place it at the origin of the world space. drawManager.text(thisdata->fPosition, thisdata->fText, thisdata->fTextAlignment, boxSize[0]+boxSize[1] == 0 ? NULL : boxSize, &thisdata->fTextBoxColor, false); } drawManager.endDrawable(); } break; case uiDrawManager::kLine: case uiDrawManager::kLineList: case uiDrawManager::kLineStrip: { drawManager.beginDrawable(); drawManager.setColor(thisdata->fColor); drawManager.setLineWidth(thisdata->fLineWidth); drawManager.setLineStyle(thisdata->fLineStyle); if (thisdata->fUIType == uiDrawManager::kLineStrip) drawManager.lineStrip(thisdata->fLines, thisdata->fDraw2D); else drawManager.lineList(thisdata->fLines, thisdata->fDraw2D); drawManager.endDrawable(); } break; case uiDrawManager::kPoint: case uiDrawManager::kPointList: { drawManager.beginDrawable(); drawManager.setColor(thisdata->fColor); drawManager.setPointSize(thisdata->fPointSize); drawManager.points(thisdata->fPoints, thisdata->fDraw2D); drawManager.endDrawable(); } break; case uiDrawManager::kRect: { drawManager.beginDrawable(); drawManager.setColor(thisdata->fColor); drawManager.setLineWidth(thisdata->fLineWidth); drawManager.setLineStyle(thisdata->fLineStyle); drawManager.setPaintStyle(thisdata->fShaded ? MUIDrawManager::kShaded : MUIDrawManager::kFlat); if (thisdata->fDraw2D) { // For 2d rectangle, an up vector in screen space is used to determine its X // and Y directions. In addition, "fRectScaleX" and "fRectScaleY"(in pixels) // specify the half-lengths of the 2d rectangle. drawManager.rect2d(thisdata->fPosition, thisdata->fRectUp, thisdata->fRectScaleX, thisdata->fRectScaleY, thisdata->fIsFilled); } else { // For 3d rectangle, the up vector should not be parallel with the normal vector. drawManager.rect(thisdata->fPosition, thisdata->fRectUp, thisdata->fRectNormal, thisdata->fRectScaleX, thisdata->fRectScaleY, thisdata->fIsFilled); } drawManager.endDrawable(); } break; case uiDrawManager::kQuad: { drawManager.beginDrawable(); drawManager.setColor(thisdata->fColor); drawManager.setLineWidth(thisdata->fLineWidth); drawManager.setLineStyle(thisdata->fLineStyle); // prepare primitive type MUIDrawManager::Primitive mode = thisdata->fIsFilled ? MUIDrawManager::kTriStrip : MUIDrawManager::kClosedLine; // prepare position list MPointArray position; for (int i = 0; i < 4; ++i) { position.append(thisdata->fQuadVertex[i]); } // prepare index MUintArray index; index.append(0); index.append(1); index.append(3); index.append(2); // draw mesh drawManager.setPaintStyle(thisdata->fShaded ? MUIDrawManager::kShaded : MUIDrawManager::kFlat); if (thisdata->fDraw2D) { drawManager.mesh2d(mode, position, NULL, thisdata->fIsFilled ? &index : NULL); } else { drawManager.mesh(mode, position, NULL, NULL, thisdata->fIsFilled ? &index : NULL); } drawManager.endDrawable(); } break; case uiDrawManager::kSphere: { drawManager.beginDrawable(); drawManager.setColor(thisdata->fColor); drawManager.setLineWidth(thisdata->fLineWidth); drawManager.setLineStyle(thisdata->fLineStyle); drawManager.setPaintStyle(thisdata->fShaded ? MUIDrawManager::kShaded : MUIDrawManager::kFlat); drawManager.sphere(thisdata->fPosition, thisdata->fRadius, thisdata->fIsFilled); drawManager.endDrawable(); } break; case uiDrawManager::kCircle: { drawManager.beginDrawable(); drawManager.setColor(thisdata->fColor); drawManager.setLineWidth(thisdata->fLineWidth); drawManager.setLineStyle(thisdata->fLineStyle); drawManager.setPaintStyle(thisdata->fShaded ? MUIDrawManager::kShaded : MUIDrawManager::kFlat); if (thisdata->fDraw2D) { // The radius in specified as pixel unit for 2d items. drawManager.circle2d(thisdata->fPosition, thisdata->fRadius, thisdata->fIsFilled); } else { drawManager.circle(thisdata->fPosition, thisdata->fCircleNormal, thisdata->fRadius, thisdata->fIsFilled); } drawManager.endDrawable(); } break; case uiDrawManager::kArc: { drawManager.beginDrawable(); drawManager.setColor(thisdata->fColor); drawManager.setLineWidth(thisdata->fLineWidth); drawManager.setLineStyle(thisdata->fLineStyle); drawManager.setPaintStyle(thisdata->fShaded ? MUIDrawManager::kShaded : MUIDrawManager::kFlat); if (thisdata->fDraw2D) { // If 2d, the range of the arc is defined by the start and end vectors // specified in screen space. drawManager.arc2d(thisdata->fPosition, thisdata->fArcStart, thisdata->fArcEnd, thisdata->fRadius, thisdata->fIsFilled); } else { // For 3d arc, the projections of the start and end vectors onto the arc plane( // determined by the normal vector) determine the range of the arc. drawManager.arc(thisdata->fPosition, thisdata->fArcStart, thisdata->fArcEnd, thisdata->fArcNormal, thisdata->fRadius, thisdata->fIsFilled); } drawManager.endDrawable(); } break; case uiDrawManager::kIcon: { MString iconName = uiDrawManagerData::fIconList[thisdata->fIconIndex]; drawManager.beginDrawable(); drawManager.setColor(thisdata->fColor); drawManager.icon(thisdata->fPosition, iconName, thisdata->fIconScale); drawManager.endDrawable(); } break; case uiDrawManager::kCone: { drawManager.beginDrawable(); drawManager.setColor(thisdata->fColor); drawManager.setLineWidth(thisdata->fLineWidth); drawManager.setLineStyle(thisdata->fLineStyle); drawManager.setPaintStyle(thisdata->fShaded ? MUIDrawManager::kShaded : MUIDrawManager::kFlat); drawManager.cone(thisdata->fPosition, thisdata->fConeDirection, thisdata->fRadius, thisdata->fConeHeight, thisdata->fIsFilled); drawManager.endDrawable(); } break; case uiDrawManager::kBox: { drawManager.beginDrawable(); drawManager.setColor(thisdata->fColor); drawManager.setLineWidth(thisdata->fLineWidth); drawManager.setLineStyle(thisdata->fLineStyle); drawManager.setPaintStyle(thisdata->fShaded ? MUIDrawManager::kShaded : MUIDrawManager::kFlat); drawManager.box(thisdata->fPosition, thisdata->fBoxUp, thisdata->fBoxRight, thisdata->fBoxScale[0], thisdata->fBoxScale[1], thisdata->fBoxScale[2], thisdata->fIsFilled); drawManager.endDrawable(); } break; default: perror("unhandled ui types."); break; } }
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); }