MMatrix ropeGenerator::getMatrixFromParamCurve( MFnNurbsCurve &curveFn, float param, float twist, MAngle divTwist ) { MPoint pDivPos; //Here we control the tangent of the rope curveFn.getPointAtParam( param, pDivPos, MSpace::kWorld ); MVector vTangent( curveFn.tangent( param, MSpace::kWorld ).normal() ); MVector vNormal( curveFn.normal( param, MSpace::kWorld ).normal() ); if ( MAngle( PrevNormal.angle( vNormal ) ).asDegrees() > 90 ) //fprintf(stderr, "Angle = %g\n",MAngle( PrevNormal.angle( vNormal )).asDegrees()); vNormal = vNormal * -1; PrevNormal = vNormal; //if ( vNormal.angle( ) ) MQuaternion qTwist( twist * divTwist.asRadians(), vTangent ); vNormal = vNormal.rotateBy( qTwist ); MVector vExtra( vNormal ^ vTangent ); vNormal.normalize(); vTangent.normalize(); vExtra.normalize(); double dTrans[4][4] ={ {vNormal.x, vNormal.y, vNormal.z, 0.0f}, {vTangent.x, vTangent.y, vTangent.z, 0.0f}, {vExtra.x, vExtra.y, vExtra.z, 0.0f}, {pDivPos.x,pDivPos.y,pDivPos.z, 1.0f}}; MMatrix mTrans( dTrans ); return mTrans; }
/* ----------------------------------------- Make a degree 1 curve from the given CVs. ----------------------------------------- */ static void jMakeCurve( MPointArray cvs ) { MStatus stat; unsigned int deg = 1; MDoubleArray knots; unsigned int i; for ( i = 0; i < cvs.length(); i++ ) knots.append( (double) i ); // Now create the curve // MFnNurbsCurve curveFn; curveFn.create( cvs, knots, deg, MFnNurbsCurve::kOpen, false, false, MObject::kNullObj, &stat ); if ( MS::kSuccess != stat ) cout<<"Error creating curve."<<endl; }
bool HesperisCurveCreator::CreateACurve(Vector3F * pos, unsigned nv, MObject &target) { MPointArray vertexArray; unsigned i=0; for(; i<nv; i++) vertexArray.append( MPoint( pos[i].x, pos[i].y, pos[i].z ) ); const int degree = 2; const int spans = nv - degree; const int nknots = spans + 2 * degree - 1; MDoubleArray knotSequences; knotSequences.append(0.0); for(i = 0; i < nknots-2; i++) knotSequences.append( (double)i ); knotSequences.append(nknots-3); MFnNurbsCurve curveFn; MStatus stat; curveFn.create(vertexArray, knotSequences, degree, MFnNurbsCurve::kOpen, false, false, target, &stat ); return stat == MS::kSuccess; }
MStatus helix::doIt( const MArgList& args ) { MStatus stat; const unsigned deg = 3; // Curve Degree const unsigned ncvs = 20; // Number of CVs const unsigned spans = ncvs - deg; // Number of spans const unsigned nknots = spans+2*deg-1;// Number of knots double radius = 4.0; // Helix radius double pitch = 0.5; // Helix pitch unsigned i; // Parse the arguments. for ( i = 0; i < args.length(); i++ ) if ( MString( "-p" ) == args.asString( i, &stat ) && MS::kSuccess == stat) { double tmp = args.asDouble( ++i, &stat ); if ( MS::kSuccess == stat ) pitch = tmp; } else if ( MString( "-r" ) == args.asString( i, &stat ) && MS::kSuccess == stat) { double tmp = args.asDouble( ++i, &stat ); if ( MS::kSuccess == stat ) radius = tmp; } MPointArray controlVertices; MDoubleArray knotSequences; // Set up cvs and knots for the helix // for (i = 0; i < ncvs; i++) controlVertices.append( MPoint( radius * cos( (double)i ), pitch * (double)i, radius * sin( (double)i ) ) ); for (i = 0; i < nknots; i++) knotSequences.append( (double)i ); // Now create the curve // MFnNurbsCurve curveFn; curveFn.create( controlVertices, knotSequences, deg, MFnNurbsCurve::kOpen, false, false, MObject::kNullObj, &stat ); if ( MS::kSuccess != stat ) cout<<"Error creating curve."<<endl; return stat; }
// COMPUTE ====================================== MStatus gear_uToPercentage::compute(const MPlug& plug, MDataBlock& data) { MStatus returnStatus; // Error check if (plug != percentage) return MS::kUnknownParameter; // Curve MFnNurbsCurve crv = data.inputValue( curve ).asNurbsCurve(); // Sliders bool in_normU = data.inputValue( normalizedU ).asBool(); double in_u = (double)data.inputValue( u ).asFloat(); unsigned in_steps = data.inputValue( steps ).asShort(); // Process if (in_normU) in_u = normalizedUToU(in_u, crv.numCVs()); // Get length MVectorArray u_subpos(in_steps); MVectorArray t_subpos(in_steps); MPoint pt; double step; for (unsigned i = 0; i < in_steps ; i++){ step = i * in_u / (in_steps - 1.0); crv.getPointAtParam(step, pt, MSpace::kWorld); u_subpos[i] = MVector(pt); step = i/(in_steps - 1.0); crv.getPointAtParam(step, pt, MSpace::kWorld); t_subpos[i] = MVector(pt); } double u_length = 0; double t_length = 0; MVector v; for (unsigned i = 0; i < in_steps ; i++){ if (i>0){ v = u_subpos[i] - u_subpos[i-1]; u_length += v.length(); v = t_subpos[i] - t_subpos[i-1]; t_length += v.length(); } } double out_perc = (u_length / t_length) * 100; // Output MDataHandle h = data.outputValue( percentage ); h.setDouble( out_perc ); data.setClean( plug ); return MS::kSuccess; }
MStatus MG_curve::compute(const MPlug& plug,MDataBlock& dataBlock) { if (plug==output) { //MStatus MStatus stat; //Point array for the curve MPointArray pointArray ; //Get data from inputs MDataHandle degreeH = dataBlock.inputValue(degree); int degreeValue = degreeH.asInt(); MDataHandle tmH = dataBlock.inputValue(transformMatrix); MMatrix tm = tmH.asMatrix(); MArrayDataHandle inputMatrixH = dataBlock.inputArrayValue(inputMatrix); inputMatrixH.jumpToArrayElement(0); //Loop to get matrix data and convert in points for (int unsigned i=0;i<inputMatrixH.elementCount();i++,inputMatrixH.next()) { MMatrix currentMatrix = inputMatrixH.inputValue(&stat).asMatrix() ; //Compensate the locator matrix MMatrix fixedMatrix = currentMatrix*tm.inverse(); MPoint matrixP (fixedMatrix[3][0],fixedMatrix[3][1],fixedMatrix[3][2]); pointArray.append(matrixP); } MFnNurbsCurve curveFn; MFnNurbsCurveData curveDataFn; MObject curveData= curveDataFn.create(); curveFn.createWithEditPoints(pointArray,degreeValue,MFnNurbsCurve::kOpen,0,0,0,curveData,&stat); MDataHandle outputH = dataBlock.outputValue(output); outputH.set(curveData); outputH.setClean(); } return MS::kSuccess; }
MStatus InstanceCallbackCmd::doIt( const MArgList& args ) { MStatus status = MS::kSuccess; // Draw a circle and get its dagPath // using an iterator MGlobal::executeCommand("circle"); MFnNurbsCurve circle; MDagPath dagPath; MItDependencyNodes iter( MFn::kNurbsCurve , &status); for(iter.reset(); !iter.isDone() ; iter.next()) { MObject item = iter.item(); if(item.hasFn(MFn::kNurbsCurve)) { circle.setObject(item); circle.getPath(dagPath); MGlobal::displayInfo("DAG_PATH is " + dagPath.fullPathName()); if(dagPath.isValid()) { // register callback for instance add AND remove // MDagMessage::addInstanceAddedCallback ( dagPath,addCallbackFunc, NULL, &status); MDagMessage::addInstanceRemovedCallback ( dagPath,remCallbackFunc, NULL, &status); MGlobal::displayInfo("CALLBACK ADDED FOR INSTANCE ADD/REMOVE"); } } } if (status != MS::kSuccess) { MGlobal::displayInfo("STATUS RETURNED IS NOT SUCCESS"); } return status; }
void HelixButton::createHelix() { MStatus st; const unsigned deg = 3; // Curve Degree const unsigned ncvs = 20; // Number of CVs const unsigned spans = ncvs - deg; // Number of spans const unsigned nknots = spans + 2 * deg - 1; // Number of knots double radius = 4.0; // Helix radius double pitch = 0.5; // Helix pitch unsigned i; MPointArray controlVertices; MDoubleArray knotSequences; // Set up cvs and knots for the helix for (i = 0; i < ncvs; i++) { controlVertices.append( MPoint( radius * cos((double)i), pitch * (double)i, radius * sin((double)i) ) ); } for (i = 0; i < nknots; i++) knotSequences.append((double)i); // Now create the curve MFnNurbsCurve curveFn; MObject curve = curveFn.create( controlVertices, knotSequences, deg, MFnNurbsCurve::kOpen, false, false, MObject::kNullObj, &st ); MGlobal::displayInfo("Helix curve created!"); if (!st) { MGlobal::displayError( HelixQtCmd::commandName + " - could not create helix: " + st.errorString() ); } }
MStatus Posts1Cmd::doIt ( const MArgList & ) { const int nPosts = 5; const double radius = 0.5; const double height = 5.0; // Get a list of currently selected objects MSelectionList selection; MGlobal::getActiveSelectionList( selection ); MDagPath dagPath; MFnNurbsCurve curveFn; double heightRatio = height / radius; // Iterate over the nurbs curves MItSelectionList iter( selection, MFn::kNurbsCurve ); for ( ; !iter.isDone(); iter.next() ) { // Get the curve and attach it to the function set iter.getDagPath( dagPath ); curveFn.setObject( dagPath ); // Get the domain of the curve, i.e. its start and end parametric values double tStart, tEnd; curveFn.getKnotDomain( tStart, tEnd ); MPoint pt; int i; double t; double tIncr = (tEnd - tStart) / (nPosts - 1); for( i=0, t=tStart; i < nPosts; i++, t += tIncr ) { // Get point along curve at parametric position t curveFn.getPointAtParam( t, pt, MSpace::kWorld ); pt.y += 0.5 * height; MGlobal::executeCommand( MString( "cylinder -pivot ") + pt.x + " " + pt.y + " " + pt.z + " -radius " + radius + " -axis 0 1 0 -heightRatio " + heightRatio ); } } return MS::kSuccess; }
MStatus CreateCurves::Curve::create(CreateCurves & instance) { MStatus status; MFnNurbsCurve curve; MObject curveObject = curve.create(points, knots, instance.m_degree, isLoop ? MFnNurbsCurve::kClosed : MFnNurbsCurve::kOpen, false, false, MObject::kNullObj, &status); if (!status) { status.perror("MFnNurbsCurve::create"); return status; } MDagPath path; if (!(status = curve.getPath(path))) { status.perror("MFnNurbsCurve::getPath"); return status; } instance.m_curves.append(path.transform()); return MStatus::kSuccess; }
bool refinementRequired(const MFnNurbsCurve & theCurve, const Knot & k1, const Knot & k2, Knot & theNewKnot, double theTolerance) { theNewKnot.param = (k1.param + k2.param) / 2.0; MPoint myInterpolatedPoint = (k1.point + k2.point) / 2.0; theCurve.getPointAtParam(theNewKnot.param, theNewKnot.point); double myError = (myInterpolatedPoint - theNewKnot.point).length(); return (myError > theTolerance); }
void MayaNurbsCurveWriter::write() { Alembic::AbcGeom::OCurvesSchema::Sample samp; samp.setBasis(Alembic::AbcGeom::kBsplineBasis); MStatus stat; mCVCount = 0; // if inheritTransform is on and the curve group is animated, // bake the cv positions in the world space MMatrix exclusiveMatrixInv = mRootDagPath.exclusiveMatrixInverse(&stat); std::size_t numCurves = 1; if (mIsCurveGrp) numCurves = mNurbsCurves.length(); std::vector<Alembic::Util::int32_t> nVertices(numCurves); std::vector<float> points; std::vector<float> width; std::vector<float> knots; std::vector<Alembic::Util::uint8_t> orders(numCurves); MMatrix transformMatrix; bool useConstWidth = false; MFnDependencyNode dep(mRootDagPath.transform()); MPlug constWidthPlug = dep.findPlug("width"); if (!constWidthPlug.isNull()) { useConstWidth = true; width.push_back(constWidthPlug.asFloat()); } for (unsigned int i = 0; i < numCurves; i++) { MFnNurbsCurve curve; if (mIsCurveGrp) { curve.setObject(mNurbsCurves[i]); MMatrix inclusiveMatrix = mNurbsCurves[i].inclusiveMatrix(&stat); transformMatrix = inclusiveMatrix*exclusiveMatrixInv; } else { curve.setObject(mRootDagPath.node()); } if (i == 0) { if (curve.form() == MFnNurbsCurve::kOpen) { samp.setWrap(Alembic::AbcGeom::kNonPeriodic); } else { samp.setWrap(Alembic::AbcGeom::kPeriodic); } if (curve.degree() == 3) { samp.setType(Alembic::AbcGeom::kCubic); } else if (curve.degree() == 1) { samp.setType(Alembic::AbcGeom::kLinear); } else { samp.setType(Alembic::AbcGeom::kVariableOrder); } } else { if (curve.form() == MFnNurbsCurve::kOpen) { samp.setWrap(Alembic::AbcGeom::kNonPeriodic); } if ((samp.getType() == Alembic::AbcGeom::kCubic && curve.degree() != 3) || (samp.getType() == Alembic::AbcGeom::kLinear && curve.degree() != 1)) { samp.setType(Alembic::AbcGeom::kVariableOrder); } } orders[i] = static_cast<Alembic::Util::uint8_t>(curve.degree() + 1); Alembic::Util::int32_t numCVs = curve.numCVs(&stat); MPointArray cvArray; stat = curve.getCVs(cvArray, MSpace::kObject); mCVCount += numCVs; nVertices[i] = numCVs; for (Alembic::Util::int32_t j = 0; j < numCVs; j++) { MPoint transformdPt; if (mIsCurveGrp) { transformdPt = cvArray[j]*transformMatrix; } else { transformdPt = cvArray[j]; } points.push_back(static_cast<float>(transformdPt.x)); points.push_back(static_cast<float>(transformdPt.y)); points.push_back(static_cast<float>(transformdPt.z)); } MDoubleArray knotsArray; curve.getKnots(knotsArray); knots.reserve(knotsArray.length() + 2); // need to add a knot to the start and end (M + 2N + 1) if (knotsArray.length() > 1) { unsigned int knotsLength = knotsArray.length(); if (knotsArray[0] == knotsArray[knotsLength - 1] || knotsArray[0] == knotsArray[1]) { knots.push_back(knotsArray[0]); } else { knots.push_back(2 * knotsArray[0] - knotsArray[1]); } for (unsigned int j = 0; j < knotsLength; ++j) { knots.push_back(knotsArray[j]); } if (knotsArray[0] == knotsArray[knotsLength - 1] || knotsArray[knotsLength - 1] == knotsArray[knotsLength - 2]) { knots.push_back(knotsArray[knotsLength - 1]); } else { knots.push_back(2 * knotsArray[knotsLength - 1] - knotsArray[knotsLength - 2]); } } // width MPlug widthPlug = curve.findPlug("width"); if (!useConstWidth && !widthPlug.isNull()) { MObject widthObj; MStatus status = widthPlug.getValue(widthObj); MFnDoubleArrayData fnDoubleArrayData(widthObj, &status); MDoubleArray doubleArrayData = fnDoubleArrayData.array(); Alembic::Util::int32_t arraySum = doubleArrayData.length(); if (arraySum == numCVs) { for (Alembic::Util::int32_t i = 0; i < arraySum; i++) { width.push_back(static_cast<float>(doubleArrayData[i])); } } else if (status == MS::kSuccess) { MString msg = "Curve "; msg += curve.partialPathName(); msg += " has incorrect size for the width vector."; msg += "\nUsing default constant width of 0.1."; MGlobal::displayWarning(msg); width.clear(); width.push_back(0.1f); useConstWidth = true; } else { width.push_back(widthPlug.asFloat()); useConstWidth = true; } } else if (!useConstWidth) { // pick a default value width.clear(); width.push_back(0.1f); useConstWidth = true; } } Alembic::AbcGeom::GeometryScope scope = Alembic::AbcGeom::kVertexScope; if (useConstWidth) scope = Alembic::AbcGeom::kConstantScope; samp.setCurvesNumVertices(Alembic::Abc::Int32ArraySample(nVertices)); samp.setPositions(Alembic::Abc::V3fArraySample( (const Imath::V3f *)&points.front(), points.size() / 3 )); samp.setWidths(Alembic::AbcGeom::OFloatGeomParam::Sample( Alembic::Abc::FloatArraySample(width), scope) ); if (samp.getType() == Alembic::AbcGeom::kVariableOrder) { samp.setOrders(Alembic::Abc::UcharArraySample(orders)); } if (!knots.empty()) { samp.setKnots(Alembic::Abc::FloatArraySample(knots)); } mSchema.set(samp); }
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; }
MStatus multiCurve::compute( const MPlug& plug, MDataBlock& data ) { MStatus stat; if ( plug == outputCurves ) { MDataHandle numCurvesHandle = data.inputValue(numCurves, &stat); PERRORfail(stat, "multiCurve::compute getting numCurves"); int num = numCurvesHandle.asLong(); MDataHandle curveOffsetHandle = data.inputValue(curveOffset, &stat); PERRORfail(stat, "multiCurve::compute getting curveOffset"); double baseOffset = curveOffsetHandle.asDouble(); MDataHandle inputCurveHandle = data.inputValue(inputCurve, &stat); PERRORfail(stat, "multiCurve::compute getting inputCurve"); MObject inputCurveObject ( inputCurveHandle.asNurbsCurveTransformed() ); MFnNurbsCurve inCurveFS ( inputCurveObject ); MArrayDataHandle outputArray = data.outputArrayValue(outputCurves, &stat); PERRORfail(stat, "multiCurve::compute getting output data handle"); // Create an array data build that is preallocated to hold just // the number of curves we plan on creating. When this builder // is set in to the MArrayDataHandle at the end of the compute // method, the new array will replace the existing array in the // scene. // // If the number of elements of the multi does not change between // compute cycles, then one can reuse the space allocated on a // previous cycle by extracting the existing builder from the // MArrayDataHandle: // MArrayDataBuilder builder( outputArray.builder(&stat) ); // this later form of the builder will allow you to rewrite elements // of the array, and to grow it, but the array can only be shrunk by // explicitly removing elements with the method // MArrayDataBuilder::removeElement(unsigned index); // MArrayDataBuilder builder(outputCurves, num, &stat); PERRORfail(stat, "multiCurve::compute creating builder"); for (int curveNum = 0; curveNum < num; curveNum++) { MDataHandle outHandle = builder.addElement(curveNum); MFnNurbsCurveData dataCreator; MObject outCurveData = dataCreator.create(); MObject outputCurve = inCurveFS.copy(inputCurveObject, outCurveData, &stat); PERRORfail(stat, "multiCurve::compute copying curve"); MFnNurbsCurve outCurveFS ( outputCurve ); MPointArray cvs; double offset = baseOffset * (curveNum+1); outCurveFS.getCVs ( cvs, MSpace::kWorld ); int numCVs = cvs.length(); for (int i = 0; i < numCVs; i++) { cvs[i].x += offset; } outCurveFS.setCVs ( cvs ); outHandle.set(outCurveData); } // Set the builder back into the output array. This statement // is always required, no matter what constructor was used to // create the builder. stat = outputArray.set(builder); PERRORfail(stat, "multiCurve::compute setting the builder"); // Since we compute all the elements of the array, instead of // just marking the plug we were asked to compute as clean, mark // every element of the array as clean to prevent further calls // to this compute method during this DG evaluation cycle. stat = outputArray.setAllClean(); PERRORfail(stat, "multiCurve::compute cleaning outputCurves"); } else { return MS::kUnknownParameter; } return stat; }
void n_tentacle::computeSlerp(const MMatrix &matrix1, const MMatrix &matrix2, const MFnNurbsCurve &curve, double parameter, double blendRot, double iniLength, double curveLength, double stretch, double globalScale, int tangentAxis, MVector &outPos, MVector &outRot) { //curveLength = curve.length() double lenRatio = iniLength / curveLength; MQuaternion quat1; quat1 = matrix1; MQuaternion quat2; quat2 = matrix2; this->bipolarityCheck(quat1, quat2); //need to adjust the parameter in order to maintain the length between elements, also for the stretch MVector tangent; MPoint pointAtParam; MPoint finaPos; double p = lenRatio * parameter * globalScale; double finalParam = p + (parameter - p) * stretch; if(curveLength * finalParam > curveLength) { double lengthDiff = curveLength - (iniLength * parameter); double param = curve.knot(curve.numKnots() - 1); tangent = curve.tangent(param, MSpace::kWorld); tangent.normalize(); curve.getPointAtParam(param, pointAtParam, MSpace::kWorld); finaPos = pointAtParam; pointAtParam += (- tangent) * lengthDiff; //MGlobal::displayInfo("sdf"); } else { double param = curve.findParamFromLength(curveLength * finalParam); tangent = curve.tangent(param, MSpace::kWorld); tangent.normalize(); curve.getPointAtParam(param, pointAtParam, MSpace::kWorld); } MQuaternion slerpQuat = slerp(quat1, quat2, blendRot); MMatrix slerpMatrix = slerpQuat.asMatrix(); int axisId = abs(tangentAxis) - 1; MVector slerpMatrixYAxis = MVector(slerpMatrix(axisId, 0), slerpMatrix(axisId, 1), slerpMatrix(axisId, 2)); slerpMatrixYAxis.normalize(); if(tangentAxis < 0) slerpMatrixYAxis = - slerpMatrixYAxis; double angle = tangent.angle(slerpMatrixYAxis); MVector axis = slerpMatrixYAxis ^ tangent; axis.normalize(); MQuaternion rotationToSnapOnCurve(angle, axis); MQuaternion finalQuat = slerpQuat * rotationToSnapOnCurve; MEulerRotation finalEuler = finalQuat.asEulerRotation(); outRot.x = finalEuler.x; outRot.y = finalEuler.y; outRot.z = finalEuler.z; outPos = pointAtParam; }
bool ToMayaCurveConverter::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const { MStatus s; IECore::ConstCurvesPrimitivePtr curves = IECore::runTimeCast<const IECore::CurvesPrimitive>( from ); assert( curves ); if ( !curves->arePrimitiveVariablesValid() || !curves->numCurves() ) { return false; } int curveIndex = indexParameter()->getNumericValue(); if( curveIndex < 0 || curveIndex >= (int)curves->numCurves() ) { IECore::msg( IECore::Msg::Warning,"ToMayaCurveConverter::doConversion", boost::format( "Invalid curve index \"%d\"") % curveIndex ); return false; } IECore::ConstV3fVectorDataPtr p = curves->variableData< IECore::V3fVectorData >( "P", IECore::PrimitiveVariable::Vertex ); if( !p ) { IECore::msg( IECore::Msg::Warning,"ToMayaCurveConverter::doConversion", "Curve has no \"P\" data" ); return false; } const std::vector<int>& verticesPerCurve = curves->verticesPerCurve()->readable(); int curveBase = 0; for( int i=0; i<curveIndex; ++i ) { curveBase += verticesPerCurve[i]; } MPointArray vertexArray; int numVertices = verticesPerCurve[curveIndex]; int cvOffset = 0; if( curves->basis() != IECore::CubicBasisf::linear() && !curves->periodic() ) { // Maya implicitly duplicates end points, so they're explicitly duplicated in the CurvePrimitives. // We need to remove those duplicates when converting back to Maya. Remove 2 cvs at start, 2 at end. if( numVertices < 8 ) { IECore::msg( IECore::Msg::Warning,"ToMayaCurveConverter::doConversion", "The Curve Primitive does not have enough CVs to be converted into a Maya Curve. Needs at least 8." ); return false; } cvOffset = 2; } const std::vector<Imath::V3f>& pts = p->readable(); // triple up the start points for cubic periodic curves: if( curves->periodic() && curves->basis() != IECore::CubicBasisf::linear() ) { vertexArray.append( IECore::convert<MPoint, Imath::V3f>( pts[curveBase] ) ); vertexArray.append( vertexArray[0] ); } for( int i = cvOffset; i < numVertices-cvOffset; ++i ) { vertexArray.append( IECore::convert<MPoint, Imath::V3f>( pts[i + curveBase] ) ); } // if the curve is periodic, the first N cvs must be identical to the last N cvs, where N is the degree // of the curve: if( curves->periodic() ) { if( curves->basis() == IECore::CubicBasisf::linear() ) { // linear: N = 1 vertexArray.append( vertexArray[0] ); } else { // cubic: N = 3 vertexArray.append( vertexArray[0] ); vertexArray.append( vertexArray[1] ); vertexArray.append( vertexArray[2] ); } } unsigned vertexArrayLength = vertexArray.length(); MDoubleArray knotSequences; if( curves->basis() == IECore::CubicBasisf::linear() ) { for( unsigned i=0; i < vertexArrayLength; ++i ) { knotSequences.append( i ); } } else { if( curves->periodic() ) { // Periodic curve, knots must be spaced out. knotSequences.append( -1 ); for( unsigned i=0; i < vertexArrayLength+1; ++i ) { knotSequences.append( i ); } } else { // For a cubic curve, the first three and last three knots must be duplicated for the curve start/end to start at the first/last CV. knotSequences.append( 0 ); knotSequences.append( 0 ); for( unsigned i=0; i < vertexArrayLength-2; ++i ) { knotSequences.append( i ); } knotSequences.append( vertexArrayLength-3 ); knotSequences.append( vertexArrayLength-3 ); } } MFnNurbsCurve fnCurve; fnCurve.create( vertexArray, knotSequences, curves->basis() == IECore::CubicBasisf::linear() ? 1 : 3, curves->periodic() ? MFnNurbsCurve::kPeriodic : MFnNurbsCurve::kOpen, false, false, to, &s ); if (!s) { IECore::msg( IECore::Msg::Warning,"ToMayaCurveConverter::doConversion", s.errorString().asChar() ); return false; } return true; }
IECore::PrimitivePtr FromMayaCurveConverter::doPrimitiveConversion( MFnNurbsCurve &fnCurve ) const { // decide on the basis and periodicity int mDegree = fnCurve.degree(); IECore::CubicBasisf basis = IECore::CubicBasisf::linear(); if( m_linearParameter->getTypedValue()==false && mDegree==3 ) { basis = IECore::CubicBasisf::bSpline(); } bool periodic = false; if( fnCurve.form()==MFnNurbsCurve::kPeriodic ) { periodic = true; } // get the points and convert them MPointArray mPoints; fnCurve.getCVs( mPoints, space() ); if( periodic ) { // maya duplicates the first points at the end, whereas we just wrap around. // remove the duplicates. mPoints.setLength( mPoints.length() - mDegree ); } bool duplicateEnds = false; if( !periodic && mDegree==3 ) { // there's an implicit duplication of the end points that we need to make explicit duplicateEnds = true; } IECore::V3fVectorDataPtr pointsData = new IECore::V3fVectorData; std::vector<Imath::V3f> &points = pointsData->writable(); std::vector<Imath::V3f>::iterator transformDst; if( duplicateEnds ) { points.resize( mPoints.length() + 4 ); transformDst = points.begin(); *transformDst++ = IECore::convert<Imath::V3f>( mPoints[0] ); *transformDst++ = IECore::convert<Imath::V3f>( mPoints[0] ); } else { points.resize( mPoints.length() ); transformDst = points.begin(); } std::transform( MArrayIter<MPointArray>::begin( mPoints ), MArrayIter<MPointArray>::end( mPoints ), transformDst, IECore::VecConvert<MPoint, V3f>() ); if( duplicateEnds ) { points[points.size()-1] = IECore::convert<Imath::V3f>( mPoints[mPoints.length()-1] ); points[points.size()-2] = IECore::convert<Imath::V3f>( mPoints[mPoints.length()-1] ); } // make and return the curve IECore::IntVectorDataPtr vertsPerCurve = new IECore::IntVectorData; vertsPerCurve->writable().push_back( points.size() ); return new IECore::CurvesPrimitive( vertsPerCurve, basis, periodic, pointsData ); }
MStatus sgHair_controlJoint::compute( const MPlug& plug, MDataBlock& data ) { MStatus status; MDataHandle hStaticRotation = data.inputValue( aStaticRotation ); m_bStaticRotation = hStaticRotation.asBool(); if( m_isDirtyMatrix ) { MDataHandle hInputBaseCurveMatrix = data.inputValue( aInputBaseCurveMatrix ); m_mtxBaseCurve = hInputBaseCurveMatrix.asMatrix(); } if( m_isDirtyParentMatrixBase ) { MDataHandle hJointParenBasetMatrix = data.inputValue( aJointParentBaseMatrix ); m_mtxJointParentBase = hJointParenBasetMatrix.asMatrix(); } if( m_isDirtyCurve || m_isDirtyParentMatrixBase ) { MDataHandle hInputBaseCurve = data.inputValue( aInputBaseCurve ); MFnNurbsCurve fnCurve = hInputBaseCurve.asNurbsCurve(); fnCurve.getCVs( m_cvs ); getJointPositionBaseWorld(); } if( m_isDirtyGravityOption || m_isDirtyCurve || m_isDirtyParentMatrixBase ) { MDataHandle hGravityParam = data.inputValue( aGravityParam ); MDataHandle hGravityRange = data.inputValue( aGravityRange ); MDataHandle hGravityWeight = data.inputValue( aGravityWeight ); MDataHandle hGravityOffsetMatrix = data.inputValue( aGravityOffsetMatrix ); m_paramGravity = hGravityParam.asDouble(); m_rangeGravity = hGravityRange.asDouble(); m_weightGravity = hGravityWeight.asDouble(); m_mtxGravityOffset = hGravityOffsetMatrix.asMatrix(); m_mtxGravityOffset( 3,0 ) = 0.0; m_mtxGravityOffset( 3,1 ) = 0.0; m_mtxGravityOffset( 3,2 ) = 0.0; setGravityJointPositionWorld(); } setOutput(); MArrayDataHandle hArrOutput = data.outputValue( aOutput ); MArrayDataBuilder builderOutput( aOutput, m_cvs.length() ); for( int i=0; i< m_cvs.length(); i++ ) { MDataHandle hOutput = builderOutput.addElement( i ); MDataHandle hOutTrans = hOutput.child( aOutTrans ); MDataHandle hOutOrient = hOutput.child( aOutOrient ); hOutTrans.set( m_vectorArrTransJoint[i] ); hOutOrient.set( m_vectorArrRotateJoint[i] ); } hArrOutput.set( builderOutput ); hArrOutput.setAllClean(); data.setClean( plug ); m_isDirtyMatrix = false; m_isDirtyCurve = false; m_isDirtyGravityOption = false; m_isDirtyParentMatrixBase = false; return MS::kSuccess; }
MStatus clusterControledCurve::compute( const MPlug& plug, MDataBlock& data ) { //MFnDependencyNode thisNode( thisMObject() ); //cout << thisNode.name() << ", start" << endl; MStatus status; MDataHandle hInputCurve = data.inputValue( aInputCurve, &status ); CHECK_MSTATUS_AND_RETURN_IT( status ); MDataHandle hInputCurveMatrix = data.inputValue( aInputCurveMatrix, &status ); CHECK_MSTATUS_AND_RETURN_IT( status ); MDataHandle hOutputCurve = data.outputValue( aOutputCurve, &status ); CHECK_MSTATUS_AND_RETURN_IT( status ); MArrayDataHandle hArrBindPreMatrix = data.inputArrayValue( aBindPreMatrix, &status ); CHECK_MSTATUS_AND_RETURN_IT( status ); MArrayDataHandle hArrMatrix = data.inputArrayValue( aMatrix, &status ); CHECK_MSTATUS_AND_RETURN_IT( status ); MArrayDataHandle hArrWeightList = data.inputArrayValue( aWeightList, &status ); CHECK_MSTATUS_AND_RETURN_IT( status ); MDataHandle hUpdate = data.inputValue( aUpdate, &status ); CHECK_MSTATUS_AND_RETURN_IT( status ); MObject oInputCurve = hInputCurve.asNurbsCurve(); int bindPreMatrixLength = hArrBindPreMatrix.elementCount(); int matrixLength = hArrMatrix.elementCount(); MFnNurbsCurve fnInputCurve = oInputCurve; int numCVs = fnInputCurve.numCVs(); int weightListLength = hArrWeightList.elementCount(); if( weightListLength > 100 ) { cout << "WeightList Count Error : " << weightListLength << endl; return MS::kFailure; } MPointArray inputCvPoints; MPointArray outputCvPoints; fnInputCurve.getCVs( inputCvPoints ); outputCvPoints.setLength( numCVs ); MMatrix matrix; MMatrix inputCurveMatrix = hInputCurveMatrix.asMatrix(); MMatrix inputCurveMatrixInverse = inputCurveMatrix.inverse(); if( requireUpdate ) CHECK_MSTATUS_AND_RETURN_IT( updateBindPreMatrix( oInputCurve, inputCurveMatrixInverse, hArrMatrix, hArrBindPreMatrix, hUpdate.asBool() ) ); for( int i=0; i< numCVs; i++ ) { inputCvPoints[i] *= inputCurveMatrix; } for( int i=0; i< numCVs; i++ ) { outputCvPoints[i] = MPoint( 0,0,0 ); double weight; for( int j=0; j< matrixLength; j++ ) { weight = setWeights[i][j]; hArrMatrix.jumpToElement( j ); matrix = hArrMatrix.inputValue().asMatrix(); outputCvPoints[i] += inputCvPoints[i]*bindPreMatrix[j]*matrix*weight; } } for( int i=0; i< numCVs; i++ ) { outputCvPoints[i] *= inputCurveMatrixInverse; } MFnNurbsCurveData outputCurveData; MObject oOutputCurve = outputCurveData.create(); fnInputCurve.copy( oInputCurve, oOutputCurve ); MFnNurbsCurve fnOutputCurve( oOutputCurve, &status ); CHECK_MSTATUS_AND_RETURN_IT( status ); fnOutputCurve.setCVs( outputCvPoints ); hOutputCurve.set( oOutputCurve ); data.setClean( plug ); //cout << thisNode.name() << ", end" << endl; return status; }
MStatus particlePathsCmd::doIt( const MArgList& args ) { MStatus stat = parseArgs( args ); if( stat != MS::kSuccess ) { return stat; } MFnParticleSystem cloud( particleNode ); if( ! cloud.isValid() ) { MGlobal::displayError( "The function set is invalid!" ); return MS::kFailure; } // // Create curves from the particle system in two stages. First, sample // all particle positions from the start time to the end time. Then, // use the data that was collected to create curves. // // Create the particle hash table at a fixed size. This should work fine // for small particle systems, but may become inefficient for larger ones. // If the plugin is running very slow, increase the size. The value should // be roughly the number of particles that are expected to be emitted // within the time period. // ParticleIdHash hash(1024); MIntArray idList; // // Stage 1 // MVectorArray positions; MIntArray ids; int i = 0; for (double time = start; time <= finish + TOLERANCE; time += increment) { MTime timeSeconds(time,MTime::kSeconds); // It is necessary to query the worldPosition attribute to force the // particle positions to update. // cloud.evaluateDynamics(timeSeconds,false); // MGlobal::executeCommand(MString("getAttr ") + cloud.name() + // MString(".worldPosition")); if (!cloud.isValid()) { MGlobal::displayError( "Particle system has become invalid." ); return MS::kFailure; } MGlobal::displayInfo( MString("Received ") + (int)(cloud.count()) + " particles, at time " + time); // Request position and ID data for particles // cloud.position( positions ); cloud.particleIds( ids ); if (ids.length() != cloud.count() || positions.length() != cloud.count()) { MGlobal::displayError( "Invalid array sizes." ); return MS::kFailure; } for (int j = 0; j < (int)cloud.count(); j++) { // Uncomment to show particle positions as the plugin accumulates // samples. /* MGlobal::displayInfo(MString("(") + (positions[j])[0] + MString(",") + (positions[j])[1] + MString(",") + (positions[j])[2] + MString(")")); */ MPoint pt(positions[j]); if (hash.getPoints(ids[j]).length() == 0) { idList.append(ids[j]); } hash.insert(ids[j],pt); } i++; } // // Stage 2 // for (i = 0; i < (int)(idList.length()); i++) { MPointArray points = hash.getPoints(idList[i]); // Don't bother with single samples if (points.length() <= 1) { continue; } // Add two additional points, so that the curve covers all sampled // values. // MPoint p1 = points[0]*2 - points[1]; MPoint p2 = points[points.length()-1]*2 - points[points.length()-2]; points.insert(p1,0); points.append(p2); // Uncomment to show information about the generated curves /* MGlobal::displayInfo( MString("ID ") + (int)(idList[i]) + " has " + (int)(points.length()) + " curve points."); for (int j = 0; j < (int)(points.length()); j++) { MGlobal::displayInfo(MString("(") + points[j][0] + MString(",") + points[j][1] + MString(",") + points[j][2] + MString(")")); } */ MDoubleArray knots; knots.insert(0.0,0); for (int j = 0; j < (int)(points.length()); j++) { knots.append((double)j); } knots.append(points.length()-1); MStatus status; MObject dummy; MFnNurbsCurve curve; curve.create(points,knots,3,MFnNurbsCurve::kOpen,false,false,dummy,&status); if (!status) { MGlobal::displayError("Failed to create nurbs curve."); return MS::kFailure; } } return MS::kSuccess; }
MStatus splineSolverNode::preSolve() { MStatus stat; setRotatePlane(false); setSingleChainOnly(true); setPositionOnly(false); //Get Handle MIkHandleGroup * handle_group = handleGroup(); if (NULL == handle_group) { return MS::kFailure; } MObject handle = handle_group->handle( 0 ); MDagPath handlePath = MDagPath::getAPathTo( handle ); fnHandle.setObject( handlePath ); //Get Curve MPlug inCurvePlug = fnHandle.findPlug( "inCurve" ); MDataHandle curveHandle = inCurvePlug.asMDataHandle(); MObject inputCurveObject = curveHandle.asNurbsCurveTransformed(); curveFn.setObject( inputCurveObject ); float initCurveLength = curveFn.length(); MVector initNormal = curveFn.normal(0); MVector initTangent = curveFn.tangent(0); float stretchRatio = 1; // Get the position of the end_effector // MDagPath effectorPath; fnHandle.getEffector(effectorPath); tran.setObject( effectorPath ); // Get the start joint position // MDagPath startJointPath; fnHandle.getStartJoint( startJointPath ); joints.clear(); //Get Joints while (true) { effectorPath.pop(); joints.push_back( effectorPath ); if (effectorPath == startJointPath) break; } std::reverse(joints.begin(), joints.end()); if (!fnHandle.hasAttribute("str")) { //Add Custom Attributes to Handle MFnNumericAttribute fnAttr; MObject attr = fnAttr.create("stretchRatio", "str", MFnNumericData::kDouble, stretchRatio); fnAttr.setKeyable(1); fnAttr.setWritable(1); fnAttr.setMin(0); fnAttr.setMax(1); fnAttr.setHidden(0); fnAttr.setStorable(1); fnAttr.setReadable(1); fnHandle.addAttribute(attr, MFnDependencyNode::kLocalDynamicAttr); attr = fnAttr.create("anchorPosition", "ancp", MFnNumericData::kDouble, 0.0); fnAttr.setKeyable(1); fnAttr.setWritable(1); fnAttr.setMin(0); fnAttr.setMax(1); fnAttr.setHidden(0); fnAttr.setStorable(1); fnAttr.setReadable(1); fnHandle.addAttribute(attr, MFnDependencyNode::kLocalDynamicAttr); attr = fnAttr.create("curveLength", "cvLen", MFnNumericData::kDouble, initCurveLength); fnAttr.setKeyable(0); fnAttr.setWritable(1); fnAttr.setHidden(1); fnAttr.setStorable(1); fnAttr.setReadable(1); fnHandle.addAttribute(attr, MFnDependencyNode::kLocalDynamicAttr); attr = fnAttr.create("initNormal", "norm", MFnNumericData::k3Double); fnAttr.setDefault(initNormal.x, initNormal.y, initNormal.z); fnAttr.setKeyable(0); fnAttr.setWritable(1); fnAttr.setHidden(1); fnAttr.setStorable(1); fnAttr.setReadable(1); fnHandle.addAttribute(attr, MFnDependencyNode::kLocalDynamicAttr); attr = fnAttr.create("initTangent", "tang", MFnNumericData::k3Double); fnAttr.setDefault(initTangent.x, initTangent.y, initTangent.z); fnAttr.setKeyable(0); fnAttr.setWritable(1); fnAttr.setHidden(1); fnAttr.setStorable(1); fnAttr.setReadable(1); fnHandle.addAttribute(attr, MFnDependencyNode::kLocalDynamicAttr); attr = fnAttr.create("jointsLength", "jsLen", MFnNumericData::kDouble, getJointsTotalLenght()); fnAttr.setKeyable(0); fnAttr.setWritable(1); fnAttr.setHidden(1); fnAttr.setStorable(1); fnAttr.setReadable(1); fnHandle.addAttribute(attr, MFnDependencyNode::kLocalDynamicAttr); attr = fnAttr.create("startTwist", "strtw", MFnNumericData::kDouble, 0.0); fnAttr.setKeyable(1); fnAttr.setWritable(1); fnAttr.setHidden(0); fnAttr.setStorable(1); fnAttr.setReadable(1); fnHandle.addAttribute(attr, MFnDependencyNode::kLocalDynamicAttr); attr = fnAttr.create("endTwist", "endtw", MFnNumericData::kDouble, 0.0); fnAttr.setKeyable(1); fnAttr.setWritable(1); fnAttr.setHidden(0); fnAttr.setStorable(1); fnAttr.setReadable(1); fnHandle.addAttribute(attr, MFnDependencyNode::kLocalDynamicAttr); MObject twistRamp = MRampAttribute::createCurveRamp("twistRamp", "twr"); fnHandle.addAttribute(twistRamp, MFnDependencyNode::kLocalDynamicAttr); MObject scaleRamp = MRampAttribute::createCurveRamp("scaleRamp", "scr"); fnHandle.addAttribute(scaleRamp, MFnDependencyNode::kLocalDynamicAttr); } else { MPlug strPlug = fnHandle.findPlug("str"); stretchRatio = strPlug.asDouble(); } return MS::kSuccess; }
/* static */ bool PxrUsdMayaTranslatorCurves::Create( const UsdGeomCurves& curves, MObject parentNode, const PxrUsdMayaPrimReaderArgs& args, PxrUsdMayaPrimReaderContext* context) { if (not curves) { return false; } const UsdPrim& prim = curves.GetPrim(); MStatus status; // Create node (transform) MObject mayaNodeTransformObj; if (not PxrUsdMayaTranslatorUtil::CreateTransformNode(prim, parentNode, args, context, &status, &mayaNodeTransformObj)) { return false; } VtArray<GfVec3f> points; VtArray<int> curveOrder; VtArray<int> curveVertexCounts; VtArray<float> curveWidths; VtArray<GfVec2d> curveRanges; VtArray<double> curveKnots; // LIMITATION: xxx REVISIT xxx // Non-animated Attrs // Assuming that a number of these USD attributes are assumed to not be animated // Some we may want to expose as animatable later. // curves.GetCurveVertexCountsAttr().Get(&curveVertexCounts); // not animatable // XXX: // Only supporting single curve for now. // Sanity Checks if (curveVertexCounts.size() == 0) { MGlobal::displayError( TfStringPrintf("VertexCount arrays is empty on NURBS curves <%s>. Skipping...", prim.GetPath().GetText()).c_str()); return false; // No verts for the curve, so exit } else if (curveVertexCounts.size() > 1) { MGlobal::displayWarning( TfStringPrintf("Multiple curves in <%s>. Reading first one...", prim.GetPath().GetText()).c_str()); } int curveIndex = 0; curves.GetWidthsAttr().Get(&curveWidths); // not animatable // Gather points. If args.GetReadAnimData() is TRUE, // pick the first avaiable sample or default UsdTimeCode pointsTimeSample=UsdTimeCode::EarliestTime(); std::vector<double> pointsTimeSamples; size_t numTimeSamples = 0; if (args.GetReadAnimData()) { curves.GetPointsAttr().GetTimeSamples(&pointsTimeSamples); numTimeSamples = pointsTimeSamples.size(); if (numTimeSamples>0) { pointsTimeSample = pointsTimeSamples[0]; } } curves.GetPointsAttr().Get(&points, pointsTimeSample); if (points.size() == 0) { MGlobal::displayError( TfStringPrintf("Points arrays is empty on NURBS curves <%s>. Skipping...", prim.GetPath().GetText()).c_str()); return false; // invalid nurbscurves, so exit } if (UsdGeomNurbsCurves nurbsSchema = UsdGeomNurbsCurves(prim)) { nurbsSchema.GetOrderAttr().Get(&curveOrder); // not animatable nurbsSchema.GetKnotsAttr().Get(&curveKnots); // not animatable nurbsSchema.GetRangesAttr().Get(&curveRanges); // not animatable } else { // Handle basis curves originally modelled in Maya as nurbs. curveOrder.resize(1); UsdGeomBasisCurves basisSchema = UsdGeomBasisCurves(prim); TfToken typeToken; basisSchema.GetTypeAttr().Get(&typeToken); if (typeToken == UsdGeomTokens->linear) { curveOrder[0] = 2; curveKnots.resize(points.size()); for (size_t i=0; i < curveKnots.size(); ++i) { curveKnots[i] = i; } } else { curveOrder[0] = 4; // Strip off extra end points; assuming this is non-periodic. VtArray<GfVec3f> tmpPts(points.size() - 2); std::copy(points.begin() + 1, points.end() - 1, tmpPts.begin()); points.swap(tmpPts); // Cubic curves in Maya have numSpans + 2*3 - 1, and for geometry // that came in as basis curves, we have numCV's - 3 spans. See the // MFnNurbsCurve documentation and the nurbs curve export // implementation in mojitoplugmaya for more details. curveKnots.resize(points.size() -3 + 5); int knotIdx = 0; for (size_t i=0; i < curveKnots.size(); ++i) { if (i < 3) { curveKnots[i] = 0.0; } else { if (i <= curveKnots.size() - 3) { ++knotIdx; } curveKnots[i] = double(knotIdx); } } } } // == Convert data size_t mayaNumVertices = points.size(); MPointArray mayaPoints(mayaNumVertices); for (size_t i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } double *knots=curveKnots.data(); MDoubleArray mayaKnots( knots, curveKnots.size()); int mayaDegree = curveOrder[curveIndex] - 1; MFnNurbsCurve::Form mayaCurveForm = MFnNurbsCurve::kOpen; // HARDCODED bool mayaCurveCreate2D = false; bool mayaCurveCreateRational = true; // == Create NurbsCurve Shape Node MFnNurbsCurve curveFn; MObject curveObj = curveFn.create(mayaPoints, mayaKnots, mayaDegree, mayaCurveForm, mayaCurveCreate2D, mayaCurveCreateRational, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { return false; } MString nodeName( prim.GetName().GetText() ); nodeName += "Shape"; curveFn.setName(nodeName, false, &status); std::string nodePath( prim.GetPath().GetText() ); nodePath += "/"; nodePath += nodeName.asChar(); if (context) { context->RegisterNewMayaNode( nodePath, curveObj ); // used for undo/redo } // == Animate points == // Use blendShapeDeformer so that all the points for a frame are contained in a single node // Almost identical code as used with MayaMeshReader.cpp // if (numTimeSamples > 0) { MPointArray mayaPoints(mayaNumVertices); MObject curveAnimObj; MFnBlendShapeDeformer blendFn; MObject blendObj = blendFn.create(curveObj); if (context) { context->RegisterNewMayaNode(blendFn.name().asChar(), blendObj ); // used for undo/redo } for (unsigned int ti=0; ti < numTimeSamples; ++ti) { curves.GetPointsAttr().Get(&points, pointsTimeSamples[ti]); for (unsigned int i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } // == Create NurbsCurve Shape Node MFnNurbsCurve curveFn; if ( curveAnimObj.isNull() ) { curveAnimObj = curveFn.create(mayaPoints, mayaKnots, mayaDegree, mayaCurveForm, mayaCurveCreate2D, mayaCurveCreateRational, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { continue; } } else { // Reuse the already created curve by copying it and then setting the points curveAnimObj = curveFn.copy(curveAnimObj, mayaNodeTransformObj, &status); curveFn.setCVs(mayaPoints); } blendFn.addTarget(curveObj, ti, curveAnimObj, 1.0); curveFn.setIntermediateObject(true); if (context) { context->RegisterNewMayaNode( curveFn.fullPathName().asChar(), curveAnimObj ); // used for undo/redo } } // Animate the weights so that curve0 has a weight of 1 at frame 0, etc. MFnAnimCurve animFn; // Construct the time array to be used for all the keys MTimeArray timeArray; timeArray.setLength(numTimeSamples); for (unsigned int ti=0; ti < numTimeSamples; ++ti) { timeArray.set( MTime(pointsTimeSamples[ti]), ti); } // Key/Animate the weights MPlug plgAry = blendFn.findPlug( "weight" ); if ( !plgAry.isNull() && plgAry.isArray() ) { for (unsigned int ti=0; ti < numTimeSamples; ++ti) { MPlug plg = plgAry.elementByLogicalIndex(ti, &status); MDoubleArray valueArray(numTimeSamples, 0.0); valueArray[ti] = 1.0; // Set the time value where this curve's weight should be 1.0 MObject animObj = animFn.create(plg, NULL, &status); animFn.addKeys(&timeArray, &valueArray); if (context) { context->RegisterNewMayaNode(animFn.name().asChar(), animObj ); // used for undo/redo } } } } return true; }
Knot(const MFnNurbsCurve & theCurve, double theParam) : param(theParam) { theCurve.getPointAtParam(theParam, point); }
MStatus splineSolverNode::doSimpleSolver() // // Solve single joint in the x-y plane // // - first it calculates the angle between the handle and the end-effector. // - then it determines which way to rotate the joint. // { //Do Real Solve // MStatus stat; float curCurveLength = curveFn.length(); MPlug crvLengPlug = fnHandle.findPlug("cvLen"); double initCurveLength = crvLengPlug.asDouble(); //Twist MPlug twistRamp = fnHandle.findPlug("twistRamp"); MRampAttribute curveAttribute( twistRamp, &stat ); MPlug startTwistPlug = fnHandle.findPlug("strtw"); double startTwist = startTwistPlug.asDouble(); MPlug endTwistPlug = fnHandle.findPlug("endtw"); double endTwist = endTwistPlug.asDouble(); //Scale Ramp MPlug scaleRamp = fnHandle.findPlug("scaleRamp"); MRampAttribute curveScaleAttribute( scaleRamp, &stat ); //Roll MPlug rollPlug = fnHandle.findPlug("roll"); double roll = rollPlug.asDouble(); MPlug strPlug = fnHandle.findPlug("str"); float stretchRatio = strPlug.asDouble(); float normCrvLength = curCurveLength / initCurveLength; double scale[3] = {1 +stretchRatio*(normCrvLength -1), 1, 1}; //Get Anchor Position MPlug ancPosPlug = fnHandle.findPlug("ancp"); double anchorPos = ancPosPlug.asDouble(); MPlug jointsTotLengthPlug = fnHandle.findPlug("jsLen"); double jointsTotalLength = jointsTotLengthPlug.asDouble(); double difLengthCurveJoints = curCurveLength - (jointsTotalLength * scale[0]); float startLength = 0.0 + anchorPos*( difLengthCurveJoints ); float parm = curveFn.findParamFromLength( startLength ); MPoint pBaseJoint, pEndJoint; curveFn.getPointAtParam( parm, pBaseJoint ); //get Init normal MPlug initNormalPlug = fnHandle.findPlug("norm"); double nx = initNormalPlug.child(0).asDouble(); double ny = initNormalPlug.child(1).asDouble(); double nz = initNormalPlug.child(2).asDouble(); MVector eyeUp( nx, ny, nz ); //get Init Tangent MPlug initTangentPlug = fnHandle.findPlug("tang"); double tx = initTangentPlug.child(0).asDouble(); double ty = initTangentPlug.child(1).asDouble(); double tz = initTangentPlug.child(2).asDouble(); MVector eyeV( tx, ty, tz ); MFnIkJoint j( joints[0] ); j.setTranslation( MVector( pBaseJoint ), MSpace::kWorld ); float jointRotPercent = 1.0/joints.size(); float currJointRot = 0; float prevTwist = 0; double angle; //j.setScale(scale); for (int i = 0; i < joints.size(); i++) { MFnIkJoint j( joints[i]); pBaseJoint = j.rotatePivot(MSpace::kWorld); //Calculate Scale float scaleValue; curveScaleAttribute.getValueAtPosition(currJointRot, scaleValue, &stat); //if ( scale[0] >= 1 ) // Stretch scale[1] = 1 + scaleValue * ( 1 - scale[0] ); /* else //Squash scale[1] = 1 + scaleValue * ( 1.0 - scale[0] ); */ if (scale[1] < 0) scale[1] = 0; scale[2] = scale[1]; j.setScale(scale); //j.setRotation( rot, j.rotationOrder() ); if( i == joints.size() - 1) //Effector Position pEndJoint = tran.rotatePivot(MSpace::kWorld); else { //get position of next joint MFnIkJoint j2( joints[i + 1]); pEndJoint = j2.rotatePivot(MSpace::kWorld); } MVector vBaseJoint(pBaseJoint[0]-pEndJoint[0], pBaseJoint[1]-pEndJoint[1], pBaseJoint[2]-pEndJoint[2]); startLength += vBaseJoint.length(); MVector eyeAim(1.0,0.0,0.0); MPoint pFinalPos; float parm = curveFn.findParamFromLength( startLength ); //Aim to final Pos curveFn.getPointAtParam( parm, pFinalPos, MSpace::kWorld ); MVector eyeU(pBaseJoint[0]-pFinalPos[0], pBaseJoint[1]-pFinalPos[1], pBaseJoint[2]-pFinalPos[2]); eyeU.normalize(); MVector eyeW( eyeU ^ eyeV ); eyeW.normalize(); eyeV = eyeW ^ eyeU; MQuaternion qU( -eyeAim, eyeU ); MVector upRotated( eyeUp.rotateBy( qU )); angle = acos( upRotated*eyeV ); //Calculate Twist { float twistValue; curveAttribute.getValueAtPosition(currJointRot, twistValue, &stat); double rotVal = (1-twistValue)*startTwist + twistValue*endTwist; angle += MAngle(rotVal, MAngle::kDegrees).asRadians(); currJointRot += jointRotPercent; } //Calculate Roll angle += roll; MQuaternion qV(angle, eyeU); MQuaternion q(qU*qV); j.setRotation( q, MSpace::kWorld ); } return MS::kSuccess; }