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 sseDeformer::compute(const MPlug& plug, MDataBlock& data) { MStatus status; if (plug.attribute() != outputGeom) { printf("Ignoring requested plug\n"); return status; } unsigned int index = plug.logicalIndex(); MObject thisNode = this->thisMObject(); // get input value MPlug inPlug(thisNode,input); inPlug.selectAncestorLogicalIndex(index,input); MDataHandle hInput = data.inputValue(inPlug, &status); MCheckStatus(status, "ERROR getting input mesh\n"); // get the input geometry MDataHandle inputData = hInput.child(inputGeom); if (inputData.type() != MFnData::kMesh) { printf("Incorrect input geometry type\n"); return MStatus::kFailure; } MObject iSurf = inputData.asMesh() ; MFnMesh inMesh; inMesh.setObject( iSurf ) ; MDataHandle outputData = data.outputValue(plug); outputData.copy(inputData); if (outputData.type() != MFnData::kMesh) { printf("Incorrect output mesh type\n"); return MStatus::kFailure; } MObject oSurf = outputData.asMesh() ; if(oSurf.isNull()) { printf("Output surface is NULL\n"); return MStatus::kFailure; } MFnMesh outMesh; outMesh.setObject( oSurf ) ; MCheckStatus(status, "ERROR setting points\n"); // get all points at once for demo purposes. Really should get points from the current group using iterator MFloatPointArray pts; outMesh.getPoints(pts); int nPoints = pts.length(); MDataHandle envData = data.inputValue(envelope, &status); float env = envData.asFloat(); MDataHandle sseData = data.inputValue(sseEnabled, &status); bool sseEnabled = (bool) sseData.asBool(); // NOTE: Using MTimer and possibly other classes disables // autovectorization with Intel <=10.1 compiler on OSX and Linux!! // Must compile this function with -fno-exceptions on OSX and // Linux to guarantee autovectorization is done. Use -fvec_report2 // to check for vectorization status messages with Intel compiler. MTimer timer; timer.beginTimer(); if(sseEnabled) { // Innter loop will autovectorize. Around 3x faster than the // loop below it. It would be faster if first element was // guaranteed to be aligned on 16 byte boundary. for(int i=0; i<nPoints; i++) { float* ptPtr = &pts[i].x; for(int j=0; j<4; j++) { ptPtr[j] = env * (cosf(ptPtr[j]) * sinf(ptPtr[j]) * tanf(ptPtr[j])); } } } else { // This inner loop will not autovectorize. for(int i=0; i<nPoints; i++) { MFloatPoint& pt = pts[i]; for(int j=0; j<3; j++) { pt[j] = env * (cosf(pt[j]) * sinf(pt[j]) * tanf(pt[j])); } } } timer.endTimer(); if(sseEnabled) { printf("SSE enabled, runtime %f\n", timer.elapsedTime()); } else { printf("SSE disabled, runtime %f\n", timer.elapsedTime()); } outMesh.setPoints(pts); 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 proWater::compute(const MPlug& plug, MDataBlock& dataBlock) { MStatus status = MStatus::kUnknownParameter; if (plug.attribute() == outputGeom) { // get the input corresponding to this output // unsigned int index = plug.logicalIndex(); MObject thisNode = this->thisMObject(); MPlug inPlug(thisNode,input); inPlug.selectAncestorLogicalIndex(index,input); MDataHandle hInput = dataBlock.inputValue(inPlug); // get the input geometry and input groupId // MDataHandle hGeom = hInput.child(inputGeom); MDataHandle hGroup = hInput.child(groupId); unsigned int groupId = hGroup.asLong(); MDataHandle hOutput = dataBlock.outputValue(plug); hOutput.copy(hGeom); MStatus returnStatus; MDataHandle envData = dataBlock.inputValue(envelope, &returnStatus); if (MS::kSuccess != returnStatus) return returnStatus; float env = envData.asFloat(); MDataHandle timeData = dataBlock.inputValue(time, &returnStatus); if(MS::kSuccess != returnStatus) return returnStatus; double t = timeData.asDouble(); MDataHandle dirData = dataBlock.inputValue(dir, &returnStatus); if(MS::kSuccess != returnStatus) return returnStatus; double dirDeg = dirData.asDouble(); MDataHandle bigData = dataBlock.inputValue(bigFreq, &returnStatus); if(MS::kSuccess != returnStatus) return returnStatus; double bigFreqAmp = bigData.asDouble(); MDataHandle ampData = dataBlock.inputValue(amplitude1, &returnStatus); if(MS::kSuccess != returnStatus) return returnStatus; double amp1 = ampData.asDouble(); MDataHandle freqData = dataBlock.inputValue(frequency1, &returnStatus); if(MS::kSuccess != returnStatus) return returnStatus; double freq1 = freqData.asDouble(); MDataHandle ampData2 = dataBlock.inputValue(amplitude2, &returnStatus); if(MS::kSuccess != returnStatus) return returnStatus; double amp2 = ampData2.asDouble(); MDataHandle freqData2 = dataBlock.inputValue(frequency2, &returnStatus); if(MS::kSuccess != returnStatus) return returnStatus; double freq2 = freqData2.asDouble(); // Get the MFnMesh MStatus stat; MObject inputObj = hOutput.data(); MFnMesh * meshFn = new MFnMesh(inputObj, &stat); // do the deformation // MItGeometry iter(hOutput,groupId,false); for ( ; !iter.isDone(); iter.next()) { MPoint pt = iter.position(); //float2 uvPoint; //float u,v; //uvPoint[0] = u; //uvPoint[1] = v; //meshFn->getUVAtPoint(pt, uvPoint, MSpace::kObject); float u = pt.x; //uvPoint[0]*100; float v = pt.z; //uvPoint[1]*100; float degDir = dirDeg; float dir = degDir* M_PI/180; float dirX = cos(dir); float dirY = sin(dir); float bigFreq = 0.01; float bigWaves = scaled_raw_noise_3d(0, 1, (u + 3*t*dirX)*bigFreq*dirX, (v + 3*t*dirY)*bigFreq*dirY*2, t*0.01); float frequency1 = freq1/10;//0.2; float amplitude1 = amp1;//1.3; float firstOctave = -(std::abs(scaled_raw_noise_3d(-amplitude1, amplitude1, (float)(u + 0.7*t*dirX)*frequency1*0.4, (float)(v + 0.7*t*dirY)*frequency1*0.6, 0.05*t))-amplitude1); float frequency2 = freq2/10; float amplitude2 = amp2; float secondOctave = - (std::abs(scaled_raw_noise_3d(-amplitude2, amplitude2, (float)(u + 0.7*t*dirX)*frequency2*0.35, (float)(v + 0.7*t*dirY)*frequency2*0.65, 0.005*t))-amplitude2); float frequency3 = freq1/10; float amplitude3 = amp1/1.5; float thirdOctave = - (std::abs(scaled_raw_noise_3d(-amplitude3, amplitude3, (float)(u + t*0.5*dirX)*frequency3*0.4, (float)(v + t*0.5*dirY)*frequency3*0.6, 30))-amplitude3); float frequency4 = freq2/10; float amplitude4 = amp2/1.5; float fourthOctave = scaled_raw_noise_3d(-amplitude4, amplitude4, (float)(u + t*0.5*dirX)*frequency4*0.4, (float)(v + t*0.5*dirY)*frequency4*0.6, 50); float frequency5 = freq2; float amplitude5 = amp2/2; float fifthOctave = scaled_raw_noise_3d(-amplitude5, amplitude5, (float)(u + t*0.5*dirX)*frequency5*0.15, (float)(v + t*0.5*dirY)*frequency5*0.85, 0.001*t); float disp = bigFreqAmp*bigWaves + 7*(bigWaves)*firstOctave + secondOctave + thirdOctave*thirdOctave + fourthOctave + std::abs(bigWaves-1)*fifthOctave; pt = pt + iter.normal()*disp; iter.setPosition(pt); } delete meshFn; status = MStatus::kSuccess; } return status; }
MStatus splatDeformer::compute(const MPlug& plug, MDataBlock& data) { // do this if we are using an OpenMP implementation that is not the same as Maya's. // Even if it is the same, it does no harm to make this call. MThreadUtils::syncNumOpenMPThreads(); MStatus status = MStatus::kUnknownParameter; if (plug.attribute() != outputGeom) { return status; } unsigned int index = plug.logicalIndex(); MObject thisNode = this->thisMObject(); // get input value MPlug inPlug(thisNode,input); inPlug.selectAncestorLogicalIndex(index,input); MDataHandle hInput = data.inputValue(inPlug, &status); MCheckStatus(status, "ERROR getting input mesh\n"); // get the input geometry MDataHandle inputData = hInput.child(inputGeom); if (inputData.type() != MFnData::kMesh) { printf("Incorrect input geometry type\n"); return MStatus::kFailure; } // get the input groupId - ignored for now... MDataHandle hGroup = inputData.child(groupId); unsigned int groupId = hGroup.asLong(); // get deforming mesh MDataHandle deformData = data.inputValue(deformingMesh, &status); MCheckStatus(status, "ERROR getting deforming mesh\n"); if (deformData.type() != MFnData::kMesh) { printf("Incorrect deformer geometry type %d\n", deformData.type()); return MStatus::kFailure; } MObject dSurf = deformData.asMeshTransformed(); MFnMesh fnDeformingMesh; fnDeformingMesh.setObject( dSurf ) ; MDataHandle outputData = data.outputValue(plug); outputData.copy(inputData); if (outputData.type() != MFnData::kMesh) { printf("Incorrect output mesh type\n"); return MStatus::kFailure; } MItGeometry iter(outputData, groupId, false); // create fast intersector structure MMeshIntersector intersector; intersector.create(dSurf); // get all points at once. Faster to query, and also better for // threading than using iterator MPointArray verts; iter.allPositions(verts); int nPoints = verts.length(); // use bool variable as lightweight object for failure check in loop below bool failed = false; MTimer timer; timer.beginTimer(); #ifdef _OPENMP #pragma omp parallel for #endif for(int i=0; i<nPoints; i++) { // Cannot break out of an OpenMP loop, so if one of the // intersections failed, skip the rest if(failed) continue; // mesh point object must be in loop-local scope to avoid race conditions MPointOnMesh meshPoint; // Do intersection. Need to use per-thread status value as // MStatus has internal state and may trigger race conditions // if set from multiple threads. Probably benign in this case, // but worth being careful. MStatus localStatus = intersector.getClosestPoint(verts[i], meshPoint); if(localStatus != MStatus::kSuccess) { // NOTE - we cannot break out of an OpenMP region, so set // bad status and skip remaining iterations failed = true; continue; } // default OpenMP scheduling breaks traversal into large // chunks, so low risk of false sharing here in array write. verts[i] = meshPoint.getPoint(); } timer.endTimer(); printf("Runtime for threaded loop %f\n", timer.elapsedTime()); // write values back onto output using fast set method on iterator iter.setAllPositions(verts); if(failed) { printf("Closest point failed\n"); return MStatus::kFailure; } return status; }
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); float maxCreaseSharpness=0.0f; OpenSubdiv::Far::TopologyRefiner * refiner = gatherTopology(inMeshFn, inMeshItPolygon, type, options, &maxCreaseSharpness); assert(refiner); // Refine & Interpolate refiner->RefineUniform(OpenSubdiv::Far::TopologyRefiner::UniformOptions(subdivisionLevel)); Vertex const * controlVerts = reinterpret_cast<Vertex const *>(inMeshFn.getRawPoints(&status)); std::vector<Vertex> refinedVerts( refiner->GetNumVerticesTotal() - refiner->GetLevel(0).GetNumVertices()); Vertex const * srcVerts = controlVerts; Vertex * dstVerts = &refinedVerts[0]; for (int level = 1; level <= subdivisionLevel; ++level) { OpenSubdiv::Far::PrimvarRefiner(*refiner).Interpolate(level, srcVerts, dstVerts); srcVerts = dstVerts; dstVerts += refiner->GetLevel(level).GetNumVertices(); } // == 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, 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 finalproject::compute(const MPlug& plug, MDataBlock& data) { // do this if we are using an OpenMP implementation that is not the same as Maya's. // Even if it is the same, it does no harm to make this call. MThreadUtils::syncNumOpenMPThreads(); MStatus status = MStatus::kUnknownParameter; if (plug.attribute() != outputGeom) { return status; } unsigned int index = plug.logicalIndex(); MObject thisNode = this->thisMObject(); // get input value MPlug inPlug(thisNode,input); inPlug.selectAncestorLogicalIndex(index,input); MDataHandle hInput = data.inputValue(inPlug, &status); MCheckStatus(status, "ERROR getting input mesh\n"); // get the input geometry MDataHandle inputData = hInput.child(inputGeom); if (inputData.type() != MFnData::kMesh) { printf("Incorrect input geometry type\n"); return MStatus::kFailure; } // get the input groupId - ignored for now... MDataHandle hGroup = inputData.child(groupId); unsigned int groupId = hGroup.asLong(); // get deforming mesh MDataHandle deformData = data.inputValue(deformingMesh, &status); MCheckStatus(status, "ERROR getting deforming mesh\n"); if (deformData.type() != MFnData::kMesh) { printf("Incorrect deformer geometry type %d\n", deformData.type()); return MStatus::kFailure; } MDataHandle offloadData = data.inputValue(offload, &status); //gathers world space positions of the object and the magnet MObject dSurf = deformData.asMeshTransformed(); MObject iSurf = inputData.asMeshTransformed(); MFnMesh fnDeformingMesh, fnInputMesh; fnDeformingMesh.setObject( dSurf ) ; fnInputMesh.setObject( iSurf ) ; MDataHandle outputData = data.outputValue(plug); outputData.copy(inputData); if (outputData.type() != MFnData::kMesh) { printf("Incorrect output mesh type\n"); return MStatus::kFailure; } MItGeometry iter(outputData, groupId, false); // get all points at once. Faster to query, and also better for // threading than using iterator MPointArray objVerts; iter.allPositions(objVerts); int objNumPoints = objVerts.length(); MPointArray magVerts, tempverts; fnDeformingMesh.getPoints(magVerts); fnInputMesh.getPoints(tempverts); int magNumPoints = magVerts.length(); double min = DBL_MAX, max = -DBL_MAX; //finds min and max z-coordinate values to determine middle point (choice of z-axis was ours) for (int i = 0; i < magNumPoints; i++) { min = magVerts[i].z < min ? magVerts[i].z : min; max = magVerts[i].z > max ? magVerts[i].z : max; } double middle = (min + max) / 2; double polarity[magNumPoints]; //assigns polarity based on middle point of mesh for (int i = 0; i < magNumPoints; i++) { polarity[i] = magVerts[i].z > middle ? max / magVerts[i].z : -min / magVerts[i].z; } double* objdVerts = (double *)malloc(sizeof(double) * objNumPoints * 3); double* magdVerts = (double *)malloc(sizeof(double) * magNumPoints * 3); //creates handles to use attribute data MDataHandle vecX = data.inputValue(transX, &status); MDataHandle vecY = data.inputValue(transY, &status); MDataHandle vecZ = data.inputValue(transZ, &status); //gathers previously stored coordinates of the center of the object double moveX = vecX.asFloat(); double moveY = vecY.asFloat(); double moveZ = vecZ.asFloat(); //translates object based on the position stored in the attribute values for (int i=0; i<objNumPoints; i++) { objdVerts[i * 3] = tempverts[i].x + moveX; objdVerts[i * 3 + 1] = tempverts[i].y + moveY; objdVerts[i * 3 + 2] = tempverts[i].z + moveZ; } for (int i=0; i<magNumPoints; i++) { magdVerts[i * 3] = magVerts[i].x; magdVerts[i * 3 + 1] = magVerts[i].y; magdVerts[i * 3 + 2] = magVerts[i].z; } double teslaData = data.inputValue(tesla, &status).asDouble(); MDataHandle posiData = data.inputValue(positivelycharged, &status); double pivot[6] = {DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX}; //finds the pivot point of the object in world space prior to being affected by the magnet for (int i = 0; i < tempverts.length(); i++) { pivot[0] = tempverts[i].x < pivot[0] ? tempverts[i].x : pivot[0]; pivot[1] = tempverts[i].x > pivot[1] ? tempverts[i].x : pivot[1]; pivot[2] = tempverts[i].y < pivot[2] ? tempverts[i].y : pivot[2]; pivot[3] = tempverts[i].y > pivot[3] ? tempverts[i].y : pivot[3]; pivot[4] = tempverts[i].z < pivot[4] ? tempverts[i].z : pivot[4]; pivot[5] = tempverts[i].z > pivot[5] ? tempverts[i].z : pivot[5]; } MTimer timer; timer.beginTimer(); //main function call magnetForce(magNumPoints, objNumPoints, teslaData, magdVerts, objdVerts, polarity, posiData.asBool(), offloadData.asBool()); timer.endTimer(); printf("Runtime for threaded loop %f\n", timer.elapsedTime()); for (int i=0; i<objNumPoints; i++) { objVerts[i].x = objdVerts[i * 3 + 0]; objVerts[i].y = objdVerts[i * 3 + 1]; objVerts[i].z = objdVerts[i * 3 + 2]; } //finds the pivot point of object in world space after being affected by the magnet double objCenter[6] = {DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX}; for (int i = 0; i < tempverts.length(); i++) { objCenter[0] = objVerts[i].x < objCenter[0] ? objVerts[i].x : objCenter[0]; objCenter[1] = objVerts[i].x > objCenter[1] ? objVerts[i].x : objCenter[1]; objCenter[2] = objVerts[i].y < objCenter[2] ? objVerts[i].y : objCenter[2]; objCenter[3] = objVerts[i].y > objCenter[3] ? objVerts[i].y : objCenter[3]; objCenter[4] = objVerts[i].z < objCenter[4] ? objVerts[i].z : objCenter[4]; objCenter[5] = objVerts[i].z > objCenter[5] ? objVerts[i].z : objCenter[5]; } //creates vector based on the two calculated pivot points moveX = (objCenter[0] + objCenter[1]) / 2 - (pivot[0] + pivot[1]) / 2; moveY = (objCenter[2] + objCenter[3]) / 2 - (pivot[2] + pivot[3]) / 2; moveZ = (objCenter[4] + objCenter[5]) / 2 - (pivot[4] + pivot[5]) / 2; //stores pivot vector for next computation if (teslaData) { vecX.setFloat(moveX); vecY.setFloat(moveY); vecZ.setFloat(moveZ); } // write values back onto output using fast set method on iterator iter.setAllPositions(objVerts, MSpace::kWorld); free(objdVerts); free(magdVerts); return status; }