MThreadRetVal slidingDeformer2::compute_sliding( void* voidPThread ) { slidingDeformer2SlidingThread* pThread = ( slidingDeformer2SlidingThread* )voidPThread; slidingDeformer2SlidingTask* pTask = pThread->pTask; MPointOnMesh pointOnMesh; MIntArray& indicesMoved = *pTask->pIndicesCheck; MPointArray& pointsMoved = *pTask->pPointsMoved; MPointArray& pointsResult = *pTask->pPointsResult; MVectorArray& vectorArr = *pTask->pVectorArr; MPoint pointClose; MVector normal; int index; float env = pTask->env; float invEnv = 1-pTask->env; for( int i = pThread->start; i < pThread->end; i++ ) { index = indicesMoved[i]; pTask->pMeshIntersector->getClosestPoint( pointsMoved[ index ], pointOnMesh ); pointClose = pointOnMesh.getPoint(); pointsResult[ index ] = vectorArr[index] + pointClose*env + pointsMoved[ index ]*invEnv; } return MThreadRetVal( 0 ); }
MThreadRetVal slidingDeformer2::compute_getDist( void* voidPThread ) { slidingDeformer2GetDistThread* pThread = ( slidingDeformer2GetDistThread* )voidPThread; slidingDeformer2GetDistTask* pTask = pThread->pTask; MPointOnMesh pointOnMesh; MVectorArray& vectorArr = *pTask->pVectors; MPointArray& pointsOrig = *pTask->pPointsOrig; MVector vPoint; MVector getPoint; MVector normal; double dot; for( int i = pThread->start; i < pThread->end; i++ ) { pTask->pMeshIntersector->getClosestPoint( pointsOrig[i], pointOnMesh ); getPoint = pointOnMesh.getPoint(); vectorArr[i] = MVector( pointsOrig[i] ) - getPoint; } return MThreadRetVal( 0 ); }
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; }