// #### buildUVList // // Face-varying data expects a list of per-face per-vertex // floats. This method reads the UVs from the mesh and // concatenates them into such a list. // MStatus OsdMeshData::buildUVList( MFnMesh& meshFn, std::vector<float>& uvList ) { MStatus status = MS::kSuccess; MItMeshPolygon polyIt( _meshDagPath ); MFloatArray uArray; MFloatArray vArray; // If user hasn't given us a UV set, use the current one MString *uvSetPtr=NULL; if ( _uvSet.numChars() > 0 ) { if (uvSetNameIsValid(meshFn, _uvSet)) { uvSetPtr = &_uvSet; } else { MGlobal::displayWarning(MString("OpenSubdivShader: uvSet \""+_uvSet+"\" does not exist.")); } } else { uvSetPtr = NULL; } // pull UVs from Maya mesh status = meshFn.getUVs( uArray, vArray, uvSetPtr ); MCHECK_RETURN(status, "OpenSubdivShader: Error reading UVs"); if ( uArray.length() == 0 || vArray.length() == 0 ) { MGlobal::displayWarning("OpenSubdivShader: Mesh has no UVs"); return MS::kFailure; } // list of UV values uvList.clear(); uvList.resize( meshFn.numFaceVertices()*2 ); int uvListIdx = 0; // for each face-vertex copy UVs into list, adjusting for renderman orientation for ( polyIt.reset(); !polyIt.isDone(); polyIt.next() ) { int faceIdx = polyIt.index(); unsigned int numPolyVerts = polyIt.polygonVertexCount(); for ( unsigned int faceVertIdx = 0; faceVertIdx < numPolyVerts; faceVertIdx++ ) { int uvIdx; polyIt.getUVIndex( faceVertIdx, uvIdx, uvSetPtr ); // convert maya UV orientation to renderman orientation uvList[ uvListIdx++ ] = uArray[ uvIdx ]; uvList[ uvListIdx++ ] = 1.0f - vArray[ uvIdx ]; } } return status; }
MStatus liqAttachPrefAttribute::redoIt() { MFnTypedAttribute tAttr; MStatus status; for ( unsigned i( 0 ); i < objectNames.length(); i++ ) { MSelectionList nodeList; nodeList.add( objectNames[i] ); MObject depNodeObj; nodeList.getDependNode( 0, depNodeObj ); MDagPath dagNode; nodeList.getDagPath( 0, dagNode ); MFnDependencyNode depNode( depNodeObj ); MObject prefAttr; MString attrName, varName; // make sure the renderer description is up to date liqglo.liquidRenderer.setRenderer(); // build the name of the attribute varName = ( ( exportN && depNodeObj.hasFn( MFn::kMesh ) )? "N":"P" ); attrName = "rman"; attrName += varName; attrName += ( ( liqglo.liquidRenderer.requires__PREF )? "__":"" ); attrName += varName + "ref"; // create the attribute prefAttr = tAttr.create( attrName, attrName, MFnData::kPointArray ); if ( depNodeObj.hasFn( MFn::kNurbsSurface ) ) { MFnNurbsSurface nodeFn( depNodeObj ); MPointArray nodePArray; MItSurfaceCV cvs( dagNode, MObject::kNullObj, liqglo.liquidRenderer.requires_SWAPPED_UVS == false, &status ); while( !cvs.isDone() ) { while( !cvs.isRowDone() ) { MPoint pt = (worldSpace)? cvs.position( MSpace::kWorld ) : cvs.position( MSpace::kObject ); nodePArray.append( pt ); cvs.next(); } cvs.nextRow(); } nodeFn.addAttribute( prefAttr ); MFnPointArrayData pArrayData; MObject prefDefault = pArrayData.create( nodePArray ); MPlug nodePlug( depNodeObj, prefAttr ); nodePlug.setValue( prefDefault ); } else if ( depNodeObj.hasFn( MFn::kNurbsCurve ) ) { // Carsten: added support for PREF on nurbs curves // MFnNurbsCurve nodeFn( depNodeObj ); MPointArray nodePArray; nodeFn.getCVs( nodePArray ); nodeFn.addAttribute( prefAttr ); MFnPointArrayData pArrayData; MObject prefDefault = pArrayData.create( nodePArray ); MPlug nodePlug( depNodeObj, prefAttr ); nodePlug.setValue( prefDefault ); } else if ( depNodeObj.hasFn( MFn::kMesh ) ) { MFnMesh nodeFn( depNodeObj ); // Moritz: modified this line to dim nodePArray -- otherwise // nodePArray.set() in the wile loop below throws an exception // which was why __Pref didn't work MPointArray nodePArray( MFnMesh( depNodeObj ).numVertices() ); unsigned count; nodeFn.addAttribute( prefAttr ); if ( exportN ) { // export Nref unsigned vertex; unsigned normal; unsigned face = 0; unsigned faceVertex = 0; unsigned int numNormals = nodeFn.numNormals(); unsigned int numPoints = nodeFn.numVertices(); MFloatVectorArray normals; MVectorArray normalAttArray; nodeFn.getNormals( normals ); if ( numNormals > numPoints ) { // if we get more than 1 normal per vertex, // force the arraysize to the full facevarying size unsigned faceVaryingCount( 0 ); for ( unsigned pOn( 0 ); pOn < nodeFn.numPolygons(); pOn++ ) faceVaryingCount += nodeFn.polygonVertexCount( pOn ); normalAttArray.setLength( faceVaryingCount ); } else normalAttArray.setLength(normals.length()); for ( MItMeshPolygon polyIt ( depNodeObj ); polyIt.isDone() == false; polyIt.next() ) { count = polyIt.polygonVertexCount(); while ( count > 0 ) { --count; normal = polyIt.normalIndex( count ); vertex = polyIt.vertexIndex( count ); if( numNormals == numPoints ) normalAttArray.set(normals[normal], vertex); else normalAttArray.set(normals[normal], faceVertex); ++faceVertex; } ++face; } MFnVectorArrayData pArrayData; MObject prefDefault = pArrayData.create( normalAttArray ); MPlug nodePlug( depNodeObj, prefAttr ); nodePlug.setValue( prefDefault ); } else { // TODO: do we need to account for the altMeshExport algo that's // used in liquidRibMeshData? // Moritz: no, it's basically the same as the algo below for ( MItMeshPolygon polyIt( dagNode, MObject::kNullObj ); !polyIt.isDone(); polyIt.next()) { count = polyIt.polygonVertexCount(); while ( count > 0 ) { --count; unsigned vertexIndex = polyIt.vertexIndex( count ); MPoint nodePoint = (worldSpace)? polyIt.point( count, MSpace::kWorld ) : polyIt.point( count, MSpace::kObject ); // Moritz: this returns MS::kFailure but seems to work?! nodePArray.set( nodePoint, vertexIndex ); } } MFnPointArrayData pArrayData; MObject prefDefault = pArrayData.create( nodePArray ); MPlug nodePlug( depNodeObj, prefAttr ); nodePlug.setValue( prefDefault ); } } else cerr << "Neither a Nurbs nor a Mesh !!" << endl; } return MS::kSuccess; }
// // Recursively traverse a mesh by processing each face, and the neighbouring faces along it's edges. // The initial invocation of this routine provides the basis for the new first vertex/edge // and faces. // // The result of this routine is an array of values that map the old CV indices to the new ones. Along // the a new list of reindexed CVs is built, along with a list of poly counts and connetions. These // can be used to build a new mesh with the reordering specfied by the seed face and vertices. // // // Inputs: // path : Path to the object being traversed // faceIdx : Current face being traversed // v0, v1 : Veretices that define the direction of travel along the face // faceTraversal : An array booleans to track which faces have been // : traversed, controls the recursion // origVertices : The vertices from the original mesh. The could be obtained // : from the path, but are passed in for efficiency // // Outputs: // cvMapping : Mapping of the existing vertices to their new indices // : the fist values in the final array will be the intial v0, v1 // cvMappingInverse : The inverse of the cvMapping // : the value of items v0 and v1 will be 0 and 1 respectively // newPolygonCounts : Vertex counts for each of the new faces // newPolygonConnects : Connections, specified in terms of new CV indices // newVertices : The orginal vertices resorted based on the reindexing // // MStatus meshMapUtils::traverseFace( MDagPath& path, int faceIdx, int v0, int v1, MIntArray& faceTraversal, MIntArray& cvMapping, MIntArray& cvMappingInverse, MIntArray& newPolygonCounts, MIntArray& newPolygonConnects, MFloatPointArray& origVertices, MFloatPointArray& newVertices ) { int vtxCnt = -1; int dir = 0; int dummy; // For setIndex calls MStatus stat = MStatus::kSuccess; MFnMesh theMesh( path, &stat ); MItMeshPolygon polyIt( path ); MItMeshEdge edgeIt( path ); if( stat != MStatus::kSuccess ) { MGlobal::displayError( " theMesh.getPoint failed"); return stat; } // // Skip over any faces already processed, this is not a failure // if( faceTraversal[faceIdx] ) { return MStatus::kSuccess; } // // get the vertex/edge information and sort it based on the user seed // MIntArray vtxOrig; MIntArray edgeOrig; polyIt.setIndex( faceIdx, dummy ); polyIt.getEdges( edgeOrig ); polyIt.getVertices( vtxOrig ); vtxCnt = vtxOrig.length(); // // the sorted V/E info // MIntArray vtxSorted( vtxCnt ); MIntArray edgeSorted( vtxCnt ); // // Build a new array ordered with v0, then v1, first figure out the // starting point, and direction // int v0Idx = -1; int i; for( i = 0; i < vtxCnt; i++ ) { if( vtxOrig[i] == v0 ) { // We've found v0, now find in what direction we need to travel to find v1 v0Idx = i; if( vtxOrig[IDX(i+1, vtxCnt)] == v1 ) { dir = 1; } else if( vtxOrig[IDX(i-1, vtxCnt)] == v1 ) { dir = -1; } break; } } if (dir == 0) { MGlobal::displayError("Selected vertices are not adjacent"); return MS::kFailure; } // Now sort the vertex/edge arrays for( i = 0; i < vtxCnt; i++ ) { vtxSorted[i] = vtxOrig[IDX( v0Idx + i * dir, vtxCnt )]; if( dir == 1 ) { edgeSorted[i] = edgeOrig[IDX( v0Idx + i * dir, vtxCnt )]; } else { edgeSorted[i] = edgeOrig[IDX( v0Idx - 1 + i * dir, vtxCnt )]; } } // Add any new CVs to the vertex array being constructed for ( i = 0; i < vtxCnt; i++ ) { MPoint pos; int index = vtxSorted[i]; if( cvMapping[index] == -1 ) { if( stat != MStatus::kSuccess ) { MGlobal::displayError( " theMesh.getPoint failed"); return stat; } // Added the new CV, and mark it as transferred newVertices.append( origVertices[index] ); // Store the mapping from the old CV indices to the new ones cvMapping[index] = newVertices.length()-1; cvMappingInverse[newVertices.length()-1] = index; } } // // Add the new face count // newPolygonCounts.append( vtxCnt ); // // Add the new polyConnects for ( i = 0; i < vtxCnt; i++ ) { newPolygonConnects.append( cvMapping[vtxSorted[i]] ); } // Mark this face as complete faceTraversal[faceIdx] = true; // // Now recurse over the edges of this face // for( i = 0; i < (int)edgeSorted.length(); i++ ) { int nextEdge = edgeSorted[i]; int2 nextEdgeVtx; stat = theMesh.getEdgeVertices(nextEdge, nextEdgeVtx ); // // Find the vertex, in the sorted array, that starts the next edge int baseIdx = -1; bool swap = false; int j; for( j = 0; j < (int)vtxSorted.length(); j++ ) { if( vtxSorted[j] == nextEdgeVtx[0] ) { baseIdx = j; break; } } assert( baseIdx != -1 ); // // Now look forward and backward in the vertex array to find the // edge's other point, this indicates the edges direction. This // is needed to guide the next recursion level, and keep the // normals pointed consistenly // if( vtxSorted[IDX(baseIdx+1, vtxCnt)] == nextEdgeVtx[1] ) { // Nothing } else if ( vtxSorted[IDX(baseIdx-1, vtxCnt)] == nextEdgeVtx[1] ) { swap = true; } MIntArray connectedFaces; edgeIt.setIndex( nextEdge, dummy ); edgeIt.getConnectedFaces( connectedFaces ); // A single face is simply the current one. Recurse over the others if( connectedFaces.length() > 1 ) { int nextFace; if( connectedFaces[0] == faceIdx ) { nextFace = connectedFaces[1]; } else { nextFace = connectedFaces[0]; } int nextVtx0 = -1; int nextVtx1 = -1; if ( !swap ) { nextVtx0 = nextEdgeVtx[1]; nextVtx1 = nextEdgeVtx[0]; } else { nextVtx0 = nextEdgeVtx[0]; nextVtx1 = nextEdgeVtx[1]; } stat = traverseFace( path, nextFace, nextVtx0, nextVtx1, faceTraversal, cvMapping, cvMappingInverse, newPolygonCounts, newPolygonConnects, origVertices, newVertices ); // Break out of edge loop on error if( stat != MStatus::kSuccess ) { break; } } } return stat; }