MStatus VolumePushCollider::compute(const MPlug& plug, MDataBlock& dataBlock) { MStatus status; if (plug == aOutput) { // inCollider MArrayDataHandle hInCollider = dataBlock.inputArrayValue(aInCollider); // inVolume MArrayDataHandle hInVolume = dataBlock.inputArrayValue(aInVolume); // output MArrayDataHandle hOutput = dataBlock.inputArrayValue(aOutput); MDoubleArray daValues(hInVolume.elementCount()); for (unsigned int c=0; c<hInCollider.elementCount(); c++) { // Calculate the total of every collider value for each volume status = hInCollider.jumpToArrayElement(c); CHECK_MSTATUS_AND_RETURN_IT(status); MMatrix mInCollider = hInCollider.inputValue().asMatrix(); MTransformationMatrix tmInCollider(mInCollider); MPoint pInCollider = tmInCollider.getTranslation(MSpace::kWorld, &status); CHECK_MSTATUS_AND_RETURN_IT(status); for (unsigned int v=0; v<hInVolume.elementCount(); v++) { // pointMatrixMult status = hInVolume.jumpToArrayElement(v); CHECK_MSTATUS_AND_RETURN_IT(status); MMatrix mInVolume = hInVolume.inputValue().asMatrix(); MVector vVolCollider = pInCollider * mInVolume; // condition if (vVolCollider.length() <= 1.0) { // reverse daValues[v] += abs(1.0 - vVolCollider.length()); } } } for (unsigned int i=0; i<hInVolume.elementCount(); i++) { // set outputs status = hOutput.jumpToArrayElement(i); CHECK_MSTATUS_AND_RETURN_IT(status); hOutput.outputValue().set(daValues[i]); } dataBlock.setClean(plug); } return MS::kSuccess; }
MStatus MG_curve::compute(const MPlug& plug,MDataBlock& dataBlock) { if (plug==output) { //MStatus MStatus stat; //Point array for the curve MPointArray pointArray ; //Get data from inputs MDataHandle degreeH = dataBlock.inputValue(degree); int degreeValue = degreeH.asInt(); MDataHandle tmH = dataBlock.inputValue(transformMatrix); MMatrix tm = tmH.asMatrix(); MArrayDataHandle inputMatrixH = dataBlock.inputArrayValue(inputMatrix); inputMatrixH.jumpToArrayElement(0); //Loop to get matrix data and convert in points for (int unsigned i=0;i<inputMatrixH.elementCount();i++,inputMatrixH.next()) { MMatrix currentMatrix = inputMatrixH.inputValue(&stat).asMatrix() ; //Compensate the locator matrix MMatrix fixedMatrix = currentMatrix*tm.inverse(); MPoint matrixP (fixedMatrix[3][0],fixedMatrix[3][1],fixedMatrix[3][2]); pointArray.append(matrixP); } MFnNurbsCurve curveFn; MFnNurbsCurveData curveDataFn; MObject curveData= curveDataFn.create(); curveFn.createWithEditPoints(pointArray,degreeValue,MFnNurbsCurve::kOpen,0,0,0,curveData,&stat); MDataHandle outputH = dataBlock.outputValue(output); outputH.set(curveData); outputH.setClean(); } return MS::kSuccess; }
// ========================================================================================================== // ========================================================================================================== virtual MStatus compute(const MPlug& plug, MDataBlock& dataBlock) { // enable this node or not if ( dataBlock.inputValue(aEnable).asBool() == false ) { return MS::kSuccess; } // check if the inpute attribute is connected // in Not, stop compute() // in order to avoid crash when disconnect input attributes on the fly //cout << "isPlugConnect: " << isPlugConnect(aVolumeObj) << endl; if ( isPlugConnect(aSourceObj) == false || isPlugConnect(aVolumeObj) == false ) { return MS::kSuccess; } // execution when output attr needs to be updated if ( plug == aOutValue || plug == aOutMesh || plug == aOutCompList ) { // test if input source object is a valid type if ( dataBlock.inputValue(aSourceObj).type() != MFnData::kMesh ) { MGlobal::displayInfo( MString("No Object Input!") ); return MS::kSuccess; } MObject sourceObj = dataBlock.inputValue(aSourceObj).asMeshTransformed(); MArrayDataHandle arrayHandle = dataBlock.inputValue(aVolumeObj); arrayHandle.jumpToArrayElement(0); MSelectionList sList; // add the vertice every ligal loop for ( int idx=0; idx < arrayHandle.elementCount(); idx++, arrayHandle.next() ) { // first, check if the sub-plug is un-connected if ( isPlugConnect( aVolumeObj, idx ) == false ) { cout << "No Data " << idx << endl; continue; } // second, check if the input object is mesh if ( arrayHandle.inputValue().type() != MFnData::kMesh ) { return MS::kSuccess; MGlobal::displayError( "input voulme objects is not mesh" ); } // input volume object as Wrold mesh MObject volumeObj = arrayHandle.inputValue().asMeshTransformed(); MFnMesh sourceMeshFn; MFnMesh volumeMeshFn; // third, test if the input obj is compatible with meshFn if ( volumeMeshFn.hasObj(sourceObj) && volumeMeshFn.hasObj(volumeObj) ) { volumeMeshFn.setObject(volumeObj); // check if object is closed if ( isClosedMesh(volumeObj) == false ) { if ( dataBlock.inputValue(aClosedObj).asBool() == true ) { //MGlobal::displayInfo( MString("The volume object is not closed!") ); continue; } } sourceMeshFn.setObject( sourceObj ); int numVtx = sourceMeshFn.numVertices(); vector<int> tmpCompArray; // an temporary int array to store component index // do hit test // to check if each source's component is inside // for ( int i=0; i < numVtx; i++ ) { // get each vertex of source object MPoint srcVtx; sourceMeshFn.getPoint( i, srcVtx, MSpace::kWorld ); // Test how much hit is for each vertex // declare parameters for allIntersection() MFloatPoint raySource; raySource.setCast(srcVtx); MFloatVector rayDirection(0, 0, 1); MFloatPointArray hitPoints; MIntArray hitFaces; bool hit = volumeMeshFn.allIntersections( raySource, rayDirection, NULL, NULL, false, MSpace::kWorld, 99999, false, NULL, true, hitPoints, NULL, &hitFaces, NULL, NULL, NULL, 1e-6 ); if (hit) { int isInside = hitFaces.length() % 2; // cout << "isInside: " << isInside << endl; // if the mod is odd, it's inside if ( isInside > 0 ) { tmpCompArray.push_back(i); } } } // declare a dynamic array to recieve All elements from tmpCompArray int* compArray = new int[tmpCompArray.size()]; // copy array data from tmpCompArray --> compArray memcpy( &compArray[0], &tmpCompArray[0], sizeof( int ) * tmpCompArray.size() ); // the below processes are to collect component data, and then select them in viewport // // first, get dagPath from the source object MDagPath dPathSrcObj = getConnectNodeDagPath(aSourceObj); // second, get the selection list storing components by feeding comopnet array MSelectionList vtxSelList = getVtxSelList( dPathSrcObj, compArray, tmpCompArray.size() ); sList.merge(vtxSelList); delete [] compArray; } } // end of loop // if so, actively select these component int compType = dataBlock.inputValue(aComponentType).asInt(); MSelectionList currCompSelList; if( dataBlock.inputValue(aKeepSel).asBool() == true ) { // clear if last-time is not keep selection if (flag==0) { addSelComponentList.clear(); flag = 1; } else { addSelComponentList.merge(sList); // merge the accumulative components currCompSelList = convertVtxSListToCompSList( addSelComponentList, compType ); MGlobal::setActiveSelectionList( currCompSelList, MGlobal::kReplaceList ); flag = 1; } } else { addSelComponentList.clear(); // celar all components addSelComponentList.merge(sList); currCompSelList = convertVtxSListToCompSList( addSelComponentList, compType ); MGlobal::setActiveSelectionList( currCompSelList, MGlobal::kReplaceList ); flag = 0; } // keep this node selecting if ( dataBlock.inputValue(aFixPanel).asBool() == true ) MGlobal::select( thisMObject(), MGlobal::kAddToList ); // **** OUTPUT ATTRIBUTE **** MObject currCompList = getCompListFromSList( currCompSelList ); MFnComponentListData compListDataFn; MObject currCompListData = compListDataFn.create(); // pointer to the component data compListDataFn.add( currCompList ); dataBlock.outputValue(aOutCompList).set( currCompListData ); // MFnMeshData outMeshDataFn; MObject outObj = outMeshDataFn.create(); MFnMesh outMeshFn( outObj ); outMeshFn.copy( sourceObj, outObj ); dataBlock.outputValue(aOutMesh).set( outObj ); } // end of if ( plug == aOutValue || plug == aOutMesh ) return MS::kSuccess; }
MStatus n_tentacle::compute( const MPlug& plug, MDataBlock& data ) { MStatus returnStatus; //make sure we have the curve MObject curveObj = data.inputValue(curve).asNurbsCurve(); if(!curveObj.isNull()) { //get the data MArrayDataHandle inMatrixArrayHnd = data.inputArrayValue(matrix); int tangentAxisI = data.inputValue(tangentAxis).asInt(); if(tangentAxisI > 2) tangentAxisI = - (tangentAxisI - 2); else tangentAxisI = tangentAxisI + 1; double stretchF = data.inputValue(stretch).asDouble(); double globalScaleF = data.inputValue(globalScale).asDouble(); double iniLengthF = data.inputValue(iniLength).asDouble(); const MFnNurbsCurve curve(curveObj); MArrayDataHandle parameterArrayHnd = data.inputArrayValue(parameter); MArrayDataHandle blendRotArrayHnd = data.inputArrayValue(blendRot); MArrayDataHandle intervalArrayHnd = data.inputArrayValue(interval); MArrayDataHandle outTranslateArrayHnd = data.outputArrayValue(outTranslate); MArrayDataHandle outRotateArrayHnd = data.outputArrayValue(outRotate); int parameterNrPlugs = parameterArrayHnd.elementCount(); int blendRotNrPlugs = blendRotArrayHnd.elementCount(); int outTranslateNrPlugs = outTranslateArrayHnd.elementCount(); int outRotateNrPlugs = outRotateArrayHnd.elementCount(); //get the current curve length double currCurveLen = curve.length(); if(this->init == false) { if(outTranslateNrPlugs == parameterNrPlugs && outRotateNrPlugs == parameterNrPlugs && parameterNrPlugs == blendRotNrPlugs) { this->init = true; } } if( plug == outTranslate || plug == outRotate || plug == outRotateX || plug == outRotateY || plug == outRotateZ) { if(this->init) { MArrayDataBuilder tbuilder(outTranslate, parameterNrPlugs); MArrayDataBuilder rbuilder(outRotate, parameterNrPlugs); for(int i = 0; i < parameterNrPlugs; i++) { intervalArrayHnd.jumpToArrayElement(i); int intervalI = intervalArrayHnd.inputValue().asInt(); inMatrixArrayHnd.jumpToArrayElement(intervalI); MMatrix matrix1 = inMatrixArrayHnd.inputValue().asMatrix(); this->removeMatrixScale(matrix1); inMatrixArrayHnd.jumpToArrayElement(intervalI + 1); MMatrix matrix2 = inMatrixArrayHnd.inputValue().asMatrix(); this->removeMatrixScale(matrix2); parameterArrayHnd.jumpToArrayElement(i); double parameterF = parameterArrayHnd.inputValue().asDouble(); blendRotArrayHnd.jumpToArrayElement(i); double blendRotF = blendRotArrayHnd.inputValue().asDouble(); MVector outPos, outRot; this->computeSlerp(matrix1, matrix2, curve, parameterF, blendRotF, iniLengthF, currCurveLen, stretchF, globalScaleF, tangentAxisI, outPos, outRot); MDataHandle outTranslateHnd = tbuilder.addElement(i); outTranslateHnd.set3Double(outPos.x, outPos.y, outPos.z); MDataHandle outRotateHnd = rbuilder.addElement(i); double rotation[3]; outRotateHnd.set( outRot.x, outRot.y, outRot.z ); //this->output(outPos, outRot, i, outTranslateArrayHnd, outRotateArrayHnd); } outTranslateArrayHnd.set(tbuilder); outTranslateArrayHnd.setAllClean(); outRotateArrayHnd.set(rbuilder); outRotateArrayHnd.setAllClean(); } data.setClean(plug); } else { return MS::kUnknownParameter; } } return MS::kSuccess; }
MStatus nwayDeformerNode::deform( MDataBlock& data, MItGeometry& itGeo, const MMatrix &localToWorldMatrix, unsigned int mIndex ) { // clock_t clock_start=clock(); MObject thisNode = thisMObject(); MStatus status; MThreadUtils::syncNumOpenMPThreads(); // for OpenMP MArrayDataHandle hBlendMesh = data.inputArrayValue(aBlendMesh); short numIter = data.inputValue( aIteration ).asShort(); short nblendMode = data.inputValue( aBlendMode ).asShort(); short ntetMode = data.inputValue( aTetMode ).asShort(); double visualisationMultiplier = data.inputValue(aVisualisationMultiplier).asDouble(); bool visualiseEnergy = data.inputValue( aVisualiseEnergy ).asBool(); bool nrotationCosistency = data.inputValue( aRotationConsistency ).asBool(); if( nrotationCosistency != rotationCosistency) { numMesh = 0; rotationCosistency = nrotationCosistency; } MPointArray Mpts; itGeo.allPositions(Mpts); int nnumMesh = hBlendMesh.elementCount(); int numPts = Mpts.length(); int numTet = (int)tetList.size()/4; // initialisation if(tetMode != ntetMode) { // clock_t clock_start=clock(); tetMode = ntetMode; numMesh = 0; // point list pts.resize(numPts); for(int i=0; i<numPts; i++) { pts[i] << Mpts[i].x, Mpts[i].y, Mpts[i].z; } std::vector<Matrix4d> P; getMeshData(data, input, inputGeom, mIndex, tetMode, pts, tetList, faceList, edgeList, vertexList, P); dim = removeDegenerate(tetMode, numPts, tetList, faceList, edgeList, vertexList, P); makeAdjacencyList(tetMode, tetList, edgeList, vertexList, adjacencyList); makeTetMatrix(tetMode, pts, tetList, faceList, edgeList, vertexList, P); // prepare ARAP solver numTet = (int)tetList.size()/4; PI.resize(numTet); for(int i=0; i<numTet; i++) { PI[i] = P[i].inverse().eval(); } std::vector<double> tetWeight(numTet,1.0); std::vector< std::map<int,double> > constraint(0); //constraint[0][0]=1.0; isError = ARAPprecompute(PI, tetList, tetWeight, constraint, EPSILON, dim, constraintMat, solver); // MString es="Init timing: "; // double timing=(double)(clock()- clock_start)/CLOCKS_PER_SEC; // es += timing; // MGlobal::displayInfo(es); } if(isError>0) return MS::kFailure; // if blend mesh is added, compute log for each tet logR.resize(nnumMesh); logS.resize(nnumMesh); R.resize(nnumMesh); S.resize(nnumMesh); GL.resize(nnumMesh); logGL.resize(nnumMesh); quat.resize(nnumMesh); L.resize(nnumMesh); // for recomputation of parametrisation if(numMesh>nnumMesh || nblendMode != blendMode) { numMesh =0; blendMode = nblendMode; } for(int j=numMesh; j<nnumMesh; j++) { hBlendMesh.jumpToElement(j); MFnMesh blendMesh(hBlendMesh.inputValue().asMesh()); MPointArray Mbpts; blendMesh.getPoints( Mbpts ); if(numPts != Mbpts.length()) { MGlobal::displayInfo("incompatible mesh"); return MS::kFailure; } std::vector<Vector3d> bpts(numPts); for(int i=0; i<numPts; i++) { bpts[i] << Mbpts[i].x, Mbpts[i].y, Mbpts[i].z; } std::vector<Matrix4d> Q(numTet); makeTetMatrix(tetMode, bpts, tetList, faceList, edgeList, vertexList, Q); logR[j].resize(numTet); logS[j].resize(numTet); R[j].resize(numTet); S[j].resize(numTet); GL[j].resize(numTet); logGL[j].resize(numTet); quat[j].resize(numTet); L[j].resize(numTet); for(int i=0; i<numTet; i++) { Matrix4d aff=PI[i]*Q[i]; GL[j][i]=aff.block(0,0,3,3); L[j][i]=transPart(aff); parametriseGL(GL[j][i], logS[j][i] ,R[j][i]); } if( blendMode == BM_LOG3) { for(int i=0; i<numTet; i++) logGL[j][i]=GL[j][i].log(); } else if( blendMode == BM_SQL) { for(int i=0; i<numTet; i++) { S[j][i]=expSym(logS[j][i]); Quaternion<double> q(R[j][i].transpose()); quat[j][i] << q.x(), q.y(), q.z(), q.w(); } } else if( blendMode == BM_SlRL) { for(int i=0; i<numTet; i++) { S[j][i]=expSym(logS[j][i]); } } // traverse tetrahedra to compute continuous log of rotation if(rotationCosistency) { std::set<int> remain; std::queue<int> later; // load initial rotation from the attr Matrix3d initR; double angle = data.inputValue(aInitRotation).asDouble(); initR << 0,M_PI * angle/180.0,0, -M_PI * angle/180.0,0,0, 0,0,0; std::vector<Matrix3d> prevSO(numTet, initR); // create the adjacency graph to traverse for(int i=0; i<numTet; i++) { remain.insert(remain.end(),i); } while(!remain.empty()) { int next; if( !later.empty()) { next = later.front(); later.pop(); remain.erase(next); } else { next = *remain.begin(); remain.erase(remain.begin()); } logR[j][next]=logSOc(R[j][next],prevSO[next]); for(int k=0; k<adjacencyList[next].size(); k++) { int f=adjacencyList[next][k]; if(remain.erase(f)>0) { prevSO[f]=logR[j][next]; later.push(f); } } } } else { for(int i=0; i<numTet; i++) logR[j][i] = logSO(R[j][i]); } } numMesh=nnumMesh; if(numMesh == 0) return MS::kSuccess; // load weights std::vector<double> weight(numMesh); MArrayDataHandle hWeight = data.inputArrayValue(aWeight); if(hWeight.elementCount() != numMesh) { return MS::kSuccess; } for(int i=0; i<numMesh; i++) { hWeight.jumpToArrayElement(i); weight[i]=hWeight.inputValue().asDouble(); } // compute ideal affine std::vector<Vector3d> new_pts(numPts); std::vector<Matrix4d> A(numTet); std::vector<Matrix3d> AR(numTet),AS(numTet); std::vector<Vector3d> AL(numTet); blendMatList(L, weight, AL); if(blendMode==BM_SRL) { blendMatList(logR, weight, AR); blendMatList(logS, weight, AS); #pragma omp parallel for for(int i=0; i<numTet; i++) { AR[i] = expSO(AR[i]); AS[i] = expSym(AS[i]); } } else if(blendMode == BM_LOG3) { // log blendMatList(logGL, weight, AR); #pragma omp parallel for for(int i=0; i<numTet; i++) { AR[i] = AR[i].exp(); AS[i] = Matrix3d::Identity(); } } else if(blendMode == BM_SQL) { // quaternion std::vector<Vector4d> Aq(numTet); blendMatLinList(S, weight, AS); blendQuatList(quat, weight, Aq); #pragma omp parallel for for(int i=0; i<numTet; i++) { Quaternion<double> Q(Aq[i]); AR[i] = Q.matrix().transpose(); } } else if(blendMode == BM_SlRL) { // expSO+linear Sym blendMatList(logR, weight, AR); blendMatLinList(S, weight, AS); #pragma omp parallel for for(int i=0; i<numTet; i++) { AR[i] = expSO(AR[i]); } } else if(blendMode == BM_AFF) { // linear blendMatLinList(GL, weight, AR); for(int i=0; i<numTet; i++) { AS[i] = Matrix3d::Identity(); } } else { return MS::kFailure; } MatrixXd G(dim+1,3),Sol; std::vector<double> tetEnergy(numTet); // iterate to determine vertices position for(int k=0; k<numIter; k++) { for(int i=0; i<numTet; i++) { A[i]=pad(AS[i]*AR[i],AL[i]); } // solve ARAP std::vector<Vector3d> constraintVector(0); std::vector<double> tetWeight(numTet,1.0); //constraintVector[0]=pts[0]; ARAPSolve(A, PI, tetList, tetWeight, constraintVector, EPSILON, dim, constraintMat, solver, Sol); // set new vertices position for(int i=0; i<numPts; i++) { new_pts[i][0]=Sol(i,0); new_pts[i][1]=Sol(i,1); new_pts[i][2]=Sol(i,2); } // if iteration continues if(k+1<numIter || visualiseEnergy) { std::vector<Matrix4d> Q(numTet); makeTetMatrix(tetMode, new_pts, tetList, faceList, edgeList, vertexList, Q); Matrix3d S,R; #pragma omp parallel for for(int i=0; i<numTet; i++) { polarHigham((PI[i]*Q[i]).block(0,0,3,3), S, AR[i]); tetEnergy[i] = (S-AS[i]).squaredNorm(); } } } // set new vertex position for(int i=0; i<numPts; i++) { Mpts[i].x=Sol(i,0); Mpts[i].y=Sol(i,1); Mpts[i].z=Sol(i,2); } itGeo.setAllPositions(Mpts); // set vertex color according to ARAP energy if(visualiseEnergy) { std::vector<double> ptsEnergy; makePtsWeightList(tetMode, numPts, tetList, faceList, edgeList, vertexList, tetEnergy, ptsEnergy); //double max_energy = *std::max_element(ptsEnergy.begin(), ptsEnergy.end()); outputAttr(data, aEnergy, ptsEnergy); for(int i=0; i<numPts; i++) { ptsEnergy[i] *= visualisationMultiplier; // or /= max_energy } visualise(data, outputGeom, ptsEnergy); } // MString es="Runtime timing: "; // double timing=(double)(clock()- clock_start)/CLOCKS_PER_SEC; // es += timing; // MGlobal::displayInfo(es); return MS::kSuccess; }
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 probeDeformerARAPNode::deform( MDataBlock& data, MItGeometry& itGeo, const MMatrix &localToWorldMatrix, unsigned int mIndex ) { MObject thisNode = thisMObject(); MStatus status; MThreadUtils::syncNumOpenMPThreads(); // for OpenMP bool worldMode = data.inputValue( aWorldMode ).asBool(); bool areaWeighted = data.inputValue( aAreaWeighted ).asBool(); short stiffnessMode = data.inputValue( aStiffness ).asShort(); short blendMode = data.inputValue( aBlendMode ).asShort(); short tetMode = data.inputValue( aTetMode ).asShort(); short numIter = data.inputValue( aIteration ).asShort(); short constraintMode = data.inputValue( aConstraintMode ).asShort(); short visualisationMode = data.inputValue( aVisualisationMode ).asShort(); mesh.transWeight = data.inputValue( aTransWeight ).asDouble(); double constraintWeight = data.inputValue( aConstraintWeight ).asDouble(); double normExponent = data.inputValue( aNormExponent ).asDouble(); double visualisationMultiplier = data.inputValue(aVisualisationMultiplier).asDouble(); MArrayDataHandle hMatrixArray = data.inputArrayValue(aMatrix); MArrayDataHandle hInitMatrixArray = data.inputArrayValue(aInitMatrix); // check connection if(hMatrixArray.elementCount() > hInitMatrixArray.elementCount() || hMatrixArray.elementCount() == 0 || blendMode == BM_OFF){ return MS::kSuccess; }else if(hMatrixArray.elementCount() < hInitMatrixArray.elementCount()){ std::set<int> indices; for(int i=0;i<hInitMatrixArray.elementCount();i++){ hInitMatrixArray.jumpToArrayElement(i); indices.insert(hInitMatrixArray.elementIndex()); } for(int i=0;i<hMatrixArray.elementCount();i++){ hMatrixArray.jumpToArrayElement(i); indices.erase(hMatrixArray.elementIndex()); } deleteAttr(data, aInitMatrix, indices); deleteAttr(data, aProbeConstraintRadius, indices); deleteAttr(data, aProbeWeight, indices); } bool isNumProbeChanged = (numPrb != hMatrixArray.elementCount()); numPrb = hMatrixArray.elementCount(); B.setNum(numPrb); // read matrices from probes std::vector<Matrix4d> initMatrix(numPrb), matrix(numPrb); readMatrixArray(hInitMatrixArray, initMatrix); readMatrixArray(hMatrixArray, matrix); // read vertex positions MPointArray Mpts; itGeo.allPositions(Mpts); int numPts = Mpts.length(); // compute distance if(!data.isClean(aARAP) || !data.isClean(aComputeWeight) || isNumProbeChanged){ // load points list if(worldMode){ for(int j=0; j<numPts; j++ ) Mpts[j] *= localToWorldMatrix; } pts.resize(numPts); for(int i=0;i<numPts;i++){ pts[i] << Mpts[i].x, Mpts[i].y, Mpts[i].z; } // make tetrahedral structure getMeshData(data, input, inputGeom, mIndex, tetMode, pts, mesh.tetList, faceList, edgeList, vertexList, mesh.tetMatrix, mesh.tetWeight); mesh.dim = removeDegenerate(tetMode, numPts, mesh.tetList, faceList, edgeList, vertexList, mesh.tetMatrix); makeTetMatrix(tetMode, pts, mesh.tetList, faceList, edgeList, vertexList, mesh.tetMatrix, mesh.tetWeight); makeTetCenterList(tetMode, pts, mesh.tetList, tetCenter); mesh.numTet = (int)mesh.tetList.size()/4; mesh.computeTetMatrixInverse(); // initial probe position for(int i=0;i<numPrb;i++){ B.centre[i] = transPart(initMatrix[i]); } // compute distance between probe and tetrahedra D.setNum(numPrb, numPts, mesh.numTet); D.computeDistTet(tetCenter, B.centre); D.findClosestTet(); D.computeDistPts(pts, B.centre); D.findClosestPts(); if(!areaWeighted){ mesh.tetWeight.clear(); mesh.tetWeight.resize(mesh.numTet,1.0); } } // (re)compute ARAP if(!data.isClean(aARAP) || isNumProbeChanged){ // load painted weights if(stiffnessMode == SM_PAINT) { VectorXd ptsWeight(numPts); for (int i=0; !itGeo.isDone(); itGeo.next()){ double w=weightValue(data, mIndex, itGeo.index()); ptsWeight[i++] = (w>EPSILON) ? w : EPSILON; } makeTetWeightList(tetMode, mesh.tetList, faceList, edgeList, vertexList, ptsWeight, mesh.tetWeight); }else if(stiffnessMode == SM_LEARN) { std::vector<double> tetEnergy(mesh.numTet,0); MArrayDataHandle hSupervisedMesh = data.inputArrayValue(aSupervisedMesh); int numSupervisedMesh = hSupervisedMesh.elementCount(); for(int j=0;j<numSupervisedMesh;j++){ hSupervisedMesh.jumpToElement(j); MFnMesh ex_mesh(hSupervisedMesh.inputValue().asMesh()); MPointArray Mspts; ex_mesh.getPoints( Mspts ); if(numPts != Mspts.length()){ MGlobal::displayInfo("incompatible mesh"); return MS::kFailure; } std::vector<Vector3d> spts(numPts); for(int i=0;i<numPts;i++){ spts[i] << Mspts[i].x, Mspts[i].y, Mspts[i].z; } std::vector<double> dummy_weight; makeTetMatrix(tetMode, spts, mesh.tetList, faceList, edgeList, vertexList, Q, dummy_weight); Matrix3d S,R; for(int i=0;i<mesh.numTet;i++) { polarHigham((mesh.tetMatrixInverse[i]*Q[i]).block(0,0,3,3), S, R); tetEnergy[i] += (S-Matrix3d::Identity()).squaredNorm(); } } // compute weight (stiffness) double max_energy = *std::max_element(tetEnergy.begin(), tetEnergy.end()); for(int i=0;i<mesh.numTet;i++) { double w = 1.0 - tetEnergy[i]/(max_energy+EPSILON); mesh.tetWeight[i] *= w*w; } } // find constraint points constraint.resize(3*numPrb); for(int i=0;i<numPrb;i++){ constraint[3*i] = T(i,mesh.tetList[4*D.closestTet[i]],constraintWeight); constraint[3*i+1] = T(i,mesh.tetList[4*D.closestTet[i]+1],constraintWeight); constraint[3*i+2] = T(i,mesh.tetList[4*D.closestTet[i]+2],constraintWeight); } if( constraintMode == CONSTRAINT_NEIGHBOUR ){ std::vector<double> probeConstraintRadius(numPrb); MArrayDataHandle handle = data.inputArrayValue(aProbeConstraintRadius); if(handle.elementCount() != numPrb){ MGlobal::displayInfo("# of Probes and probeConstraintRadius are different"); return MS::kFailure; } for(int i=0;i<numPrb;i++){ handle.jumpToArrayElement(i); probeConstraintRadius[i]=handle.inputValue().asDouble(); } double constraintRadius = data.inputValue( aConstraintRadius ).asDouble(); for(int i=0;i<numPrb;i++){ double r = constraintRadius * probeConstraintRadius[i]; for(int j=0;j<numPts;j++){ if(D.distPts[i][j]<r){ constraint.push_back(T(i,j,constraintWeight * pow((r-D.distPts[i][j])/r,normExponent))); } } } } int numConstraint=constraint.size(); mesh.constraintWeight.resize(numConstraint); mesh.constraintVal.resize(numConstraint,numPrb); for(int cur=0;cur<numConstraint;cur++){ mesh.constraintWeight[cur] = std::make_pair(constraint[cur].col(), constraint[cur].value()); } // isError = mesh.ARAPprecompute(); status = data.setClean(aARAP); } // END of ARAP precomputation if(isError>0){ return MS::kFailure; } // probe weight computation if(!data.isClean(aComputeWeight) || isNumProbeChanged){ // load probe weights MArrayDataHandle handle = data.inputArrayValue(aProbeWeight); if(handle.elementCount() != numPrb){ MGlobal::displayInfo("# of Probes and probeWeight are different"); isError = ERROR_ATTR; return MS::kFailure; } double effectRadius = data.inputValue( aEffectRadius ).asDouble(); std::vector<double> probeWeight(numPrb), probeRadius(numPrb); for(int i=0;i<numPrb;i++){ handle.jumpToArrayElement(i); probeWeight[i] = handle.inputValue().asDouble(); probeRadius[i] = probeWeight[i] * effectRadius; } wr.resize(mesh.numTet);ws.resize(mesh.numTet);wl.resize(mesh.numTet); for(int j=0;j<mesh.numTet;j++){ wr[j].resize(numPrb); ws[j].resize(numPrb); wl[j].resize(numPrb); } short weightMode = data.inputValue( aWeightMode ).asShort(); if (weightMode == WM_INV_DISTANCE){ for(int j=0;j<mesh.numTet;j++){ double sum=0.0; std::vector<double> idist(numPrb); for (int i = 0; i<numPrb; i++){ idist[i] = probeRadius[i] / pow(D.distTet[i][j], normExponent); sum += idist[i]; } for (int i = 0; i<numPrb; i++){ wr[j][i] = ws[j][i] = wl[j][i] = sum > 0 ? idist[i] / sum : 0.0; } } } else if (weightMode == WM_CUTOFF_DISTANCE){ for(int j=0;j<mesh.numTet;j++){ for (int i = 0; i<numPrb; i++){ wr[j][i] = ws[j][i] = wl[j][i] = (D.distTet[i][j] > probeRadius[i]) ? 0 : pow((probeRadius[i] - D.distTet[i][j]) / probeRadius[i], normExponent); } } }else if (weightMode == WM_DRAW){ float val; MRampAttribute rWeightCurveR( thisNode, aWeightCurveR, &status ); MRampAttribute rWeightCurveS( thisNode, aWeightCurveS, &status ); MRampAttribute rWeightCurveL( thisNode, aWeightCurveL, &status ); for(int j=0;j<mesh.numTet;j++){ for (int i = 0; i < numPrb; i++){ rWeightCurveR.getValueAtPosition(D.distTet[i][j] / probeRadius[i], val); wr[j][i] = val; rWeightCurveS.getValueAtPosition(D.distTet[i][j] / probeRadius[i], val); ws[j][i] = val; rWeightCurveL.getValueAtPosition(D.distTet[i][j] / probeRadius[i], val); wl[j][i] = val; } } }else if(weightMode & WM_HARMONIC){ Laplacian harmonicWeighting; makeFaceTet(data, input, inputGeom, mIndex, pts, harmonicWeighting.tetList, harmonicWeighting.tetMatrix, harmonicWeighting.tetWeight); harmonicWeighting.numTet = (int)harmonicWeighting.tetList.size()/4; std::vector<T> weightConstraint(numPrb); // the vertex closest to the probe is given probeWeight for(int i=0;i<numPrb;i++){ weightConstraint[i]=T(i,D.closestPts[i],probeWeight[i]); } // vertices within effectRadius are given probeWeight if( data.inputValue( aNeighbourWeighting ).asBool() ){ for(int i=0;i<numPrb;i++){ for(int j=0;j<numPts;j++){ if(D.distPts[i][j]<probeRadius[i]){ weightConstraint.push_back(T(i,j,probeWeight[i])); } } } } // set boundary condition for weight computation int numConstraint=weightConstraint.size(); harmonicWeighting.constraintWeight.resize(numConstraint); harmonicWeighting.constraintVal.resize(numConstraint,numPrb); harmonicWeighting.constraintVal.setZero(); for(int i=0;i<numConstraint;i++){ harmonicWeighting.constraintVal(i,weightConstraint[i].row())=weightConstraint[i].value(); harmonicWeighting.constraintWeight[i] = std::make_pair(weightConstraint[i].col(), weightConstraint[i].value()); } // clear tetWeight if(!areaWeighted){ harmonicWeighting.tetWeight.clear(); harmonicWeighting.tetWeight.resize(harmonicWeighting.numTet,1.0); } // solve the laplace equation if( weightMode == WM_HARMONIC_ARAP){ harmonicWeighting.computeTetMatrixInverse(); harmonicWeighting.dim = numPts + harmonicWeighting.numTet; isError = harmonicWeighting.ARAPprecompute(); }else if(weightMode == WM_HARMONIC_COTAN){ harmonicWeighting.dim = numPts; isError = harmonicWeighting.cotanPrecompute(); } if(isError>0) return MS::kFailure; std::vector< std::vector<double> > w_tet(numPrb); harmonicWeighting.harmonicSolve(); for(int i=0;i<numPrb;i++){ makeTetWeightList(tetMode, mesh.tetList, faceList, edgeList, vertexList, harmonicWeighting.Sol.col(i), w_tet[i]); for(int j=0;j<mesh.numTet; j++){ wr[j][i] = ws[j][i] = wl[j][i] = w_tet[i][j]; } } } // normalise weights short normaliseWeightMode = data.inputValue( aNormaliseWeight ).asShort(); for(int j=0;j<mesh.numTet;j++){ D.normaliseWeight(normaliseWeightMode, wr[j]); D.normaliseWeight(normaliseWeightMode, ws[j]); D.normaliseWeight(normaliseWeightMode, wl[j]); } status = data.setClean(aComputeWeight); } // END of weight computation // setting up transformation matrix B.rotationConsistency = data.inputValue( aRotationConsistency ).asBool(); bool frechetSum = data.inputValue( aFrechetSum ).asBool(); blendedSE.resize(mesh.numTet); blendedR.resize(mesh.numTet); blendedS.resize(mesh.numTet); blendedL.resize(mesh.numTet);A.resize(mesh.numTet); for(int i=0;i<numPrb;i++){ B.Aff[i]=initMatrix[i].inverse()*matrix[i]; } B.parametrise(blendMode); // prepare transform matrix for each simplex #pragma omp parallel for for (int j = 0; j < mesh.numTet; j++){ // blend matrix if (blendMode == BM_SRL){ blendedS[j] = expSym(blendMat(B.logS, ws[j])); Vector3d l = blendMat(B.L, wl[j]); blendedR[j] = frechetSum ? frechetSO(B.R, wr[j]) : expSO(blendMat(B.logR, wr[j])); A[j] = pad(blendedS[j]*blendedR[j], l); } else if (blendMode == BM_SSE){ blendedS[j] = expSym(blendMat(B.logS, ws[j])); blendedSE[j] = expSE(blendMat(B.logSE, wr[j])); A[j] = pad(blendedS[j], Vector3d::Zero()) * blendedSE[j]; } else if (blendMode == BM_LOG3){ blendedR[j] = blendMat(B.logGL, wr[j]).exp(); Vector3d l = blendMat(B.L, wl[j]); A[j] = pad(blendedR[j], l); } else if (blendMode == BM_LOG4){ A[j] = blendMat(B.logAff, wr[j]).exp(); } else if (blendMode == BM_SQL){ Vector4d q = blendQuat(B.quat, wr[j]); Vector3d l = blendMat(B.L, wl[j]); blendedS[j] = blendMatLin(B.S, ws[j]); Quaternion<double> RQ(q); blendedR[j] = RQ.matrix().transpose(); A[j] = pad(blendedS[j]*blendedR[j], l); } else if (blendMode == BM_AFF){ A[j] = blendMatLin(B.Aff, wr[j]); } } // compute target vertices position tetEnergy.resize(mesh.numTet); // set constraint int numConstraints = constraint.size(); mesh.constraintVal.resize(numConstraints,3); RowVector4d cv; for(int cur=0;cur<numConstraints;cur++){ cv = pad(pts[constraint[cur].col()]) * B.Aff[constraint[cur].row()]; mesh.constraintVal(cur,0) = cv[0]; mesh.constraintVal(cur,1) = cv[1]; mesh.constraintVal(cur,2) = cv[2]; } // iterate to determine vertices position for(int k=0;k<numIter;k++){ // solve ARAP mesh.ARAPSolve(A); // set new vertices position new_pts.resize(numPts); for(int i=0;i<numPts;i++){ new_pts[i][0]=mesh.Sol(i,0); new_pts[i][1]=mesh.Sol(i,1); new_pts[i][2]=mesh.Sol(i,2); } // if iteration continues if(k+1<numIter || visualisationMode == VM_ENERGY){ std::vector<double> dummy_weight; makeTetMatrix(tetMode, new_pts, mesh.tetList, faceList, edgeList, vertexList, Q, dummy_weight); Matrix3d S,R,newS,newR; if(blendMode == BM_AFF || blendMode == BM_LOG4 || blendMode == BM_LOG3){ for(int i=0;i<mesh.numTet;i++){ polarHigham(A[i].block(0,0,3,3), blendedS[i], blendedR[i]); } } #pragma omp parallel for for(int i=0;i<mesh.numTet;i++){ polarHigham((mesh.tetMatrixInverse[i]*Q[i]).block(0,0,3,3), newS, newR); tetEnergy[i] = (newS-blendedS[i]).squaredNorm(); A[i].block(0,0,3,3) = blendedS[i]*newR; // polarHigham((A[i].transpose()*PI[i]*Q[i]).block(0,0,3,3), newS, newR); // A[i].block(0,0,3,3) *= newR; } } } for(int i=0;i<numPts;i++){ Mpts[i].x=mesh.Sol(i,0); Mpts[i].y=mesh.Sol(i,1); Mpts[i].z=mesh.Sol(i,2); } if(worldMode){ for(int i=0;i<numPts;i++) Mpts[i] *= localToWorldMatrix.inverse(); } itGeo.setAllPositions(Mpts); // set vertex colour if(visualisationMode != VM_OFF){ std::vector<double> ptsColour(numPts, 0.0); if(visualisationMode == VM_ENERGY){ makePtsWeightList(tetMode, numPts, mesh.tetList, faceList, edgeList, vertexList, tetEnergy, ptsColour); for(int i=0;i<numPts;i++){ ptsColour[i] *= visualisationMultiplier; } }else if(visualisationMode == VM_STIFFNESS){ makePtsWeightList(tetMode, numPts, mesh.tetList, faceList, edgeList, vertexList, mesh.tetWeight, ptsColour); double maxval = *std::max_element(ptsColour.begin(), ptsColour.end()); for(int i=0;i<numPts;i++){ ptsColour[i] = 1.0 - ptsColour[i]/maxval; } }else if(visualisationMode == VM_CONSTRAINT){ for(int i=0;i<constraint.size();i++){ ptsColour[constraint[i].col()] += constraint[i].value(); } }else if(visualisationMode == VM_EFFECT){ std:vector<double> wsum(mesh.numTet); for(int j=0;j<mesh.numTet;j++){ //wsum[j] = std::accumulate(wr[j].begin(), wr[j].end(), 0.0); wsum[j]= visualisationMultiplier * wr[j][numPrb-1]; } makePtsWeightList(tetMode, numPts, mesh.tetList, faceList, edgeList, vertexList, wsum, ptsColour); } visualise(data, outputGeom, ptsColour); } return MS::kSuccess; }
MStatus weightList::compute( const MPlug& plug, MDataBlock& block) { MStatus status = MS::kSuccess; unsigned i, j; MObject thisNode = thisMObject(); MPlug wPlug(thisNode, aWeights); // Write into aWeightList for( i = 0; i < 3; i++) { status = wPlug.selectAncestorLogicalIndex( i, aWeightsList ); MDataHandle wHandle = wPlug.constructHandle(block); MArrayDataHandle arrayHandle(wHandle, &status); McheckErr(status, "arrayHandle construction failed\n"); MArrayDataBuilder arrayBuilder = arrayHandle.builder(&status); McheckErr(status, "arrayBuilder accessing/construction failed\n"); for( j = 0; j < i+2; j++) { MDataHandle handle = arrayBuilder.addElement(j,&status); McheckErr(status, "addElement to arrayBuilder failed\n"); float val = 1.0f*(i+j); handle.set(val); } status = arrayHandle.set(arrayBuilder); McheckErr(status, "set arrayBuilder failed\n"); wPlug.setValue(wHandle); wPlug.destructHandle(wHandle); } // Read from aWeightList and print out result MArrayDataHandle arrayHandle = block.inputArrayValue(aWeightsList, &status); McheckErr(status, "arrayHandle construction for aWeightsList failed\n"); unsigned count = arrayHandle.elementCount(); for( i = 0; i < count; i++) { arrayHandle.jumpToElement(i); MDataHandle eHandle = arrayHandle.inputValue(&status).child(aWeights); McheckErr(status, "handle evaluation failed\n"); MArrayDataHandle eArrayHandle(eHandle, &status); McheckErr(status, "arrayHandle construction for aWeights failed\n"); unsigned eCount = eArrayHandle.elementCount(); for( j = 0; j < eCount; j++) { eArrayHandle.jumpToElement(j); float weight = eArrayHandle.inputValue(&status).asFloat(); McheckErr(status, "weight evaluation error\n"); fprintf(stderr, "weightList[%u][%u] = %g\n",i,j,weight); } } // Read from aWeightList and print out result using the more // efficient jumpToArrayElement() call arrayHandle = block.inputArrayValue(aWeightsList, &status); McheckErr(status, "arrayHandle construction for aWeightsList failed\n"); count = arrayHandle.elementCount(); for( i = 0; i < count; i++) { arrayHandle.jumpToArrayElement(i); MDataHandle eHandle = arrayHandle.inputValue(&status).child(aWeights); McheckErr(status, "handle evaluation failed\n"); MArrayDataHandle eArrayHandle(eHandle, &status); McheckErr(status, "arrayHandle construction for aWeights failed\n"); unsigned eCount = eArrayHandle.elementCount(); for( j = 0; j < eCount; j++) { eArrayHandle.jumpToArrayElement(j); float weight = eArrayHandle.inputValue(&status).asFloat(); McheckErr(status, "weight evaluation error\n"); fprintf(stderr, "weightList[%d][%d] = %g\n",i,j,weight); } } return status; }