// 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 ); } }
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; }
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; }
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 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 grabUVContext::doDrag ( MEvent & event, MHWRender::MUIDrawManager& drawMgr, const MHWRender::MFrameContext& context) { if (event.mouseButton() != MEvent::kLeftMouse || !event.isModifierNone() ) return MS::kFailure; MPxTexContext::doDrag(event, drawMgr, context); short x, y; event.getPosition( x, y ); fLastScreenPoint = fCurrentScreenPoint; fCurrentScreenPoint = MPoint( x, y ); double xView, yView; portToView(x, y, xView, yView); // pos at viewrect coordinate fLastPoint = fCurrentPoint; fCurrentPoint = MPoint( xView, yView, 0.0 ); if( fDragMode == kBrushSize ) { double dis = fCurrentScreenPoint.distanceTo( fLastScreenPoint ); if ( fCurrentScreenPoint[0] > fLastScreenPoint[0] ) setSize( size() + float(dis) ); else setSize( std::max( size() - float(dis), 0.01f ) ); } else { fBrushCenterScreenPoint = MPoint( x, y ); MFloatArray uUVsExported; MFloatArray vUVsExported; const MVector vec = fCurrentPoint - fLastPoint; if (!fCommand) { fCommand = (UVUpdateCommand *)(newToolCommand()); } if (fCommand) { MFnMesh mesh(fDagPath); MString currentUVSetName; mesh.getCurrentUVSetName(currentUVSetName); int nbUVs = mesh.numUVs(currentUVSetName); MDoubleArray pinData; MUintArray uvPinIds; MDoubleArray fullPinData; mesh.getPinUVs(uvPinIds, pinData, ¤tUVSetName); int len = pinData.length(); fullPinData.setLength(nbUVs); for (unsigned int i = 0; i < nbUVs; i++) { fullPinData[i] = 0.0; } while( len-- > 0 ) { fullPinData[uvPinIds[len]] = pinData[len]; } MFloatArray uValues; MFloatArray vValues; float pinWeight = 0; for (unsigned int i = 0; i < fCollectedUVs.length(); ++i) { float u, v; MStatus bGetUV = mesh.getUV(fCollectedUVs[i], u, v, ¤tUVSetName); if (bGetUV == MS::kSuccess) { pinWeight = fullPinData[fCollectedUVs[i]]; u += (float)vec[0]*(1-pinWeight); v += (float)vec[1]*(1-pinWeight); uValues.append( u ); vValues.append( v ); } } fCommand->setUVs( mesh.object(), fCollectedUVs, uValues, vValues, ¤tUVSetName ); } } return MS::kSuccess; }