MStatus resetVtxRemapNode::compute( const MPlug& plug, MDataBlock& data ) // // Description: // This method computes the value of the given output plug based // on the values of the input attributes. // // Arguments: // plug - the plug to compute // data - object that provides access to the attributes for this node // { MStatus status = MS::kSuccess; MDataHandle stateData = data.outputValue( state, &status ); MCheckStatus( status, "ERROR getting state" ); // Check for the HasNoEffect/PassThrough flag on the node. // // (stateData is an enumeration standard in all depend nodes - stored as short) // // (0 = Normal) // (1 = HasNoEffect/PassThrough) // (2 = Blocking) // ... // if( stateData.asShort() == 1 ) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Simply redirect the inMesh to the outMesh for the PassThrough effect // outputData.set(inputData.asMesh()); } else { // Check which output attribute we have been asked to // compute. If this node doesn't know how to compute it, // we must return MS::kUnknownParameter // if (plug == outMesh) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Copy the inMesh to the outMesh, and now you can // perform operations in-place on the outMesh // outputData.set(inputData.asMesh()); MObject mesh = outputData.asMesh(); fresetVtxRemapFactory.setMesh( mesh ); status = fresetVtxRemapFactory.doIt(); outputData.setClean(); } else { status = MS::kUnknownParameter; } } return status; }
MStatus LSSolverNode::compute(const MPlug& plug, MDataBlock& data) { MStatus stat; if( plug == deformed) { MDataHandle tetWorldMatrixData = data.inputValue(tetWorldMatrix, &returnStatus); McheckErr(returnStatus, "Error getting tetWorldMatrix data handle\n"); MDataHandle restShapeData = data.inputValue(restShape, &returnStatus); McheckErr(returnStatus, "Error getting step data handle\n"); MDataHandle restVerticesData = data.inputValue(restVertices, &returnStatus); McheckErr(returnStatus, "Error getting step data handle\n"); MDataHandle restElementsData = data.inputValue(restElements, &returnStatus); McheckErr(returnStatus, "Error getting step data handle\n"); MDataHandle selectedConstraintVertsData = data.inputValue(selectedConstraintVerts, &returnStatus); McheckErr(returnStatus, "Error getting step data handle\n"); MDataHandle selectedForceVertsData = data.inputValue(selectedForceVerts, &returnStatus); McheckErr(returnStatus, "Error getting step data handle\n"); MDataHandle timeData = data.inputValue(time, &returnStatus); McheckErr(returnStatus, "Error getting step data handle\n"); MDataHandle outputMeshData = data.outputValue(deformed, &returnStatus); McheckErr(returnStatus, "Error getting outputMesh data handle\n"); MMatrix twmat = tetWorldMatrixData.asMatrix(); MObject rs = restShapeData.asMesh(); double t = timeData.asDouble(); MDataHandle poissonRatioData = data.inputValue(poissonRatio, &returnStatus); McheckErr(returnStatus, "Error getting poissonRatio data handle\n"); MDataHandle youngsModulusData = data.inputValue(youngsModulus, &returnStatus); McheckErr(returnStatus, "Error getting youngsmodulus data handle\n"); MDataHandle objectDensityData = data.inputValue(objectDensity, &returnStatus); McheckErr(returnStatus, "Error getting objectDensity data handle\n"); MDataHandle frictionData = data.inputValue(friction, &returnStatus); McheckErr(returnStatus, "Error getting friction data handle\n"); MDataHandle restitutionData = data.inputValue(restitution, &returnStatus); McheckErr(returnStatus, "Error getting restitution data handle\n"); MDataHandle dampingData = data.inputValue(damping, &returnStatus); McheckErr(returnStatus, "Error getting damping data handle\n"); MDataHandle userSuppliedDtData = data.inputValue(userSuppliedDt, &returnStatus); McheckErr(returnStatus, "Error getting user supplied dt data handle\n"); MDataHandle integrationTypeData = data.inputValue(integrationType, &returnStatus); McheckErr(returnStatus, "Error getting user integrationTypeData\n"); MDataHandle forceModelTypeData = data.inputValue(forceModelType, &returnStatus); McheckErr(returnStatus, "Error getting user forceModelTypeData\n"); MDataHandle forceApplicationTimeData = data.inputValue(forceApplicationTime, &returnStatus); McheckErr(returnStatus, "Error getting user forceApplicationTime\n"); MDataHandle forceReleasedTimeData = data.inputValue(forceReleasedTime, &returnStatus); McheckErr(returnStatus, "Error getting user forceReleasedTime\n"); MDataHandle forceIncrementTimeData = data.inputValue(forceIncrementTime, &returnStatus); McheckErr(returnStatus, "Error getting user forceIncrementTime\n"); MDataHandle forceStartTimeData = data.inputValue(forceStartTime, &returnStatus); McheckErr(returnStatus, "Error getting user forceStartTime\n"); MDataHandle forceStopTimeData = data.inputValue(forceStopTime, &returnStatus); McheckErr(returnStatus, "Error getting user forceStopTime\n"); MDataHandle forceMagnitudeData = data.inputValue(forceMagnitude, &returnStatus); McheckErr(returnStatus, "Error getting user forceIdleTime\n"); MDataHandle useSuppliedForceData = data.inputValue(useSuppliedForce, &returnStatus); McheckErr(returnStatus, "Error getting user forceIdleTime\n"); MDataHandle useSuppliedConstraintsData = data.inputValue(useSuppliedConstraints, &returnStatus); McheckErr(returnStatus, "Error getting user forceIdleTime\n"); MDataHandle forceDirectionData = data.inputValue(forceDirection, &returnStatus); McheckErr(returnStatus, "Error getting user forceDirection\n"); MDataHandle contactKsData = data.inputValue(contactKs, &returnStatus); McheckErr(returnStatus, "Error getting user forceDirection\n"); MDataHandle contactKdData = data.inputValue(contactKd, &returnStatus); McheckErr(returnStatus, "Error getting user forceDirection\n"); MTime currentTime, maxTime; currentTime = MAnimControl::currentTime(); maxTime = MAnimControl::maxTime(); if (currentTime == MAnimControl::minTime()) { // retrive restVertices and restElements MFnDoubleArrayData restVertArrayData(restVerticesData.data()); MDoubleArray verts = restVertArrayData.array(); int vertArrayLen = verts.length(); double *vertArray = new double[vertArrayLen]; verts.get(vertArray); for(int v=0;v<vertArrayLen;v=v+3) { MPoint mpoint = MPoint(vertArray[v],vertArray[v+1],vertArray[v+2])*twmat; vertArray[v] = mpoint.x; vertArray[v+1] = mpoint.y; vertArray[v+2] = mpoint.z; } MFnIntArrayData restEleArrayData(restElementsData.data()); MIntArray ele = restEleArrayData.array(); int eleArrayLen = ele.length(); int *eleArray = new int[eleArrayLen]; ele.get(eleArray); MFnIntArrayData selectedConstraintVertsArrayData(selectedConstraintVertsData.data()); MIntArray sv = selectedConstraintVertsArrayData.array(); // building selectedConstraintVerts vector<int> selectedConstraintVertIndices; for (int i = 0 ; i < sv.length() ; i++) { selectedConstraintVertIndices.push_back(sv[i]); } MFnIntArrayData selectedForceVertsArrayData(selectedForceVertsData.data()); MIntArray sf = selectedForceVertsArrayData.array(); vector<int> selectedForceVertIndices; for (int i = 0 ; i < sf.length() ; i++) { selectedForceVertIndices.push_back(sf[i]); } // temporarily create force direction vector double *forceDir = forceDirectionData.asDouble3(); vector<double> dir; dir.push_back(forceDir[0]); dir.push_back(forceDir[1]);dir.push_back(forceDir[2]); prevDeformed = 0; double youngsModulusDouble = youngsModulusData.asDouble(); double poissonRatioDouble = poissonRatioData.asDouble(); double objectDensityDouble = objectDensityData.asDouble(); double frictionDouble = frictionData.asDouble(); double restitutionDouble = restitutionData.asDouble(); double dampingDouble = dampingData.asDouble(); double userSuppliedDtDouble = userSuppliedDtData.asDouble(); double forceMagnitudeDouble = forceMagnitudeData.asDouble(); int fAppT = forceApplicationTimeData.asInt(); int fReleasedT = forceReleasedTimeData.asInt(); int fIncT = forceIncrementTimeData.asInt(); int fStartT = forceStartTimeData.asInt(); int fStopT = forceStopTimeData.asInt(); int integrationTypeInt = integrationTypeData.asShort(); int forceModelTypeInt = forceModelTypeData.asShort(); bool useSuppliedForceBool = useSuppliedForceData.asBool(); bool useSuppliedConstraintsBool = useSuppliedConstraintsData.asBool(); double contactKs = contactKsData.asDouble(); double contactKd = contactKdData.asDouble(); if( sm) { delete sm; } sm = new SoftBodySim(youngsModulusDouble,poissonRatioDouble,objectDensityDouble, frictionDouble,restitutionDouble,dampingDouble, eleArrayLen, eleArray, vertArrayLen, vertArray,integrationTypeInt,forceModelTypeInt); sm->setContactAttributes(contactKs,contactKd); if (useSuppliedConstraintsBool) sm->initialize("",userSuppliedDtDouble, selectedConstraintVertIndices); else { vector<int> empty; sm->initialize("",userSuppliedDtDouble, empty); } if (useSuppliedForceBool) sm->setUserForceAttributes(forceMagnitudeDouble, dir,selectedForceVertIndices,fAppT,fReleasedT,fIncT,fStartT,fStopT); } else { sm->update(); } MFnMesh surfFn(rs,&stat); McheckErr( stat, "compute - MFnMesh error" ); MFnMeshData ouputMeshDataCreator; MObject oMesh = ouputMeshDataCreator.create(&stat); buildOutputMesh(surfFn, sm->m_vertices,oMesh); outputMeshData.set(oMesh); data.setClean(plug); } else stat = MS::kUnknownParameter; return stat; }
MStatus closestPointOnCurveNode::compute(const MPlug &plug, MDataBlock &data) { // DO THE COMPUTE ONLY FOR THE *OUTPUT* PLUGS THAT ARE DIRTIED: if ((plug == aPosition) || (plug == aPositionX) || (plug == aPositionY) || (plug == aPositionZ) || (plug == aNormal) || (plug == aNormalX) || (plug == aNormalY) || (plug == aNormalZ) || (plug == aTangent) || (plug == aTangentX) || (plug == aTangentY) || (plug == aTangentZ) || (plug == aParamU) || (plug == aDistance)) { // READ IN ".inCurve" DATA: MDataHandle inCurveDataHandle = data.inputValue(aInCurve); MObject inCurve = inCurveDataHandle.asNurbsCurve(); // READ IN ".inPositionX" DATA: MDataHandle inPositionXDataHandle = data.inputValue(aInPositionX); double inPositionX = inPositionXDataHandle.asDouble(); // READ IN ".inPositionY" DATA: MDataHandle inPositionYDataHandle = data.inputValue(aInPositionY); double inPositionY = inPositionYDataHandle.asDouble(); // READ IN ".inPositionZ" DATA: MDataHandle inPositionZDataHandle = data.inputValue(aInPositionZ); double inPositionZ = inPositionZDataHandle.asDouble(); // GET THE CLOSEST POSITION, NORMAL, TANGENT, PARAMETER-U AND DISTANCE: MPoint inPosition(inPositionX, inPositionY, inPositionZ), position; MVector normal, tangent; double paramU, distance; MDagPath dummyDagPath; closestTangentUAndDistance(dummyDagPath, inPosition, position, normal, tangent, paramU, distance, inCurve); // WRITE OUT ".position" DATA: MDataHandle positionDataHandle = data.outputValue(aPosition); positionDataHandle.set(position.x, position.y, position.z); data.setClean(plug); // WRITE OUT ".normal" DATA: MDataHandle normalDataHandle = data.outputValue(aNormal); normalDataHandle.set(normal.x, normal.y, normal.z); data.setClean(plug); // WRITE OUT ".tangent" DATA: MDataHandle tangentDataHandle = data.outputValue(aTangent); tangentDataHandle.set(tangent.x, tangent.y, tangent.z); data.setClean(plug); // WRITE OUT ".paramU" DATA: MDataHandle paramUDataHandle = data.outputValue(aParamU); paramUDataHandle.set(paramU); data.setClean(plug); // WRITE OUT ".distance" DATA: MDataHandle distanceDataHandle = data.outputValue(aDistance); distanceDataHandle.set(distance); data.setClean(plug); } else { return MS::kUnknownParameter; } return MS::kSuccess; }
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 updateTCCDataNode::compute( const MPlug& plug, MDataBlock& data ) // // Description: // This method computes the value of the given output plug based // on the values of the input attributes. // // Arguments: // plug - the plug to compute // data - object that provides access to the attributes for this node // { MStatus status = MS::kSuccess; MDataHandle stateData = data.outputValue( state, &status ); MCheckStatus( status, "ERROR getting state" ); // Check for the HasNoEffect/PassThrough flag on the node. // // (stateData is an enumeration standard in all depend nodes - stored as short) // // (0 = Normal) // (1 = HasNoEffect/PassThrough) // (2 = Blocking) // ... // if( stateData.asShort() == 1 ) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Simply redirect the inMesh to the outMesh for the PassThrough effect // outputData.set(inputData.asMesh()); } else { // Check which output attribute we have been asked to // compute. If this node doesn't know how to compute it, // we must return MS::kUnknownParameter // if (plug == outMesh) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); MIntArray vR = MFnIntArrayData( data.inputValue( vtxRemap ).data() ).array(&status); MCheckStatus(status,"ERROR getting vtxRemap"); MIntArray pO = MFnIntArrayData( data.inputValue( polyOrder ).data() ).array(&status); MCheckStatus(status,"ERROR getting polyOrder"); MIntArray cS = MFnIntArrayData( data.inputValue( cShift ).data() ).array(&status); MCheckStatus(status,"ERROR getting cShift"); MIntArray dnFV = MFnIntArrayData( data.inputValue( delta_nFV ).data() ).array(&status); MCheckStatus(status,"ERROR getting deltanFV"); MIntArray dF = MFnIntArrayData( data.inputValue( delta_F ).data() ).array(&status); MCheckStatus(status,"ERROR getting deltaF"); int nVtx = data.inputValue( nV ).asInt(); MCheckStatus(status,"ERROR getting nV"); // Copy the inMesh to the outMesh, and now you can // perform operations in-place on the outMesh // outputData.set(inputData.asMesh()); MObject mesh = outputData.asMesh(); fupdateTCCDataFactory.setMesh( mesh ); fupdateTCCDataFactory.setVtxRemap( vR ); fupdateTCCDataFactory.setPolyOrder( pO ); fupdateTCCDataFactory.setCShift( cS ); fupdateTCCDataFactory.setDelta_nFV( dnFV ); fupdateTCCDataFactory.setDelta_F( dF ); fupdateTCCDataFactory.setnV( nVtx ); // Now, perform the updateTCCData // status = fupdateTCCDataFactory.doIt(); // Mark the output mesh as clean // outputData.setClean(); } else { status = MS::kUnknownParameter; } } return status; }
// ==================================== // Compute // ==================================== // // Description: // This method computes the value of the given output plug based // on the values of the input attributes. // // Arguments: // plug - the plug to compute // data - object that provides access to the attributes for this node // MStatus OsdPolySmooth::compute( const MPlug& plug, MDataBlock& data ) { MStatus returnStatus; // Check which output attribute we have been asked to compute. If this // node doesn't know how to compute it, we must return // MS::kUnknownParameter. // if( plug == a_output ) { bool createdSubdMesh = false; int subdivisionLevel = data.inputValue(a_subdivisionLevels).asInt(); short stateH = data.inputValue(state).asShort(); if ((subdivisionLevel > 0) and (stateH !=1)) { // == Retrieve input mesh ==================================== // Get attr values MObject inMeshObj = data.inputValue(a_inputPolymesh).asMesh(); short vertBoundaryMethod = data.inputValue(a_vertBoundaryMethod).asShort(); short fvarBoundaryMethod = data.inputValue(a_fvarBoundaryMethod).asShort(); bool fvarPropCorners = data.inputValue(a_fvarPropagateCorners).asBool(); bool smoothTriangles = data.inputValue(a_smoothTriangles).asBool(); short creaseMethodVal = data.inputValue(a_creaseMethod).asShort(); // Convert attr values to OSD enums HMesh::InterpolateBoundaryMethod vertInterpBoundaryMethod = ConvertMayaBoundaryMethodShortToOsdInterpolateBoundaryMethod(vertBoundaryMethod); HMesh::InterpolateBoundaryMethod fvarInterpBoundaryMethod = ConvertMayaBoundaryMethodShortToOsdInterpolateBoundaryMethod(fvarBoundaryMethod); HCatmark::CreaseSubdivision creaseMethod = (creaseMethodVal == k_creaseMethod_chaikin) ? HCatmark::k_CreaseChaikin : HCatmark::k_CreaseNormal; HCatmark::TriangleSubdivision triangleSubdivision = smoothTriangles ? HCatmark::k_New : HCatmark::k_Normal; // == Get Mesh Functions and Iterators ========================== MFnMeshData inMeshDat(inMeshObj); MFnMesh inMeshFn(inMeshObj, &returnStatus); MCHECKERR(returnStatus, "ERROR getting inMeshFn\n"); MItMeshPolygon inMeshItPolygon(inMeshObj, &returnStatus); MCHECKERR(returnStatus, "ERROR getting inMeshItPolygon\n"); // == Convert MFnMesh to OpenSubdiv ============================= // Create the hbrMesh // Note: These fvar values only need to be kept alive through the life of the farMesh std::vector<int> fvarIndices; std::vector<int> fvarWidths; HMesh *hbrMesh = createOsdHbrFromPoly( inMeshFn, inMeshItPolygon, fvarIndices, fvarWidths); assert(hbrMesh); // Create the farMesh if successfully created the hbrMesh if (hbrMesh) { // Set Boundary methods and other hbr paramters hbrMesh->SetInterpolateBoundaryMethod( vertInterpBoundaryMethod ); hbrMesh->SetFVarInterpolateBoundaryMethod( fvarInterpBoundaryMethod ); hbrMesh->SetFVarPropagateCorners(fvarPropCorners); hbrMesh->GetSubdivision()->SetCreaseSubdivisionMethod(creaseMethod); // Set HBR Catmark Subdivision parameters HCatmark *catmarkSubdivision = dynamic_cast<HCatmark *>(hbrMesh->GetSubdivision()); if (catmarkSubdivision) { catmarkSubdivision->SetTriangleSubdivisionMethod(triangleSubdivision); } // Finalize subd calculations -- apply boundary interpolation rules and resolves singular verts, etc. // NOTE: This HAS to be called after all HBR parameters are set hbrMesh->Finish(); int ncoarseverts = hbrMesh->GetNumVertices(); // Create a FarMesh from the HBR mesh and pass into // It will be owned by the OsdMesh and deleted in the ~OsdMesh() FMeshFactory meshFactory(hbrMesh, subdivisionLevel, false); FMesh *farMesh = meshFactory.Create((hbrMesh->GetTotalFVarWidth() > 0)); // == Setup OSD Data Structures ========================= int numVertexElements = 3; // only track vertex positions int numVaryingElements = 0; // XXX Future: Revise to include varying ColorSets int numVertices = inMeshFn.numVertices(); int numFarVerts = farMesh->GetNumVertices(); static OpenSubdiv::OsdCpuComputeController computeController = OpenSubdiv::OsdCpuComputeController(); OpenSubdiv::OsdCpuComputeController::ComputeContext *computeContext = OpenSubdiv::OsdCpuComputeController::ComputeContext::Create(farMesh); OpenSubdiv::OsdCpuVertexBuffer *vertexBuffer = OpenSubdiv::OsdCpuVertexBuffer::Create(numVertexElements, numFarVerts ); OpenSubdiv::OsdCpuVertexBuffer *varyingBuffer = (numVaryingElements) ? OpenSubdiv::OsdCpuVertexBuffer::Create(numVaryingElements, numFarVerts) : NULL; // == UPDATE VERTICES (can be done after farMesh generated from topology) == float const * vertex3fArray = inMeshFn.getRawPoints(&returnStatus); vertexBuffer->UpdateData(vertex3fArray, 0, numVertices ); // Hbr dupes singular vertices during Mesh::Finish() - we need // to duplicate their positions in the vertex buffer. if (ncoarseverts > numVertices) { MIntArray polyverts; for (int i=numVertices; i<ncoarseverts; ++i) { HVertex const * v = hbrMesh->GetVertex(i); HFace const * f = v->GetIncidentEdge()->GetFace(); int vidx = -1; for (int j=0; j<f->GetNumVertices(); ++j) { if (f->GetVertex(j)==v) { vidx = j; break; } } assert(vidx>-1); inMeshFn.getPolygonVertices(f->GetID(), polyverts); int vert = polyverts[vidx]; vertexBuffer->UpdateData(&vertex3fArray[0]+vert*numVertexElements, i, 1); } } // == Delete HBR // Can now delete the hbrMesh as we will only be referencing the farMesh from this point on delete hbrMesh; hbrMesh = NULL; // == Subdivide OpenSubdiv mesh ========================== computeController.Refine(computeContext, farMesh->GetKernelBatches(), vertexBuffer, varyingBuffer); computeController.Synchronize(); // == Convert subdivided OpenSubdiv mesh to MFnMesh Data outputMesh ============= // Create New Mesh Data Object MFnMeshData newMeshData; MObject newMeshDataObj = newMeshData.create(&returnStatus); MCHECKERR(returnStatus, "ERROR creating outputData"); // Create out mesh returnStatus = convertOsdFarToMayaMeshData(farMesh, vertexBuffer, subdivisionLevel, inMeshFn, newMeshDataObj); MCHECKERR(returnStatus, "ERROR convertOsdFarToMayaMesh"); // Propagate objectGroups from inMesh to outMesh (for per-facet shading, etc) returnStatus = createSmoothMesh_objectGroups(inMeshDat, subdivisionLevel, newMeshData ); // Write to output plug MDataHandle outMeshH = data.outputValue(a_output, &returnStatus); MCHECKERR(returnStatus, "ERROR getting polygon data handle\n"); outMeshH.set(newMeshDataObj); // == Cleanup OSD ============================================ // REVISIT: Re-add these deletes delete(vertexBuffer); delete(varyingBuffer); delete(computeContext); delete(farMesh); // note that the subd mesh was created (see the section below if !createdSubdMesh) createdSubdMesh = true; } } // Pass-through inMesh to outMesh if not created the subd mesh if (!createdSubdMesh) { MDataHandle outMeshH = data.outputValue(a_output, &returnStatus); returnStatus = outMeshH.copy(data.outputValue(a_inputPolymesh, &returnStatus)); MCHECKERR(returnStatus, "ERROR getting polygon data handle\n"); } // Clean up Maya Plugs data.setClean(plug); } else { // Unhandled parameter in this compute function, so return MS::kUnknownParameter // so it is handled in a parent compute() function. return MS::kUnknownParameter; } return MS::kSuccess; }
MStatus LSystemNode::compute(const MPlug& plug, MDataBlock& data) { MStatus returnStatus; if (plug == outputMesh) { /* Get time */ MDataHandle timeData = data.inputValue( time, &returnStatus ); McheckErr(returnStatus, "Error getting time data handle\n"); MTime time = timeData.asTime(); MDataHandle angleData = data.inputValue( angle, &returnStatus ); McheckErr(returnStatus, "Error getting time data handle\n"); double angle_value = angleData.asDouble(); MDataHandle stepsData = data.inputValue( steps, &returnStatus ); McheckErr(returnStatus, "Error getting time data handle\n"); double steps_value = stepsData.asDouble(); MDataHandle grammarData = data.inputValue( grammar, &returnStatus ); McheckErr(returnStatus, "Error getting time data handle\n"); MString grammar_value = grammarData.asString(); /* Get output object */ MDataHandle outputHandle = data.outputValue(outputMesh, &returnStatus); McheckErr(returnStatus, "ERROR getting polygon data handle\n"); MFnMeshData dataCreator; MObject newOutputData = dataCreator.create(&returnStatus); McheckErr(returnStatus, "ERROR creating outputData"); MFnMesh myMesh; MPointArray points; MIntArray faceCounts; MIntArray faceConnects; //MString grammar = ("F\\nF->F[+F]F[-F]F"); CylinderMesh *cm; LSystem system; system.loadProgramFromString(grammar_value.asChar()); system.setDefaultAngle(angle_value); system.setDefaultStep(steps_value); std::vector<LSystem::Branch> branches; system.process(time.value(), branches); int k = branches.size(); for(int j = 0; j < branches.size(); j++) { //1. find the position for start and end point of current branch //2. generate a cylinder MPoint start(branches[j].first[0],branches[j].first[1],branches[j].first[2]); MPoint end(branches[j].second[0],branches[j].second[1],branches[j].second[2]); cm = new CylinderMesh(start, end); cm->appendToMesh(points, faceCounts, faceConnects); } MObject newMesh = myMesh.create(points.length(), faceCounts.length(), points, faceCounts, faceConnects, newOutputData, &returnStatus); McheckErr(returnStatus, "ERROR creating new mesh"); outputHandle.set(newOutputData); data.setClean( plug ); } else return MS::kUnknownParameter; return MS::kSuccess; }
MStatus latticeNoiseNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus returnStatus; float noiseAmplitude; float noiseFreq; if( plug == output ) { // Get the lattice data from the input attribute. First get the // data object, and then use the lattice data function set to extract // the actual lattice. // // Get the data handle // MDataHandle inputData = data.inputValue( input, &returnStatus ); McheckErr( returnStatus, "ERROR getting lattice data handle\n" ); // Get the data object // MObject latticeData = inputData.data(); MFnLatticeData dataFn( latticeData ); // Get the actual geometry // MObject lattice = dataFn.lattice(); MFnLattice lattFn( lattice, &returnStatus ); McheckErr( returnStatus, "ERROR getting lattice geometry\n" ); // Do the same for the output lattice // MDataHandle outputData = data.outputValue( output, &returnStatus ); McheckErr( returnStatus, "ERROR getting lattice data handle\n" ); // Get the data object // latticeData = outputData.data(); if ( latticeData.isNull() ) { // The data object for this attribute has not been created yet, so // we'll create it // latticeData = dataFn.create(); } else { // Use the data object that is already there // dataFn.setObject( latticeData ); } // Get the actual geometry // MObject outLattice = dataFn.lattice(); MFnLattice outLattFn( outLattice, &returnStatus ); McheckErr( returnStatus, "ERROR getting lattice geometry\n" ); // Get the amplitude and frequency // MDataHandle ampData = data.inputValue( amplitude, &returnStatus ); McheckErr( returnStatus, "ERROR getting amplitude\n" ); noiseAmplitude = ampData.asFloat(); MDataHandle freqData = data.inputValue( frequency, &returnStatus ); McheckErr( returnStatus, "ERROR getting frequency\n" ); noiseFreq = freqData.asFloat(); // Get the time. // MDataHandle timeData = data.inputValue( time, &returnStatus ); McheckErr( returnStatus, "ERROR getting time data handle\n" ); MTime time = timeData.asTime(); float seconds = (float)time.as( MTime::kSeconds ); // Easiest way to modify frequency is by modifying the time // seconds = seconds * noiseFreq; // We have the information we need now. We'll apply noise to the // points upon the lattice // unsigned s, t, u; lattFn.getDivisions( s, t, u ); // match up the divisions in the lattices // outLattFn.setDivisions( s, t, u ); for ( unsigned i = 0; i < s; i++ ) { for ( unsigned j = 0; j < t; j++ ) { for ( unsigned k = 0; k < u; k++ ) { MPoint & point = lattFn.point( i, j, k ); MPoint & outPoint = outLattFn.point( i, j, k ); pnt noisePnt = noise::atPointAndTime( (float)point.x, (float)point.y, (float)point.z, seconds ); // Make noise between -1 and 1 instead of 0 and 1 // noisePnt.x = ( noisePnt.x * 2.0F ) - 1.0F; noisePnt.y = ( noisePnt.y * 2.0F ) - 1.0F; noisePnt.z = ( noisePnt.z * 2.0F ) - 1.0F; outPoint.x = point.x + ( noisePnt.x * noiseAmplitude ); outPoint.y = point.y + ( noisePnt.y * noiseAmplitude ); outPoint.z = point.z + ( noisePnt.z * noiseAmplitude ); } } } outputData.set( latticeData ); data.setClean(plug); } else { return MS::kUnknownParameter; } return MS::kSuccess; }
MStatus weightControllerNode::compute( const MPlug& plug, MDataBlock& dataBlock){ MObject thisNode = thisMObject(); MStatus status; if(plug != aOutputs || ! plug.isElement()){ return MS::kSuccess; } float3 &uu = dataBlock.inputValue(aLocator).asFloat3(); Vector3f loc(uu[0],uu[1],uu[2]); MArrayDataHandle hVertices=dataBlock.inputArrayValue(aVertices); int num=hVertices.elementCount(); if(num==0){return MS::kSuccess; } // compute the weight std::vector< Vector3f > v(num); std::vector< float > r(num); for(int i=0;i<num;i++){ float3 &uu=hVertices.inputValue().asFloat3(); Vector3f u(uu[0],uu[1],uu[2]); v[i] = u-loc; r[i] = v[i].norm(); if(i<num-1){ hVertices.next(); } } std::vector<float> w(num, 0.0f), A(num), D(num); for(int i=0;i<num;i++){ int j=(i+1)% num; A[i]=(v[i].cross(v[j])).norm(); D[i]=v[i].dot(v[j]); } bool flag=true; // check if it is on the boundary for(int i=0;i<num;i++){ if(r[i]<EPSILON){ // at a vertex w[i]=1.0; flag=false; break; }else if(abs(A[i])<EPSILON && D[i] < 0){ // on an edge int j=(i+1) % num; w[i]=r[j]; w[j]=r[i]; flag=false; break; } } // if it is not on the boundary if(flag){ for(int i=0;i<num;i++){ int k=(i-1+num)% num; if(fabs(A[k])>EPSILON) w[i]+=(r[k]-D[k]/r[i])/A[k]; if(fabs(A[i])>EPSILON) w[i]+=(r[(i+1)% num]-D[i]/r[i])/A[i]; } } float sum=0.0; for(unsigned int i=0;i<num;i++) sum += w[i]; for(unsigned int i=0;i<num;i++) w[i] /= sum; // writing output MPlug wPlug(thisNode, aOutputs); MDataHandle wHandle = wPlug.constructHandle(dataBlock); MArrayDataHandle arrayHandle(wHandle, &status); CHECK_MSTATUS_AND_RETURN_IT(status); MArrayDataBuilder arrayBuilder = arrayHandle.builder(&status); CHECK_MSTATUS_AND_RETURN_IT(status); for(unsigned int i = 0; i < num; i++) { MDataHandle handle = arrayBuilder.addElement(i,&status); CHECK_MSTATUS_AND_RETURN_IT(status); handle.set(w[i]); } status = arrayHandle.set(arrayBuilder); CHECK_MSTATUS_AND_RETURN_IT(status); wPlug.setValue(wHandle); dataBlock.setClean(plug); return MS::kSuccess; }
MStatus sgIkSmoothStretch::compute( const MPlug& plug, MDataBlock& data ) { MStatus stat; if ( plug == aOutputDistance ) { MArrayDataHandle hArrInputDistance = data.inputArrayValue( aInputDistance ); MDataHandle hStretchAble = data.inputValue( aStretchAble ); MDataHandle hSmoothArea = data.inputValue( aSmoothArea ); float stretchAble = hStretchAble.asFloat(); double allDistance = 0.0; int arrayCount = hArrInputDistance.elementCount(); double* outputDistances = new double[arrayCount]; int multMinus = 1; for( int i=0; i<arrayCount; i++ ) { MDataHandle hInputDistance = hArrInputDistance.inputValue(); double inputDistance = hInputDistance.asDouble(); if( inputDistance < 0 ) { multMinus = -1; outputDistances[i] = -inputDistance; } else { outputDistances[i] = inputDistance; } allDistance += outputDistances[i]; hArrInputDistance.next(); } MDataHandle hInPosition = data.inputValue( aInPosition ); MDataHandle hInPositionX = hInPosition.child( aInPositionX ); MDataHandle hInPositionY = hInPosition.child( aInPositionY ); MDataHandle hInPositionZ = hInPosition.child( aInPositionZ ); double smoothArea = hSmoothArea.asDouble()*0.1; double poseDistance = sqrt( pow( hInPositionX.asDouble(), 2 )+pow( hInPositionY.asDouble(), 2 )+pow( hInPositionZ.asDouble(), 2 ) ) ; allDistance = fabs( allDistance ); double stretchRate = getSmoothStretchRate( outputDistances[0], outputDistances[1], poseDistance, smoothArea ); double smoothRate = getSmoothRate( outputDistances[0], outputDistances[1], poseDistance, smoothArea ); double currentRate = ( 1-stretchAble )*smoothRate + stretchAble*stretchRate; outputDistances[0] *= currentRate*multMinus; outputDistances[1] *= currentRate*multMinus; MArrayDataHandle hArrOutputDistance = data.outputArrayValue( aOutputDistance ); MArrayDataBuilder bArrOutputDistance( aOutputDistance, arrayCount, &stat ); for( int i=0; i<arrayCount; i++ ) { MDataHandle hOutputDistance = bArrOutputDistance.addElement( i ); hOutputDistance.set( outputDistances[i] ); } hArrOutputDistance.set( bArrOutputDistance ); hArrOutputDistance.setAllClean(); data.setClean( plug ); } return MS::kSuccess; }
MStatus MG_dotProduct::compute(const MPlug& plug,MDataBlock& dataBlock) { MStatus returnStatus; if ((plug==dotProductA)|| (plug==dotProductMax)|| (plug==proj1on2)|| (plug==proj2on1)|| (plug==angleInBetweenAttr)|| (plug==angleX)|| (plug==angleY)|| (plug==angleZ)) /*get time */ { //creating handles to the input values MDataHandle vector1DataH = dataBlock.inputValue(vector1); MFloatPoint vector1V = vector1DataH.asFloatVector(); MDataHandle vector2DataH = dataBlock.inputValue(vector2); MFloatPoint vector2V = vector2DataH.asFloatVector(); MDataHandle xAxisH = dataBlock.inputValue(projAxisX); MFloatPoint xAxisData = xAxisH.asFloatVector(); MDataHandle yAxisH = dataBlock.inputValue(projAxisY); MFloatPoint yAxisData = yAxisH.asFloatVector(); MDataHandle zAxisH = dataBlock.inputValue(projAxisZ); MFloatPoint zAxisData = zAxisH.asFloatVector(); MDataHandle normData = dataBlock.inputValue(normalize); bool norm =normData.asBool(); //Creating some neededs variables float dotResult; // variable that will hold the dot product result float maxValue; //variable that will hold the dot product max value float distance1; // variable that will hold the vector 1 lenght float distance2; //variable that will hold the vector 2 lenght float angleDeg; //variable that will hold the angle inbetween the two vectors //float cosRad ; //variable that will hold the cosine value in radiants //Dot product math float vec1Array[3] = {vector1V[0],vector1V[1],vector1V[2]}; vector <float> vec1 = makeVector(vec1Array) ; float vec2Array[3] = {vector2V[0],vector2V[1],vector2V[2]}; vector <float> vec2 = makeVector(vec2Array) ; dotResult = vecDotProduct(vec1,vec2); distance1 = vectorLength(vec1); distance2 = vectorLength(vec2); maxValue = distance1*distance2; if (norm == 1) { if (maxValue ==0) { dotResult=0; }else{ dotResult = dotResult/maxValue; } } //Projection v2 on v1 float projV2=0; //variable that will hold the value projection of v2 projected on v1 vector <float> v1Norm; // variable that will hold the normalized v1 vector vector<float> v2Vec; // variable that will hold the projected vector if (distance1 != 0) { projV2 = projVector(vec2,vec1); v1Norm = normVector(vec1); v2Vec = scalarVector(v1Norm,projV2); }else{ //initialize the vector as 0 0 0 float zeroVec2[3]= {0,0,0}; v2Vec=makeVector(zeroVec2); } //Projection v1 on v2 float projV1=0; //variable that will hold the value projection of v1 projected on v2 vector <float> v2Norm;// variable that will hold the normalized v2 vector vector <float> v1Vec;// variable that will hold the projected vector if (distance2 != 0) { projV1 = projVector(vec1,vec2); v2Norm = normVector(vec2); v1Vec = scalarVector(v2Norm,projV1); }else{ //initialize the vector as 0 0 0 float zeroVec1[3]= {0,0,0}; v1Vec=makeVector(zeroVec1); } //Angle in between if ((distance2*distance1)!=0) { angleDeg=angleInbetweenVector(vec1,vec2); }else{ angleDeg=0; } //Angle inbetween splitted into X,Y,Z world rotation //float dotResultV1X; // splitting inbetween angle into X Y Z rotation //converting axis from node into vector class float xAxisArray[3] = {xAxisData[0],xAxisData[1],xAxisData[2]}; vector<float> xAxisVec = makeVector(xAxisArray) ; float yAxisArray[3] = {yAxisData[0],yAxisData[1],yAxisData[2]}; vector<float> yAxisVec = makeVector(yAxisArray) ; float zAxisArray[3] = {zAxisData[0],zAxisData[1],zAxisData[2]}; vector<float> zAxisVec = makeVector(zAxisArray) ; float angleProjXYDeg=0 ; float angleProjYZDeg=0 ; float angleProjXZDeg=0 ; // angle Z vector<float> projectedV1; vector<float> projectedV2; projectedV1= projectVectorOnPlane(vec1,xAxisVec,yAxisVec); projectedV2= projectVectorOnPlane(vec2,xAxisVec,yAxisVec); angleProjXYDeg=angleInbetweenVector(projectedV1,projectedV2); // angle X projectedV1= projectVectorOnPlane(vec1,zAxisVec,yAxisVec); projectedV2= projectVectorOnPlane(vec2,zAxisVec,yAxisVec); angleProjYZDeg=angleInbetweenVector(projectedV1,projectedV2); // angle Y projectedV1= projectVectorOnPlane(vec1,zAxisVec,xAxisVec); projectedV2= projectVectorOnPlane(vec2,zAxisVec,xAxisVec); angleProjXZDeg=angleInbetweenVector(projectedV1,projectedV2); //Setting output values MDataHandle output = dataBlock.outputValue(dotProductA); MDataHandle outputMax = dataBlock.outputValue(dotProductMax); MDataHandle projV1Output = dataBlock.outputValue(proj1on2); MDataHandle projV2Output = dataBlock.outputValue(proj2on1); MDataHandle angleInBetweenOutput = dataBlock.outputValue(angleInBetweenAttr); MDataHandle angleXout = dataBlock.outputValue(angleX); MDataHandle angleYout = dataBlock.outputValue(angleY); MDataHandle angleZout = dataBlock.outputValue(angleZ); output.set(dotResult); outputMax.set(maxValue); projV1Output.set(v1Vec[0],v1Vec[1],v1Vec[2]); projV2Output.set(v2Vec[0],v2Vec[1],v2Vec[2]); angleInBetweenOutput.set(angleDeg); angleXout.set(angleProjYZDeg); angleYout.set(angleProjXZDeg); angleZout.set(angleProjXYDeg); //SetClean tells maya attribute is update outputMax.setClean(); output.setClean(); projV1Output.setClean(); projV2Output.setClean(); angleInBetweenOutput.setClean(); angleXout.setClean(); angleYout.setClean(); angleZout.setClean(); } return MS::kSuccess; }
MStatus splitUVNode::compute( const MPlug& plug, MDataBlock& data ) // // Description: // This method computes the value of the given output plug based // on the values of the input attributes. // // Arguments: // plug - the plug to compute // data - object that provides access to the attributes for this node // { MStatus status = MS::kSuccess; MDataHandle stateData = data.outputValue( state, &status ); MCheckStatus( status, "ERROR getting state" ); // Check for the HasNoEffect/PassThrough flag on the node. // // (stateData is an enumeration standard in all depend nodes - stored as short) // // (0 = Normal) // (1 = HasNoEffect/PassThrough) // (2 = Blocking) // ... // if( stateData.asShort() == 1 ) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Simply redirect the inMesh to the outMesh for the PassThrough effect // outputData.set(inputData.asMesh()); } else { // Check which output attribute we have been asked to // compute. If this node doesn't know how to compute it, // we must return MS::kUnknownParameter // if (plug == outMesh) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Now, we get the value of the uvList and use it to perform // the operation on this mesh // MDataHandle inputUVs = data.inputValue( uvList, &status); MCheckStatus(status,"ERROR getting uvList"); // Copy the inMesh to the outMesh, and now you can // perform operations in-place on the outMesh // outputData.set(inputData.asMesh()); MObject mesh = outputData.asMesh(); // Retrieve the UV list from the component list. // // Note, we use a component list to store the components // because it is more compact memory wise. (ie. comp[81:85] // is smaller than comp[81], comp[82],...,comp[85]) // MObject compList = inputUVs.data(); MFnComponentListData compListFn( compList ); unsigned i; int j; MIntArray uvIds; for( i = 0; i < compListFn.length(); i++ ) { MObject comp = compListFn[i]; if( comp.apiType() == MFn::kMeshMapComponent ) { MFnSingleIndexedComponent uvComp( comp ); for( j = 0; j < uvComp.elementCount(); j++ ) { int uvId = uvComp.element(j); uvIds.append( uvId ); } } } // Set the mesh object and uvList on the factory // fSplitUVFactory.setMesh( mesh ); fSplitUVFactory.setUVIds( uvIds ); // Now, perform the splitUV // status = fSplitUVFactory.doIt(); // Mark the output mesh as clean // outputData.setClean(); } else { status = MS::kUnknownParameter; } } return status; }
MStatus VmIslandNode::compute( const MPlug& i_plug, MDataBlock& io_dataBlock ) { MStatus status; fprintf( stderr, "VmIslandNode::compute()...\n" ); //Check plugs if( i_plug == oa_update ) { //Make sure all internal structures are up to date with attributes fprintf( stderr, "VmIslandNode::compute(oa_update)\n" ); MDataHandle seedHandle = io_dataBlock.inputValue( ia_seed, & status); const long seed = seedHandle.asLong(); CHECK_MSTATUS( status ); MDataHandle roughnessHandle = io_dataBlock.inputValue( ia_roughness, & status); const float roughness = roughnessHandle.asFloat(); CHECK_MSTATUS( status ); MDataHandle planeHeightHandle = io_dataBlock.inputValue( ia_planeHeight, & status); const long planeHeight = planeHeightHandle.asLong(); CHECK_MSTATUS( status ); MDataHandle smoothHandle = io_dataBlock.inputValue( ia_smooth, & status); const long smooth = smoothHandle.asLong(); CHECK_MSTATUS( status ); MDataHandle resolutionHandle = io_dataBlock.inputValue( ia_resolution, & status); const long resolution = resolutionHandle.asLong(); CHECK_MSTATUS( status ); MDataHandle planeSizeHandle = io_dataBlock.inputValue( ia_planeSize, & status); const long planeSize = planeSizeHandle.asLong(); CHECK_MSTATUS( status ); MDataHandle gridSizeHandle = io_dataBlock.inputValue( ia_gridSize, & status); const long gridSize = gridSizeHandle.asLong(); m_gridSize = (int) gridSize; CHECK_MSTATUS( status ); //Grass //-------------- MDataHandle baseWidthHandle = io_dataBlock.inputValue( ia_baseWidth, & status); const float baseWidth = baseWidthHandle.asFloat(); CHECK_MSTATUS( status ); MDataHandle grassMultiplierHandle = io_dataBlock.inputValue( ia_grassMultiplier, & status); const long grassMultiplier = grassMultiplierHandle.asLong(); CHECK_MSTATUS( status ); MDataHandle grassSegmentLengthHandle = io_dataBlock.inputValue( ia_grassSegmentLength, & status); const float grassSegmentLength = grassSegmentLengthHandle.asFloat(); CHECK_MSTATUS( status ); MDataHandle grassNumSegmentsHandle = io_dataBlock.inputValue( ia_grassNumSegments, & status); const long grassNumSegments = grassNumSegmentsHandle.asLong(); CHECK_MSTATUS( status ); //MDataHandle windDirectionHandle = io_dataBlock.inputValue( ia_windDirection, & status); MFloatVector& windDirVec = io_dataBlock.inputValue( ia_windDirection, & status).asFloatVector(); const Vcore::Vec3 windDirection = Vec3(windDirVec.x, windDirVec.y, windDirVec.z); CHECK_MSTATUS( status ); MDataHandle grassBendAmountHandle = io_dataBlock.inputValue( ia_grassBendAmount, & status); const float grassBendAmount = grassBendAmountHandle.asFloat(); CHECK_MSTATUS( status ); MDataHandle windSpreadHandle = io_dataBlock.inputValue( ia_windSpread, & status); const float windSpread = windSpreadHandle.asFloat(); CHECK_MSTATUS( status ); MDataHandle clockHandle = io_dataBlock.inputValue( ia_clock, & status); const float clock = clockHandle.asLong(); CHECK_MSTATUS( status ); //Colours //----------------- MFloatVector& grassBaseColour1Vec = io_dataBlock.inputValue( ia_grassBaseColour1, & status).asFloatVector(); const Vcore::Vec3 grassBaseColour1 = Vec3(grassBaseColour1Vec.x, grassBaseColour1Vec.y, grassBaseColour1Vec.z); CHECK_MSTATUS( status ); MFloatVector& grassTipColour1Vec = io_dataBlock.inputValue( ia_grassTipColour1, & status).asFloatVector(); const Vcore::Vec3 grassTipColour1 = Vec3(grassTipColour1Vec.x, grassTipColour1Vec.y, grassTipColour1Vec.z); CHECK_MSTATUS( status ); MFloatVector& grassBaseColour2Vec = io_dataBlock.inputValue( ia_grassBaseColour2, & status).asFloatVector(); const Vcore::Vec3 grassBaseColour2 = Vec3(grassBaseColour2Vec.x, grassBaseColour2Vec.y, grassBaseColour2Vec.z); CHECK_MSTATUS( status ); MFloatVector& grassTipColour2Vec = io_dataBlock.inputValue( ia_grassTipColour2, & status).asFloatVector(); const Vcore::Vec3 grassTipColour2 = Vec3(grassTipColour2Vec.x, grassTipColour2Vec.y, grassTipColour2Vec.z); CHECK_MSTATUS( status ); //Update paramters of external lib system and rebuild m_island.setPlaneParameters( planeSize, planeHeight, seed, roughness, resolution, gridSize, grassMultiplier, baseWidth, grassSegmentLength, grassNumSegments, windDirection, grassBendAmount, windSpread, clock, smooth, grassBaseColour1, grassTipColour1, grassBaseColour2, grassTipColour2 ); //Rebuild object and check for success const bool updateOK = m_island.build(); m_cachedVertices = m_island.getComponents( Vcore::Visland::VERTICES ); m_cachedColours = m_island.getComponents( Vcore::Visland::COLOURS ); m_cachedNormals = m_island.getComponents( Vcore::Visland::NORMALS ); m_cachedIndices = m_island.getAllIndices(); m_geomInstances = m_island.getAllGeometryInstances(); // We must set a value for the plug we have been asked to evaluate, // even if we are not going to use it. We set it in the data-block, // and to set it we use outputValue(). // // Here we usually set the result to true. The caller who triggered the // computation for this attribute might not look at the value that // we are setting this plug to. But they do ask for the value of this plug, // only to trigger an update of the internal structures. See the draw() // and boundingBox() methods to see how this is done. MDataHandle updateHandle = io_dataBlock.outputValue( i_plug ); updateHandle.set( updateOK ); //Need to set plug to clean to refresh it io_dataBlock.setClean( i_plug ); } else if( i_plug == oa_rib ) { //Set up rib system to ready renderman values fprintf( stderr, "VmIslandNode::compute(oa_rib)\n" ); MDataHandle seedHandle = io_dataBlock.inputValue( ia_seed, & status); const long seed = seedHandle.asLong(); CHECK_MSTATUS( status ); MDataHandle smoothHandle = io_dataBlock.inputValue( ia_smooth, & status); const float smooth = smoothHandle.asLong(); CHECK_MSTATUS( status ); MDataHandle roughnessHandle = io_dataBlock.inputValue( ia_roughness, & status); const float roughness = roughnessHandle.asFloat(); CHECK_MSTATUS( status ); MDataHandle rmanResolutionHandle = io_dataBlock.inputValue( ia_rmanResolution, & status); const long rmanResolution = rmanResolutionHandle.asLong(); CHECK_MSTATUS( status ); MDataHandle planeHeightHandle = io_dataBlock.inputValue( ia_planeHeight, & status); const long planeHeight = planeHeightHandle.asLong(); CHECK_MSTATUS( status ); MDataHandle planeSizeHandle = io_dataBlock.inputValue( ia_planeSize, & status); const long planeSize = planeSizeHandle.asLong(); CHECK_MSTATUS( status ); //Grass //---------------- MDataHandle gridSizeHandle = io_dataBlock.inputValue( ia_gridSize, & status); const long gridSize = gridSizeHandle.asLong(); CHECK_MSTATUS( status ); MDataHandle grassMultiplierHandle = io_dataBlock.inputValue( ia_grassMultiplier, & status); const long grassMultiplier = grassMultiplierHandle.asLong(); CHECK_MSTATUS( status ); MDataHandle baseWidthHandle = io_dataBlock.inputValue( ia_baseWidth, & status); const float baseWidth = baseWidthHandle.asFloat(); m_gridSize = (int) baseWidth; CHECK_MSTATUS( status ); MDataHandle grassSegmentLengthHandle = io_dataBlock.inputValue( ia_grassSegmentLength, & status); const float grassSegmentLength = grassSegmentLengthHandle.asFloat(); CHECK_MSTATUS( status ); MDataHandle grassNumSegmentsHandle = io_dataBlock.inputValue( ia_grassNumSegments, & status); const long grassNumSegments = grassNumSegmentsHandle.asLong(); CHECK_MSTATUS( status ); MFloatVector& windDirVec = io_dataBlock.inputValue( ia_windDirection, & status).asFloatVector(); const Vcore::Vec3 windDirection = Vec3(windDirVec.x, windDirVec.y, windDirVec.z); CHECK_MSTATUS( status ); MDataHandle grassBendAmountHandle = io_dataBlock.inputValue( ia_grassBendAmount, & status); const float grassBendAmount = grassBendAmountHandle.asFloat(); CHECK_MSTATUS( status ); MDataHandle windSpreadHandle = io_dataBlock.inputValue( ia_windSpread, & status); const float windSpread = windSpreadHandle.asFloat(); CHECK_MSTATUS( status ); MDataHandle clockHandle = io_dataBlock.inputValue( ia_clock, & status); const float clock = clockHandle.asLong(); CHECK_MSTATUS( status ); //Colours //------------------- MFloatVector& grassBaseColour1Vec = io_dataBlock.inputValue( ia_grassBaseColour1, & status).asFloatVector(); const Vcore::Vec3 grassBaseColour1 = Vec3(grassBaseColour1Vec.x, grassBaseColour1Vec.y, grassBaseColour1Vec.z); CHECK_MSTATUS( status ); MFloatVector& grassTipColour1Vec = io_dataBlock.inputValue( ia_grassTipColour1, & status).asFloatVector(); const Vcore::Vec3 grassTipColour1 = Vec3(grassTipColour1Vec.x, grassTipColour1Vec.y, grassTipColour1Vec.z); CHECK_MSTATUS( status ); MFloatVector& grassBaseColour2Vec = io_dataBlock.inputValue( ia_grassBaseColour2, & status).asFloatVector(); const Vcore::Vec3 grassBaseColour2 = Vec3(grassBaseColour2Vec.x, grassBaseColour2Vec.y, grassBaseColour2Vec.z); CHECK_MSTATUS( status ); MFloatVector& grassTipColour2Vec = io_dataBlock.inputValue( ia_grassTipColour2, & status).asFloatVector(); const Vcore::Vec3 grassTipColour2 = Vec3(grassTipColour2Vec.x, grassTipColour2Vec.y, grassTipColour2Vec.z); CHECK_MSTATUS( status ); char rib[4096]; sprintf( rib, "seed=%d;roughness=%f;planeHeight=%d;planeSize=%d;resolution=%d;gridSize=%d;grassMultiplier=%d;baseWidth=%f;grassSegmentLength=%f;grassNumSegments=%d;windDirectionX=%f;windDirectionY=%f;windDirectionZ=%f;grassBendAmount=%f;windSpread=%f;clock=%d;smooth=%d;grassBaseColour1X=%f;grassBaseColour1Y=%f;grassBaseColour1Z=%f;grassTipColour1X=%f;grassTipColour1Y=%f;grassTipColour1Z=%f;grassBaseColour2X=%f;grassBaseColour2Y=%f;grassBaseColour2Z=%f;grassTipColour2X=%f;grassTipColour2Y=%f;grassTipColour2Z=%f;", (int) seed, (float) roughness, (int) planeHeight, (int) planeSize, (int) rmanResolution , (int) gridSize, (int) grassMultiplier, (float) baseWidth, (float) grassSegmentLength, (int) grassNumSegments, (float) windDirection.x, (float) windDirection.y, (float) windDirection.z, (float) grassBendAmount, (float) windSpread, (int) clock, (int) smooth, (float) grassBaseColour1.x, (float) grassBaseColour1.y, (float) grassBaseColour1.z, (float) grassTipColour1.x, (float) grassTipColour1.y, (float) grassTipColour1.z, (float) grassBaseColour2.x, (float) grassBaseColour2.y, (float) grassBaseColour2.z, (float) grassTipColour2.x, (float) grassTipColour2.y, (float) grassTipColour2.z ); // We must set a value for the plug we have been asked to evaluate, // even if we are not going to use it. We set it in the data-block, // and to set it we use outputValue(). // // Here we are calculating a string value, and that value will // be used by the caller in a "rib-gen" operation - a process in // which a RIB file is generated for Renderman. // // Notice also that strings in Maya or more complicated than numbers. // We need to make a data object for the string data. MFnStringData stringDataFn; MObject stringDataObj = stringDataFn.create( rib, & status ); CHECK_MSTATUS( status ); MDataHandle ribHandle = io_dataBlock.outputValue( i_plug ); ribHandle.set( stringDataObj ); io_dataBlock.setClean( i_plug ); } else { //Shouldn't be here. return MStatus::kSuccess; } }
MStatus meshOpNode::compute( const MPlug& plug, MDataBlock& data ) // // Description: // This method computes the value of the given output plug based // on the values of the input attributes. // // Arguments: // plug - the plug to compute // data - object that provides access to the attributes for this node // { MStatus status = MS::kSuccess; MDataHandle stateData = data.outputValue( state, &status ); MCheckStatus( status, "ERROR getting state" ); // Check for the HasNoEffect/PassThrough flag on the node. // // (stateData is an enumeration standard in all depend nodes) // // (0 = Normal) // (1 = HasNoEffect/PassThrough) // (2 = Blocking) // ... // if( stateData.asShort() == 1 ) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Simply redirect the inMesh to the outMesh for the PassThrough effect // outputData.set(inputData.asMesh()); } else { // Check which output attribute we have been asked to // compute. If this node doesn't know how to compute it, // we must return MS::kUnknownParameter // if (plug == outMesh) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Now, we get the value of the component list and the operation // type and use it to perform the mesh operation on this mesh // MDataHandle inputIDs = data.inputValue( cpList, &status); MCheckStatus(status,"ERROR getting componentList"); MDataHandle opTypeData = data.inputValue( opType, &status); MCheckStatus(status,"ERROR getting opType"); // Copy the inMesh to the outMesh, so you can // perform operations directly on outMesh // outputData.set(inputData.asMesh()); MObject mesh = outputData.asMesh(); // Retrieve the ID list from the component list. // // Note, we use a component list to store the components // because it is more compact memory wise. (ie. comp[81:85] // is smaller than comp[81], comp[82],...,comp[85]) // MObject compList = inputIDs.data(); MFnComponentListData compListFn( compList ); // Get what operation is requested and // what type of component is expected for this operation. MeshOperation operationType = (MeshOperation) opTypeData.asShort(); MFn::Type componentType = meshOpFty::getExpectedComponentType(operationType); unsigned i; int j; MIntArray cpIds; for( i = 0; i < compListFn.length(); i++ ) { MObject comp = compListFn[i]; if( comp.apiType() == componentType ) { MFnSingleIndexedComponent siComp( comp ); for( j = 0; j < siComp.elementCount(); j++ ) cpIds.append( siComp.element(j) ); } } // Set the mesh object and component List on the factory // fmeshOpFactory.setMesh( mesh ); fmeshOpFactory.setComponentList( compList ); fmeshOpFactory.setComponentIDs( cpIds ); fmeshOpFactory.setMeshOperation( operationType ); // Now, perform the meshOp // status = fmeshOpFactory.doIt(); // Mark the output mesh as clean // outputData.setClean(); } else { status = MS::kUnknownParameter; } } return status; }
// // A very simple implementation of validAndSetValue(). No lock // or limit checking on the rocking attribute is done in this method. // If you wish to apply locks and limits to the rocking attribute, you // would follow the approach taken in the rockingTransformCheck example. // Meaning you would implement methods similar to: // * applyRotationLocks(); // * applyRotationLimits(); // * checkAndSetRotation(); // but for the rocking attribute. The method checkAndSetRotation() // would be called below rather than updating the rocking attribute // directly. // MStatus rockingTransformNode::validateAndSetValue(const MPlug& plug, const MDataHandle& handle, const MDGContext& context) { MStatus status = MS::kSuccess; // Make sure that there is something interesting to process. // if (plug.isNull()) return MS::kFailure; MDataBlock block = forceCache(*(MDGContext *)&context); MDataHandle blockHandle = block.outputValue(plug, &status); ReturnOnError(status); MString cachename = block.inputValue( acachename ).asString(); MString meshname = block.inputValue( ameshname ).asString(); /* if ( plug == aRockInX ) { // Update our new rock in x value double rockInX = handle.asDouble(); blockHandle.set(rockInX); rockXValue = rockInX; // Update the custom transformation matrix to the // right rock value. rockingTransformMatrix *ltm = getRockingTransformMatrix(); if (ltm) ltm->setRockInX(rockXValue); else MGlobal::displayError("Failed to get rock transform matrix"); blockHandle.setClean(); // Mark the matrix as dirty so that DG information // will update. dirtyMatrix(); } */ if ( plug == aframe ) { // Update our new rock in x value double rockInX = handle.asDouble(); blockHandle.set(rockInX); rockXValue = rockInX; // Update the custom transformation matrix to the // right rock value. rockingTransformMatrix *ltm = getRockingTransformMatrix(); if (ltm) ltm->setRockInX(rockXValue, cachename, meshname); else MGlobal::displayError("Failed to get rock transform matrix"); blockHandle.setClean(); // Mark the matrix as dirty so that DG information // will update. dirtyMatrix(); } // Allow processing for other attributes return ParentClass::validateAndSetValue(plug, handle, context); }
/* This function gets called by Maya to evaluate the texture. */ MStatus shiftNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus stat; if ((plug != aOutColor) && (plug.parent() != aOutColor)) return MS::kUnknownParameter; MDataHandle colorH; MFloatVector color; MDataHandle shiftH = data.inputValue( aShift, &stat); PERRORfail(stat, "compute getting shift attr"); bool shiftIt = shiftH.asBool(); MDataHandle distH = data.inputValue( aDist, &stat); PERRORfail(stat, "compute getting distance attr"); float distance = distH.asFloat(); MFloatVector clr; if ( shiftIt && distance != 0.0 ) { // first evaluate color at default sample posiiton clr = data.inputValue( aColor ).asFloatVector(); // uv is used by 2d textures // refPointCamera is used by 3d textures MDataHandle refPointCamH = data.inputValue( aRefPointCamera, &stat); PERRORfail(stat, "compute getting refPointCamera attr"); MFloatVector refPC = refPointCamH.asFloatVector(); // get current UV const float2 & oldUV = data.inputValue(aUv).asFloat2(); // shift and set the uv/refPointCamera values so // we can sample around the current uv/refPointCamera MDataHandle outUV = data.outputValue( aUv ); MDataHandle outPC = data.outputValue( aRefPointCamera ); outUV.set( oldUV[0]-distance, oldUV[1] ); outPC.set( refPC.x + distance, refPC.y + distance, refPC.z + distance); colorH = data.inputValue( aColor, &stat); // evaluate at new pos color = colorH.asFloatVector(); clr += color; outUV.set( oldUV[0]+distance, oldUV[1] ); outPC.set( refPC.x - distance, refPC.y + distance, refPC.z + distance); colorH = data.inputValue( aColor, &stat); // evaluate at new pos color = colorH.asFloatVector(); clr += color; outUV.set( oldUV[0], oldUV[1]-distance ); outPC.set( refPC.x + distance, refPC.y - distance, refPC.z + distance); colorH = data.inputValue( aColor, &stat); // evaluate at new pos color = colorH.asFloatVector(); clr += color; outUV.set( oldUV[0], oldUV[1]+distance ); outPC.set( refPC.x - distance, refPC.y - distance, refPC.z + distance); colorH = data.inputValue( aColor, &stat); // evaluate at new pos color = colorH.asFloatVector(); clr += color; clr /= 5.0; // average the colors from all locations // set sample data back to original values outUV.set( oldUV[0], oldUV[1] ); outPC.set( refPC.x, refPC.y, refPC.z ); } else { colorH = data.inputValue( aColor, &stat); clr = colorH.asFloatVector(); } MDataHandle outColorHandle = data.outputValue( aOutColor ); MFloatVector& oclr = outColorHandle.asFloatVector(); oclr = clr; outColorHandle.setClean(); return MS::kSuccess; }
// // Calls applyRotationLocks && applyRotationLimits // This method verifies that the passed value can be set on the // rotate plugs. In the base class, limits as well as locking are // checked by this method. // // The compute, validateAndSetValue, and rotateTo functions // all use this method. // MStatus rockingTransformCheckNode::checkAndSetRotation(MDataBlock &block, const MPlug& plug, const MEulerRotation& newRotation, MSpace::Space space ) { const MDGContext context = block.context(); updateMatrixAttrs(context); MStatus status = MS::kSuccess; MEulerRotation outRotation = newRotation; if (context.isNormal()) { // For easy reading. // MPxTransformationMatrix *xformMat = baseTransformationMatrix; // Get the current translation in transform space for // clamping and locking. // MEulerRotation savedRotation = xformMat->eulerRotation(MSpace::kTransform, &status); ReturnOnError(status); // Translate to transform space, since the limit test needs the // values in transform space. The locking test needs the values // in the same space as the savedR value - which is transform // space as well. // status = baseTransformationMatrix->rotateTo(newRotation, space); ReturnOnError(status); outRotation = xformMat->eulerRotation(MSpace::kTransform, &status); ReturnOnError(status); // Now that everything is in the same space, apply limits // and change the value to adhere to plug locking. // outRotation = applyRotationLimits(outRotation, block, &status); ReturnOnError(status); outRotation = applyRotationLocks(outRotation, savedRotation, &status); ReturnOnError(status); // The value that remain is in transform space. // status = xformMat->rotateTo(outRotation, MSpace::kTransform); ReturnOnError(status); // Get the value that was just set. It needs to be in transform // space since it is used to set the datablock values at the // end of this method. Getting the vaolue right before setting // ensures that the transformation matrix and data block will // be synchronized. // outRotation = xformMat->eulerRotation(MSpace::kTransform, &status); ReturnOnError(status); } else { // Get the rotation for clamping and locking. This will get the // rotate value in transform space. // double3 &s3 = block.inputValue(rotate).asDouble3(); MEulerRotation savedRotation(s3[0], s3[1], s3[2]); // Create a local transformation matrix for non-normal context // calculations. // MPxTransformationMatrix *local = createTransformationMatrix(); if (NULL == local) { MGlobal::displayError("rockingTransformCheck::checkAndSetRotation internal error"); return status; } // Fill the newly created transformation matrix. // status = computeLocalTransformation(local, block); if ( MS::kSuccess != status) { delete local; return status; } // Translate the values to transform space. This will allow the // limit and locking tests to work properly. // status = local->rotateTo(newRotation, space); if ( MS::kSuccess != status) { delete local; return status; } outRotation = local->eulerRotation(MSpace::kTransform, &status); if ( MS::kSuccess != status) { delete local; return status; } // Apply limits // outRotation = applyRotationLimits(outRotation, block, &status); if ( MS::kSuccess != status) { delete local; return status; } outRotation = applyRotationLocks(outRotation, savedRotation, &status); if ( MS::kSuccess != status) { delete local; return status; } status = local->rotateTo(outRotation, MSpace::kTransform); if ( MS::kSuccess != status) { delete local; return status; } // Get the rotate value in transform space for placement in the // datablock. // outRotation = local->eulerRotation(MSpace::kTransform, &status); if ( MS::kSuccess != status) { delete local; return status; } delete local; } MDataHandle handle = block.outputValue(plug, &status); if ( MS::kSuccess != status) { return status; } if (plug == rotate) { handle.set(outRotation.x, outRotation.y, outRotation.z); } else if (plug == rotateX) { handle.set(outRotation.x); } else if (plug == rotateY) { handle.set(outRotation.y); } else { handle.set(outRotation.z); } return status; }
MStatus puttyNode::compute( const MPlug& plug, MDataBlock& block ) { MStatus status; if ( plug == aNodeReady ) { // MGlobal::displayInfo("compute"); bool result =false; MString cmdBaseName; // get the source flag MDataHandle dh = block.inputValue(aSource,&status); SYS_ERROR_CHECK(status, "Error getting source data handle\n"); bool source = dh.asBool(); // get the command dh = block.inputValue(aScript,&status); SYS_ERROR_CHECK(status, "Error getting reload script handle\n"); MString script = dh.asString(); if (script == "") { MGlobal::displayError("no script provided!\n"); } else { // chech if script is sourced dh = block.inputValue(aScriptSourced,&status); SYS_ERROR_CHECK(status, "Error getting aScriptSourced data handle\n"); bool scriptSourced = dh.asBool(); // if it's not ready, don't do anything if (!scriptSourced) return MS::kSuccess; else { MCommandResult melResult; // now get the real name of the function and store it in a separate attribute MString cmd="basenameEx \"" + script+"\""; status = MGlobal::executeCommand(cmd,melResult); melResult.getResult(cmdBaseName); result = true; MDataHandle dhCBN = block.outputValue(aCmdBaseName,&status); SYS_ERROR_CHECK(status, "Error getting aCmdBaseName data handle\n"); dhCBN.set(cmdBaseName); dhCBN.setClean(); // see if an interface function is present, if yes, execute it cmd= "if(exists(\"" + cmdBaseName +".interface\")) {"; cmd+= "string $attr[] = `deleteAttr -q " +name()+"`; string $a;"; cmd+="for($a in $attr) deleteAttr (\""+name()+".\"+$a);"; cmd+= cmdBaseName +".interface(\"" +name()+"\");}"; status = MGlobal::executeCommand(cmd); } } // check the current status // set the result MDataHandle dhNodeReady = block.outputValue(aNodeReady,&status); SYS_ERROR_CHECK(status, "Error getting reload data handle\n"); dhNodeReady.set(result); dhNodeReady.setClean(); return MS::kSuccess; } else if (plug==aScriptSourced) { // this part of the function sources the script // try to source the script // cerr << "\nsource"; MStatus status; bool result = true; // get the source flag MDataHandle dh = block.inputValue(aSource,&status); SYS_ERROR_CHECK(status, "Error getting source data handle\n"); bool source = dh.asBool(); // get the script dh = block.inputValue(aScript,&status); SYS_ERROR_CHECK(status, "Error getting reload script handle\n"); MString script = dh.asString(); MString cmd = "source \"" + script+"\""; MCommandResult melResult; status = MGlobal::executeCommand(cmd,melResult); if (status.error()) { MGlobal::displayError( "Error sourcing mel script, please check the function you provided is valid!"); result = false; } // set the result MDataHandle dhScriptSourced = block.outputValue(aScriptSourced,&status); SYS_ERROR_CHECK(status, "Error getting ScriptSourced data handle\n"); dhScriptSourced.set(result); dhScriptSourced.setClean(); return MS::kSuccess; } return MS::kUnknownParameter; }
MStatus ProxyViz::compute( const MPlug& plug, MDataBlock& block ) { if(!m_enableCompute) return MS::kSuccess; if( plug == outValue ) { updateWorldSpace(thisMObject() ); MStatus status; ExampVox * defBox = plantExample(0); defBox->setGeomSizeMult(block.inputValue(aradiusMult).asFloat() ); defBox->setGeomBox(block.inputValue(abboxminx).asFloat(), block.inputValue(abboxminy).asFloat(), block.inputValue(abboxminz).asFloat(), block.inputValue(abboxmaxx).asFloat(), block.inputValue(abboxmaxy).asFloat(), block.inputValue(abboxmaxz).asFloat()); float grdsz = defBox->geomExtent() * 32.f ; if(grdsz < 32.f) { AHelper::Info<float>(" ProxyViz input box is too small", grdsz); grdsz = 32.f; AHelper::Info<float>(" trancated to", grdsz); } if(m_toSetGrid) { m_toSetGrid = false; resetGrid(grdsz); } if(_firstLoad) { /// internal cache only, initializing from external cache is obsolete if(!loadInternal(block) ) std::cout<<"\n ERROR proxviz cannot load internal cache"; _firstLoad = 0; } if(!m_toCheckVisibility) { MArrayDataHandle groundMeshArray = block.inputArrayValue(agroundMesh ); MArrayDataHandle groundSpaceArray = block.inputArrayValue(agroundSpace ); /// in case no ground is connected if(updateGround(groundMeshArray, groundSpaceArray )) { moveWithGround(); AHelper::Info<std::string>(" ProxyViz ground ", groundBuildLog() ); } } if(!m_hasParticle) { block.setClean(plug); return MS::kSuccess; } const int ngroups = block.inputValue(agroupcount).asInt(); MDataHandle hdata = block.inputValue(outPositionPP, &status); MFnVectorArrayData farray(hdata.data(), &status); if(!status) { MGlobal::displayInfo("proxy viz is not properly connected to a particle system"); block.setClean(plug); return MS::kSuccess; } MDataHandle scaledata = block.inputValue(outScalePP, &status); MFnVectorArrayData scalearray(scaledata.data(), &status); if(!status) { MGlobal::displayInfo("proxy viz is not properly connected to a particle system"); block.setClean(plug); return MS::kSuccess; } MDataHandle rotatedata = block.inputValue(outRotationPP, &status); MFnVectorArrayData rotatearray(rotatedata.data(), &status); if(!status) { MGlobal::displayInfo("proxy viz is not properly connected to a particle system"); block.setClean(plug); return MS::kSuccess; } MDataHandle replaceData = block.inputValue(outReplacePP, &status); MFnDoubleArrayData replaceArrayFn(replaceData.data(), &status); if(!status) { MGlobal::displayInfo("proxy viz is not properly connected to a particle system, needs userScalarPP"); block.setClean(plug); return MS::kSuccess; } MVectorArray outPosArray = farray.array(); MVectorArray outScaleArray = scalearray.array(); MVectorArray outRotateArray = rotatearray.array(); MDoubleArray outReplaceArray = replaceArrayFn.array(); if( outPosArray.length() < 1) { block.setClean(plug); return MS::kSuccess; } computePPAttribs(outPosArray, outRotateArray, outScaleArray, outReplaceArray, ngroups); float result = outPosArray.length(); MDataHandle outputHandle = block.outputValue( outValue ); outputHandle.set( result ); block.setClean(plug); } if(plug == outValue1) { MArrayDataHandle hArray = block.inputArrayValue(ainexamp); updateExamples(hArray); float result = 91.f; MDataHandle outputHandle = block.outputValue( outValue1 ); outputHandle.set( result ); block.setClean(plug); } return MS::kSuccess; }
MStatus testNpassiveNode::compute(const MPlug &plug, MDataBlock &data) { MStatus stat; if ( plug == currentState ) { // get old positions and numVerts // if num verts is different, reset topo and zero velocity // if num verts is the same, compute new velocity int ii,jj; // initialize MnCloth MObject inMeshObj = data.inputValue(inputGeom).asMesh(); MFnMesh inputMesh(inMeshObj); unsigned int numVerts = 0; numVerts = inputMesh.numVertices(); unsigned int prevNumVerts; fNObject.getNumVertices(prevNumVerts); if(numVerts != prevNumVerts) { int numPolygons = inputMesh.numPolygons(); int * faceVertCounts = new int[numPolygons]; int facesArrayLength = 0; for(ii=0;ii<numPolygons;ii++) { MIntArray verts; inputMesh.getPolygonVertices(ii,verts); faceVertCounts[ii] = verts.length(); facesArrayLength += verts.length(); } int * faces = new int[facesArrayLength]; int currIndex = 0; for(ii=0;ii<numPolygons;ii++) { MIntArray verts; inputMesh.getPolygonVertices(ii,verts); for(jj=0;jj<(int)verts.length();jj++) { faces[currIndex++] = verts[jj]; } } int numEdges = inputMesh.numEdges(); int * edges = new int[2*numEdges]; currIndex = 0; for(ii=0;ii<numEdges;ii++) { int2 edge; inputMesh.getEdgeVertices(ii,edge); edges[currIndex++] = edge[0]; edges[currIndex++] = edge[1]; } // When you are doing the initialization, the first call must to be setTopology(). All other // calls must come after this. fNObject.setTopology(numPolygons, faceVertCounts, faces,numEdges, edges ); delete[] faceVertCounts; delete[] faces; delete[] edges; MFloatPointArray vertexArray; inputMesh.getPoints(vertexArray, MSpace::kWorld); fNObject.setPositions(vertexArray,true); MFloatPointArray velocitiesArray; velocitiesArray.setLength(numVerts); for(ii=0;ii<(int)numVerts;ii++) { velocitiesArray[ii].x = 0.0f; velocitiesArray[ii].y = 0.0f; velocitiesArray[ii].z = 0.0f; velocitiesArray[ii].w = 0.0f; } fNObject.setVelocities(velocitiesArray); } else { MFloatPointArray vertexArray; MFloatPointArray prevVertexArray; inputMesh.getPoints(vertexArray, MSpace::kWorld); fNObject.getPositions(prevVertexArray); // you may want to get the playback rate for the dt // double dt = MAnimControl::playbackBy() \ 24.0; // or get the real dt by caching the last eval time double dt = 1.0/24.0; MFloatPointArray velocitiesArray; velocitiesArray.setLength(numVerts); for(ii=0;ii<(int)numVerts;ii++) { velocitiesArray[ii].x = (float)( (vertexArray[ii].x - prevVertexArray[ii].x)/dt); velocitiesArray[ii].y = (float)( (vertexArray[ii].y - prevVertexArray[ii].y)/dt); velocitiesArray[ii].z = (float)( (vertexArray[ii].x - prevVertexArray[ii].z)/dt); velocitiesArray[ii].w = 0.0f; } fNObject.setVelocities(velocitiesArray); fNObject.setPositions(vertexArray,true); } // in real life, you'd get these attribute values each frame and set them fNObject.setThickness(0.1f); fNObject.setBounce(0.0f); fNObject.setFriction(0.1f); fNObject.setCollisionFlags(true, true, true); MFnNObjectData outputData; MObject mayaNObjectData = outputData.create(); outputData.setObject(mayaNObjectData); outputData.setObjectPtr(&fNObject); outputData.setCached(false); MDataHandle currStateOutputHandle = data.outputValue(currentState); currStateOutputHandle.set(outputData.object()); } if ( plug == startState ) { int ii,jj; // initialize MnCloth MObject inMeshObj = data.inputValue(inputGeom).asMesh(); MFnMesh inputMesh(inMeshObj); int numPolygons = inputMesh.numPolygons(); int * faceVertCounts = new int[numPolygons]; int facesArrayLength = 0; for(ii=0;ii<numPolygons;ii++) { MIntArray verts; inputMesh.getPolygonVertices(ii,verts); faceVertCounts[ii] = verts.length(); facesArrayLength += verts.length(); } int * faces = new int[facesArrayLength]; int currIndex = 0; for(ii=0;ii<numPolygons;ii++) { MIntArray verts; inputMesh.getPolygonVertices(ii,verts); for(jj=0;jj<(int)verts.length();jj++) { faces[currIndex++] = verts[jj]; } } int numEdges = inputMesh.numEdges(); int * edges = new int[2*numEdges]; currIndex = 0; for(ii=0;ii<numEdges;ii++) { int2 edge; inputMesh.getEdgeVertices(ii,edge); edges[currIndex++] = edge[0]; edges[currIndex++] = edge[1]; } // When you are doing the initialization, the first call must to be setTopology(). All other // calls must come after this. fNObject.setTopology(numPolygons, faceVertCounts, faces,numEdges, edges ); delete[] faceVertCounts; delete[] faces; delete[] edges; unsigned int numVerts = 0; numVerts = inputMesh.numVertices(); MFloatPointArray vertexArray; inputMesh.getPoints(vertexArray, MSpace::kWorld); fNObject.setPositions(vertexArray,true); MFloatPointArray velocitiesArray; velocitiesArray.setLength(numVerts); for(ii=0;ii<(int)numVerts;ii++) { velocitiesArray[ii].x = 0.0f; velocitiesArray[ii].y = 0.0f; velocitiesArray[ii].z = 0.0f; velocitiesArray[ii].w = 0.0f; } fNObject.setVelocities(velocitiesArray); fNObject.setThickness(0.1f); fNObject.setBounce(0.0f); fNObject.setFriction(0.1f); fNObject.setCollisionFlags(true, true, true); MFnNObjectData outputData; MObject mayaNObjectData = outputData.create(); outputData.setObject(mayaNObjectData); outputData.setObjectPtr(&fNObject); outputData.setCached(false); MDataHandle startStateOutputHandle = data.outputValue(startState); startStateOutputHandle.set(outputData.object()); } else { stat = MS::kUnknownParameter; } return stat; }
MStatus NBuddyEMPSaverNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus status; if (plug == _outTrigger) { MDataHandle outputPathHdl = data.inputValue( _empOutputPath, &status ); NM_CheckMStatus( status, "Failed to get the output path handle"); MString outputPath = outputPathHdl.asString(); // Get the input time MDataHandle timeHdl = data.inputValue( _time, &status ); NM_CheckMStatus( status, "Failed to get time handle"); MTime time = timeHdl.asTime(); // Get the frame padding MDataHandle framePaddingHdl = data.inputValue( _framePadding, &status ); NM_CheckMStatus( status, "Failed to get the framePadding handle"); int numPad = framePaddingHdl.asInt(); // Get the frame padding MDataHandle timeStepHdl = data.inputValue( _timeStep, &status ); NM_CheckMStatus( status, "Failed to get the timeStep handle"); int timeStep = timeStepHdl.asInt(); // Get the time in frames int frameNr = (int)floor( time.as( time.uiUnit() ) ); //Create the writer, givin it the time index in seconds Nb::EmpWriter* writer = new Nb::EmpWriter( "", outputPath.asChar(), // absolute fullpath of emp frameNr, // frame timeStep, // timestep numPad, // zero-padding time.as( MTime::kSeconds ) // emp timestamp ); // Then get the inputBodies MArrayDataHandle inBodyArrayData = data.inputArrayValue( _inBodies, &status ); NM_CheckMStatus( status, "Failed to create get inBodyArrayData handle"); // Loop the input in the inBody multi plug unsigned int numBodies = inBodyArrayData.elementCount(); if ( numBodies > 0 ) { //Jump to the first element in the array inBodyArrayData.jumpToArrayElement(0); //Loop all the body inputs and add them to the empWriter for ( unsigned int i(0); i < numBodies; ++i) { MDataHandle bodyDataHnd = inBodyArrayData.inputValue( &status ); MFnPluginData dataFn(bodyDataHnd.data()); //Get naiad body from datatype naiadBodyData * bodyData = (naiadBodyData*)dataFn.data( &status ); if ( bodyData && bodyData->nBody() ) { //Add body to writer try{ Nb::String channels("*.*"); writer->write(bodyData->nBody(),channels); } catch(std::exception& e) { std::cerr << "NBuddyEMPSaverNode::compute() " << e.what() << std::endl; } } else std::cerr << "NBuddyEMPSaverNode::compute() :: No body in input " << inBodyArrayData.elementIndex() << std::endl; //Next body in the input multi inBodyArrayData.next(); } } try{ writer->close(); // Get rid of the writer object delete writer; } catch(std::exception& e) { std::cerr << "NBuddyEMPSaverNode::compute() " << e.what() << std::endl; } //Set the output to be clean indicating that we have saved out the file MDataHandle outTriggerHnd = data.outputValue( _outTrigger, &status ); outTriggerHnd.set(true); data.setClean( plug ); } return status; }
MStatus PtexUVNode::compute( const MPlug &plug, MDataBlock &data ) { MStatus stat; bool hasNoEffect = false; MDataHandle inMeshHnd = data.inputValue( inMesh ); MDataHandle outMeshHnd = data.outputValue( outMesh ); MDataHandle stateHnd = data.inputValue( state ); int state = stateHnd.asInt(); if( state == 1 ) // No Effect/Pass through hasNoEffect = true; if( !hasNoEffect && plug == outMesh ) { MObject inMeshData = inMeshHnd.asMesh(); if( !hasNoEffect ) { MFnMeshData meshDataFn; MObject newMeshData = meshDataFn.create(); MFnMesh inMeshFn( inMeshData ); inMeshFn.copy( inMeshData, newMeshData ); MFnMesh meshFn( newMeshData ); MPointArray pts; meshFn.getPoints( pts ); MStringArray uvSetNames; meshFn.getUVSetNames( uvSetNames ); unsigned int defaultUvSetCount = (unsigned int)uvSetNames.length(); int num_faces = meshFn.numPolygons(); MIntArray uvCounts; uvCounts.setLength( num_faces ); for ( int i_f = 0; i_f < num_faces; i_f++ ) { int deg = meshFn.polygonVertexCount( i_f ); uvCounts[ i_f ] = deg; if ( deg != 4 ) { return MS::kFailure; } } MIntArray uvIds; uvIds.setLength( 4 * num_faces ); if ( defaultUvSetCount == 1 ) { int currentUVCount = meshFn.numUVs( uvSetNames[0] ); MFloatArray us, vs; us.setLength( 4 * num_faces ); vs.setLength( 4 * num_faces ); for ( int i_f = 0; i_f < num_faces; i_f++ ) { float f = (float)i_f; uvIds[ 4 * i_f + 0 ] = 4 * i_f + 0; uvIds[ 4 * i_f + 1 ] = 4 * i_f + 1; uvIds[ 4 * i_f + 2 ] = 4 * i_f + 2; uvIds[ 4 * i_f + 3 ] = 4 * i_f + 3; us[ 4 * i_f + 0 ] = (float)i_f; vs[ 4 * i_f + 0 ] = 0.0f; us[ 4 * i_f + 1 ] = (float)i_f + 1.0f; vs[ 4 * i_f + 1 ] = 0.0f; us[ 4 * i_f + 2 ] = (float)i_f + 1.0f; vs[ 4 * i_f + 2 ] = 1.0f; us[ 4 * i_f + 3 ] = (float)i_f; vs[ 4 * i_f + 3 ] = 1.0f; } stat = meshFn.setUVs( us, vs, &uvSetNames[0] ); stat = meshFn.assignUVs( uvCounts, uvIds, &uvSetNames[0] ); } meshFn.updateSurface(); meshFn.syncObject(); outMeshHnd.set( newMeshData ); } } else return MS::kUnknownParameter; if( hasNoEffect ) outMeshHnd.set( inMeshHnd.asMesh() ); data.setClean( plug ); return stat; }
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 AlembicCurvesLocatorNode::compute(const MPlug &plug, MDataBlock &dataBlock) { ESS_PROFILE_SCOPE("AlembicCurvesLocatorNode::compute"); MStatus status; // update the frame number to be imported double inputTime = dataBlock.inputValue(mTimeAttr).asTime().as(MTime::kSeconds); MString &fileName = dataBlock.inputValue(mFileNameAttr).asString(); MString &identifier = dataBlock.inputValue(mIdentifierAttr).asString(); AbcG::ICurves obj; // check if we have the file if (fileName != mFileName || identifier != mIdentifier) { mSchema.reset(); if (fileName != mFileName) { delRefArchive(mFileName); mFileName = fileName; addRefArchive(mFileName); } mIdentifier = identifier; // get the object from the archive Abc::IObject iObj = getObjectFromArchive(mFileName, identifier); if (!iObj.valid()) { MGlobal::displayWarning("[ExocortexAlembic] Identifier '" + identifier + "' not found in archive '" + mFileName + "'."); return MStatus::kFailure; } obj = AbcG::ICurves(iObj, Abc::kWrapExisting); if (!obj.valid()) { MGlobal::displayWarning("[ExocortexAlembic] Identifier '" + identifier + "' in archive '" + mFileName + "' is not a Curves."); return MStatus::kFailure; } mSchema = obj.getSchema(); } if (!mSchema.valid()) { return MStatus::kFailure; } // get the sample SampleInfo sampleInfo = getSampleInfo(inputTime, mSchema.getTimeSampling(), mSchema.getNumSamples()); // check if we have to do this at all if (mNbCurves == 0 || mLastSampleInfo.floorIndex != sampleInfo.floorIndex || mLastSampleInfo.ceilIndex != sampleInfo.ceilIndex) { AbcG::ICurvesSchema::Sample sample; AbcG::ICurvesSchema::Sample sample2; mSchema.get(sample, sampleInfo.floorIndex); if (sampleInfo.alpha != 0.0) { mSchema.get(sample2, sampleInfo.ceilIndex); } // update the indices Abc::P3fArraySamplePtr samplePos = sample.getPositions(); if (mNbCurves != sample.getNumCurves() || mNbVertices != samplePos->size()) { mNbCurves = (unsigned int)sample.getNumCurves(); mNbVertices = (unsigned int)samplePos->size(); Abc::Int32ArraySamplePtr nbVertices = sample.getCurvesNumVertices(); mIndices.clear(); unsigned int offset = 0; for (unsigned int i = 0; i < mNbCurves; i++) { unsigned int verticesPerCurve = nbVertices->get()[i]; for (unsigned j = 0; j < verticesPerCurve - 1; j++) { mIndices.push_back(offset); offset++; mIndices.push_back(offset); } offset++; } } if (mPositions.size() != samplePos->size()) { mPositions.resize(samplePos->size()); } // check if we need to interpolate bool done = false; mBoundingBox.clear(); if (sampleInfo.alpha != 0.0) { Abc::P3fArraySamplePtr samplePos2 = sample2.getPositions(); if (samplePos->size() == samplePos2->size()) { float alpha = float(sampleInfo.alpha); float ialpha = 1.0f - alpha; for (unsigned int i = 0; i < samplePos->size(); i++) { mPositions[i].x = ialpha * samplePos->get()[i].x + alpha * samplePos2->get()[i].x; mPositions[i].y = ialpha * samplePos->get()[i].y + alpha * samplePos2->get()[i].y; mPositions[i].z = ialpha * samplePos->get()[i].z + alpha * samplePos2->get()[i].z; mBoundingBox.expand( MPoint(mPositions[i].x, mPositions[i].y, mPositions[i].z)); } done = true; } } if (!done) { for (unsigned int i = 0; i < samplePos->size(); i++) { mPositions[i].x = samplePos->get()[i].x; mPositions[i].y = samplePos->get()[i].y; mPositions[i].z = samplePos->get()[i].z; mBoundingBox.expand( MPoint(mPositions[i].x, mPositions[i].y, mPositions[i].z)); } } // get the colors // mColors.clear(); Abc::IC4fArrayProperty propColor; if (getArbGeomParamPropertyAlembic(obj, "color", propColor)) { mColors.clear(); SampleInfo colorSampleInfo = getSampleInfo( inputTime, propColor.getTimeSampling(), propColor.getNumSamples()); Abc::C4fArraySamplePtr sampleColor = propColor.getValue(colorSampleInfo.floorIndex); mColors.resize(mPositions.size()); if (sampleColor->size() == 1) { for (unsigned int i = 0; i < (unsigned int)mColors.size(); i++) { mColors[i].r = sampleColor->get()[0].r; mColors[i].g = sampleColor->get()[0].g; mColors[i].b = sampleColor->get()[0].b; mColors[i].a = sampleColor->get()[0].a; } } else if (sampleColor->size() == mPositions.size()) { for (unsigned int i = 0; i < sampleColor->size(); i++) { mColors[i].r = sampleColor->get()[i].r; mColors[i].g = sampleColor->get()[i].g; mColors[i].b = sampleColor->get()[i].b; mColors[i].a = sampleColor->get()[i].a; } } else if (sampleColor->size() == mNbCurves) { Abc::Int32ArraySamplePtr nbVertices = sample.getCurvesNumVertices(); unsigned int offset = 0; for (unsigned int i = 0; i < nbVertices->size(); i++) { for (unsigned j = 0; j < (unsigned int)nbVertices->get()[i]; j++) { mColors[offset].r = sampleColor->get()[i].r; mColors[offset].g = sampleColor->get()[i].g; mColors[offset].b = sampleColor->get()[i].b; mColors[offset].a = sampleColor->get()[i].a; offset++; } } } } } mLastSampleInfo = sampleInfo; MDataHandle outSent = dataBlock.outputValue(mSentinelAttr); // increment, this tells the draw routine that the display list needs to be // regenerated outSent.set((mSent + 1 % 10)); dataBlock.setClean(mSentinelAttr); return MStatus::kSuccess; }
MStatus DA_GridGenerator::compute(const MPlug &plug, MDataBlock &data) { MStatus stat; if (plug != aOutDynamicArray) return MS::kFailure; // // Control Inputs // double dWidth = data.inputValue(aWidth).asDouble(); double dHeight = data.inputValue(aHeight).asDouble(); int iResolutionX = data.inputValue(aResolutionX).asInt(); int iResolutionY = data.inputValue(aResolutionY).asInt(); short ePattern = data.inputValue(aPattern).asShort(); // Create output MFnArrayAttrsData fnOutDynamicArray; fnOutDynamicArray.create(); // Create position data MVectorArray outPositionPP = fnOutDynamicArray.vectorArray("position"); // // Create grid // double xOffset = dWidth / ((double)iResolutionX - 1); double yOffset = dHeight / ((double)iResolutionY - 1); // Keep brick pattern in range if (ePattern == 1) xOffset -= (xOffset/2) / double(iResolutionX); if (ePattern == 2) yOffset -= (yOffset/2) / double(iResolutionY); // Generate grid for(int i = 0; i < iResolutionX; i++) { for(int j = 0; j < iResolutionY; j++) { MVector position; position.x = -dWidth / 2; position.y = 0; position.z = -dHeight / 2; // Pattern offset if (ePattern == 1) position.x += (xOffset/2) * double(j % 2); if (ePattern == 2) position.z += (yOffset/2) * double(i % 2); position.x += xOffset * i; position.z += yOffset * j; outPositionPP.append( position ); } } // // Set output data // MDataHandle outArray = data.outputValue(aOutDynamicArray); outArray.set(fnOutDynamicArray.object()); // Set plug to clean data.setClean(aOutDynamicArray); // Done return MS::kSuccess; }
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; }
MStatus MayaPolySmooth::compute( const MPlug& plug, MDataBlock& data ) { MStatus status; // Check which output attribute we have been asked to compute. If this // node doesn't know how to compute it, we must return // MS::kUnknownParameter. // if( plug == a_output ) { bool createdSubdMesh = false; int subdivisionLevel = data.inputValue(a_subdivisionLevels).asInt(); short stateH = data.inputValue(state).asShort(); if ((subdivisionLevel > 0) and (stateH !=1)) { // == Retrieve input mesh ==================================== // Get attr values MObject inMeshObj = data.inputValue(a_inputPolymesh).asMesh(); short vertBoundaryMethod = data.inputValue(a_vertBoundaryMethod).asShort(); short fvarBoundaryMethod = data.inputValue(a_fvarBoundaryMethod).asShort(); bool fvarPropCorners = data.inputValue(a_fvarPropagateCorners).asBool(); bool smoothTriangles = data.inputValue(a_smoothTriangles).asBool(); short creaseMethodVal = data.inputValue(a_creaseMethod).asShort(); // == Get Mesh Functions and Iterators ========================== MFnMeshData inMeshDat(inMeshObj); MFnMesh inMeshFn(inMeshObj, &status); MCHECKERR(status, "ERROR getting inMeshFn\n"); MItMeshPolygon inMeshItPolygon(inMeshObj, &status); MCHECKERR(status, "ERROR getting inMeshItPolygon\n"); // Convert attr values to OSD enums OpenSubdiv::Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK; // == Create Far topology ========================== OpenSubdiv::Sdc::Options options; options.SetVtxBoundaryInterpolation(ConvertMayaVtxBoundary(vertBoundaryMethod)); options.SetFVarLinearInterpolation(ConvertMayaFVarBoundary(fvarBoundaryMethod, fvarPropCorners)); options.SetCreasingMethod(creaseMethodVal ? OpenSubdiv::Sdc::Options::CREASE_CHAIKIN : OpenSubdiv::Sdc::Options::CREASE_UNIFORM); options.SetTriangleSubdivision(smoothTriangles ? OpenSubdiv::Sdc::Options::TRI_SUB_SMOOTH : OpenSubdiv::Sdc::Options::TRI_SUB_CATMARK); // Storage for face-varying values (UV sets, vertex colors...) std::vector<MFloatArray> uvSet_uCoords; std::vector<MFloatArray> uvSet_vCoords; std::vector<MColorArray> colorSet_colors; bool hasUVs = false, hasColors = false; float maxCreaseSharpness=0.0f; OpenSubdiv::Far::TopologyRefiner * refiner = gatherTopology( inMeshFn, inMeshItPolygon, type, options, &hasUVs, &hasColors, uvSet_uCoords, uvSet_vCoords, colorSet_colors, &maxCreaseSharpness); assert(refiner); // == Refine & Interpolate ========================== refiner->RefineUniform(OpenSubdiv::Far::TopologyRefiner::UniformOptions(subdivisionLevel)); // Prepare vertex information Vertex const * initialVerts = reinterpret_cast<Vertex const *>(inMeshFn.getRawPoints(&status)); std::vector<Vertex> refinedVerts( refiner->GetNumVerticesTotal() - refiner->GetLevel(0).GetNumVertices()); Vertex const * srcVerts = &initialVerts[0]; Vertex * dstVerts = &refinedVerts[0]; // Verify the refiner has the correct number of values // needed to interpolate the different channels int numInitialUVs = refiner->GetLevel(0).GetNumFVarValues(CHANNELUV); int numInitialColors = refiner->GetLevel(0).GetNumFVarValues(CHANNELCOLOR); if (hasUVs && numInitialUVs <= 0) { hasUVs = false; MGlobal::displayError("Model with incorrect data, the UV channel will not be interpolated."); } if (hasColors && numInitialColors <= 0) { hasColors = false; MGlobal::displayError("Model with incorrect data, the color channel will not be interpolated."); } // Prepare UV information if needed std::vector<FVarVertexUV> initialUVs, refinedUVs; FVarVertexUV const * srcUV = NULL; FVarVertexUV * dstUV = NULL; if(hasUVs) { initialUVs.resize(numInitialUVs); refinedUVs.resize(refiner->GetNumFVarValuesTotal(CHANNELUV)); for (int i=0; i<numInitialUVs; ++i) { initialUVs[i].u = uvSet_uCoords[0][i]; initialUVs[i].v = uvSet_vCoords[0][i]; } srcUV = &initialUVs[0]; dstUV = &refinedUVs[0]; } // Prepare color information if needed std::vector<FVarVertexColor> initialColors, refinedColors; FVarVertexColor const * srcColor = NULL; FVarVertexColor * dstColor = NULL; if(hasColors) { initialColors.resize(numInitialColors); refinedColors.resize(refiner->GetNumFVarValuesTotal(CHANNELCOLOR)); for (int i=0; i<numInitialColors; ++i) { initialColors[i].r = colorSet_colors[0][i].r; initialColors[i].g = colorSet_colors[0][i].g; initialColors[i].b = colorSet_colors[0][i].b; initialColors[i].a = colorSet_colors[0][i].a; } srcColor = &initialColors[0]; dstColor = &refinedColors[0]; } // Interpolate the vertices and the different channels OpenSubdiv::Far::PrimvarRefiner primvarRefiner(*refiner); for (int level = 1; level <= subdivisionLevel; ++level) { // Interpolate vertices primvarRefiner.Interpolate(level, srcVerts, dstVerts); srcVerts = dstVerts; dstVerts += refiner->GetLevel(level).GetNumVertices(); // Interpolate the uv set if(hasUVs) { primvarRefiner.InterpolateFaceVarying(level, srcUV, dstUV, CHANNELUV); srcUV = dstUV; dstUV += refiner->GetLevel(level).GetNumFVarValues(CHANNELUV); } // Interpolate any color set if(hasColors) { primvarRefiner.InterpolateFaceVarying(level, srcColor, dstColor, CHANNELCOLOR); srcColor = dstColor; dstColor += refiner->GetLevel(level).GetNumFVarValues(CHANNELCOLOR); } } // == Convert subdivided OpenSubdiv mesh to MFnMesh Data outputMesh ============= // Create New Mesh Data Object MFnMeshData newMeshData; MObject newMeshDataObj = newMeshData.create(&status); MCHECKERR(status, "ERROR creating outputData"); // Create out mesh status = convertToMayaMeshData(*refiner, refinedVerts, hasUVs, refinedUVs, hasColors, refinedColors, inMeshFn, newMeshDataObj); MCHECKERR(status, "ERROR convertOsdFarToMayaMesh"); // Propagate objectGroups from inMesh to outMesh (for per-facet shading, etc) status = createSmoothMesh_objectGroups(inMeshFn, inMeshDat, newMeshData, subdivisionLevel, refiner->GetLevel(subdivisionLevel).GetNumFaces()); // Write to output plug MDataHandle outMeshH = data.outputValue(a_output, &status); MCHECKERR(status, "ERROR getting polygon data handle\n"); outMeshH.set(newMeshDataObj); int isolation = std::min(10,(int)ceil(maxCreaseSharpness)+1); data.outputValue(a_recommendedIsolation).set(isolation); // == Cleanup OSD ============================================ // REVISIT: Re-add these deletes delete refiner; // note that the subd mesh was created (see the section below if !createdSubdMesh) createdSubdMesh = true; } // Pass-through inMesh to outMesh if not created the subd mesh if (!createdSubdMesh) { MDataHandle outMeshH = data.outputValue(a_output, &status); status = outMeshH.copy(data.outputValue(a_inputPolymesh, &status)); MCHECKERR(status, "ERROR getting polygon data handle\n"); } // Clean up Maya Plugs data.setClean(plug); } else { // Unhandled parameter in this compute function, so return MS::kUnknownParameter // so it is handled in a parent compute() function. return MS::kUnknownParameter; } return MS::kSuccess; }
MStatus dynExprField::compute(const MPlug& plug, MDataBlock& block) // // Descriptions: // compute output force. // { MStatus status; if( !(plug == mOutputForce) ) return( MS::kUnknownParameter ); // get the logical index of the element this plug refers to. // int multiIndex = plug.logicalIndex( &status ); McheckErr(status, "ERROR in plug.logicalIndex.\n"); // Get input data handle, use outputArrayValue since we do not // want to evaluate both inputs, only the one related to the // requested multiIndex. Evaluating both inputs at once would cause // a dependency graph loop. MArrayDataHandle hInputArray = block.outputArrayValue( mInputData, &status ); McheckErr(status,"ERROR in hInputArray = block.outputArrayValue().\n"); status = hInputArray.jumpToElement( multiIndex ); McheckErr(status, "ERROR: hInputArray.jumpToElement failed.\n"); // get children of aInputData. MDataHandle hCompond = hInputArray.inputValue( &status ); McheckErr(status, "ERROR in hCompond=hInputArray.inputValue\n"); MDataHandle hPosition = hCompond.child( mInputPositions ); MObject dPosition = hPosition.data(); MFnVectorArrayData fnPosition( dPosition ); MVectorArray points = fnPosition.array( &status ); McheckErr(status, "ERROR in fnPosition.array(), not find points.\n"); // Comment out the following since velocity, and mass are // not needed in this field. // // MDataHandle hVelocity = hCompond.child( mInputVelocities ); // MObject dVelocity = hVelocity.data(); // MFnVectorArrayData fnVelocity( dVelocity ); // MVectorArray velocities = fnVelocity.array( &status ); // McheckErr(status, "ERROR in fnVelocity.array(), not find velocities.\n"); // // MDataHandle hMass = hCompond.child( mInputMass ); // MObject dMass = hMass.data(); // MFnDoubleArrayData fnMass( dMass ); // MDoubleArray masses = fnMass.array( &status ); // McheckErr(status, "ERROR in fnMass.array(), not find masses.\n"); // The attribute mInputPPData contains the attribute in an array form // parpared by the particleShape if the particleShape has per particle // attribute fieldName_attrName. // // Suppose a field with the name dynExprField1 is connecting to // particleShape1, and the particleShape1 has per particle float attribute // dynExprField1_magnitude and vector attribute dynExprField1_direction, // then hInputPPArray will contains a MdoubleArray with the corresponding // name "magnitude" and a MvectorArray with the name "direction". This // is a mechanism to allow the field attributes being driven by dynamic // expression. MArrayDataHandle mhInputPPData = block.inputArrayValue( mInputPPData, &status ); McheckErr(status,"ERROR in mhInputPPData = block.inputArrayValue().\n"); status = mhInputPPData.jumpToElement( multiIndex ); McheckErr(status, "ERROR: mhInputPPArray.jumpToElement failed.\n"); MDataHandle hInputPPData = mhInputPPData.inputValue( &status ); McheckErr(status, "ERROR in hInputPPData = mhInputPPData.inputValue\n"); MObject dInputPPData = hInputPPData.data(); MFnArrayAttrsData inputPPArray( dInputPPData ); MDataHandle hOwnerPPData = block.inputValue( mOwnerPPData, &status ); McheckErr(status, "ERROR in hOwnerPPData = block.inputValue\n"); MObject dOwnerPPData = hOwnerPPData.data(); MFnArrayAttrsData ownerPPArray( dOwnerPPData ); const MString magString("magnitude"); MFnArrayAttrsData::Type doubleType(MFnArrayAttrsData::kDoubleArray); bool arrayExist; MDoubleArray magnitudeArray; arrayExist = inputPPArray.checkArrayExist(magString, doubleType, &status); // McheckErr(status, "ERROR in checkArrayExist(magnitude)\n"); if(arrayExist) { magnitudeArray = inputPPArray.getDoubleData(magString, &status); // McheckErr(status, "ERROR in inputPPArray.doubleArray(magnitude)\n"); } MDoubleArray magnitudeOwnerArray; arrayExist = ownerPPArray.checkArrayExist(magString, doubleType, &status); // McheckErr(status, "ERROR in checkArrayExist(magnitude)\n"); if(arrayExist) { magnitudeOwnerArray = ownerPPArray.getDoubleData(magString, &status); // McheckErr(status, "ERROR in ownerPPArray.doubleArray(magnitude)\n"); } const MString dirString("direction"); MFnArrayAttrsData::Type vectorType(MFnArrayAttrsData::kVectorArray); arrayExist = inputPPArray.checkArrayExist(dirString, vectorType, &status); MVectorArray directionArray; // McheckErr(status, "ERROR in checkArrayExist(direction)\n"); if(arrayExist) { directionArray = inputPPArray.getVectorData(dirString, &status); // McheckErr(status, "ERROR in inputPPArray.vectorArray(direction)\n"); } arrayExist = ownerPPArray.checkArrayExist(dirString, vectorType, &status); MVectorArray directionOwnerArray; // McheckErr(status, "ERROR in checkArrayExist(direction)\n"); if(arrayExist) { directionOwnerArray = ownerPPArray.getVectorData(dirString, &status); // McheckErr(status, "ERROR in ownerPPArray.vectorArray(direction)\n"); } // Compute the output force. // MVectorArray forceArray; apply( block, points.length(), magnitudeArray, magnitudeOwnerArray, directionArray, directionOwnerArray, forceArray ); // get output data handle // MArrayDataHandle hOutArray = block.outputArrayValue( mOutputForce, &status); McheckErr(status, "ERROR in hOutArray = block.outputArrayValue.\n"); MArrayDataBuilder bOutArray = hOutArray.builder( &status ); McheckErr(status, "ERROR in bOutArray = hOutArray.builder.\n"); // get output force array from block. // MDataHandle hOut = bOutArray.addElement(multiIndex, &status); McheckErr(status, "ERROR in hOut = bOutArray.addElement.\n"); MFnVectorArrayData fnOutputForce; MObject dOutputForce = fnOutputForce.create( forceArray, &status ); McheckErr(status, "ERROR in dOutputForce = fnOutputForce.create\n"); // update data block with new output force data. // hOut.set( dOutputForce ); block.setClean( plug ); return( MS::kSuccess ); }
//---------------------------------------------------------------------------- MStatus BPT_InsertVtx::doCompleteCompute( MDataBlock& data ) //---------------------------------------------------------------------------- { SPEED("Berechne EdgeSplit neu: "); MStatus status; MPRINT("MACHE KOMPLETTE BERECHNUNG") MDataHandle inMeshHandle = data.inputValue(IVinMesh); MDataHandle outMeshHandle = data.outputValue(IVoutMesh); //splitCount setzen MDataHandle countHandle = data.inputValue(IVcount); fIVfty.setCount(countHandle.asInt()); MDataHandle spinHandle = data.inputValue(IVspin); fIVfty.setSpin(spinHandle.asInt()); int initialVtxCount; //wird spueueter benueuetigt, um das ValidIndicesArray gleich in der rictigen grueueueuee zu erstellen und zu schreiben //gleich zu beginn muss der MeshPath initialisiert werden, damit der MeshPath an die fty ueuebergeben werden kann // Dies geschieht besser durch die STE - sie ist darauf ausgelegt softTransformationEngine::gatherAttributeObjects(thisMObject()); softTransformationEngine::saveMeshPathes(); fIVfty.setMeshPath(meshPath); MDataHandle rHandle = data.inputValue(IVslideRelative); fIVfty.setRelative(rHandle.asInt()); MDataHandle nRelativeHandle = data.inputValue(IVnormalRelative); fIVfty.setNormalRelative(nRelativeHandle.asInt()); //selection setzen MFnIntArrayData intDataArray; MDataHandle arrayHandle = data.inputValue(IVselEdgeIDs); intDataArray.setObject(arrayHandle.data()); fIVfty.setEdgeIDs( intDataArray.array() ); arrayHandle = data.inputValue(IVselVertIDs); intDataArray.setObject(arrayHandle.data()); fIVfty.setVertIDs(intDataArray.array()); // optionen holen arrayHandle = data.inputValue(IVoptions); intDataArray.setObject(arrayHandle.data()); MIntArray optionsArray(intDataArray.array()); fIVfty.setOptions(optionsArray); MDataHandle slideHandle = data.inputValue(IVslide); fIVfty.setSlide(slideHandle.asDouble()); //whichSide attribute wird nur fueuer SLide selbst verwendet und kann nicht bereits beim command gestetzt werden MObject inMeshRef = inMeshHandle.asMesh(); fIVfty.setMesh(inMeshRef); MFnMesh meshFn(inMeshHandle.asMesh()); initialVtxCount = meshFn.numVertices(); //ACTION try { status = fIVfty.doIt(); } catch(...) { MGlobal::displayError(" An unknown, severe, error occoured.\nIf it happens again in this situation, please write a bug report.\nPlease undo the operation and save your work!"); return MS::kUnknownParameter; } MObject newOutMesh = fIVfty.getMesh(); outMeshHandle.set(newOutMesh); // --------------------- // SOFT TRANSFORMATION // --------------------- // VtxSet setzen - hier reicht es, wenn er einfach die neuen Vtx nimmt softTransformationEngine::setVtxSet(data); //------------SELECTION ROUTINE---------------------- //nur wenn sich spin nicht verueuendert hat, darf ne neue selection gemacht werden - dies wird auch von der IV berueuecksichtigt //die selection wird nur noch einmal ausgefueuehrt, weshalb scriptJobInitiated nicht mehr gesetzt wird vom scriptjob if( optionsArray[6] && !scriptJobInitated && !(meshPath.apiType() == MFn::kInvalid) ) { //auf jeden Fall erstmal die neuen Vertizen holen, damit die anderen prozeduren auch darauf arbeiten kueuennen //alles neuen Vertces sollen gewueuehlt werden, also einfach alle Indices eintragen vom initialVtxCount //bis zum jetzigen VtxCount MIntArray validEdges, validFaces; componentConverter CC(newOutMesh); int i = 0; meshFn.setObject(newOutMesh); int newCount = meshFn.numVertices(); validIndices.clear(); validIndices.setLength(newCount - initialVtxCount); for(; initialVtxCount < newCount; initialVtxCount++) validIndices[i++] = initialVtxCount; if(optionsArray[6] == 1 || optionsArray[6] == 2) //select edges { CC.getContainedEdges(validIndices,validEdges); } BPT_Helpers helper; if(optionsArray[6] == 2) //select Faces { CC.getConnectedFaces(validEdges,validFaces); //jetzt kann gleich alles beendet werden, da hiernach keine componente mehr kommt, in die man faces umwandeln mueuesste validIndices.clear(); validIndices.append(2); helper.addIntArrayToLHS(validIndices,validFaces); } if(optionsArray[6] == 1) {//edges fertigmachen validIndices.clear(); validIndices.append(1); helper.addIntArrayToLHS(validIndices,validEdges); } else if(optionsArray[6] == 5) validIndices.insert(3,0); //component Mode umschalten bei bedarf if(optionsArray[5]) { MSelectionMask::SelectionType type = MSelectionMask::kSelectMeshVerts; if(optionsArray[6] == 5) { type = MSelectionMask::kSelectMeshVerts; } else if(optionsArray[6] == 2) { type = MSelectionMask::kSelectMeshFaces; } else if(optionsArray[6] == 1) { type = MSelectionMask::kSelectMeshEdges; } MSelectionMask mask(type); MGlobal:: setComponentSelectionMask(mask); } eID = MEventMessage::addEventCallback("idle",IV_makeSelection,this); scriptJobInitated = true; } else {//ansonsten muss die SelectionList neu aufgebaut werden, allerdings ohne komponenten //diese Aktion solte auch nur einmal ausgefueuehrt werden //gegenwueuertige selection holen MSelectionList currentList; MSelectionList newList; MGlobal::getActiveSelectionList(currentList); //durch die Liste iterieren und Komponenten Filtern MItSelectionList selIter(currentList); MObject currentObj; for( ; !selIter.isDone();selIter.next() ) { selIter.getDependNode(currentObj); newList.add(currentObj); } MGlobal::setActiveSelectionList(newList, MGlobal::kAddToList); } return status; }
/*! Compute function, gets the input surface, determines what type it is and calls the appropriate conversion function Encapsulates an cowpointer to the body into the naiadBodyData type and outputs it */ MStatus NBuddySurfaceToBodyNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus status; if (plug == _outBody) { //Get the body name MDataHandle bodyNameHndl = data.inputValue( _bodyName, &status ); MString bodyName = bodyNameHndl.asString(); //Create the MFnPluginData for the naiadBody MFnPluginData dataFn; dataFn.create( MTypeId( naiadBodyData::id ), &status); NM_CheckMStatus( status, "Failed to create naiadBodyData in MFnPluginData"); //Get subdivision info from plugs so better approximations of meshes can be done int divisions = data.inputValue( _subDivide, &status ).asBool(); //Getting genericAttribute handle containing the surface and pick the correct conversion function MObject meshObj; MDataHandle inSurfaceHdl = data.inputValue( _inSurface, &status ); if (inSurfaceHdl.type() == MFnData::kNurbsSurface) { MFnNurbsSurface nurbsFn(inSurfaceHdl.asNurbsSurface()); // Create the data holder for the tesselated mesh MFnMeshData dataCreator; MObject newOutputData = dataCreator.create(&status); //Setup the tesselation parameters MTesselationParams tParams; tParams.setOutputType( MTesselationParams::kTriangles ); tParams.setFormatType( MTesselationParams::kGeneralFormat ); tParams.setUIsoparmType( MTesselationParams::kSpanEquiSpaced ); tParams.setVIsoparmType( MTesselationParams::kSpanEquiSpaced ); tParams.setUNumber( divisions+1 ); tParams.setVNumber( divisions+1 ); // Tesselate and get the returned mesh meshObj = nurbsFn.tesselate( tParams, newOutputData, &status ); NM_CheckMStatus( status, "NBuddySurfaceToBodyNode::compute Failed to tesselate nurbs surface to poly"); } else if (inSurfaceHdl.type() == MFnData::kMesh) { meshObj = inSurfaceHdl.asMesh(); if ( divisions > 0 ) { MFnMeshData dataCreator; MObject newOutputData = dataCreator.create(&status); MFnMesh meshFn(meshObj); MIntArray faceIds; for ( unsigned int i(0); i < meshFn.numPolygons(); ++i ) faceIds.append(i); meshFn.subdivideFaces( faceIds , divisions ); } } else if (inSurfaceHdl.type() == MFnData::kSubdSurface) { // Create the subd function set so we can tesselate MFnSubd subDfn(inSurfaceHdl.asSubdSurface()); // Create the data holder for the tesselated mesh MFnMeshData dataCreator; MObject newOutputData = dataCreator.create(&status); // Tesselate the subD surface meshObj = subDfn.tesselate(true, 1 , divisions , newOutputData, &status ); NM_CheckMStatus( status, "NBuddySurfaceToBodyNode::compute Failed to tesselate SubD surface to poly"); } else return status ; //Get the handle for the input transform MDataHandle inTransformHdl = data.inputValue( _inTransform, &status ); NM_CheckMStatus( status, "Failed to get inTransform handle"); MDataHandle useTransformHdl = data.inputValue( _useTransform, &status); NM_CheckMStatus( status, "Failed to get worldSpaceHdl "); bool useTransform = useTransformHdl.asBool(); //Get a new naiadBodyData naiadBodyData * newBodyData = (naiadBodyData*)dataFn.data( &status ); NM_CheckMStatus( status, "Failed to get naiadBodyData handle from MFnPluginData"); try { newBodyData->nBody = mayaMeshToNaiadBody( meshObj, std::string(bodyName.asChar()), useTransform, inTransformHdl.asMatrix() ); } catch(std::exception& ex) { NM_ExceptionPlugDisplayError("NBuddySurfaceToBodyNode::compute ", plug, ex ); } //Give the data to the output handle and set it clean MDataHandle bodyDataHnd = data.outputValue( _outBody, &status ); NM_CheckMStatus( status, "Failed to get outputData handle for outBody"); bodyDataHnd.set( newBodyData ); data.setClean( plug ); } return status; }