static bool _GetLightingParam( const MIntArray& intValues, const MFloatArray& floatValues, GfVec4f& paramValue) { bool gotParamValue = false; if (intValues.length() >= 3) { paramValue[0] = intValues[0]; paramValue[1] = intValues[1]; paramValue[2] = intValues[2]; if (intValues.length() > 3) { paramValue[3] = intValues[3]; } gotParamValue = true; } else if (floatValues.length() >= 3) { paramValue[0] = floatValues[0]; paramValue[1] = floatValues[1]; paramValue[2] = floatValues[2]; if (floatValues.length() > 3) { paramValue[3] = floatValues[3]; } gotParamValue = true; } return gotParamValue; }
// #### 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; }
unsigned int peltOverlap::checkCrossingEdges( MFloatArray &face1Orig, MFloatArray &face1Vec, MFloatArray &face2Orig, MFloatArray &face2Vec ) // Check if there are crossing edges between two faces. Return true // if there are crossing edges and false otherwise. A face is represented // by a series of edges(rays), i.e. // faceOrig[] = {orig1u, orig1v, orig2u, orig2v, ... } // faceVec[] = {vec1u, vec1v, vec2u, vec2v, ... } { unsigned int face1Size = face1Orig.length(); unsigned int face2Size = face2Orig.length(); for (unsigned int i = 0; i < face1Size; i += 2) { float o1x = face1Orig[i]; float o1y = face1Orig[i+1]; float v1x = face1Vec[i]; float v1y = face1Vec[i+1]; float n1x = v1y; float n1y = -v1x; for (unsigned int j = 0; j < face2Size; j += 2) { // Given ray1(O1, V1) and ray2(O2, V2) // Normal of ray1 is (V1.y, V1.x) float o2x = face2Orig[j]; float o2y = face2Orig[j+1]; float v2x = face2Vec[j]; float v2y = face2Vec[j+1]; float n2x = v2y; float n2y = -v2x; // Find t for ray2 // t = [(o1x-o2x)n1x + (o1y-o2y)n1y] / (v2x * n1x + v2y * n1y) float denum = v2x * n1x + v2y * n1y; // Edges are parallel if denum is close to 0. if (fabs(denum) < 0.000001f) continue; float t2 = ((o1x-o2x)* n1x + (o1y-o2y) * n1y) / denum; if (t2 < 0.00001f || t2 > 0.99999f) continue; // Find t for ray1 // t = [(o2x-o1x)n2x + (o2y-o1y)n2y] / (v1x * n2x + v1y * n2y) denum = v1x * n2x + v1y * n2y; // Edges are parallel if denum is close to 0. if (fabs(denum) < 0.000001f) continue; float t1 = ((o2x-o1x)* n2x + (o2y-o1y) * n2y) / denum; // Edges intersect if (t1 > 0.00001f && t1 < 0.99999f) return 1; } } return 0; }
// We try to do some image processing on a normal rgb image before finding the contours. // An example when this could be useful is if we want to separate all bricks in a brick wall. // We can do this by using the texture of the brick wall as input. // However it doesnt work that well :( MStatus SplitFromImage::splitFromRGBImage(MFnMesh &mesh, MString image) { cout << "Image filename: " << image.asChar() << endl; // Load image cv::Mat img, imgGray; img = cv::imread(image.asChar(), CV_LOAD_IMAGE_COLOR); if (!img.data) // Check for invalid input { cout << "Could not open or find the image" << endl; return MS::kFailure; } int thresh = 100; int max_thresh = 255; cv::RNG rng(12345); // Convert image to gray and blur it cv::cvtColor(img, imgGray, CV_BGR2GRAY); cv::blur(imgGray, imgGray, cv::Size(3, 3)); cv::Mat canny_output; std::vector<std::vector<cv::Point> > contours; std::vector<cv::Vec4i> hierarchy; // Detect edges using canny cv::Canny(imgGray, canny_output, thresh, thresh * 2, 3); // Find contours cv::findContours(img, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0)); for (int i = 0; i < contours.size(); i++) { MFloatArray uPoints; MFloatArray vPoints; for (int j = 0; j < contours[i].size(); j++) { cv::Point pt = contours[i][j]; float u = (float)pt.x / img.cols; float v = (float)pt.y / img.rows; uPoints.append(u); vPoints.append(v); } MObject newMesh; if (addPlaneSubMesh(newMesh, uPoints, vPoints, mesh) == MS::kSuccess) cout << "Added plane sub mesh!" << endl; else cout << "Couldn't add plane sub mesh!" << endl; } return MS::kSuccess; }
void ropeGenerator::createCircleUvs( int pointsCount, float uvCapSize, MFloatArray &uArray, MFloatArray &vArray, float direction) { MPoint baseVector( 0.5 * uvCapSize,0,0 ); uArray.append( baseVector.x + 0.5 ); vArray.append( baseVector.z + 0.5 ); for ( int d = 1; d < pointsCount; d++ ) { MVector vVector( baseVector ); vVector = vVector.rotateBy( MVector::kYaxis, MAngle(( 360.0 * direction / float( pointsCount )) * float( d ),MAngle::kDegrees).asRadians() ); uArray.append( vVector.x + 0.5 ); vArray.append( vVector.z + 0.5 ); } }
// uScale and vScale switched because first edge pointing in v direction void copy_patch_uvs(int &kV, int &kHE, MFloatArray &u_src, MFloatArray &v_src, MIntArray &uvIdx_src, MFloatArray &u_dst, MFloatArray &v_dst, float vScale, float uScale, MFloatArray &sc_u_dst, MFloatArray &sc_v_dst, MIntArray &uvIdx_dst, float lineThickness) { int nHE = uvIdx_src.length(); for (int k=0; k<nHE; k++) { uvIdx_dst[kHE] = kV + uvIdx_src[k]; // offset by beginning of this block of UVs kHE++; } // float offset_u = (uScale - 1) * 0.5*lineThickness; // float offset_v = (vScale - 1) * 0.5*lineThickness; lineThickness = 0.5 * lineThickness; float offset_u = lineThickness * (uScale - 1.0)/(uScale - 2*lineThickness); float offset_v = lineThickness * (vScale - 1.0)/(vScale - 2*lineThickness); int nV = u_src.length(); for (int k=0; k<nV; k++) { u_dst[kV] = u_src[k] * (1.0 - 2.0*offset_u) + offset_u; v_dst[kV] = v_src[k] * (1.0 - 2.0*offset_v) + offset_v; sc_u_dst[kV] = uScale * u_src[k]; sc_v_dst[kV] = vScale * v_src[k]; kV++; } }
void create_subdivided_face(int sdRes, int nV, double *uvs, double *itv, int Tidx, MFloatArray &uA, MFloatArray &vA, MIntArray &uvIdx) { HDS hds; hds.V.setDims(2, nV); memcpy(&hds.V.v[0], uvs, 2*nV*sizeof(double)); hds.nFV.setDims(1, 1); hds.nFV[0] = nV; hds.tip.setDims(1, nV); for (size_t k=0; k<nV; k++) { hds.tip[k] = k; } finalize_HDS(hds); size_t nHE = hds.nHE(), nIHE = hds.nIHE();⟵ hds.T.setDims(1, nHE); hds.itv.setDims(1, nHE); memset(&hds.T.v[0], 0, nHE*sizeof(bool)); if (nV==5) hds.T[Tidx] = 1; memcpy(&hds.itv.v[0], itv, nV*sizeof(double)); // border halfedge tags for (size_t k=nIHE; k<nHE; k++) { hds.itv[k] = hds.itv[hds.twin[k]]; } TCC_MAX::linear_subdivide(hds, sdRes); int sd_nV = hds.nV(); int sd_nIHE = hds.nIHE(); uA.setLength(sd_nV); vA.setLength(sd_nV); for (int k=0; k<sd_nV; k++) { uA[k] = hds.V[2*k+0]; vA[k] = hds.V[2*k+1]; } uvIdx.setLength(sd_nIHE); for (int k=0; k<sd_nIHE; k++) { uvIdx[k]=hds.tip[k]; } }
void peltOverlap::createBoundingCircle(const MStringArray &flattenFaces, MFloatArray ¢er, MFloatArray &radius) // // Description // Represent a face by a center and radius, i.e. // center = {center1u, center1v, center2u, center2v, ... } // radius = {radius1, radius2, ... } // { center.setLength(2 * flattenFaces.length()); radius.setLength(flattenFaces.length()); for(unsigned int i = 0; i < flattenFaces.length(); i++) { MSelectionList selList; selList.add(flattenFaces[i]); MDagPath dagPath; MObject comp; selList.getDagPath(0, dagPath, comp); MItMeshPolygon iter(dagPath, comp); MFloatArray uArray, vArray; iter.getUVs(uArray, vArray); // Loop through all vertices to construct edges/rays float cu = 0.f; float cv = 0.f; unsigned int j; for(j = 0; j < uArray.length(); j++) { cu += uArray[j]; cv += vArray[j]; } cu = cu / uArray.length(); cv = cv / vArray.length(); float rsqr = 0.f; for(j = 0; j < uArray.length(); j++) { float du = uArray[j] - cu; float dv = vArray[j] - cv; float dsqr = du*du + dv*dv; rsqr = dsqr > rsqr ? dsqr : rsqr; } center[2*i] = cu; center[2*i+1] = cv; radius[i] = sqrt(rsqr); } }
void ropeGenerator::createRopesUvs( int ropesCount, int pointsCount, float ropeStrength, float uvCapSize,MFloatArray &uArray, MFloatArray &vArray, float direction ) { MAngle angle( (180.0/ ropesCount ), MAngle::kDegrees ); float distanceToMoveRope = cos( angle.asRadians() ); float singleRopeRadius = sin( angle.asRadians() ); float baseAngle = 360.0f / float( ropesCount ); for ( int d = 1; d < ropesCount + 1; d++) { MFloatPointArray ropePoints( createHalfRope( pointsCount, singleRopeRadius ) ); for ( int ropP = 0; ropP < ropePoints.length(); ropP++) { MFloatPoint ropPoint( ropePoints[ropP] ); MVector ropV( ropPoint.x, ropPoint.y, ropPoint.z * ropeStrength ); ropV = ropV + MVector( 0,0,-distanceToMoveRope ); ropV = ropV.rotateBy( MVector::kYaxis, MAngle( baseAngle * float( d ), MAngle::kDegrees).asRadians() ); ropV = ropV * 0.5 * uvCapSize; uArray.append( (( ropV.x * direction) + 0.5 ) ); vArray.append( ropV.z + 0.5 ); } } }
MStatus SplitFromImage::splitFromBinaryImage(MFnMesh &mesh, MString image) { cout << "Image filename: " << image.asChar() << endl; // Load image cv::Mat img; img = cv::imread(image.asChar(), CV_LOAD_IMAGE_GRAYSCALE); if (!img.data) // Check for invalid input { cout << "Could not open or find the image" << endl; return MS::kFailure; } std::vector<std::vector<cv::Point> > contours; std::vector<cv::Vec4i> hierarchy; // Find contours cv::findContours(img, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0)); for (int i = 0; i < contours.size(); i++) { MFloatArray uPoints; MFloatArray vPoints; for (int j = 0; j < contours[i].size(); j++) { cv::Point pt = contours[i][j]; float u = (float)pt.x / img.cols; float v = (float)pt.y / img.rows; uPoints.append(u); vPoints.append(v); } MObject newMesh; if (addPlaneSubMesh(newMesh, uPoints, vPoints, mesh) == MS::kSuccess) cout << "Added plane sub mesh!" << endl; else cout << "Couldn't add plane sub mesh!" << endl; } return MS::kSuccess; }
float peltOverlap::area(const MFloatArray &orig) { float sum = 0.f; unsigned int num = orig.length() / 2; for (unsigned int i = 0; i < num; i++) { unsigned int idx = 2 * i; unsigned int idy = (i + 1 ) % num; idy = 2 * idy + 1; unsigned int idy2 = (i + num - 1) % num; idy2 = 2 * idy2 + 1; sum += orig[idx] * (orig[idy] - orig[idy2]); } return fabs(sum) * 0.5f; }
bool peltOverlap::createRayGivenFace(const MString &face, MFloatArray &orig, MFloatArray &vec) // // Description // Represent a face by a series of edges(rays), i.e. // orig = {orig1u, orig1v, orig2u, orig2v, ... } // vec = {vec1u, vec1v, vec2u, vec2v, ... } // // return false if no valid uv's. { MSelectionList selList; selList.add(face); MDagPath dagPath; MObject comp; selList.getDagPath(0, dagPath, comp); MItMeshPolygon iter(dagPath, comp); MFloatArray uArray, vArray; iter.getUVs(uArray, vArray); if (uArray.length() == 0 || vArray.length() == 0) return false; orig.setLength(2 * uArray.length()); vec.setLength( 2 * uArray.length()); // Loop through all vertices to construct edges/rays float u = uArray[uArray.length() - 1]; float v = vArray[vArray.length() - 1]; for(unsigned int j = 0; j < uArray.length(); j++) { orig[2*j] = uArray[j]; orig[2*j+1] = vArray[j]; vec[2*j] = u - uArray[j]; vec[2*j+1] = v - vArray[j]; u = uArray[j]; v = vArray[j]; } return true; }
MStatus XmlCacheFormat::readFloatArray( MFloatArray& array, unsigned arraySize ) { MStringArray value; readXmlTagValue(floatArrayTag, value); assert( value.length() == arraySize ); array.setLength( arraySize ); for ( unsigned int i = 0; i < value.length(); i++ ) { array[i] = (float)strtod( value[i].asChar(), NULL ); } return MS::kSuccess; }
static bool _GetLightingParam( const MIntArray& intValues, const MFloatArray& floatValues, float& paramValue) { bool gotParamValue = false; if (floatValues.length() > 0) { paramValue = floatValues[0]; gotParamValue = true; } return gotParamValue; }
MStatus XmlCacheFormat::writeFloatArray( const MFloatArray& array ) { int size = array.length(); assert(size != 0); writeXmlTagValue(sizeTag,size); startXmlBlock( floatArrayTag ); for(int i = 0; i < size; i++) { writeXmlValue(array[i]); } endXmlBlock(); return MS::kSuccess; }
static bool _GetLightingParam( const MIntArray& intValues, const MFloatArray& floatValues, bool& paramValue) { bool gotParamValue = false; if (intValues.length() > 0) { paramValue = (intValues[0] == 1); gotParamValue = true; } else if (floatValues.length() > 0) { paramValue = GfIsClose(floatValues[0], 1.0f, 1e-5); gotParamValue = true; } return gotParamValue; }
MStatus TransferUV::redoIt() { MStatus status; MFnMesh sourceFnMesh(sourceDagPath); MFnMesh targetFnMesh(targetDagPath); // Get current UV sets and keep them to switch back to them at the last MString currentSourceUVSet = sourceFnMesh.currentUVSetName(); MString currentTargetUVSet = targetFnMesh.currentUVSetName(); // Switch to uv sets specified in flags before starting transfer process // This is required because MFnMesh does not work properly with // "Non-current" UV sets sourceFnMesh.setCurrentUVSetName(sourceUvSet); targetFnMesh.setCurrentUVSetName(targetUvSet); MString* sourceUvSetPtr = &sourceUvSet; MString* targetUvSetPtr = &targetUvSet; MFloatArray sourceUarray; MFloatArray sourceVarray; MIntArray sourceUvCounts; MIntArray sourceUvIds; // Get mesh information for each status = sourceFnMesh.getUVs(sourceUarray, sourceVarray, sourceUvSetPtr); if (status != MS::kSuccess) { MGlobal::displayError("Failed to get source UVs"); CHECK_MSTATUS_AND_RETURN_IT(status); } status = targetFnMesh.getUVs(originalUarray, originalVarray, targetUvSetPtr); if (status != MS::kSuccess) { MGlobal::displayError("Failed to get original UVs"); CHECK_MSTATUS_AND_RETURN_IT(status); } status = sourceFnMesh.getAssignedUVs(sourceUvCounts, sourceUvIds, sourceUvSetPtr); if (status != MS::kSuccess) { MGlobal::displayError("Failed to get source assigned UVs"); CHECK_MSTATUS_AND_RETURN_IT(status); } status = targetFnMesh.getAssignedUVs(originalUvCounts, originalUvIds, targetUvSetPtr); if (status != MS::kSuccess) { MGlobal::displayError("Failed to get original assigned UVs"); CHECK_MSTATUS_AND_RETURN_IT(status); } // Resize source uv array so it becomes same size as number of targets uv unsigned int targetNumUVs = targetFnMesh.numUVs(); if (targetNumUVs > sourceUarray.length()) { sourceUarray.setLength(targetNumUVs); sourceVarray.setLength(targetNumUVs); } status = targetFnMesh.setUVs(sourceUarray, sourceVarray, targetUvSetPtr); if (MS::kSuccess != status) { MGlobal::displayError("Failed to set source UVs"); return status; } status = targetFnMesh.assignUVs(sourceUvCounts, sourceUvIds, targetUvSetPtr); if (MS::kSuccess != status) { MGlobal::displayError("Failed to assign source UVs"); return status; } // Switch back to originals sourceFnMesh.setCurrentUVSetName(currentSourceUVSet); targetFnMesh.setCurrentUVSetName(currentTargetUVSet); return MS::kSuccess; }
void ToMayaMeshConverter::addUVSet( MFnMesh &fnMesh, const MIntArray &polygonCounts, IECore::ConstMeshPrimitivePtr mesh, const std::string &sPrimVarName, const std::string &tPrimVarName, const std::string &stIdPrimVarName, MString *uvSetName ) const { IECore::PrimitiveVariableMap::const_iterator sIt = mesh->variables.find( sPrimVarName ); bool haveS = sIt != mesh->variables.end(); IECore::PrimitiveVariableMap::const_iterator tIt = mesh->variables.find( tPrimVarName ); bool haveT = tIt != mesh->variables.end(); IECore::PrimitiveVariableMap::const_iterator stIdIt = mesh->variables.find( stIdPrimVarName ); bool haveSTId = stIdIt != mesh->variables.end(); if ( haveS && haveT ) { if ( sIt->second.interpolation != IECore::PrimitiveVariable::FaceVarying ) { IECore::msg( IECore::Msg::Warning,"ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has unsupported interpolation (expected FaceVarying).") % sPrimVarName ); return; } if ( tIt->second.interpolation != IECore::PrimitiveVariable::FaceVarying ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has unsupported interpolation (expected FaceVarying).") % tPrimVarName); return; } if ( !sIt->second.data ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has no data." ) % sPrimVarName ); } if ( !tIt->second.data ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has no data." ) % tPrimVarName ); } /// \todo Employ some M*Array converters to simplify this int numUVs = mesh->variableSize( IECore::PrimitiveVariable::FaceVarying ); IECore::ConstFloatVectorDataPtr u = IECore::runTimeCast<const IECore::FloatVectorData>(sIt->second.data); if ( !u ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has unsupported type \"%s\"." ) % sPrimVarName % sIt->second.data->typeName() ); return; } assert( (int)u->readable().size() == numUVs ); IECore::ConstFloatVectorDataPtr v = IECore::runTimeCast<const IECore::FloatVectorData>(tIt->second.data); if ( !v ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has unsupported type \"%s\"." ) % tPrimVarName % tIt->second.data->typeName() ); return; } assert( (int)v->readable().size() == numUVs ); const std::vector<float> &uAll = u->readable(); const std::vector<float> &vAll = v->readable(); if ( uvSetName ) { bool setExists = false; MStringArray existingSets; fnMesh.getUVSetNames( existingSets ); for ( unsigned i=0; i < existingSets.length(); ++i ) { if ( *uvSetName == existingSets[i] ) { fnMesh.clearUVs( uvSetName ); setExists = true; break; } } if ( !setExists ) { MDagPath dag; MStatus s = fnMesh.getPath( dag ); if ( s ) { fnMesh.createUVSetWithName( *uvSetName ); } else { fnMesh.createUVSetDataMeshWithName( *uvSetName ); } } } MIntArray uvIds; uvIds.setLength( numUVs ); MFloatArray uArray; MFloatArray vArray; if( haveSTId ) { // Get compressed uv values by matching them with their uvId. IECore::ConstIntVectorDataPtr uvId = IECore::runTimeCast<const IECore::IntVectorData>(stIdIt->second.data); if ( !uvId ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"%s\" has unsupported type \"%s\"." ) % stIdPrimVarName % stIdIt->second.data->typeName() ); return; } const std::vector<int> &uvIdData = uvId->readable(); assert( (int)uvIdData.size() == numUVs ); int highestId = 0; for ( int i = 0; i < numUVs; i++) { uvIds[i] = uvIdData[i]; if( uvIdData[i] > highestId ) { highestId = uvIdData[i]; } } // u and v arrays need only be as long as the number of unique uvIds uArray.setLength( highestId + 1 ); vArray.setLength( highestId + 1 ); for ( int i = 0; i < numUVs; i++ ) { uArray[ uvIds[i] ] = uAll[i]; // FromMayaMeshConverter does the opposite of this vArray[ uvIds[i] ] = 1 - vAll[i]; } } else { // If for some reason we cannot find the uv indices, set the UVs using the old way // the performances in maya won't be good (for weigth painting in particular) uArray.setLength( numUVs ); vArray.setLength( numUVs ); for ( int i = 0; i < numUVs; i++) { uArray[i] = u->readable()[i]; // FromMayaMeshConverter does the opposite of this vArray[i] = 1 - v->readable()[i]; } for ( int i = 0; i < numUVs; i++) { uvIds[i] = i; } } MStatus s = fnMesh.setUVs( uArray, vArray, uvSetName ); if ( !s ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Failed to set UVs." ); return; } s = fnMesh.assignUVs( polygonCounts, uvIds, uvSetName ); if ( !s ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Failed to assign UVs." ); return; } } else if ( haveS ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "Primitive variable \"%s\" found, but not \"%s\"." ) % sPrimVarName % tPrimVarName ); } else if ( haveT ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "Primitive variable \"%s\" found, but not \"%s\"." ) % tPrimVarName % sPrimVarName ); } else { assert( !uvSetName ); } }
PXR_NAMESPACE_OPEN_SCOPE bool MayaMeshWriter::_GetMeshUVSetData( const MFnMesh& mesh, const MString& uvSetName, VtArray<GfVec2f>* uvArray, TfToken* interpolation, VtArray<int>* assignmentIndices) { MStatus status; // Sanity check first to make sure this UV set even has assigned values // before we attempt to do anything with the data. MIntArray uvCounts, uvIds; status = mesh.getAssignedUVs(uvCounts, uvIds, &uvSetName); if (status != MS::kSuccess) { return false; } if (uvCounts.length() == 0 || uvIds.length() == 0) { return false; } // using itFV.getUV() does not always give us the right answer, so // instead, we have to use itFV.getUVIndex() and use that to index into the // UV set. MFloatArray uArray; MFloatArray vArray; mesh.getUVs(uArray, vArray, &uvSetName); if (uArray.length() != vArray.length()) { return false; } // We'll populate the assignment indices for every face vertex, but we'll // only push values into the data if the face vertex has a value. All face // vertices are initially unassigned/unauthored. const unsigned int numFaceVertices = mesh.numFaceVertices(&status); uvArray->clear(); assignmentIndices->assign((size_t)numFaceVertices, -1); *interpolation = UsdGeomTokens->faceVarying; MItMeshFaceVertex itFV(mesh.object()); unsigned int fvi = 0; for (itFV.reset(); !itFV.isDone(); itFV.next(), ++fvi) { if (!itFV.hasUVs(uvSetName)) { // No UVs for this faceVertex, so leave it unassigned. continue; } int uvIndex; itFV.getUVIndex(uvIndex, &uvSetName); if (uvIndex < 0 || static_cast<size_t>(uvIndex) >= uArray.length()) { return false; } GfVec2f value(uArray[uvIndex], vArray[uvIndex]); uvArray->push_back(value); (*assignmentIndices)[fvi] = uvArray->size() - 1; } PxrUsdMayaUtil::MergeEquivalentIndexedValues(uvArray, assignmentIndices); PxrUsdMayaUtil::CompressFaceVaryingPrimvarIndices(mesh, interpolation, assignmentIndices); return true; }
MStatus exportJointClusterData::doIt( const MArgList& args ) // // Process the command // 1. parse the args // 2. find the jointClusters in the scene // 3. iterate over their members, writing their weight data out to file // { // parse args to get the file name from the command-line // MStatus stat = parseArgs(args); if (stat != MS::kSuccess) { return stat; } // count the processed jointClusters // unsigned int jcCount = 0; // Iterate through graph and search for jointCluster nodes // MItDependencyNodes iter( MFn::kJointCluster); for ( ; !iter.isDone(); iter.next() ) { MObject object = iter.item(); MFnWeightGeometryFilter jointCluster(object); // get the joint driving this cluster // MObject joint = jointForCluster(object); if (joint.isNull()) { displayError("Joint is not attached to cluster."); continue; } MObject deformSet = jointCluster.deformerSet(&stat); CheckError(stat,"Error getting deformer set."); MFnSet setFn(deformSet, &stat); //need the fn to get the members CheckError(stat,"Error getting deformer set fn."); MSelectionList clusterSetList; //get all the members // stat = setFn.getMembers(clusterSetList, true); CheckError(stat,"Could not make member list with getMembers."); // print out the name of joint and the number of associated skins // MFnDependencyNode fnJoint(joint); fprintf(file,"%s %u\n",fnJoint.name().asChar(), clusterSetList.length()); for (unsigned int kk = 0; kk < clusterSetList.length(); ++kk) { MDagPath skinpath; MObject components; MFloatArray weights; clusterSetList.getDagPath(kk,skinpath,components); jointCluster.getWeights(skinpath,components,weights); // print out the path name of the skin & the weight count // fprintf(file, "%s %u\n",skinpath.partialPathName().asChar(), weights.length()); // loop through the components and print their index and weight // unsigned counter =0; MItGeometry gIter(skinpath,components); for (/* nothing */ ; !gIter.isDone() && counter < weights.length(); gIter.next()) { fprintf(file,"%d %f\n",gIter.index(),weights[counter]); counter++; } } jcCount++; } fclose(file); if (0 == jcCount) { displayError("No jointClusters found in this scene."); return MS::kFailure; } return MS::kSuccess; }
void MayaObject::getMeshData(MPointArray& points, MFloatVectorArray& normals, MFloatArray& uArray, MFloatArray& vArray, MIntArray& triPointIndices, MIntArray& triNormalIndices, MIntArray& triUvIndices, MIntArray& triMatIndices) { MStatus stat; MObject meshObject = this->mobject; MMeshSmoothOptions options; MFnMesh tmpMesh(this->mobject, &stat); MFnMeshData meshData; MObject dataObject; MObject smoothedObj; // create smooth mesh if needed if (tmpMesh.findPlug("displaySmoothMesh").asBool()) { stat = tmpMesh.getSmoothMeshDisplayOptions(options); if (stat) { if (!tmpMesh.findPlug("useSmoothPreviewForRender", false, &stat).asBool()) { //Logging::debug(MString("useSmoothPreviewForRender turned off")); int smoothLevel = tmpMesh.findPlug("renderSmoothLevel", false, &stat).asInt(); options.setDivisions(smoothLevel); } if (options.divisions() > 0) { dataObject = meshData.create(); smoothedObj = tmpMesh.generateSmoothMesh(dataObject, &options, &stat); if (stat) { meshObject = smoothedObj; } } } } MFnMesh meshFn(meshObject, &stat); CHECK_MSTATUS(stat); MItMeshPolygon faceIt(meshObject, &stat); CHECK_MSTATUS(stat); meshFn.getPoints(points); meshFn.getNormals(normals, MSpace::kObject); meshFn.getUVs(uArray, vArray); uint numVertices = points.length(); uint numNormals = normals.length(); uint numUvs = uArray.length(); //Logging::debug(MString("numVertices ") + numVertices); //Logging::debug(MString("numNormals ") + numNormals); //Logging::debug(MString("numUvs ") + numUvs); // some meshes may have no uv's // to avoid problems I add a default uv coordinate if (numUvs == 0) { Logging::warning(MString("Object has no uv's: ") + this->shortName); uArray.append(0.0); vArray.append(0.0); } for (uint nid = 0; nid < numNormals; nid++) { if (normals[nid].length() < 0.1f) Logging::warning(MString("Malformed normal in ") + this->shortName); } MPointArray triPoints; MIntArray triVtxIds; MIntArray faceVtxIds; MIntArray faceNormalIds; for (faceIt.reset(); !faceIt.isDone(); faceIt.next()) { int faceId = faceIt.index(); int numTris; faceIt.numTriangles(numTris); faceIt.getVertices(faceVtxIds); int perFaceShadingGroup = 0; if (this->perFaceAssignments.length() > 0) perFaceShadingGroup = this->perFaceAssignments[faceId]; MIntArray faceUVIndices; faceNormalIds.clear(); for (uint vtxId = 0; vtxId < faceVtxIds.length(); vtxId++) { faceNormalIds.append(faceIt.normalIndex(vtxId)); int uvIndex; if (numUvs == 0) { faceUVIndices.append(0); } else{ faceIt.getUVIndex(vtxId, uvIndex); //if (uvIndex > uArray.length()) // Logging::info(MString("-----------------> UV Problem!!! uvIndex ") + uvIndex + " > uvArray in object " + this->shortName); faceUVIndices.append(uvIndex); } } for (int triId = 0; triId < numTris; triId++) { int faceRelIds[3]; faceIt.getTriangle(triId, triPoints, triVtxIds); for (uint triVtxId = 0; triVtxId < 3; triVtxId++) { for (uint faceVtxId = 0; faceVtxId < faceVtxIds.length(); faceVtxId++) { if (faceVtxIds[faceVtxId] == triVtxIds[triVtxId]) { faceRelIds[triVtxId] = faceVtxId; } } } uint vtxId0 = faceVtxIds[faceRelIds[0]]; uint vtxId1 = faceVtxIds[faceRelIds[1]]; uint vtxId2 = faceVtxIds[faceRelIds[2]]; uint normalId0 = faceNormalIds[faceRelIds[0]]; uint normalId1 = faceNormalIds[faceRelIds[1]]; uint normalId2 = faceNormalIds[faceRelIds[2]]; uint uvId0 = faceUVIndices[faceRelIds[0]]; uint uvId1 = faceUVIndices[faceRelIds[1]]; uint uvId2 = faceUVIndices[faceRelIds[2]]; triPointIndices.append(vtxId0); triPointIndices.append(vtxId1); triPointIndices.append(vtxId2); triNormalIndices.append(normalId0); triNormalIndices.append(normalId1); triNormalIndices.append(normalId2); triUvIndices.append(uvId0); triUvIndices.append(uvId1); triUvIndices.append(uvId2); triMatIndices.append(perFaceShadingGroup); //Logging::debug(MString("vtxIds ") + vtxId0 + " " + vtxId1 + " " + vtxId2); //Logging::debug(MString("nIds ") + normalId0 + " " + normalId1 + " " + normalId2); //Logging::debug(MString("uvIds ") + uvId0 + " " + uvId1 + " " + uvId2); } } }
MStatus Mesh::load(MDagPath& meshDag,MDagPath *pDagPath) { MStatus stat; std::vector<MFloatArray> weights; std::vector<MIntArray> Ids; std::vector<MIntArray> jointIds; unsigned int numJoints = 0; std::vector<vertexInfo> vertices; MFloatPointArray points; MFloatVectorArray normals; if (!meshDag.hasFn(MFn::kMesh)) return MS::kFailure; MFnMesh mesh(meshDag); /*{ mesh.getPoints(points,MSpace::kWorld); MPoint pos; mesh.getPoint(1,pos,MSpace::kWorld); for(unsigned i = 0;i < points.length();i++) { MFloatPoint fp = points[i]; float x = fp.x; float y = fp.y; float z = fp.z; fp = fp; } }*/ int numVertices = mesh.numVertices(); vertices.resize(numVertices); weights.resize(numVertices); Ids.resize(numVertices); jointIds.resize(numVertices); // 获取UV坐标集的名称 MStringArray uvsets; int numUVSets = mesh.numUVSets(); if (numUVSets > 0) { stat = mesh.getUVSetNames(uvsets); if (MS::kSuccess != stat) { std::cout << "Error retrieving UV sets names\n"; return MS::kFailure; } } // 保存UV集信息 for (int i=m_uvsets.size(); i<uvsets.length(); i++) { uvset uv; uv.size = 2; uv.name = uvsets[i].asChar(); m_uvsets.push_back(uv); } MStringArray colorSetsNameArray; m_colorSets.clear(); int numColorSets = mesh.numColorSets(); if (numColorSets > 0) { mesh.getColorSetNames(colorSetsNameArray); } for (int i = 0; i != colorSetsNameArray.length(); ++i) { std::string name = colorSetsNameArray[i].asChar(); m_colorSets.push_back(name); } // 检查法线是否反 bool opposite = false; mesh.findPlug("opposite",true).getValue(opposite); // get connected skin cluster (if present) bool foundSkinCluster = false; MItDependencyNodes kDepNodeIt( MFn::kSkinClusterFilter ); for( ;!kDepNodeIt.isDone() && !foundSkinCluster; kDepNodeIt.next()) { MObject kObject = kDepNodeIt.item(); m_pSkinCluster = new MFnSkinCluster(kObject); unsigned int uiNumGeometries = m_pSkinCluster->numOutputConnections(); for(unsigned int uiGeometry = 0; uiGeometry < uiNumGeometries; ++uiGeometry ) { unsigned int uiIndex = m_pSkinCluster->indexForOutputConnection(uiGeometry); MObject kOutputObject = m_pSkinCluster->outputShapeAtIndex(uiIndex); if(kOutputObject == mesh.object()) { foundSkinCluster = true; } else { delete m_pSkinCluster; m_pSkinCluster = NULL; } } // load connected skeleton (if present) if (m_pSkinCluster) { if (!m_pSkeleton) m_pSkeleton = new skeleton(); stat = m_pSkeleton->load(m_pSkinCluster); if (MS::kSuccess != stat) std::cout << "Error loading skeleton data\n"; } else { // breakable; } } // get connected shaders MObjectArray shaders; MIntArray shaderPolygonMapping; stat = mesh.getConnectedShaders(0,shaders,shaderPolygonMapping); if (MS::kSuccess != stat) { std::cout << "Error getting connected shaders\n"; return MS::kFailure; } if (shaders.length() <= 0) { std::cout << "No connected shaders, skipping mesh\n"; return MS::kFailure; } // create a series of arrays of faces for each different submesh std::vector<faceArray> polygonSets; polygonSets.resize(shaders.length()); // Get faces data // prepare vertex table for (int i=0; i<vertices.size(); i++) vertices[i].next = -2; //get vertex positions from mesh data mesh.getPoints(points,MSpace::kWorld); mesh.getNormals(normals,MSpace::kWorld); //get list of vertex weights if (m_pSkinCluster) { MItGeometry iterGeom(meshDag); for (int i=0; !iterGeom.isDone(); iterGeom.next(), i++) { weights[i].clear(); Ids[i].clear(); MObject component = iterGeom.component(); MFloatArray vertexWeights; stat=m_pSkinCluster->getWeights(meshDag,component,vertexWeights,numJoints); int nWeights = vertexWeights.length(); for(int j = 0;j<nWeights;j++) { if(vertexWeights[j] >= 0.00001f || vertexWeights[j] <= -0.00001f ) { // 记录该节点j Ids[i].append(j); weights[i].append(vertexWeights[j]); } } //weights[i]= vertexWeights; if (MS::kSuccess != stat) { std::cout << "Error retrieving vertex weights\n"; } // get ids for the joints if (m_pSkeleton) { jointIds[i].clear(); if(weights[i].length() > 0 ) { MDagPathArray influenceObjs; m_pSkinCluster->influenceObjects(influenceObjs,&stat); if (MS::kSuccess != stat) { std::cout << "Error retrieving influence objects for given skin cluster\n"; } jointIds[i].setLength(weights[i].length()); for (int j=0; j<jointIds[i].length(); j++) { bool foundJoint = false; for (int k=0; k<m_pSkeleton->getJoints().size() && !foundJoint; k++) { if (influenceObjs[Ids[i][j]].partialPathName() == m_pSkeleton->getJoints()[k].name) { foundJoint=true; jointIds[i][j] = m_pSkeleton->getJoints()[k].id; } } } } } } } // create an iterator to go through mesh polygons if (mesh.numPolygons() > 0) { const char *name = mesh.name().asChar(); MItMeshPolygon faceIter(mesh.object(),&stat); if (MS::kSuccess != stat) { std::cout << "Error accessing mesh polygons\n"; return MS::kFailure; } // iterate over mesh polygons for (; !faceIter.isDone(); faceIter.next()) { int numTris=0; faceIter.numTriangles(numTris); // for every triangle composing current polygon extract triangle info for (int iTris=0; iTris<numTris; iTris++) { MPointArray triPoints; MIntArray tempTriVertexIdx,triVertexIdx; int idx; // create a new face to store triangle info face newFace; // extract triangle vertex indices faceIter.getTriangle(iTris,triPoints,tempTriVertexIdx); // convert indices to face-relative indices MIntArray polyIndices; faceIter.getVertices(polyIndices); unsigned int iPoly, iObj; for (iObj=0; iObj < tempTriVertexIdx.length(); ++iObj) { // iPoly is face-relative vertex index for (iPoly=0; iPoly < polyIndices.length(); ++iPoly) { if (tempTriVertexIdx[iObj] == polyIndices[iPoly]) { triVertexIdx.append(iPoly); break; } } } // iterate over triangle's vertices for (int i=0; i<3; i++) { bool different = true; int vtxIdx = faceIter.vertexIndex(triVertexIdx[i]); int nrmIdx = faceIter.normalIndex(triVertexIdx[i]); // get vertex color MColor color; if (faceIter.hasColor(triVertexIdx[i])) { //This method gets the average color of the all the vertices in this face stat = faceIter.getColor(color,triVertexIdx[i]); if (MS::kSuccess != stat) { color = MColor(1,1,1,1); } if (color.r > 1) color.r = 1; if (color.g > 1) color.g = 1; if (color.b > 1) color.b = 1; if (color.a > 1) color.a = 1; } else { color = MColor(1,1,1,1); } if (vertices[vtxIdx].next == -2) // first time we encounter a vertex in this position { // save vertex position points[vtxIdx].cartesianize(); vertices[vtxIdx].pointIdx = vtxIdx; // save vertex normal vertices[vtxIdx].normalIdx = nrmIdx; // save vertex colour vertices[vtxIdx].r = color.r; vertices[vtxIdx].g = color.g; vertices[vtxIdx].b = color.b; vertices[vtxIdx].a = color.a; // save vertex texture coordinates vertices[vtxIdx].u.resize(uvsets.length()); vertices[vtxIdx].v.resize(uvsets.length()); // save vbas vertices[vtxIdx].vba.resize(weights[vtxIdx].length()); for (int j=0; j<weights[vtxIdx].length(); j++) { vertices[vtxIdx].vba[j] = (weights[vtxIdx])[j]; } // save joint ids vertices[vtxIdx].jointIds.resize(jointIds[vtxIdx].length()); for (int j=0; j<jointIds[vtxIdx].length(); j++) { vertices[vtxIdx].jointIds[j] = (jointIds[vtxIdx])[j]; } // save uv sets data for (int j=0; j<uvsets.length(); j++) { float2 uv; stat = faceIter.getUV(triVertexIdx[i],uv,&uvsets[j]); if (MS::kSuccess != stat) { uv[0] = 0; uv[1] = 0; } vertices[vtxIdx].u[j] = uv[0]; vertices[vtxIdx].v[j] = (-1)*(uv[1]-1); } // save vertex index in face info newFace.v[i] = vtxIdx; // update value of index to next vertex info (-1 means nothing next) vertices[vtxIdx].next = -1; } else // already found at least 1 vertex in this position { // check if a vertex with same attributes has been saved already for (int k=vtxIdx; k!=-1 && different; k=vertices[k].next) { different = false; MFloatVector n1 = normals[vertices[k].normalIdx]; MFloatVector n2 = normals[nrmIdx]; if (n1.x!=n2.x || n1.y!=n2.y || n1.z!=n2.z) { different = true; } if (vertices[k].r!=color.r || vertices[k].g!=color.g || vertices[k].b!= color.b || vertices[k].a!=color.a) { different = true; } for (int j=0; j<uvsets.length(); j++) { float2 uv; stat = faceIter.getUV(triVertexIdx[i],uv,&uvsets[j]); if (MS::kSuccess != stat) { uv[0] = 0; uv[1] = 0; } uv[1] = (-1)*(uv[1]-1); if (vertices[k].u[j]!=uv[0] || vertices[k].v[j]!=uv[1]) { different = true; } } idx = k; } // if no identical vertex has been saved, then save the vertex info if (different) { vertexInfo vtx; // save vertex position vtx.pointIdx = vtxIdx; // save vertex normal vtx.normalIdx = nrmIdx; // save vertex colour vtx.r = color.r; vtx.g = color.g; vtx.b = color.b; vtx.a = color.a; // save vertex vba vtx.vba.resize(weights[vtxIdx].length()); for (int j=0; j<weights[vtxIdx].length(); j++) { vtx.vba[j] = (weights[vtxIdx])[j]; } // save joint ids vtx.jointIds.resize(jointIds[vtxIdx].length()); for (int j=0; j<jointIds[vtxIdx].length(); j++) { vtx.jointIds[j] = (jointIds[vtxIdx])[j]; } // save vertex texture coordinates vtx.u.resize(uvsets.length()); vtx.v.resize(uvsets.length()); for (int j=0; j<uvsets.length(); j++) { float2 uv; stat = faceIter.getUV(triVertexIdx[i],uv,&uvsets[j]); if (MS::kSuccess != stat) { uv[0] = 0; uv[1] = 0; } vtx.u[j] = uv[0]; vtx.v[j] = (-1)*(uv[1]-1); } vtx.next = -1; vertices.push_back(vtx); // save vertex index in face info newFace.v[i] = vertices.size()-1; vertices[idx].next = vertices.size()-1; } else { newFace.v[i] = idx; } } } // end iteration of triangle vertices // add face info to the array corresponding to the submesh it belongs // skip faces with no shaders assigned if (shaderPolygonMapping[faceIter.index()] >= 0) polygonSets[shaderPolygonMapping[faceIter.index()]].push_back(newFace); } // end iteration of triangles } } std::cout << "done reading mesh triangles\n"; // create a submesh for every different shader linked to the mesh unsigned shaderLength = shaders.length(); for (int i=0; i<shaderLength; i++) { // check if the submesh has at least 1 triangle if (polygonSets[i].size() > 0) { //create new submesh SubMesh* pSubmesh = new SubMesh(); const char *nm = mesh.name().asChar(); const char *nm1 = mesh.partialPathName().asChar(); const char *nm2 = mesh.parentNamespace().asChar(); const char *nm3 = mesh.fullPathName().asChar(); const char *nm4 = meshDag.fullPathName().asChar(); pSubmesh->m_name = meshDag.partialPathName(); if(pDagPath) pSubmesh->m_name = pDagPath->partialPathName(); const char *szName = pSubmesh->m_name.asChar(); if(shaderLength > 1) { char a[256]; sprintf(a,"%d",i); pSubmesh->m_name += a; } OutputDebugString(pSubmesh->m_name.asChar()); OutputDebugString("\n"); //OutputDebugString(szName); //OutputDebugString("\n"); //load linked shader stat = pSubmesh->loadMaterial(shaders[i],uvsets); if (stat != MS::kSuccess) { MFnDependencyNode shadingGroup(shaders[i]); std::cout << "Error loading submesh linked to shader " << shadingGroup.name().asChar() << "\n"; return MS::kFailure; } //load vertex and face data stat = pSubmesh->load(polygonSets[i],vertices,points,normals,opposite); //add submesh to current mesh m_submeshes.push_back(pSubmesh); } } return MS::kSuccess; }
MStatus Molecule3Cmd::redoIt() { MStatus stat; MDagPath dagPath; MFnMesh meshFn; // Create a ball int nBallPolys; MPointArray ballVerts; MIntArray ballPolyCounts; MIntArray ballPolyConnects; MFloatArray ballUCoords; MFloatArray ballVCoords; MIntArray ballFvUVIDs; genBall( MPoint::origin, ballRodRatio * radius.value(), segs, nBallPolys, ballVerts, ballPolyCounts, ballPolyConnects, true, ballUCoords, ballVCoords, ballFvUVIDs ); unsigned int i, j, vertOffset; MPointArray meshVerts; MPoint p0, p1; MObject objTransform; // Setup for rods int nRodPolys; MPointArray rodVerts; MIntArray rodPolyCounts; MIntArray rodPolyConnects; MFloatArray rodUCoords; MFloatArray rodVCoords; MIntArray rodFvUVIDs; // Setup for newMesh int nNewPolys; MPointArray newVerts; MIntArray newPolyCounts; MIntArray newPolyConnects; MFloatArray newUCoords; MFloatArray newVCoords; MIntArray newFvUVIDs; int uvOffset; MDagModifier dagMod; MFnDagNode dagFn; objTransforms.clear(); // Iterate over the meshes unsigned int mi; for( mi=0; mi < selMeshes.length(); mi++ ) { dagPath = selMeshes[mi]; meshFn.setObject( dagPath ); uvOffset = 0; nNewPolys = 0; newVerts.clear(); newPolyCounts.clear(); newPolyConnects.clear(); newUCoords.clear(); newVCoords.clear(); newFvUVIDs.clear(); // Generate balls meshFn.getPoints( meshVerts, MSpace::kWorld ); for( i=0; i < meshVerts.length(); i++ ) { vertOffset = newVerts.length(); // Add the ball to the new mesh nNewPolys += nBallPolys; // Move the ball vertices to the mesh vertex. Add it to the newMesh for( j=0; j < ballVerts.length(); j++ ) newVerts.append( meshVerts[i] + ballVerts[j] ); for( j=0; j < ballPolyCounts.length(); j++ ) newPolyCounts.append( ballPolyCounts[j] ); for( j=0; j < ballPolyConnects.length(); j++ ) newPolyConnects.append( vertOffset + ballPolyConnects[j] ); // Only add the uv coordinates once, since they are shared // by all balls if( i == 0 ) { for( j=0; j < ballUCoords.length(); j++ ) { newUCoords.append( ballUCoords[j] ); newVCoords.append( ballVCoords[j] ); } } for( j=0; j < ballFvUVIDs.length(); j++ ) { newFvUVIDs.append( uvOffset + ballFvUVIDs[j] ); } } uvOffset = newUCoords.length(); // Generate rods int nRods = 0; MItMeshEdge edgeIter( dagPath ); for( ; !edgeIter.isDone(); edgeIter.next(), nRods++ ) { p0 = edgeIter.point( 0, MSpace::kWorld ); p1 = edgeIter.point( 1, MSpace::kWorld ); // N.B. Generate the uv coordinates only once since they // are referenced by all rods genRod( p0, p1, radius.value(), segs, nRodPolys, rodVerts, rodPolyCounts, rodPolyConnects, nRods == 0, rodUCoords, rodVCoords, rodFvUVIDs ); vertOffset = newVerts.length(); // Add the rod to the mesh nNewPolys += nRodPolys; for( i=0; i < rodVerts.length(); i++ ) newVerts.append( rodVerts[i] ); for( i=0; i < rodPolyCounts.length(); i++ ) newPolyCounts.append( rodPolyCounts[i] ); for( i=0; i < rodPolyConnects.length(); i++ ) newPolyConnects.append( vertOffset + rodPolyConnects[i] ); // First rod if( nRods == 0 ) { // Add rod's uv coordinates to the list for( i=0; i < rodUCoords.length(); i++ ) { newUCoords.append( rodUCoords[i] ); newVCoords.append( rodVCoords[i] ); } } // Set the face-vertex-uvIDs for( i=0; i < rodFvUVIDs.length(); i++ ) { newFvUVIDs.append( uvOffset + rodFvUVIDs[i] ); } } objTransform = meshFn.create( newVerts.length(), nNewPolys, newVerts, newPolyCounts, newPolyConnects, newUCoords, newVCoords, MObject::kNullObj, &stat ); if( !stat ) { MGlobal::displayError( MString( "Unable to create mesh: " ) + stat.errorString() ); return stat; } objTransforms.append( objTransform ); meshFn.assignUVs( newPolyCounts, newFvUVIDs ); meshFn.updateSurface(); // Rename transform node dagFn.setObject( objTransform ); dagFn.setName( "molecule" ); // Put mesh into the initial shading group dagMod.commandToExecute( MString( "sets -e -fe initialShadingGroup " ) + meshFn.name() ); } // Select all the newly created molecule meshes MString cmd( "select -r" ); for( i=0; i < objTransforms.length(); i++ ) { dagFn.setObject( objTransforms[i] ); cmd += " " + dagFn.name(); } dagMod.commandToExecute( cmd ); return dagMod.doIt(); }
MStatus sgBulgeDeformer::deform(MDataBlock& dataBlock, MItGeometry& iter, const MMatrix& mtx, unsigned int index) { MStatus status; float bulgeWeight = dataBlock.inputValue(aBulgeWeight).asFloat(); double bulgeRadius = dataBlock.inputValue(aBulgeRadius).asDouble(); MArrayDataHandle hArrInputs = dataBlock.inputArrayValue(aBulgeInputs); MPointArray allPositions; iter.allPositions(allPositions); if (mem_resetElements) { unsigned int elementCount = hArrInputs.elementCount(); mem_meshInfosInner.resize(mem_maxLogicalIndex); mem_meshInfosOuter.resize(mem_maxLogicalIndex); for (unsigned int i = 0; i < elementCount; i++, hArrInputs.next()) { MDataHandle hInput = hArrInputs.inputValue(); MDataHandle hMatrix = hInput.child(aMatrix); MDataHandle hMesh = hInput.child(aMesh); MMatrix mtxMesh = hMatrix.asMatrix(); MObject oMesh = hMesh.asMesh(); MFnMeshData meshDataInner, meshDataOuter; MObject oMeshInner = meshDataInner.create(); MObject oMeshOuter = meshDataOuter.create(); MFnMesh fnMesh; fnMesh.copy(oMesh, oMeshInner); fnMesh.copy(oMesh, oMeshOuter); sgMeshInfo* newMeshInfoInner = new sgMeshInfo(oMeshInner, hMatrix.asMatrix()); sgMeshInfo* newMeshInfoOuter = new sgMeshInfo(oMeshOuter, hMatrix.asMatrix()); mem_meshInfosInner[hArrInputs.elementIndex()] = newMeshInfoInner; mem_meshInfosOuter[hArrInputs.elementIndex()] = newMeshInfoOuter; } } for (unsigned int i = 0; i < elementCount; i++) { mem_meshInfosInner[i]->setBulge(bulgeWeight, MSpace::kWorld ); } MFloatArray weightList; weightList.setLength(allPositions.length()); for (unsigned int i = 0; i < weightList.length(); i++) weightList[i] = 0.0f; MMatrixArray inputMeshMatrixInverses; inputMeshMatrixInverses.setLength(elementCount); for (unsigned int i = 0; i < elementCount; i++) { inputMeshMatrixInverses[i] = mem_meshInfosInner[i]->matrix(); } for (unsigned int i = 0; i < allPositions.length(); i++) { float resultWeight = 0; for (unsigned int infoIndex = 0; infoIndex < elementCount; infoIndex++) { MPoint localPoint = allPositions[i] * mtx* inputMeshMatrixInverses[infoIndex]; MPoint innerPoint = mem_meshInfosInner[infoIndex]->getClosestPoint(localPoint); MPoint outerPoint = mem_meshInfosOuter[infoIndex]->getClosestPoint(localPoint); MVector innerVector = innerPoint - localPoint; MVector outerVector = outerPoint - localPoint; if (innerVector * outerVector < 0) { double innerLength = innerVector.length(); double outerLength = outerVector.length(); double allLength = innerLength + outerLength; float numerator = float( innerLength * outerLength ); float denominator = float( pow(allLength / 2.0, 2) ); resultWeight = numerator / denominator; } } weightList[i] = resultWeight; } for (unsigned int i = 0; i < allPositions.length(); i++) { allPositions[i] += weightList[i] * MVector(0, 1, 0); } iter.setAllPositions(allPositions); return MS::kSuccess; }
// ------------------------------------------- // set the sampling function from the UI/command line. // Returns validity of the function bool AnimationHelper::setSamplingFunction ( const MFloatArray& function ) { std::vector<SamplingInterval> parsedFunction; // Order and parse the given floats as a function uint elementCount = function.length(); if ( elementCount > 1 && elementCount % 3 != 0 ) return false; if ( elementCount == 0 ) { generateSamplingFunction(); return true; } else if ( elementCount == 1 ) { SamplingInterval interval; interval.start = ( float ) animationStartTime().as ( MTime::kSeconds ); interval.end = ( float ) animationEndTime().as ( MTime::kSeconds ); interval.period = function[0]; parsedFunction.push_back ( interval ); } else { uint intervalCount = elementCount / 3; parsedFunction.resize ( intervalCount ); for ( uint i = 0; i < intervalCount; ++i ) { SamplingInterval& interval = parsedFunction[i]; interval.start = function[i * 3]; interval.end = function[i * 3 + 1]; interval.period = function[i * 3 + 2]; } } // Check for a valid sampling function uint parsedFunctionSize = ( uint ) parsedFunction.size(); for ( uint i = 0; i < parsedFunctionSize; ++i ) { SamplingInterval& interval = parsedFunction[i]; if ( interval.end <= interval.start ) return false; if ( interval.period > interval.end - interval.start ) return false; if ( i > 0 && parsedFunction[i - 1].end > interval.start ) return false; if ( interval.period <= 0.0f ) return false; } // Gather the sampling times mSamplingTimes.clear(); float previousTime = ( float ) animationStartTime().as ( MTime::kSeconds ); float previousPeriodTakenRatio = 1.0f; for ( std::vector<SamplingInterval>::iterator it = parsedFunction.begin(); it != parsedFunction.end(); ++it ) { SamplingInterval& interval = ( *it ); float time = interval.start; if ( time == previousTime ) { // Continuity in the sampling, calculate overlap start time time = time + ( 1.0f - previousPeriodTakenRatio ) * interval.period; } for ( ; time <= interval.end - interval.period + FLT_TOLERANCE; time += interval.period ) { mSamplingTimes.push_back ( time ); } mSamplingTimes.push_back ( time ); previousTime = interval.end; previousPeriodTakenRatio = ( interval.end - time ) / interval.period; } return true; }
MStatus meshOpFty::doLightningSplit(MFnMesh& meshFn) // // Description: // Performs the kSplitLightning operation on the selected mesh // and components. It may not split all the selected components. // { unsigned int i, j; // These are the input arrays to the split function. The following // algorithm fills them in with the arguments for a continuous // split that goes through some of the selected faces. // MIntArray placements; MIntArray edgeIDs; MFloatArray edgeFactors; MFloatPointArray internalPoints; // The following array is going to be used to determine which faces // have been split. Since the split function can only split faces // which are adjacent to the earlier face, we may not split // all the faces // bool* faceTouched = new bool[fComponentIDs.length()]; for (i = 0; i < fComponentIDs.length(); ++i) faceTouched[i] = false; // We need a starting point. For this example, the first face in // the component list is picked. Also get a polygon iterator // to this face. // MItMeshPolygon itPoly(fMesh); for (; !itPoly.isDone(); itPoly.next()) { if (fComponentIDs[0] == itPoly.index()) break; } if (itPoly.isDone()) { // Should never happen. // delete [] faceTouched; return MS::kFailure; } // In this example, edge0 is called the starting edge and // edge1 is called the destination edge. This algorithm will split // each face from the starting edge to the destination edge // while going through two inner points inside each face. // int edge0, edge1; MPoint innerVert0, innerVert1; int nextFaceIndex = 0; // We need a starting edge. For this example, the first edge in the // edge list is used. // MIntArray edgeList; itPoly.getEdges(edgeList); edge0 = edgeList[0]; bool done = false; while (!done) { // Set this face as touched so that we don't try to split it twice // faceTouched[nextFaceIndex] = true; // Get the current face's center. It is used later in the // algorithm to calculate inner vertices. // MPoint faceCenter = itPoly.center(); // Iterate through the connected faces to find an untouched, // selected face and get the ID of the shared edge. That face // will become the next face to be split. // MIntArray faceList; itPoly.getConnectedFaces(faceList); nextFaceIndex = -1; for (i = 0; i < fComponentIDs.length(); ++i) { for (j = 0; j < faceList.length(); ++j) { if (fComponentIDs[i] == faceList[j] && !faceTouched[i]) { nextFaceIndex = i; break; } } if (nextFaceIndex != -1) break; } if (nextFaceIndex == -1) { // There is no selected and untouched face adjacent to this // face, so this algorithm is done. Pick the first edge that // is not the starting edge as the destination edge. // done = true; edge1 = -1; for (i = 0; i < edgeList.length(); ++i) { if (edgeList[i] != edge0) { edge1 = edgeList[i]; break; } } if (edge1 == -1) { // This should not happen, since there should be more than // one edge for each face // delete [] faceTouched; return MS::kFailure; } } else { // The next step is to find out which edge is shared between // the two faces and use it as the destination edge. To do // that, we need to iterate through the faces and get the // next face's list of edges. // itPoly.reset(); for (; !itPoly.isDone(); itPoly.next()) { if (fComponentIDs[nextFaceIndex] == itPoly.index()) break; } if (itPoly.isDone()) { // Should never happen. // delete [] faceTouched; return MS::kFailure; } // Look for a common edge ID in the two faces edge lists // MIntArray nextFaceEdgeList; itPoly.getEdges(nextFaceEdgeList); edge1 = -1; for (i = 0; i < edgeList.length(); ++i) { for (j = 0; j < nextFaceEdgeList.length(); ++j) { if (edgeList[i] == nextFaceEdgeList[j]) { edge1 = edgeList[i]; break; } } if (edge1 != -1) break; } if (edge1 == -1) { // Should never happen. // delete [] faceTouched; return MS::kFailure; } // Save the edge list for the next iteration // edgeList = nextFaceEdgeList; } // Calculate the two inner points that the split will go through. // For this example, the midpoints between the center and the two // farthest vertices of the edges are used. // // Find the 3D positions of the edges' vertices // MPoint edge0vert0, edge0vert1, edge1vert0, edge1vert1; MItMeshEdge itEdge(fMesh, MObject::kNullObj ); for (; !itEdge.isDone(); itEdge.next()) { if (itEdge.index() == edge0) { edge0vert0 = itEdge.point(0); edge0vert1 = itEdge.point(1); } if (itEdge.index() == edge1) { edge1vert0 = itEdge.point(0); edge1vert1 = itEdge.point(1); } } // Figure out which are the farthest from each other // double distMax = edge0vert0.distanceTo(edge1vert0); MPoint max0, max1; max0 = edge0vert0; max1 = edge1vert0; double newDist = edge0vert1.distanceTo(edge1vert0); if (newDist > distMax) { max0 = edge0vert1; max1 = edge1vert0; distMax = newDist; } newDist = edge0vert0.distanceTo(edge1vert1); if (newDist > distMax) { max0 = edge0vert0; max1 = edge1vert1; distMax = newDist; } newDist = edge0vert1.distanceTo(edge1vert1); if (newDist > distMax) { max0 = edge0vert1; max1 = edge1vert1; } // Calculate the two inner points // innerVert0 = (faceCenter + max0) / 2.0; innerVert1 = (faceCenter + max1) / 2.0; // Add this split's information to the input arrays. If this is // the last split, also add the destination edge's split information. // placements.append((int) MFnMesh::kOnEdge); placements.append((int) MFnMesh::kInternalPoint); placements.append((int) MFnMesh::kInternalPoint); if (done) placements.append((int) MFnMesh::kOnEdge); edgeIDs.append(edge0); if (done) edgeIDs.append(edge1); edgeFactors.append(0.5f); if (done) edgeFactors.append(0.5f); MFloatPoint point1((float)innerVert0[0], (float)innerVert0[1], (float)innerVert0[2], (float)innerVert0[3]); MFloatPoint point2((float)innerVert1[0], (float)innerVert1[1], (float)innerVert1[2], (float)innerVert1[3]); internalPoints.append(point1); internalPoints.append(point2); // For the next iteration, the current destination // edge becomes the start edge. // edge0 = edge1; } // Release the dynamically-allocated memory and do the actual split // delete [] faceTouched; return meshFn.split(placements, edgeIDs, edgeFactors, internalPoints); }
/* static */ bool UsdMayaTranslatorMesh::_AssignUVSetPrimvarToMesh( const UsdGeomPrimvar& primvar, MFnMesh& meshFn) { const TfToken& primvarName = primvar.GetPrimvarName(); // Get the raw data before applying any indexing. VtVec2fArray uvValues; if (!primvar.Get(&uvValues) || uvValues.empty()) { TF_WARN("Could not read UV values from primvar '%s' on mesh: %s", primvarName.GetText(), primvar.GetAttr().GetPrimPath().GetText()); return false; } // This is the number of UV values assuming the primvar is NOT indexed. VtIntArray assignmentIndices; if (primvar.GetIndices(&assignmentIndices)) { // The primvar IS indexed, so the indices array is what determines the // number of UV values. int unauthoredValuesIndex = primvar.GetUnauthoredValuesIndex(); // Replace any index equal to unauthoredValuesIndex with -1. if (unauthoredValuesIndex != -1) { for (int& index : assignmentIndices) { if (index == unauthoredValuesIndex) { index = -1; } } } // Furthermore, if unauthoredValuesIndex is valid for uvValues, then // remove it from uvValues and shift the indices (we don't want to // import the unauthored value into Maya, where it has no meaning). if (unauthoredValuesIndex >= 0 && static_cast<size_t>(unauthoredValuesIndex) < uvValues.size()) { // This moves [unauthoredValuesIndex + 1, end) to // [unauthoredValuesIndex, end - 1), erasing the // unauthoredValuesIndex. std::move( uvValues.begin() + unauthoredValuesIndex + 1, uvValues.end(), uvValues.begin() + unauthoredValuesIndex); uvValues.pop_back(); for (int& index : assignmentIndices) { if (index > unauthoredValuesIndex) { index = index - 1; } } } } // Go through the UV data and add the U and V values to separate // MFloatArrays. MFloatArray uCoords; MFloatArray vCoords; for (const GfVec2f& v : uvValues) { uCoords.append(v[0]); vCoords.append(v[1]); } MStatus status; MString uvSetName(primvarName.GetText()); if (primvarName == UsdUtilsGetPrimaryUVSetName()) { // We assume that the primary USD UV set maps to Maya's default 'map1' // set which always exists, so we shouldn't try to create it. uvSetName = "map1"; } else { status = meshFn.createUVSet(uvSetName); if (status != MS::kSuccess) { TF_WARN("Unable to create UV set '%s' for mesh: %s", uvSetName.asChar(), meshFn.fullPathName().asChar()); return false; } } // The following two lines should have no effect on user-visible state but // prevent a Maya crash in MFnMesh.setUVs after creating a crease set. // XXX this workaround is needed pending a fix by Autodesk. MString currentSet = meshFn.currentUVSetName(); meshFn.setCurrentUVSetName(currentSet); // Create UVs on the mesh from the values we collected out of the primvar. // We'll assign mesh components to these values below. status = meshFn.setUVs(uCoords, vCoords, &uvSetName); if (status != MS::kSuccess) { TF_WARN("Unable to set UV data on UV set '%s' for mesh: %s", uvSetName.asChar(), meshFn.fullPathName().asChar()); return false; } const TfToken& interpolation = primvar.GetInterpolation(); // Build an array of value assignments for each face vertex in the mesh. // Any assignments left as -1 will not be assigned a value. MIntArray uvIds = _GetMayaFaceVertexAssignmentIds(meshFn, interpolation, assignmentIndices, -1); MIntArray vertexCounts; MIntArray vertexList; status = meshFn.getVertices(vertexCounts, vertexList); if (status != MS::kSuccess) { TF_WARN("Could not get vertex counts for UV set '%s' on mesh: %s", uvSetName.asChar(), meshFn.fullPathName().asChar()); return false; } status = meshFn.assignUVs(vertexCounts, uvIds, &uvSetName); if (status != MS::kSuccess) { TF_WARN("Could not assign UV values to UV set '%s' on mesh: %s", uvSetName.asChar(), meshFn.fullPathName().asChar()); return false; } return true; }
// h�mta all n�dv�ndig data och l�gger det i ett MeshData-objekt, som senare anv�nds vid exportering. bool Exporter::ExtractMeshData(MFnMesh &mesh, UINT index) { MeshData mesh_data; MFloatPointArray points; MFloatVectorArray normals; MSpace::Space world_space = MSpace::kTransform; // DAG-path mesh_data.mesh_path = mesh.dagPath(); // namn och id mesh_data.name = mesh.name(); mesh_data.id = index; std::string name = mesh.partialPathName().asChar(); if (!strcmp(name.substr(0, 5).c_str(), "Blend")){ return true; } // triangulera meshen innan man h�mtar punkterna MString command = "polyTriangulate -ch 1 " + mesh_data.name; if (!MGlobal::executeCommand(command)) { return false; } // h�mta icke-indexerade vertexpunkter if (!mesh.getPoints(points, world_space)) { return false; } for (int i = 0; i < points.length(); i++){ point temppoints = { points[i].x, points[i].y, points[i].z }; vec3 temppurepoints = { points[i].x, points[i].y, points[i].z }; mesh_data.points.push_back(temppoints); mesh_data.purepoints.push_back(temppurepoints); } // h�mta icke-indexerade normaler if (!mesh.getNormals(normals, world_space)) { return false; } for (int i = 0; i < normals.length(); i++){ vec3 tempnormals = { normals[i].x, normals[i].y, normals[i].z }; mesh_data.normals.push_back(tempnormals); } //variabler f�r att mellanlagra uvdata och tangenter/bitangenter MStringArray uvSets; mesh.getUVSetNames(uvSets); uvSet tempUVSet; MFloatArray Us; MFloatArray Vs; vec2 UVs; // iterera �ver uvsets och ta ut koordinater, tangenter och bitangenter for (int i = 0; i < uvSets.length(); i++) { MString currentSet = uvSets[i]; mesh.getUVs(Us, Vs, ¤tSet); for (int a = 0; a < Us.length(); a++){ UVs.u = Us[a]; UVs.v = Vs[a]; //1-Vs in order to get correct UV angles tempUVSet.UVs.push_back(UVs); } mesh.getTangents(tempUVSet.tangents, world_space, ¤tSet); mesh.getBinormals(tempUVSet.binormals, world_space, ¤tSet); mesh_data.uvSets.push_back(tempUVSet); } //itererar �ver trianglar och returnerar ID:n f�r associerade vertiser, normaler och uvset MItMeshPolygon itFaces(mesh.dagPath()); while (!itFaces.isDone()) { face tempface; // printf("%d", itFaces.vertexIndex(0)); // printf(" %d", itFaces.vertexIndex(1)); // printf(" %d\n", itFaces.vertexIndex(2)); int vc = itFaces.polygonVertexCount(); for (int i = 0; i < vc; ++i) { tempface.verts[i].pointID = itFaces.vertexIndex(i); tempface.verts[i].normalID = itFaces.normalIndex(i); for (int k = 0; k < uvSets.length(); ++k) { int temptexCoordsID; itFaces.getUVIndex(i, temptexCoordsID, &uvSets[k]); tempface.verts[i].texCoordsID.push_back(temptexCoordsID); } } mesh_data.faces.push_back(tempface); itFaces.next(); } // l�gg till mesh_data i scen-datan scene_.meshes.push_back(mesh_data); return true; }
// // Change the UVS for the given selection on this mesh object. // /////////////////////////////////////////////////////////////////////////////// MStatus flipUVCmd::getTweakedUVs( const MObject & meshObj, // Object MIntArray & uvList, // UVs to move MFloatArray & uPos, // Moved UVs MFloatArray & vPos ) // Moved UVs { MStatus status; unsigned int i; MFloatArray uArray; MFloatArray vArray; MFnMesh mesh( meshObj ); // Read all UVs from the poly object status = mesh.getUVs(uArray, vArray); CHECK_MSTATUS_AND_RETURN_IT(status); unsigned int nbUvShells = 1; MIntArray uvShellIds; if ((!flipGlobal) || extendToShell) { // First, extract the UV shells. status = mesh.getUvShellsIds(uvShellIds, nbUvShells); CHECK_MSTATUS_AND_RETURN_IT(status); } if (extendToShell) { // Find all shells that have at least a selected UV. bool *selected = new bool[nbUvShells]; for (i = 0 ; i<nbUvShells ; i++) selected[i] = false; for (i = 0 ; i<uvList.length() ; i++) { int indx = uvList[i]; selected[uvShellIds[indx]] = true; } // Now recompute a new list of UVs to modify. unsigned int numUvs = mesh.numUVs(); unsigned int numSelUvs = 0; // Preallocate a buffer, large enough to hold all Ids. This // prevents multiple reallocation from happening when growing // the array. uvList.setLength(numUvs); for (i = 0 ; i<numUvs ; i++) { if (selected[uvShellIds[i]]) uvList[numSelUvs++] = i; } // clamp the array to the proper size. uvList.setLength(numSelUvs); delete [] selected; } // For global flips, just pretend there is only one shell if (flipGlobal) nbUvShells = 1; float *minMax = new float[nbUvShells*4]; for (i = 0 ; i<nbUvShells ; i++) { minMax[4*i+0] = 1e30F; // Min U minMax[4*i+1] = 1e30F; // Min V minMax[4*i+2] = -1e30F; // Max U minMax[4*i+3] = -1e30F; // Max V } // Get the bounding box of the UVs, for each shell if flipGlobal // is true, or for the whole selection if false. for (i = 0 ; i<uvList.length() ; i++) { int indx = uvList[i]; int shellId = 0; if (!flipGlobal) shellId = uvShellIds[indx]; if (uArray[indx] < minMax[4*shellId+0]) minMax[4*shellId+0] = uArray[indx]; if (vArray[indx] < minMax[4*shellId+1]) minMax[4*shellId+1] = vArray[indx]; if (uArray[indx] > minMax[4*shellId+2]) minMax[4*shellId+2] = uArray[indx]; if (vArray[indx] > minMax[4*shellId+3]) minMax[4*shellId+3] = vArray[indx]; } // Adjust the size of the output arrays uPos.setLength(uvList.length()); vPos.setLength(uvList.length()); for (i = 0 ; i<uvList.length() ; i++) { int shellId = 0; int indx = uvList[i]; if (!flipGlobal) shellId = uvShellIds[indx]; // Flip U or V along the bounding box center. if (horizontal) { uPos[i] = minMax[4*shellId+0] + minMax[4*shellId+2] - uArray[indx]; vPos[i] = vArray[indx]; } else { uPos[i] = uArray[indx]; vPos[i] = minMax[4*shellId+1] + minMax[4*shellId+3] - vArray[indx]; } } delete [] minMax; return MS::kSuccess; }
MStatus ColorSplineParameterHandler<S>::doSetValue( IECore::ConstParameterPtr parameter, MPlug &plug ) const { assert( parameter ); typename IECore::TypedParameter< S >::ConstPtr p = IECore::runTimeCast<const IECore::TypedParameter< S > >( parameter ); if( !p ) { return MS::kFailure; } MRampAttribute fnRAttr( plug ); if ( !fnRAttr.isColorRamp() ) { return MS::kFailure; } const S &spline = p->getTypedValue(); MStatus s; MIntArray indicesToReuse; plug.getExistingArrayAttributeIndices( indicesToReuse, &s ); assert( s ); int nextNewLogicalIndex = 0; if( indicesToReuse.length() ) { nextNewLogicalIndex = 1 + *std::max_element( MArrayIter<MIntArray>::begin( indicesToReuse ), MArrayIter<MIntArray>::end( indicesToReuse ) ); } assert( indicesToReuse.length() == fnRAttr.getNumEntries() ); size_t pointsSizeMinus2 = spline.points.size() - 2; unsigned pointIndex = 0; unsigned numExpectedPoints = 0; for ( typename S::PointContainer::const_iterator it = spline.points.begin(); it != spline.points.end(); ++it, ++pointIndex ) { // we commonly double up the endpoints on cortex splines to force interpolation to the end. // maya does this implicitly, so we skip duplicated endpoints when passing the splines into maya. // this avoids users having to be responsible for managing the duplicates, and gives them some consistency // with the splines they edit elsewhere in maya. if( ( pointIndex==1 && *it == *spline.points.begin() ) || ( pointIndex==pointsSizeMinus2 && *it == *spline.points.rbegin() ) ) { continue; } MPlug pointPlug; if( indicesToReuse.length() ) { pointPlug = plug.elementByLogicalIndex( indicesToReuse[0] ); indicesToReuse.remove( 0 ); } else { pointPlug = plug.elementByLogicalIndex( nextNewLogicalIndex++ ); } s = pointPlug.child( 0 ).setValue( it->first ); assert( s ); MPlug colorPlug = pointPlug.child( 1 ); colorPlug.child( 0 ).setValue( it->second[0] ); colorPlug.child( 1 ).setValue( it->second[1] ); colorPlug.child( 2 ).setValue( it->second[2] ); // hardcoding interpolation of 3 (spline) because the MRampAttribute::MInterpolation enum values don't actually // correspond to the necessary plug values at all. s = pointPlug.child( 2 ).setValue( 3 ); assert( s ); numExpectedPoints++; } // delete any of the original indices which we didn't reuse. we can't use MRampAttribute::deleteEntries // here as it's utterly unreliable. if( indicesToReuse.length() ) { MString plugName = plug.name(); MObject node = plug.node(); MFnDagNode fnDAGN( node ); if( fnDAGN.hasObj( node ) ) { plugName = fnDAGN.fullPathName() + "." + plug.partialName(); } for( unsigned i=0; i<indicesToReuse.length(); i++ ) { // using mel because there's no equivalant api method as far as i know. MString command = "removeMultiInstance -b true \"" + plugName + "[" + indicesToReuse[i] + "]\""; s = MGlobal::executeCommand( command ); assert( s ); if( !s ) { return s; } } } #ifndef NDEBUG { assert( fnRAttr.getNumEntries() == numExpectedPoints ); MIntArray indices; MFloatArray positions; MColorArray colors; MIntArray interps; fnRAttr.getEntries( indices, positions, colors, interps, &s ); assert( s ); assert( numExpectedPoints == positions.length() ); assert( numExpectedPoints == colors.length() ); assert( numExpectedPoints == interps.length() ); assert( numExpectedPoints == indices.length() ); for ( unsigned i = 0; i < positions.length(); i++ ) { float position = positions[ i ]; const MVector color( colors[ i ][ 0 ], colors[ i ][ 1 ], colors[ i ][ 2 ] ); bool found = false; for ( typename S::PointContainer::const_iterator it = spline.points.begin(); it != spline.points.end() && !found; ++it ) { MVector color2( it->second[0], it->second[1], it->second[2] ); if ( fabs( it->first - position ) < 1.e-3f && ( color2 - color ).length() < 1.e-3f ) { found = true; } } assert( found ); } } #endif return MS::kSuccess; }