MTransformationMatrix SurfaceAttach::matrix(const MFnNurbsSurface &fnSurface, const int plugID, const double dataOffset, const bool dataReverse, const short dataGenus, const double dataStaticLength, const MMatrix &dataParentInverse, const short dataDirection) { // Do all the Fancy stuff to input UV values double parmU = this->uInputs[plugID]; double parmV = this->vInputs[plugID]; // Fix U Flipping from 1.0 to 0.0 if (uInputs[plugID] == 1.0 && parmU == 0.0) parmU = 1.0; if (vInputs[plugID] == 1.0 && parmV == 0.0) parmV = 1.0; if (dataDirection == 0) this->calculateUV(plugID, dataOffset, dataReverse, dataGenus, dataStaticLength, parmU); else this->calculateUV(plugID, dataOffset, dataReverse, dataGenus, dataStaticLength, parmV); // Calculate transformations from UV values const MVector normal = fnSurface.normal(parmU, parmV, MSpace::Space::kWorld); MPoint point; fnSurface.getPointAtParam(parmU, parmV, point, MSpace::Space::kWorld); MVector tanU, tanV; fnSurface.getTangents(parmU, parmV, tanU, tanV, MSpace::Space::kWorld); const double dubArray[4][4] = { tanU.x, tanU.y, tanU.z, 0.0, normal.x, normal.y, normal.z, 0.0, tanV.x, tanV.y, tanV.z, 0.0, point.x, point.y, point.z, 1.0 }; const MMatrix mat (dubArray); return MTransformationMatrix (mat * dataParentInverse); }
MStatus cvColor::compute( const MPlug& plug, MDataBlock& data ) { MStatus stat; // cout << "cvColor::compute\n"; if ( plug == cvLocations ) { MDataHandle inputData = data.inputValue ( inputSurface, &stat ); if (!stat) { stat.perror("cvColor::compute get inputSurface"); return stat; } MObject surf = inputData.asNurbsSurface(); MFnNurbsSurface surfFn (surf, &stat); if (!stat) { stat.perror("cvColor::compute surface creator"); return stat; } MDataHandle outputData = data.outputValue ( cvLocations, &stat ); if (!stat) { stat.perror("cvColor::compute get cvLocations"); return stat; } MObject cvs = outputData.data(); MFnPointArrayData cvData(cvs, &stat); if (!stat) { stat.perror("cvColor::compute point array data creator"); return stat; } MPointArray cvArray; stat = surfFn.getCVs( cvArray, MSpace::kObject); if (!stat) { stat.perror("cvColor::compute getCVs"); return stat; } stat = cvData.set ( cvArray ); if (!stat) { stat.perror("cvColor::compute setCVs"); return stat; } outputData.set ( cvs ); stat = data.setClean ( plug ); if (!stat) { stat.perror("cvColor::compute setClean"); return stat; } } else { return MS::kUnknownParameter; } return MS::kSuccess; }
MStatus makeSurf() { cout << ">>>> Start creation of test surface <<<<" << endl; // Set up knots // MDoubleArray knotArray; int i; // Add extra starting knots so that the first CV matches the curve start point // knotArray.append( 0.0 ); knotArray.append( 0.0 ); for ( i = 0; i <= NUM_SPANS; i++ ) { knotArray.append( (double)i ); } // Add extra ending knots so that the last CV matches the curve end point // knotArray.append( (double)i ); knotArray.append( (double)i ); // Now, Set up CVs // MPointArray cvArray; // We need a 2D array of CVs with NUM_SPANS + 3 CVs on a side // int last = NUM_SPANS + 3; for ( i = 0; i < last; i++ ) { for ( int j = 0; j < last; j++ ) { MPoint cv; cv.x = (((double)(j))/((double)(NUM_SPANS + 3)) * WIDTH) - (WIDTH/2.0); cv.z = (((double)(i))/((double)(NUM_SPANS + 3)) * WIDTH) - (WIDTH/2.0); double dist = sqrt( cv.x*cv.x + cv.z*cv.z ); cv.y = cos( dist ) * VERTICAL_SCALING; cvArray.append( cv ); } } // Create the surface // MFnNurbsSurface mfnNurbsSurf; MStatus stat; mfnNurbsSurf.create( cvArray, knotArray, knotArray, 3, 3, MFnNurbsSurface::kOpen, MFnNurbsSurface::kOpen, true, MObject::kNullObj, &stat ); if ( stat ) { cout << ">>>> Test Surface Creation Successfull <<<<\n"; } else { stat.perror("MFnNurbsSurface::create"); cout << ">>>> Test Surface Creation Failed <<<<\n"; } return stat; }
void SurfaceAttach::surfaceLengthsV(const MFnNurbsSurface &fnSurface, const double parmU) { MPoint pointA; fnSurface.getPointAtParam(parmU, 0.0, pointA, MSpace::Space::kWorld); this->length = 0.0; MPoint pointB; double *s = &this->sampler[0]; double *d = &this->distances[0]; for (size_t i=0; i < this->sampleCount; i++){ fnSurface.getPointAtParam(parmU, *s++, pointB, MSpace::Space::kWorld); // Add the measured distanced to 'length' and set the measured length in 'distances' this->length += pointA.distanceTo(pointB); *d++ = this->length; pointA.x = pointB.x; pointA.y = pointB.y; pointA.z = pointB.z; } }
MObject fullLoft::loft( MArrayDataHandle &inputArray, MObject &newSurfData, MStatus &stat ) { MFnNurbsSurface surfFn; MPointArray cvs; MDoubleArray ku, kv; int i, j; int numCVs; int numCurves = inputArray.elementCount (); // Ensure that we have at least 1 element in the input array // We must not do an inputValue on an element that does not // exist. if ( numCurves < 1 ) return MObject::kNullObj; // Count the number of CVs inputArray.jumpToElement(0); MDataHandle elementHandle = inputArray.inputValue(&stat); if (!stat) { stat.perror("fullLoft::loft: inputValue"); return MObject::kNullObj; } MObject countCurve (elementHandle.asNurbsCurve()); MFnNurbsCurve countCurveFn (countCurve); numCVs = countCurveFn.numCVs (&stat); PERRORnull("fullLoft::loft counting CVs"); // Create knot vectors for U and V // U dimension contains one CV from each curve, triple knotted for (i = 0; i < numCurves; i++) { ku.append (double (i)); ku.append (double (i)); ku.append (double (i)); } // V dimension contains all of the CVs from one curve, triple knotted at // the ends kv.append( 0.0 ); kv.append( 0.0 ); kv.append( 0.0 ); for ( i = 1; i < numCVs - 3; i ++ ) kv.append( (double) i ); kv.append( numCVs-3 ); kv.append( numCVs-3 ); kv.append( numCVs-3 ); // Build the surface's CV array for (int curveNum = 0; curveNum < numCurves; curveNum++) { MObject curve (inputArray.inputValue ().asNurbsCurve ()); MFnNurbsCurve curveFn (curve); MPointArray curveCVs; stat = curveFn.getCVs (curveCVs, MSpace::kWorld); PERRORnull("fullLoft::loft getting CVs"); if (curveCVs.length() != (unsigned)numCVs) stat = MS::kFailure; PERRORnull("fullLoft::loft inconsistent number of CVs - rebuild curves"); // Triple knot for every curve but the first int repeats = (curveNum == 0) ? 1 : 3; for (j = 0; j < repeats; j++) for ( i = 0; i < numCVs; i++ ) cvs.append (curveCVs [i]); stat = inputArray.next (); } MObject surf = surfFn.create(cvs, ku, kv, 3, 3, MFnNurbsSurface::kOpen, MFnNurbsSurface::kOpen, false, newSurfData, &stat ); PERRORnull ("fullLoft::Loft create surface"); return surf; }
MObject readNurbs(double iFrame, Alembic::AbcGeom::INuPatch & iNode, MObject & iObject) { MStatus status; MObject obj; Alembic::AbcGeom::INuPatchSchema schema = iNode.getSchema(); // no interpolation for now Alembic::AbcCoreAbstract::index_t index, ceilIndex; getWeightAndIndex(iFrame, schema.getTimeSampling(), schema.getNumSamples(), index, ceilIndex); Alembic::AbcGeom::INuPatchSchema::Sample samp; schema.get(samp, Alembic::Abc::ISampleSelector(index)); Alembic::Abc::P3fArraySamplePtr pos = samp.getPositions(); Alembic::Abc::FloatArraySamplePtr weights = samp.getPositionWeights(); MString surfaceName(iNode.getName().c_str()); unsigned int degreeU = samp.getUOrder() - 1; unsigned int degreeV = samp.getVOrder() - 1; unsigned int numCVInU = samp.getNumU(); unsigned int numCVInV = samp.getNumV(); // cv points unsigned int numCV = numCVInU*numCVInV; unsigned int curPos = 0; MPointArray controlVertices; controlVertices.setLength(numCV); for (unsigned int v = 0; v < numCVInV; ++v) { for (unsigned int u = 0; u < numCVInU; ++u, ++curPos) { unsigned int mayaIndex = u * numCVInV + (numCVInV - v - 1); MPoint pt((*pos)[curPos].x, (*pos)[curPos].y, (*pos)[curPos].z); if (weights) { pt.w = (*weights)[curPos]; } // go from u,v order to reversed v, u order controlVertices.set(pt, mayaIndex); } } // Nurbs form // Alemblic file does not record the form of nurb surface, we get the form // by checking the CV data. If the first degree number CV overlap the last // degree number CV, then the form is kPeriodic. If only the first CV overlaps // the last CV, then the form is kClosed. MFnNurbsSurface::Form formU = MFnNurbsSurface::kPeriodic; MFnNurbsSurface::Form formV = MFnNurbsSurface::kPeriodic; // Check all curves bool notOpen = true; for (unsigned int v = 0; notOpen && v < numCVInV; v++) { for (unsigned int u = 0; u < degreeU; u++) { unsigned int firstIndex = u * numCVInV + (numCVInV - v - 1); unsigned int lastPeriodicIndex = (numCVInU - degreeU + u) * numCVInV + (numCVInV - v - 1); if (!controlVertices[firstIndex].isEquivalent(controlVertices[lastPeriodicIndex])) { formU = MFnNurbsSurface::kOpen; notOpen = false; break; } } } if (formU == MFnNurbsSurface::kOpen) { formU = MFnNurbsSurface::kClosed; for (unsigned int v = 0; v < numCVInV; v++) { unsigned int lastUIndex = (numCVInU - 1) * numCVInV + (numCVInV - v - 1); if (! controlVertices[numCVInV-v-1].isEquivalent(controlVertices[lastUIndex])) { formU = MFnNurbsSurface::kOpen; break; } } } notOpen = true; for (unsigned int u = 0; notOpen && u < numCVInU; u++) { for (unsigned int v = 0; v < degreeV; v++) { unsigned int firstIndex = u * numCVInV + (numCVInV - v - 1); unsigned int lastPeriodicIndex = u * numCVInV + (degreeV - v - 1); //numV - (numV - vDegree + v) - 1; if (!controlVertices[firstIndex].isEquivalent(controlVertices[lastPeriodicIndex])) { formV = MFnNurbsSurface::kOpen; notOpen = false; break; } } } if (formV == MFnNurbsSurface::kOpen) { formV = MFnNurbsSurface::kClosed; for (unsigned int u = 0; u < numCVInU; u++) { if (! controlVertices[u * numCVInV + (numCVInV-1)].isEquivalent(controlVertices[u * numCVInV])) { formV = MFnNurbsSurface::kOpen; break; } } } Alembic::Abc::FloatArraySamplePtr uKnot = samp.getUKnot(); Alembic::Abc::FloatArraySamplePtr vKnot = samp.getVKnot(); unsigned int numKnotsInU = static_cast<unsigned int>(uKnot->size() - 2); MDoubleArray uKnotSequences; uKnotSequences.setLength(numKnotsInU); for (unsigned int i = 0; i < numKnotsInU; ++i) { uKnotSequences.set((*uKnot)[i+1], i); } unsigned int numKnotsInV = static_cast<unsigned int>(vKnot->size() - 2); MDoubleArray vKnotSequences; vKnotSequences.setLength(numKnotsInV); for (unsigned int i = 0; i < numKnotsInV; i++) { vKnotSequences.set((*vKnot)[i+1], i); } // Node creation try the API first MFnNurbsSurface mFn; obj = mFn.create(controlVertices, uKnotSequences, vKnotSequences, degreeU, degreeV, formU, formV, true, iObject, &status); // something went wrong, try open/open create if (status != MS::kSuccess && (formU != MFnNurbsSurface::kOpen || formV != MFnNurbsSurface::kOpen)) { obj = mFn.create(controlVertices, uKnotSequences, vKnotSequences, degreeU, degreeV, MFnNurbsSurface::kOpen, MFnNurbsSurface::kOpen, true, iObject, &status); } if (status == MS::kSuccess) { mFn.setName(surfaceName); } else { MString errorMsg = "Could not create Nurbs Surface: "; errorMsg += surfaceName; MGlobal::displayError(errorMsg); } trimSurface(samp, mFn); return obj; }
MStatus MG_nurbsRivet::compute(const MPlug& plug,MDataBlock& dataBlock) { //Get recompute value MDataHandle recomputeH = dataBlock.inputValue(recompute); bool recomputeV = recomputeH.asBool(); //input mesh MDataHandle inputNurbsH = dataBlock.inputValue(inputNurbSurface); MObject inputNurb = inputNurbsH.asNurbsSurfaceTransformed(); MMatrix offsetMatrixV = dataBlock.inputValue(offsetMatrix).asMatrix(); double U,V; MFnNurbsSurface nurbsFn ; nurbsFn.setObject(inputNurb); MStatus stat; if (recomputeV == true) { //input point MDataHandle inputPointH = dataBlock.inputValue(inputPoint); MPoint inputP = inputPointH.asVector(); MPoint closestP = nurbsFn.closestPoint(inputP,NULL,NULL,false,1e+99,MSpace::kObject); stat = nurbsFn.getParamAtPoint(closestP,U,V,MSpace::kObject); //Handle to U and V MDataHandle uValueH =dataBlock.outputValue(uValue); MDataHandle vValueH =dataBlock.outputValue(vValue); uValueH.set(float(U)); vValueH.set(float(V)); uValueH.setClean(); vValueH.setClean(); MDataHandle recomputeOutH = dataBlock.outputValue(recompute); } MDataHandle uH = dataBlock.inputValue(uValue); MDataHandle vH = dataBlock.inputValue(vValue); U = uH.asFloat(); V = vH.asFloat(); MPoint outPoint ; MVector uVec ; MVector vVec; MVector normal; //Get point stat = nurbsFn.getPointAtParam(U,V,outPoint,MSpace::kObject); //Since if getting both the U and V tangent was leading to some little rotation snapping //of the rivet I only used the U tangent and calculated the next one by dot product //of the normal and U tangent leading to a 100% stable rivet nurbsFn.getTangents(U,V,uVec,vVec,MSpace::kObject); uVec.normalize(); vVec.normalize(); MVector vVecCross; //Get normal normal = nurbsFn.normal(U,V,MSpace::kObject); normal.normalize(); vVecCross =(uVec^normal); //Build the maya matrix double myMatrix[4][4]={ { uVec.x, uVec.y , uVec.z, 0}, { normal[0], normal[1] , normal[2], 0}, {vVecCross.x, vVecCross.y , vVecCross.z, 0}, { outPoint[0], outPoint[1] , outPoint[2], 1}}; MMatrix rotMatrix (myMatrix); MMatrix offsetMatrixV2 = offsetMatrixV*rotMatrix; MTransformationMatrix matrixFn(offsetMatrixV2); double angles[3]; MTransformationMatrix::RotationOrder rotOrder; rotOrder =MTransformationMatrix::kXYZ; matrixFn.getRotation(angles,rotOrder,MSpace::kObject ); //get back radians value double radX,radY,radZ; radX=angles[0]; radY=angles[1]; radZ=angles[2]; //convert to degree double rotX,rotY,rotZ; rotX = radX*toDeg; rotY = radY*toDeg; rotZ = radZ*toDeg; MDataHandle outputRotateH = dataBlock.outputValue(outputRotate); outputRotateH.set3Double(rotX,rotY,rotZ); outputRotateH.setClean(); //let set the output matrix too MDataHandle outMH= dataBlock.outputValue(outputMatrix); outMH.set(rotMatrix); outMH.setClean(); MDataHandle outputH = dataBlock.outputValue(output); outputH.set(offsetMatrixV2[3][0],offsetMatrixV2[3][1],offsetMatrixV2[3][2]); outputH.setClean(); return MS::kSuccess; }