예제 #1
0
MStatus testNucleusNode::compute(const MPlug &plug, MDataBlock &data)
{
	MStatus stat;

	if ( plug == nextState )
	{
        
        //get the value of the currentTime 
        MTime currTime = data.inputValue(currentTime).asTime();        
        MObject inputData;
        //pull on start state or current state depending on the current time.
        if(currTime.value() <= 0.0) {
            MArrayDataHandle multiDataHandle = data.inputArrayValue(startState);
            multiDataHandle.jumpToElement(0);
            inputData =multiDataHandle.inputValue().data();
        }
        else {
            MArrayDataHandle multiDataHandle = data.inputArrayValue(currentState);
            multiDataHandle.jumpToElement(0);
            inputData =multiDataHandle.inputValue().data();
        }                
                
        MFnNObjectData inputNData(inputData);                
        MnCloth * nObj = NULL;
        inputNData.getObjectPtr(nObj);        
        
        MFloatPointArray points;
        nObj->getPositions(points);
        unsigned int ii;
        for(ii=0;ii<points.length();ii++) {            
            points[ii].y = (float) sin(points[ii].x + currTime.value()*4.0f*(3.1415f/180.0f));
        }
        nObj->setPositions(points);

        delete nObj;        
        data.setClean(plug);
	}
	else if ( plug == currentState )
	{        
	    data.setClean(plug);

	}
    else if (plug == startState) {        
	    data.setClean(plug);
    }
    else {
		stat = MS::kUnknownParameter;
	}
	return stat;
}
예제 #2
0
void SurfaceAttach::setOutPlugs(MDataBlock dataBlock, const MFnNurbsSurface &fnSurface,
                                const double dataOffset, const bool dataReverse, const short dataGenus, const double dataStaticLength,
                                const MMatrix &dataParentInverse, const short dataDirection) {

    MTransformationMatrix tfm;
    MVector t;
    MEulerRotation r;

    MArrayDataHandle outputHandle = dataBlock.outputArrayValue(SurfaceAttach::out);
    std::int32_t count = outputHandle.elementCount();
    MDataHandle o;

    for (unsigned int k = 0; k < count; ++k) {
        outputHandle.jumpToElement(k);

        // Get Transformations
        tfm = this->matrix(fnSurface, outputHandle.elementIndex(), dataOffset, dataReverse, dataGenus,
                           dataStaticLength, dataParentInverse, dataDirection);
        t = tfm.translation(MSpace::Space::kWorld);
        r = tfm.eulerRotation();

        o = outputHandle.outputValue();
        o.child(SurfaceAttach::translate).set(t);
        o.child(SurfaceAttach::rotate).set(r.x, r.y, r.z);
    }

    // Mark Clean
    dataBlock.setClean(SurfaceAttach::translate);
    dataBlock.setClean(SurfaceAttach::rotate);
    dataBlock.setClean(SurfaceAttach::out);
}
예제 #3
0
MStatus HRBFSkinCluster::skinLB(MMatrixArray&  transforms,
	int numTransforms,
	MArrayDataHandle& weightListHandle,
	MItGeometry& iter) {
	MStatus returnStatus;

	// Iterate through each point in the geometry.
	//
	for (; !iter.isDone(); iter.next()) {
		MPoint pt = iter.position();
		MPoint skinned;
		// get the weights for this point -> must be dependent on the iterator somehow
		MArrayDataHandle weightsHandle = weightListHandle.inputValue().child(weights);
		// compute the skinning -> TODO: what's the order that the weights are given in? Appears to just be maya list relatives order.
		for (int i = 0; i<numTransforms; ++i) {
			if (MS::kSuccess == weightsHandle.jumpToElement(i)) {
				skinned += (pt * transforms[i]) * weightsHandle.inputValue().asDouble();
			}
		}

		// Set the final position.
		iter.setPosition(skinned);
		// advance the weight list handle
		weightListHandle.next();
	}
	return returnStatus;
}
예제 #4
0
MStatus ffdPlanar::getBoundingBox( MDataBlock& block,
                                   unsigned int multiIndex,
                                   MBoundingBox &boundingBoxOut )
{
    MStatus status = MS::kSuccess;
    
    MArrayDataHandle inputHandle = block.outputArrayValue( input );
    inputHandle.jumpToElement( multiIndex );
    MObject mesh = inputHandle.outputValue().child( inputGeom ).asMesh();
    
    MBoundingBox boundingBox = MBoundingBox();
    MFnMesh meshFn( mesh, &status );
    MCheckErr( status, "Error getting mesh from mesh object\n" );
    
    MPointArray pointArray = MPointArray();
    meshFn.getPoints( pointArray, MSpace::kTransform );
    
    for ( int i = 0; i < pointArray.length(); i++ )
    {
        boundingBox.expand( pointArray[i] );
    }
    
    boundingBoxOut = boundingBox;
    return status;
}
예제 #5
0
MStatus RippleDeformer::deform(MDataBlock& dataBlock,
								MItGeometry& itGeo,
								const MMatrix& localToWorldMatrix,
								unsigned int geomIndex)
{
	MStatus status;
	
	//get attriubtes as a datahandle
	float env = dataBlock.inputValue(envelope).asFloat();
	float amplitude = dataBlock.inputValue(aAmplitude).asFloat();
	float displace = dataBlock.inputValue(aDisplace).asFloat();
	//get the mesh 
	
	//retrieve the handle to the input attribute
	MArrayDataHandle hInput = dataBlock.outputArrayValue(input, &status);
	CHECK_MSTATUS_AND_RETURN_IT(status);
	//get the input array index handle
	status = hInput.jumpToElement(geomIndex);
	//get the handle of geomIndex attribute
	MDataHandle hInputElement = hInput.outputValue(&status);
	//Get the MObject of the input geometry of geomindex
	MObject oInputGeom = hInputElement.child(inputGeom).asMesh();

	MFnMesh fnMesh(oInputGeom, &status);
	CHECK_MSTATUS_AND_RETURN_IT(status);
	if (oInputGeom.isNull())
	{
		return MS::kSuccess;
	}

	MFloatVectorArray normals;
	fnMesh.getVertexNormals(false, normals);

	MPoint pointPos;
	float weight;
	
	for (; !itGeo.isDone(); itGeo.next())
	{
		//get current point position
		pointPos = itGeo.position();
		weight = weightValue(dataBlock, geomIndex, itGeo.index());
		pointPos.x = pointPos.x + sin(itGeo.index() + displace) * amplitude * normals[itGeo.index()].x * weight * env;
		pointPos.y = pointPos.y + sin(itGeo.index() + displace) * amplitude * normals[itGeo.index()].y * weight * env;
		pointPos.z = pointPos.z + sin(itGeo.index() + displace) * amplitude * normals[itGeo.index()].z * weight * env;
		//setPosition
		itGeo.setPosition(pointPos);
	}	
	
	return MS::kSuccess;
}
예제 #6
0
// COMPUTE ======================================
MStatus gear_curveCns::deform( MDataBlock& data, MItGeometry& iter, const MMatrix &mat, unsigned int mIndex )
{
    MStatus returnStatus;

	MArrayDataHandle adh = data.inputArrayValue( inputs );
	int deformer_count = adh.elementCount( &returnStatus );

	// Process
	while (! iter.isDone()){
		if (iter.index() < deformer_count){
			adh.jumpToElement(iter.index());
			MTransformationMatrix m(adh.inputValue().asMatrix() * mat.inverse());
			MVector v = m.getTranslation(MSpace::kWorld, &returnStatus );
			MPoint pt(v);
			iter.setPosition(pt);
		}
		iter.next();
	}
 
    return MS::kSuccess;
}
예제 #7
0
MStatus PushDeformer::deform(MDataBlock& dataBlock,
								MItGeometry& itGeo,
								const MMatrix& localToWorldMatrix,
								unsigned int geomIndex)
{
	MStatus status;
	//get attribute handles
	double bulgeAmount = dataBlock.inputValue(aAmount, &status).asDouble();
	CHECK_MSTATUS_AND_RETURN_IT(status);
	m_taskData.envelope = dataBlock.inputValue(envelope, &status).asFloat();
	CHECK_MSTATUS_AND_RETURN_IT(status);
	bool useStressV = dataBlock.inputValue(aUseStress, &status).asBool();
	CHECK_MSTATUS_AND_RETURN_IT(status);
	int multiThreadingType = dataBlock.inputValue(aMultiThreadingType, &status).asBool();
	CHECK_MSTATUS_AND_RETURN_IT(status);

	if (m_taskData.envelope <= 0.001)
	{
		return MS::kSuccess;
	}
	// if the use stress plug is turned on pull 
	MDoubleArray stressV;
	if (useStressV == true)
	{
		//pull out the raw data as an Mobject
		MObject stressMap = dataBlock.inputValue(aStressMap, &status).data();
		CHECK_MSTATUS_AND_RETURN_IT(status);
		MFnDoubleArrayData stressDataFn(stressMap);
    m_taskData.stressV = stressDataFn.array();
	}

	//retrieve the handle to the output array attribute
	MArrayDataHandle hInput = dataBlock.outputArrayValue(input, &status);
	CHECK_MSTATUS_AND_RETURN_IT(status);
	//get the input array index handle
	status = hInput.jumpToElement(geomIndex);
	//get the handle of geomIndex attribute
	MDataHandle hInputElement = hInput.outputValue(&status);
	CHECK_MSTATUS_AND_RETURN_IT(status);
	//Get the MObject of the input geometry of geomindex
	MObject oInputGeom = hInputElement.child(inputGeom).asMesh();
	MFnMesh fnMesh(oInputGeom, &status);
	CHECK_MSTATUS_AND_RETURN_IT(status);

  
	fnMesh.getVertexNormals(false, m_taskData.normals, MSpace::kWorld);
	itGeo.allPositions(m_taskData.points, MSpace::kWorld);
  //MGlobal::displayInfo( "test" );
  /*for (int i = 0; i < itGeo.count();  i++)
	{
    MGlobal::displayInfo( MFnAttribute(weightList).isArray );
  }*/
  m_taskData.bulgeAmount = bulgeAmount;

  if(multiThreadingType == 1)
  {
    ThreadData* pThreadData = createThreadData( NUM_TASKS, &m_taskData );
    MThreadPool::newParallelRegion( createTasks, (void*)pThreadData );
    itGeo.setAllPositions(m_taskData.points);
    delete [] pThreadData;
    return MS::kSuccess;
  }


  else if(multiThreadingType == 2)
  {
    tbb::parallel_for(size_t(0), size_t(itGeo.count()), [this](size_t i)
    {
		  //const float w = weightValue(dataBlock, geomIndex, i);
      const float w = 1.0;
		  if (m_taskData.useStressV == true && (m_taskData.stressV.length() > 0))
		  {
			  //deform
			  m_taskData.points[i] += (MVector(m_taskData.normals[i]) * m_taskData.bulgeAmount * m_taskData.envelope * w * m_taskData.stressV[i]);
		  }
		  else
		  {
			  //deform
        m_taskData.points[i] += m_taskData.normals[i] * m_taskData.bulgeAmount * m_taskData.envelope * w;
		  }  
  
    });
  }

  
	//
  else if(multiThreadingType == 3)
  #pragma omp parallel for 

  for (int i = 0; i < itGeo.count();  i++)
	{
		float w = weightValue(dataBlock, geomIndex, itGeo.index());
		if (useStressV == true && (stressV.length() > 0))
		{
			//deform
      m_taskData.points[i] += (MVector(m_taskData.normals[i]) * bulgeAmount * m_taskData.envelope * w * m_taskData.stressV[i]);
			
		}
		else
		{
			//deform
      m_taskData.points[i] += m_taskData.normals[i] * bulgeAmount * m_taskData.envelope * w;

		}
	}
  else
  {
    for (; !itGeo.isDone(); itGeo.next())
	  {
		  float w = weightValue(dataBlock, geomIndex, itGeo.index());
		  if (useStressV == true && (stressV.length() > 0))
		  {
			  //deform
        m_taskData.points[itGeo.index()] += (MVector(m_taskData.normals[itGeo.index()]) * bulgeAmount * m_taskData.envelope * w * m_taskData.stressV[itGeo.index()]);
			
		  }
		  else
		  {
			  //deform
        m_taskData.points[itGeo.index()] += m_taskData.normals[itGeo.index()] * bulgeAmount * m_taskData.envelope * w;
		  }
	  }
  }
	itGeo.setAllPositions(m_taskData.points);

	return MS::kSuccess;

}
예제 #8
0
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;
}
예제 #9
0
void TestDeformer::_deform_on_one_mesh(MDataBlock& data,
                                      MItGeometry& iter,
                                      const MMatrix& localToWorldMatrix,
                                      unsigned int mIndex,
                                      MObject &driver_mesh,
                                      const MDataHandle &envelopeHandle, MArrayDataHandle &vertMapArrayData, MPointArray &tempOutputPts)
{
    MStatus status;

    float env = envelopeHandle.asFloat();

    // use driver_meshVertIter to walk through the vertex of the current driver mesh
    MItMeshVertex driver_meshVertIter( driver_mesh, &status );
    CHECK_MSTATUS( status );

    int i = 0;
    iter.reset();
    while( !iter.isDone(&status) )
    {
        CHECK_MSTATUS( status );

        // get the weight
        float weight = weightValue( data, mIndex, iter.index() ); //painted weight
        float ww = weight * env;

        if ( fabs(ww) > FLT_EPSILON )//if ( ww != 0 )
        {
            __debug("%s(), vertMapArrayData.elementCount()=%d, iter.index()=%d",
                    __FUNCTION__, vertMapArrayData.elementCount(), iter.index());

            // get index_mapped to which the currrent vertex vI is mapped
            CHECK_MSTATUS(vertMapArrayData.jumpToElement(iter.index()));
            int index_mapped = vertMapArrayData.inputValue(&status).asInt();
            CHECK_MSTATUS( status );

            if( index_mapped >= 0 )
            {
                __debug("index_mapped=%d", index_mapped);

                int prevInt;
                CHECK_MSTATUS( driver_meshVertIter.setIndex(index_mapped, prevInt) );

                // vertex wrold position on driver mesh
                MPoint mappedPt = driver_meshVertIter.position( MSpace::kWorld, &status );
                CHECK_MSTATUS( status );
                // vertex wrold position on driven mesh
                MPoint iterPt = iter.position(MSpace::kObject, &status) * localToWorldMatrix;
                CHECK_MSTATUS( status );

                // use ww to interpolate between mappedPt and iterPt
                MPoint pt = iterPt + ((mappedPt - iterPt) * ww );
                pt = pt * localToWorldMatrix.inverse();

                /// put the deform points to tempOutputPts
                tempOutputPts[i] += pt;
            }
        }//if
        CHECK_MSTATUS(iter.next());
        ++i;
    }//while
}
예제 #10
0
void TestDeformer::initVertMapping(MDataBlock& data,
                          MItGeometry& iter,
                          const MMatrix& localToWorldMatrix,
                          unsigned int mIndex)
{
    MStatus status;


    MArrayDataHandle vertMapOutArrayData = data.outputArrayValue( vert_map, &status );
    CHECK_MSTATUS( status );

    // use vertMapOutArrayBuilder to modify vertMapOutArrayData
    iter.reset();
    int count = iter.count();
    MArrayDataBuilder vertMapOutArrayBuilder( vert_map, count, &status );
    CHECK_MSTATUS( status );


    MPointArray allPts;// world vertex position of the driven mesh
    allPts.clear();

    // walk through the driven mesh
    /// copy MItGeometry's vertex to vertMapOutArrayData
    int i = 0;
    while( !iter.isDone(&status) )
    {
        CHECK_MSTATUS( status );

        MDataHandle initIndexDataHnd = vertMapOutArrayBuilder.addElement( i, &status );
        CHECK_MSTATUS( status );

        int negIndex = -1;

        initIndexDataHnd.setInt( negIndex );
        initIndexDataHnd.setClean();

        // append a vertex position(world coordination) to allPts
        CHECK_MSTATUS(allPts.append( iter.position() * localToWorldMatrix ));
        i = i+1;
        iter.next();
    }
    CHECK_MSTATUS(vertMapOutArrayData.set( vertMapOutArrayBuilder ));




    /// Append more vertex from each driver mesh to vertMapOutArrayData
    MArrayDataHandle meshAttrHandle = data.inputArrayValue( driver_mesh, &status );
    CHECK_MSTATUS( status );

    int numMeshes = meshAttrHandle.elementCount();
    __debug("%s(), numMeshes=%d", __FUNCTION__, numMeshes);

    CHECK_MSTATUS(meshAttrHandle.jumpToElement(0));
    for( int meshIndex=0; meshIndex < numMeshes; ++meshIndex )
    {
        __debug("%s(), meshIndex=%d", __FUNCTION__, meshIndex);

        MDataHandle currentMesh = meshAttrHandle.inputValue(&status);
        CHECK_MSTATUS(status);

        MObject meshMobj = currentMesh.asMesh();
        __debug("%s(), meshMobj.apiTypeStr()=%s", __FUNCTION__, meshMobj.apiTypeStr());

        __debugMeshInfo(__FUNCTION__, meshMobj);
        {
            _initVertMapping_on_one_mesh(meshMobj, vertMapOutArrayBuilder, allPts);// Note: vertMapOutArrayBuilder is updated in this function!
            //CHECK_MSTATUS(vertMapOutArrayData.set( vertMapOutArrayBuilder ));
        }

        if( !meshAttrHandle.next() )
        {
            break;
        }
    }// for (mesh
    CHECK_MSTATUS(vertMapOutArrayData.set( vertMapOutArrayBuilder ));



}
예제 #11
0
MStatus TestDeformer::deform(MDataBlock& data,
                          MItGeometry& iter,
                          const MMatrix& localToWorldMatrix,
                          unsigned int mIndex)
{
    MStatus status;

    // get the current node state
    short initialized_mapping = data.inputValue( initialized_data, &status).asShort();
    CHECK_MSTATUS(status);
    __debug("%s(), initialized_mapping=%d, mIndex=%d", __FUNCTION__, initialized_mapping, mIndex);

    if( initialized_mapping == 1 )
    {
        initVertMapping(data, iter, localToWorldMatrix, mIndex);

        // set initialized_data to 2 automatically. User don't have to set it manully.
        MObject tObj  =  thisMObject();
        MPlug setInitMode = MPlug( tObj, initialized_data  );
        setInitMode.setShort( 2 );
        // and sync initialized_mapping from initialized_data
        // so, the code section:
        //     if (initialized_mapping == 2)
        //     {
        //         ...
        //     }
        // will be executed when this deform() function is called next time.
        initialized_mapping = data.inputValue( initialized_data, &status ).asShort();
        CHECK_MSTATUS(status);
    }

    if( initialized_mapping == 2 )
    {
        envelope = MPxDeformerNode::envelope;
        MDataHandle envelopeHandle = data.inputValue( envelope, &status );
        CHECK_MSTATUS( status );

        MArrayDataHandle vertMapArrayData  = data.inputArrayValue( vert_map, &status  );
        CHECK_MSTATUS( status );

        MArrayDataHandle meshAttrHandle = data.inputArrayValue( driver_mesh, &status );
        CHECK_MSTATUS( status );


        /// 1. init tempOutputPts to zero points
        MPointArray tempOutputPts;
        iter.reset();
        while( !iter.isDone(&status) )
        {
            CHECK_MSTATUS(tempOutputPts.append(MPoint(0, 0, 0)));
            CHECK_MSTATUS(iter.next());
        }
        assert(tempOutputPts.length() == iter.count());


        /// 2. set tempOutputPts to deform values which comes from each driver mesh
        iter.reset();

        int numMeshes = meshAttrHandle.elementCount();
        __debug("%s(), numMeshes=%d", __FUNCTION__, numMeshes);

        CHECK_MSTATUS(meshAttrHandle.jumpToElement(0));
        // for each driver mesh
        for( int count=0; count < numMeshes; ++count )
        {
            __debug("%s(), count=%d", __FUNCTION__, count);

            // for one driver mesh: currentMesh
            MDataHandle currentMesh = meshAttrHandle.inputValue(&status);
            CHECK_MSTATUS( status );
            MObject meshMobj = currentMesh.asMesh();
            __debugMeshInfo(__FUNCTION__, meshMobj);

            // accumulate deform values of currentMesh to tempOutputPts
            _deform_on_one_mesh(data, iter, localToWorldMatrix, mIndex,
                                meshMobj,
                                envelopeHandle, vertMapArrayData, tempOutputPts );


            if( !meshAttrHandle.next() )
            {
                break;
            }

        }// for each driver mesh


        /// 3. add deform value to this geometry(driven mesh)
        int i = 0;
        iter.reset();
        while( !iter.isDone(&status) )
        {
            MPoint p = iter.position(MSpace::kObject, &status);
            CHECK_MSTATUS(status);

            // add the deform value to this vertex
            CHECK_MSTATUS(iter.setPosition( p + tempOutputPts[i]/numMeshes ));

            CHECK_MSTATUS(iter.next());
            ++i;
        }
        assert(tempOutputPts.length() == iter.count());
    }// if

	return( MS::kSuccess );
}
예제 #12
0
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;
}
예제 #13
0
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 CageDeformerNode::deform( MDataBlock& data, MItGeometry& itGeo, const MMatrix &localToWorldMatrix, unsigned int mIndex )
{
    /// main
    MStatus status;
    MThreadUtils::syncNumOpenMPThreads();    // for OpenMP
    // load cage mesh and other attributes
    MObject oCageMesh = data.inputValue( aCageMesh ).asMesh();
    short blendMode = data.inputValue(aBlendMode).asShort();
	bool rotationCosistency = data.inputValue( aRotationConsistency ).asBool();
	bool frechetSum = data.inputValue( aFrechetSum ).asBool();
    short newConstraintMode = data.inputValue(aConstraintMode).asShort();
    double newConstraintWeight = data.inputValue( aConstraintWeight ).asDouble();
    if ( oCageMesh.isNull() || blendMode == 99)
        return MS::kSuccess;
    short newCageMode = data.inputValue(aCageMode).asShort();
    MFnMesh fnCageMesh( oCageMesh, &status );
    CHECK_MSTATUS_AND_RETURN_IT( status );
    MPointArray cagePoints;
    fnCageMesh.getPoints( cagePoints,  MSpace::kWorld );
    // save initial cage state
    if (initCagePoints.length() != cagePoints.length()){
        initCageMesh = oCageMesh;
        initCagePoints=cagePoints;
    }
    // when cage mode is changed
    if(newCageMode != cageMode || newConstraintMode != constraintMode || newConstraintWeight != constraintWeight)
    {
        cageMode = newCageMode;
        constraintMode = newConstraintMode;
        constraintWeight = newConstraintWeight;
	    std::vector<double> tetWeight;
        // read target mesh data
        MArrayDataHandle hInput = data.outputArrayValue( input, &status );
        CHECK_MSTATUS_AND_RETURN_IT( status );
        status = hInput.jumpToElement( mIndex );
        CHECK_MSTATUS_AND_RETURN_IT( status );
        MObject oInputGeom = hInput.outputValue().child( inputGeom ).asMesh();
        MFnMesh inputMesh(oInputGeom);
        inputMesh.getPoints( pts );
		numPts=pts.length();
        for(int j=0; j<numPts; j++ )
            pts[j] *= localToWorldMatrix;
        MIntArray count;
        inputMesh.getTriangles( count, meshTriangles );
		numTet=meshTriangles.length()/3;
		std::vector<Matrix4d> P(numTet);
        tetCenter.resize(numTet);
        tetMatrixC(pts, meshTriangles, P, tetCenter);
        PI.resize(numTet);
		for(int i=0;i<numTet;i++)
			PI[i] = P[i].inverse();
        // prepare cage tetrahedra
        MFnMesh fnInitCageMesh( initCageMesh, &status );
        if(cageMode == 10 || cageMode == 11)  // face mode
        {
			if(cageMode == 10){       // triangulate faces by MAYA standard
                MIntArray count;
                fnInitCageMesh.getTriangles( count, triangles );
                tetWeight.resize(triangles.length()/3, 1.0f);
			}else if(cageMode ==11){  // trianglate faces with more than 3 edges in a symmetric way
				triangles.clear();
				MItMeshPolygon iter(initCageMesh);
				MIntArray tmp;
                MVector normal;
				tetWeight.reserve(4*iter.count());
                unsigned int l;
				for(unsigned int i=0; ! iter.isDone(); i++){
					iter.getVertices(tmp);
					l=tmp.length();
					if(l==3){
						tetWeight.push_back(1.0);
						triangles.append(tmp[0]);
						triangles.append(tmp[1]);
						triangles.append(tmp[2]);
					}else{
						for(unsigned int j=0;j<l;j++){
                            tetWeight.push_back((l-2.0)/l);
							triangles.append(tmp[j]);
							triangles.append(tmp[(j+1) % l]);
							triangles.append(tmp[(j+2) % l]);
						}
					}
					iter.next();
				}
            }
            // face mode compute init matrix
            numPrb=triangles.length()/3;
            initMatrix.resize(numPrb);
            tetMatrix(initCagePoints, triangles, cageMode, initMatrix);
            // compute weight
            w.resize(numTet);
            std::vector< std::vector<double> > idist(numTet);
            for(int j=0;j<numTet;j++){
                idist[j].resize(numPrb);
                w[j].resize(numPrb);
                double sidist = 0.0;
                for(int i=0;i<numPrb;i++){
                    idist[j][i] = tetWeight[i]/distPtTri(tetCenter[j],initMatrix[i]);
                    sidist += idist[j][i];
                }
                assert(sidist>0.0f);
                for(int i=0;i<numPrb;i++)
                    w[j][i] = idist[j][i] /sidist;
            }// face mode end
        }else if(cageMode == 0 || cageMode == 1){   // vertex mode
            triangles.clear();
            std::vector<int> tetCount(initCagePoints.length());
            MItMeshVertex iter(initCageMesh);
            for(int j=0; ! iter.isDone(); j++){
                MIntArray v;
                iter.getConnectedVertices(v);     // at each vertex, construct tetrahedra from connected edges
                int l=v.length();
                if(l==3){
                    if(isDegenerate(initCagePoints[j],initCagePoints[v[0]],initCagePoints[v[1]],initCagePoints[v[2]]) != 0){
                        tetCount[j]++;
                        triangles.append(j);
                        triangles.append(v[0]);
                        triangles.append(v[1]);
                        triangles.append(v[2]);
                    }
                }else{
                    for(int k=0;k<l;k++){
                        if(isDegenerate(initCagePoints[j],initCagePoints[v[k]],initCagePoints[v[(k+1) % l]],initCagePoints[v[(k+2) % l]]) != 0){
                            tetCount[j]++;
                            triangles.append(j);
                            triangles.append(v[k]);
                            triangles.append(v[(k+1) % l]);
                            triangles.append(v[(k+2) % l]);
                        }
                    }
                }
                iter.next();
            }
            numPrb=triangles.length()/4;
            initMatrix.resize(numPrb);
            tetMatrix(initCagePoints, triangles, cageMode, initMatrix);
            // vertex mode compute weight
            w.resize(numTet);
            std::vector< std::vector<double> > idist(numTet);
            tetWeight.resize(numPrb);
            for(int i=0;i<numPrb;i++)
                tetWeight[i]=1.0/(double)tetCount[triangles[4*i]];
            for(int j=0;j<numTet;j++){
                idist[j].resize(numPrb);
                w[j].resize(numPrb);
                double sidist = 0.0;
                for(int i=0;i<numPrb;i++){
                    Vector3d c(initCagePoints[triangles[4*i]].x,initCagePoints[triangles[4*i]].y,initCagePoints[triangles[4*i]].z);
                    idist[j][i] = tetWeight[i] / ((tetCenter[j]-c).squaredNorm());
                    sidist += idist[j][i];
                }
                assert(sidist>0.0f);
                for(int i=0;i<numPrb;i++)
                    w[j][i] = idist[j][i] /sidist;
            }
        }else if(cageMode == 5 || cageMode == 6 ){ // vertex averaged normal mode
            triangles.clear();
            std::vector<int> tetCount(initCagePoints.length());
            MItMeshVertex iter(initCageMesh);
            for(int j=0; ! iter.isDone(); j++){
                MIntArray v;
                iter.getConnectedVertices(v);
                int l=v.length();
                for(int k=0;k<l;k++){
                    tetCount[j]++;
                    triangles.append(j);
                    triangles.append(v[k]);
                    triangles.append(v[(k+1) % l]);
                }
                iter.next();
            }
            numPrb=triangles.length()/3;
            initMatrix.resize(numPrb);
            tetMatrix(initCagePoints, triangles, cageMode, initMatrix);
            // vertex mode compute weight
            w.resize(numTet);
            std::vector< std::vector<double> > idist(numTet);
            tetWeight.resize(numPrb);
            for(int i=0;i<numPrb;i++)
                tetWeight[i]=1.0/(double)tetCount[triangles[3*i]];
            for(int j=0;j<numTet;j++){
                idist[j].resize(numPrb);
                w[j].resize(numPrb);
                double sidist = 0.0;
                for(int i=0;i<numPrb;i++){
                    Vector3d c(initCagePoints[triangles[3*i]].x,initCagePoints[triangles[3*i]].y,initCagePoints[triangles[3*i]].z);
                    idist[j][i] = tetWeight[i] / ((tetCenter[j]-c).squaredNorm());
                    sidist += idist[j][i];
                }
                assert(sidist>0.0f);
                for(int i=0;i<numPrb;i++)
                    w[j][i] = idist[j][i] /sidist;
            }
        }// end of cage setup
        
        // find constraint points
        if(constraintMode == 1){
            numConstraint = numPrb;
        }else{
            numConstraint = 1;    // at least one constraint is necessary to determine global translation
        }
        constraintTet.resize(numConstraint);
        constraintVector.resize(numConstraint);
        // for each cage tetrahedra, constraint the point on the mesh with largest weight
        for(int i=0;i<numConstraint;i++){
            constraintTet[i] = 0;
            for(int j=1;j<numTet;j++){
                if(w[j][i] > w[constraintTet[i]][i]){
                    constraintTet[i] = j;
                }
            }
            constraintVector[i] << tetCenter[constraintTet[i]](0), tetCenter[constraintTet[i]](1), tetCenter[constraintTet[i]](2), 1.0;
        }
        // precompute arap solver
        arapHI(PI, meshTriangles);
    }
    // compute deformation
    if( ! rotationCosistency || numPrb != prevNs.size()){        // clear previous rotation
        prevThetas.clear();
        prevThetas.resize(numPrb, 0.0);
        prevNs.clear();
        prevNs.resize(numPrb, Vector3d::Zero());
    }
    //  find affine transformations for tetrahedra
    std::vector<Matrix4d> cageMatrix(numPrb), SE(numPrb), logSE(numPrb),logAff(numPrb),aff(numPrb);
    std::vector<Matrix3d> logR(numPrb),R(numPrb),logS(numPrb),logGL(numPrb);
    std::vector<Vector3d> L(numPrb);
    std::vector<Vector4d> quat(numPrb);
    tetMatrix(cagePoints, triangles, cageMode, cageMatrix);
    for(int i=0; i<numPrb; i++)
        aff[i]=initMatrix[i].inverse()*cageMatrix[i];
    // compute parametrisation
    if(blendMode == 0 || blendMode == 1 || blendMode == 5)  // polarexp or quaternion
    {
        for(unsigned int i=0;i<numPrb;i++){
            parametriseGL(aff[i].block(0,0,3,3), logS[i] ,R[i]);
            L[i] = transPart(aff[i]);
            if(blendMode == 0){  // Rotational log
                logR[i]=logSOc(R[i], prevThetas[i], prevNs[i]);
            }else if(blendMode == 1){ // Eucledian log
                SE[i]=affine(R[i], L[i]);
                logSE[i]=logSEc(SE[i], prevThetas[i], prevNs[i]);
            }else if(blendMode == 5){ // quaternion
                Quaternion<double> Q(R[i].transpose());
                quat[i] << Q.x(), Q.y(), Q.z(), Q.w();
            }
        }
    }else if(blendMode == 2){    //logmatrix3
        for(unsigned int i=0;i<numPrb;i++){
            logGL[i] = aff[i].block(0,0,3,3).log();
            L[i] = transPart(aff[i]);
        }
    }else if(blendMode == 3){   // logmatrix4
        for(unsigned int i=0;i<numPrb;i++){
            logAff[i] = aff[i].log();
        }
    }
    // compute blended matrices
#pragma omp parallel for
    std::vector<Matrix4d> At(numTet);
    for(int j=0; j<numTet; j++ ){
        if(blendMode==0){
            Matrix3d RR=Matrix3d::Zero();
            Matrix3d SS=Matrix3d::Zero();
            Vector3d l=Vector3d::Zero();
            for(unsigned int i=0; i<numPrb; i++){
                RR += w[j][i] * logR[i];
                SS += w[j][i] * logS[i];
                l += w[j][i] * L[i];
            }
            SS = expSym(SS);
            if(frechetSum){
                RR = frechetSO(R, w[j]);
            }else{
                RR = expSO(RR);
            }
            At[j] = affine(SS*RR, l);
        }else if(blendMode==1){    // rigid transformation
            Matrix4d EE=Matrix4d::Zero();
            Matrix3d SS=Matrix3d::Zero();
            for(unsigned int i=0; i<numPrb; i++){
                EE +=  w[j][i] * logSE[i];
                SS +=  w[j][i] * logS[i];
            }
            if(frechetSum){
                EE = frechetSE(SE, w[j]);
            }else{
                EE = expSE(EE);
            }
            At[j] = affine(expSym(SS),Vector3d::Zero())*EE;
        }else if(blendMode == 2){    //logmatrix3
            Matrix3d G=Matrix3d::Zero();
            Vector3d l=Vector3d::Zero();
            for(unsigned int i=0; i<numPrb; i++){
                G +=  w[j][i] * logGL[i];
                l += w[j][i] * L[i];
            }
            At[j] = affine(G.exp(), l);
        }else if(blendMode == 3){   // logmatrix4
            Matrix4d A=Matrix4d::Zero();
            for(unsigned int i=0; i<numPrb; i++)
                A +=  w[j][i] * logAff[i];
            At[j] = A.exp();
        }else if(blendMode == 5){ // quaternion
            Vector4d q=Vector4d::Zero();
            Matrix3d SS=Matrix3d::Zero();
            Vector3d l=Vector3d::Zero();
            for(unsigned int i=0; i<numPrb; i++){
                q += w[j][i] * quat[i];
                SS += w[j][i] * logS[i];
                l += w[j][i] * L[i];
            }
            SS = expSym(SS);
            Quaternion<double> Q(q);
            Matrix3d RR = Q.matrix().transpose();
            At[j] = affine(SS*RR, l);
        }else if(blendMode==10){
            At[j] = Matrix4d::Zero();
            for(unsigned int i=0; i<numPrb; i++){
                At[j] += w[j][i] * aff[i];
            }
        }
    }
    
    // compute target vertices position
    MatrixXd G=MatrixXd::Zero(numTet+numPts,3);
    arapG(At, PI, meshTriangles, aff, G);
    MatrixXd Sol = solver.solve(G);
    for(unsigned int i=0;i<numPts;i++){
        pts[i].x=Sol(i,0);
        pts[i].y=Sol(i,1);
        pts[i].z=Sol(i,2);
        pts[i] *= localToWorldMatrix.inverse();
    }
    itGeo.setAllPositions(pts);
    return MS::kSuccess;
}
예제 #15
0
MStatus puttyNode::deform( MDataBlock& block, MItGeometry& iter, const MMatrix& worldMatrix, unsigned int multiIndex)
{
//	MGlobal::displayInfo("deform");
    MStatus status = MS::kSuccess;

    /////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // get inputs
    //
	
	// get the node ready flag
	MDataHandle dh = block.inputValue(aScriptSourced,&status);
	SYS_ERROR_CHECK(status, "Error getting aScriptSourced data handle\n");
	bool scriptSourced = dh.asBool();
	if (!scriptSourced)
		return MS::kSuccess;


	dh = block.inputValue(aNodeReady,&status);
	SYS_ERROR_CHECK(status, "Error getting node ready data handle\n");
	bool nodeReady = dh.asBool();

	// if it's not ready, don't do anything
	if (!nodeReady)
		return MS::kSuccess;

    dh = block.inputValue(aDefSpace,&status);
    SYS_ERROR_CHECK(status, "Error getting defSpace data handle\n");
    short defSpace = dh.asShort();
    
    dh = block.inputValue(aDefWeights,&status);
    SYS_ERROR_CHECK(status, "Error getting defWeights data handle\n");
    short defWeights = dh.asShort();
 
    dh = block.inputValue(aDefEnvelope,&status);
    SYS_ERROR_CHECK(status, "Error getting defEnvelope data handle\n");
    short defEnvelope = dh.asShort();
    

    
    // get the command
    dh = block.inputValue(aCmdBaseName,&status);
    SYS_ERROR_CHECK(status, "Error getting aCmdBaseName  handle\n");    
    MString script =  dh.asString(); 
        
 /*   if (script == "")
    {
        status = MS::kFailure;
        USER_ERROR_CHECK(status, "no script provided!\n");    
    }
   */ 
    /////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // build mel cmd string
    //
    
    // check if it's a valid cmd
        
   
    // get the envelope
    //
    double env = 1;
    
    if (defEnvelope == MSD_ENVELOPE_AUTO)
    {
        dh = block.inputValue(envelope,&status);
    	SYS_ERROR_CHECK(status, "Error getting envelope data handle\n");	
	    env = double(dh.asFloat());	
        
        // early stop 'cause there is nothing more to do
        if (env == 0.0)
            return MS::kSuccess;
    }
    
    // get the points, transform them into the right space if needed
    //
    int count = iter.count();
    MVectorArray points(count);
    for ( ; !iter.isDone(); iter.next()) 
        points[iter.index()] = iter.position();
        
    if ( defSpace == MSD_SPACE_WORLD )
    {
        for (int i = 0;i<count;i++)
            points[i] = MPoint(points[i]) * worldMatrix;
    }
    
    
    // get the weights
    //
    MDoubleArray weights;
    if ( defWeights == MSD_WEIGHTS_AUTO)
    {
        weights.setLength(count);
        
        for (int i = 0;i<count;i++)
            weights[i]  = weightValue(block,multiIndex,i);
        
    }


    // get the object name and type
    // get the input geometry, traverse through the data handles    
    MArrayDataHandle adh = block.outputArrayValue( input, &status );
    SYS_ERROR_CHECK(status,"error getting input array data handle.\n");

    status = adh.jumpToElement( multiIndex );
    SYS_ERROR_CHECK(status, "input jumpToElement failed.\n");

    // compound data 
    MDataHandle cdh = adh.inputValue( &status );
    SYS_ERROR_CHECK(status, "error getting input inputValue\n");
   
    // input geometry child
    dh = cdh.child( inputGeom );
    MObject dInputGeometry = dh.data();
   
    // get the type      
    MString geometryType = dInputGeometry.apiTypeStr();

    // get the name    
//    MFnDagNode dagFn( dInputGeometry, &status);
//    SYS_ERROR_CHECK(status, "error converting geometry obj to dag node\n");
   
//    MString geometryName = dagFn.fullPathName(&status);
//    SYS_ERROR_CHECK(status, "error getting full path name \n");

//    MString geometryType = "";
//    MString geometryName = "";
    
    /////////////////////////////////////////////////////////////////////////////////////////////////
    //  
    //  set the current values on the temp plugs for the script to be picked up
    //
    
    // the position
    MObject thisNode = thisMObject();
    
    MPlug currPlug(thisNode,aCurrPosition);
    MFnVectorArrayData vecD;
    MObject currObj = vecD.create(points,&status);
    currPlug.setValue(currObj);
    SYS_ERROR_CHECK(status, "error setting currPosPlug value\n");
    
    // the weights
    currPlug =MPlug(thisNode,aCurrWeight);
    MFnDoubleArrayData dblD;
    currObj = dblD.create(weights,&status);
    currPlug.setValue(currObj);
    SYS_ERROR_CHECK(status, "error setting currWeightsPlug value\n");
    
    // world matrix
    currPlug =MPlug(thisNode,aCurrWorldMatrix);
    MFnMatrixData matD;
    currObj = matD.create(worldMatrix,&status);
    currPlug.setValue(currObj);
    SYS_ERROR_CHECK(status, "error setting currWorldMatrixPlug value\n");

    // the multi index
    currPlug =MPlug(thisNode,aCurrMultiIndex);
    currPlug.setValue(int(multiIndex));
    SYS_ERROR_CHECK(status, "error setting currMultiIndexPlug value\n");
    
    // geometry name/type
//    currPlug =MPlug(thisNode,aCurrGeometryName);
//    currPlug.setValue(geometryName);
//    SYS_ERROR_CHECK(status, "error setting aCurrGeometryName value\n");

    currPlug =MPlug(thisNode,aCurrGeometryType);
    currPlug.setValue(geometryType);
    SYS_ERROR_CHECK(status, "error setting aCurrGeometryType value\n");

   
    /////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // execute the mel script
    //
    MString melCmd = script+"(\"" +name()+"\","+count+")";
    
    MCommandResult melResult;
    status = MGlobal::executeCommand(melCmd,melResult);
	
	// if the command did not work, then try to resource the script
	// (might have been that we were in a fresh scene and nothing was ready yet
	if (status != MS::kSuccess)
	{
		dh = block.inputValue(aScript,&status);
	    SYS_ERROR_CHECK(status, "Error getting aCmdBaseName  handle\n");    
		MString scriptFile =  dh.asString(); 	

		// try to source the script
		MString cmd = "source \"" + scriptFile+"\"";
			
		MCommandResult melResult;
		status = MGlobal::executeCommand(cmd,melResult);
		// if successfull, retry the command 
		if (!status.error())
		{
			status = MGlobal::executeCommand(melCmd,melResult);
		}
	}

	USER_ERROR_CHECK(status, "Error executing mel command, please check the function you provided is valid, error free and has the appropriate parameters!");

    // check the result type
    if ((melResult.resultType()) != (MCommandResult::kDoubleArray))
    {
        USER_ERROR_CHECK(MS::kFailure, "result of mel command has wrong type, should be doubleArray (which will be interpreted as vectorArray)!");
    }
    
    // get the result as a double array
    MDoubleArray newP;  
    status = melResult.getResult(newP);
    USER_ERROR_CHECK(status, "Error getting result of mel command!");
    
    int newCount = newP.length()/3;
    // size check
    if (newCount != count)
    {
        USER_ERROR_CHECK(MS::kFailure, "the size of the result does not match the size of the input!");
    }

    // convert the double array into a vector array
    MPointArray newPoints(newCount);
    
    for(int i=0;i<newCount;i++)
        newPoints[i]=MPoint(newP[i*3],newP[i*3+1],newP[i*3+2]);
    
    /////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // interprete and apply the result
    //


  
    // do the envelope and weights   
    if ((defEnvelope == MSD_ENVELOPE_AUTO)||((defWeights == MSD_WEIGHTS_AUTO)))
    {
        MDoubleArray envPP(count, env);
    
        if (defWeights == MSD_WEIGHTS_AUTO)
        { 
            for (int i = 0;i<count;i++)
                envPP[i] *= weights[i];
        }

        // linear interpolation between old and new points
        for (int i = 0;i<count;i++)
            newPoints[i] = (points[i] * (1-envPP[i])) + (newPoints[i] * envPP[i]);
    }


    // retransform the result if it was in world space
    if ( defSpace == MSD_SPACE_WORLD )
    {
        MMatrix worldMatrixInv = worldMatrix.inverse();
        
        for (int i = 0;i<count;i++)
            newPoints[i] *= worldMatrixInv;
    }
 
 
    // set the points    
    iter.reset();
  	for ( ; !iter.isDone(); iter.next()) 
     	iter.setPosition(newPoints[iter.index()]);    

    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;
}
예제 #17
0
MStatus
HRBFSkinCluster::skinDQ(MMatrixArray&  transforms,
						int numTransforms,
						MArrayDataHandle& weightListHandle,
						MItGeometry& iter) {
	MStatus returnStatus;

	// compute dual quaternions. we're storing them as a parallel array.
	std::vector<MQuaternion> tQuaternions(numTransforms); // translation quaterions
	std::vector<MQuaternion> rQuaternions(numTransforms); // rotation quaternions

	for (int i = 0; i < numTransforms; i++) {
		rQuaternions.at(i) = getRotationQuaternion(transforms[i]);
		rQuaternions.at(i).normalizeIt();
		tQuaternions.at(i) = getTranslationQuaternion(transforms[i], rQuaternions.at(i));
#if DEBUG_PRINTS
		std::cout << "rota quaternion " << i << " is: " << rQuaternions.at(i) << std::endl;
		std::cout << "tran quaternion " << i << " is: " << tQuaternions.at(i) << std::endl;
#endif
	}

	MQuaternion rBlend; // blended rotation quaternions
	MQuaternion tBlend; // blended translation quaternions
	MQuaternion scaleMe; // Maya's quaternion scaling is in-place
	double weight;


	// Iterate through each point in the geometry.
	//
	for (; !iter.isDone(); iter.next()) {
		MPoint pt = iter.position();
		MPoint skinned;

		rBlend = MQuaternion(); // reset
		tBlend = MQuaternion(); // reset
		rBlend[3] = 0.0;
		tBlend[3] = 0.0;

		// get the weights for this point
		MArrayDataHandle weightsHandle = weightListHandle.inputValue().child(weights);

		// compute the skinning
		for (int i = 0; i<numTransforms; ++i) {
			if (MS::kSuccess == weightsHandle.jumpToElement(i)) {
				weight = weightsHandle.inputValue().asDouble();
				scaleMe = rQuaternions.at(i);
				rBlend = rBlend + scaleMe.scaleIt(weight);
				scaleMe = tQuaternions.at(i);
				tBlend = tBlend + scaleMe.scaleIt(weight);
			}
		}

		MMatrix dqMatrix = makeDQMatrix(rBlend.normalizeIt(), tBlend);
		skinned = pt * dqMatrix;

		// Set the final position.
		iter.setPosition(skinned);

		// advance the weight list handle
		weightListHandle.next();
	}
	return returnStatus;
}
예제 #18
0
MObject fullLoft::loft( MArrayDataHandle &inputArray, MObject &newSurfData,
					  MStatus &stat )
{
	MFnNurbsSurface surfFn;
	MPointArray cvs;
	MDoubleArray ku, kv;
	int i, j;
	int numCVs;
	int numCurves = inputArray.elementCount ();

	// Ensure that we have at least 1 element in the input array
	// We must not do an inputValue on an element that does not
	// exist.
	if ( numCurves < 1 )
		return MObject::kNullObj;

	// Count the number of CVs
	inputArray.jumpToElement(0);
	MDataHandle elementHandle = inputArray.inputValue(&stat);
	if (!stat) {
		stat.perror("fullLoft::loft: inputValue");
		return MObject::kNullObj;
	}
	MObject countCurve (elementHandle.asNurbsCurve());
	MFnNurbsCurve countCurveFn (countCurve);
	numCVs = countCurveFn.numCVs (&stat);
	PERRORnull("fullLoft::loft counting CVs");

	// Create knot vectors for U and V
	// U dimension contains one CV from each curve, triple knotted
	for (i = 0; i < numCurves; i++)
	{
		ku.append (double (i));
		ku.append (double (i));
		ku.append (double (i));
	}

	// V dimension contains all of the CVs from one curve, triple knotted at
	// the ends
	kv.append( 0.0 );
	kv.append( 0.0 );
	kv.append( 0.0 );

	for ( i = 1; i < numCVs - 3; i ++ )
		kv.append( (double) i );

	kv.append( numCVs-3 );
	kv.append( numCVs-3 );
	kv.append( numCVs-3 );

	// Build the surface's CV array
	for (int curveNum = 0; curveNum < numCurves; curveNum++)
	{
		MObject curve (inputArray.inputValue ().asNurbsCurve ());
		MFnNurbsCurve curveFn (curve);
		MPointArray curveCVs;

		stat = curveFn.getCVs (curveCVs, MSpace::kWorld);
		PERRORnull("fullLoft::loft getting CVs");

		if (curveCVs.length() != (unsigned)numCVs)
			stat = MS::kFailure;
		PERRORnull("fullLoft::loft inconsistent number of CVs - rebuild curves");

		// Triple knot for every curve but the first
		int repeats = (curveNum == 0) ? 1 : 3;

		for (j = 0; j < repeats; j++)
			for ( i = 0; i < numCVs; i++ )
				cvs.append (curveCVs [i]);

		stat = inputArray.next ();
	}
	MObject surf = surfFn.create(cvs, ku, kv, 3, 3,
								 MFnNurbsSurface::kOpen,
								 MFnNurbsSurface::kOpen,
								 false, newSurfData, &stat );
	PERRORnull ("fullLoft::Loft create surface");

	return surf;
}
예제 #19
0
MStatus snapDeformer::deform(MDataBlock &data, MItGeometry &iter, const MMatrix &mat, unsigned int multiIndex) {
	MStatus stat;


    //lets see if we need to do anything
	MDataHandle DataHandle = data.inputValue(envelope, &stat);
	float env = DataHandle.asFloat();
	if (env == 0)
		return stat;
    DataHandle = data.inputValue(weight, &stat);
	const float weight = DataHandle.asFloat();
    if (weight == 0)
		return stat;
    
    env = (env*weight);


	//space target
	DataHandle = data.inputValue(space, &stat);
    int SpaceInt = DataHandle.asInt();

    //space source
	DataHandle = data.inputValue(spaceSource, &stat);
    int SpaceSourceInt = DataHandle.asInt();

    //pointlist
    MArrayDataHandle pointArrayHandle = data.inputArrayValue(pointList);


	//snapMesh
	MFnMesh	SnapMesh;
	DataHandle = data.inputValue(snapMesh, &stat);
    if (!stat)
        return Err(stat,"Can't get mesh to snap to");
    MObject SnapMeshObj = DataHandle.asMesh();
    SnapMesh.setObject(SnapMeshObj);
    MPointArray snapPoints;
    if (SpaceSourceInt==0)
        SnapMesh.getPoints(snapPoints, MSpace::kWorld);
    else
        SnapMesh.getPoints(snapPoints, MSpace::kObject);
    


    iter.reset();
    for ( ; !iter.isDone(); iter.next()) 	{
        //check for painted weights
        float currEnv = env * weightValue(data, multiIndex, iter.index());

        //get point to snap to
        unsigned int index;
        stat = pointArrayHandle.jumpToElement(iter.index());
        if (!stat)
            index = 0;
        else {
            DataHandle = pointArrayHandle.outputValue();
            index = DataHandle.asInt();
        }

        if (index != -1) {
            //calc point location
            MPoint currPoint;
            if (snapPoints.length() > index)
                currPoint = snapPoints[index];

            if (SpaceInt == 0)
                currPoint *= mat.inverse();

            if (currEnv !=1)
            {
                MPoint p = (currPoint- iter.position());
                currPoint = iter.position() + (p*currEnv);
            }


            //set point location
            iter.setPosition(currPoint);
        }
            
            
    }

    return stat;
}
예제 #20
0
MStatus
HRBFSkinCluster::deform( MDataBlock& block,
                      MItGeometry& iter,
                      const MMatrix& m,
                      unsigned int multiIndex)
//
// Method: deform1
//
// Description:   Deforms the point with a simple smooth skinning algorithm
//
// Arguments:
//   block      : the datablock of the node
//   iter       : an iterator for the geometry to be deformed
//   m          : matrix to transform the point into world space
//   multiIndex : the index of the geometry that we are deforming
//
//
{
	MStatus returnStatus;

	// get HRBF status
	MDataHandle HRBFstatusData = block.inputValue(rebuildHRBF, &returnStatus);
	McheckErr(returnStatus, "Error getting rebuildHRBF handle\n");
	int rebuildHRBFStatusNow = HRBFstatusData.asInt();
	// handle signaling to the rest of deform that HRBFs must be rebuild
	bool signalRebuildHRBF = false;
	signalRebuildHRBF = (rebuildHRBFStatus != rebuildHRBFStatusNow);
	MMatrixArray bindTFs; // store just the bind transforms in here.
	MMatrixArray boneTFs; // ALWAYS store just the bone transforms in here.

	// get HRBF export status
	MDataHandle exportCompositionData = block.inputValue(exportComposition, &returnStatus);
	McheckErr(returnStatus, "Error getting exportComposition handle\n");
	int exportCompositionStatusNow = exportCompositionData.asInt();

	MDataHandle HRBFExportSamplesData = block.inputValue(exportHRBFSamples, &returnStatus);
	McheckErr(returnStatus, "Error getting exportHRBFSamples handle\n");
	std::string exportHRBFSamplesStatusNow = HRBFExportSamplesData.asString().asChar();

	MDataHandle HRBFExportValuesData = block.inputValue(exportHRBFValues, &returnStatus);
	McheckErr(returnStatus, "Error getting exportHRBFValues handle\n");
	std::string exportHRBFValuesStatusNow = HRBFExportValuesData.asString().asChar();

	// get skinning type
	MDataHandle useDQData = block.inputValue(useDQ, &returnStatus);
	McheckErr(returnStatus, "Error getting useDQ handle\n");
	int useDQNow = useDQData.asInt();

	// determine if we're using HRBF
	MDataHandle useHRBFData = block.inputValue(useHRBF, &returnStatus);
	McheckErr(returnStatus, "Error getting useHRBFData handle\n");
	int useHRBFnow = useHRBFData.asInt();

	// get envelope because why not
	MDataHandle envData = block.inputValue(envelope, &returnStatus);
	float env = envData.asFloat();

	// get point in space for evaluating HRBF
	MDataHandle checkHRBFAtData = block.inputValue(checkHRBFAt, &returnStatus);
	McheckErr(returnStatus, "Error getting useDQ handle\n");
	double* data = checkHRBFAtData.asDouble3();

	// get the influence transforms
	//
	MArrayDataHandle transformsHandle = block.inputArrayValue( matrix ); // tell block what we want
	int numTransforms = transformsHandle.elementCount();
	if ( numTransforms == 0 ) { // no transforms, no problems
		return MS::kSuccess;
	}
	MMatrixArray transforms; // fetch transform matrices -> actual joint matrices
	for ( int i=0; i<numTransforms; ++i ) {
		MMatrix worldTF = MFnMatrixData(transformsHandle.inputValue().data()).matrix();
		transforms.append(worldTF);
		boneTFs.append(worldTF);
		transformsHandle.next();
	}
	// inclusive matrices inverse of the driving transform at time of bind
	// matrices for transforming vertices to joint local space
	MArrayDataHandle bindHandle = block.inputArrayValue( bindPreMatrix ); // tell block what we want
	if ( bindHandle.elementCount() > 0 ) {
		for ( int i=0; i<numTransforms; ++i ) {
			MMatrix bind = MFnMatrixData(bindHandle.inputValue().data()).matrix();
			transforms[i] = bind * transforms[i];
			bindHandle.next();
			if (signalRebuildHRBF) bindTFs.append(bind);
		}
	}

	MArrayDataHandle weightListHandle = block.inputArrayValue(weightList);
	if (weightListHandle.elementCount() == 0) {
		// no weights - nothing to do
		std::cout << "no weights!" << std::endl;
		//rebuildHRBFStatus = rebuildHRBFStatusNow - 1; // HRBFs will need to rebuilt no matter what
		return MS::kSuccess;
	}

	// print HRBF samples if requested
	if (exportHRBFSamplesStatusNow != exportHRBFSamplesStatus) {
		std::cout << "instructed to export HRBF samples: " << exportHRBFSamplesStatusNow.c_str() << std::endl;
		exportHRBFSamplesStatus = exportHRBFSamplesStatusNow;
		// TODO: handle exporting HRBFs to the text file format
		hrbfMan->debugSamplesToConsole(exportHRBFSamplesStatus);
	}

	// print HRBF values if requested
	if (exportHRBFValuesStatusNow != exportHRBFValuesStatus) {
		std::cout << "instructed to export HRBF values: " << exportHRBFValuesStatusNow.c_str() << std::endl;
		exportHRBFValuesStatus = exportHRBFValuesStatusNow;
		// TODO: handle exporting HRBFs to the text file format
		hrbfMan->debugValuesToConsole(exportHRBFValuesStatus);
	}

	// print HRBF composition if requested
	if (exportCompositionStatusNow != exportCompositionStatus) {
		std::cout << "instructed to export HRBF composition." << std::endl;
		exportCompositionStatus = exportCompositionStatusNow;
		// TODO: handle exporting HRBFs to the text file format
		hrbfMan->debugCompositionToConsole(boneTFs, numTransforms);
	}

	// check the HRBF value if the new point is significantly different
	MPoint checkHRBFHereNow(data[0], data[1], data[2]);
	if ((checkHRBFHereNow - checkHRBFHere).length() > 0.0001) {
		if (hrbfMan->m_HRBFs.size() == numTransforms) {
			std::cout << "checking HRBF at x:" << data[0] << " y: " << data[1] << " z: " << data[2] << std::endl;
			hrbfMan->compose(boneTFs);
			float val = 0.0f;
			float dx = 0.0f;
			float dy = 0.0f;
			float dz = 0.0f;
			float grad = 0.0f;

			hrbfMan->mf_vals->trilinear(data[0], data[1], data[2], val);
			hrbfMan->mf_gradX->trilinear(data[0], data[1], data[2], dx);
			hrbfMan->mf_gradY->trilinear(data[0], data[1], data[2], dy);
			hrbfMan->mf_gradZ->trilinear(data[0], data[1], data[2], dz);
			hrbfMan->mf_gradMag->trilinear(data[0], data[1], data[2], grad);
			std::cout << "val: " << val << " dx: " << dx << " dy: " << dy << " dz: " << dz << " grad: " << grad << std::endl;
			checkHRBFHere = checkHRBFHereNow;
		}
	}

	// rebuild HRBFs if needed
	if (signalRebuildHRBF) {
		std::cout << "instructed to rebuild HRBFs" << std::endl;
		rebuildHRBFStatus = rebuildHRBFStatusNow;

		MArrayDataHandle parentIDCsHandle = block.inputArrayValue(jointParentIdcs); // tell block what we want
		std::vector<int> jointParentIndices(numTransforms);
		if (parentIDCsHandle.elementCount() > 0) {
			for (int i = 0; i<numTransforms; ++i) {
				jointParentIndices[i] = parentIDCsHandle.inputValue().asInt();
				parentIDCsHandle.next();
			}
		}

		MArrayDataHandle jointNamesHandle = block.inputArrayValue(jointNames); // tell block what we want
		std::vector<std::string> jointNames(numTransforms);
		if (jointNamesHandle.elementCount() > 0) {
			for (int i = 0; i<numTransforms; ++i) {
				jointNames[i] = jointNamesHandle.inputValue().asString().asChar();
				jointNamesHandle.next();
			}
		}

		// debug
		//std::cout << "got joint hierarchy info! it's:" << std::endl;
		//for (int i = 0; i < numTransforms; ++i) {
		//	std::cout << i << ": " << jointNames[i].c_str() << " : " << jointParentIndices[i] << std::endl;
		//}
		std::cout << "rebuilding HRBFs... " << std::endl;
		hrbfMan->buildHRBFs(jointParentIndices, jointNames, bindTFs, boneTFs, 
			weightListHandle, iter, weights);
		std::cout << "done rebuilding!" << std::endl;
		weightListHandle.jumpToElement(0); // reset this, it's an iterator. trust me.
		iter.reset(); // reset this iterator so we can go do normal skinning
	}


	// perform traditional skinning
	if (useDQNow != 0) {
		returnStatus = skinDQ(transforms, numTransforms, weightListHandle, iter);
	}
	else {
		returnStatus = skinLB(transforms, numTransforms, weightListHandle, iter);
	}

	// do HRBF corrections
	if (useHRBFnow != 0) {
		if (hrbfMan->m_HRBFs.size() == numTransforms) {
			hrbfMan->compose(boneTFs);
			iter.reset();
			hrbfMan->correct(iter);
		}
	}

	return returnStatus;
}
예제 #21
0
MStatus stringFormat::compute (const MPlug& plug, MDataBlock& data)
{
	
	MStatus status;
 
	// Check that the requested recompute is one of the output values
	//
	if (plug == attrOutput) {
		// Read the input values
		//
		MDataHandle inputData = data.inputValue (attrFormat, &status);
		CHECK_MSTATUS( status );
		MString format = inputData.asString();

        // Get input data handle, use outputArrayValue since we do not
        // want to evaluate all inputs, only the ones related to the
        // requested multiIndex. This is for efficiency reasons.
        //
		MArrayDataHandle vals = data.outputArrayValue(attrValues, &status);
		CHECK_MSTATUS( status );

		int indx = 0;
		int param;
		char letter;
		while ((indx = findNextMatch(format, indx, param, letter)) > 0) {
			double val = 0.;
			status = vals.jumpToElement(param);
			if (status == MStatus::kSuccess) {
				MDataHandle thisVal = vals.inputValue( &status );
				if (status == MStatus::kSuccess) {
					val = thisVal.asDouble();
				}
			}
			MString replace;
			bool valid = false;
			switch (letter) {
				case 'd':					// Integer
				val = floor(val+.5);
				// No break here

				case 'f':					// Float
				replace.set(val);
				valid = true;
				break;

				case 't':					// Timecode
				{
					const char * sign = "";
					if (val<0) {
						sign = "-";
						val = -val;
					}
					int valInt = (int)(val+.5);
					int sec = valInt / 24;
					int frame = valInt - sec * 24;
					int min = sec / 60;
					sec -= min * 60;
					int hour = min / 60;
					min -= hour * 60;
					char buffer[90];
					if (hour>0)
						sprintf(buffer, "%s%d:%02d:%02d.%02d", 
								sign, hour, min, sec, frame);
					else
						sprintf(buffer, "%s%02d:%02d.%02d", 
								sign, min, sec, frame);
					replace = buffer;
				}
				valid = true;
				break;
			}

			if (valid) {
				format = format.substring(0, indx-2) + 
					replace + format.substring(indx+2, format.length()-1);
				indx += replace.length() - 3;
			}
		}

		// Store the result
		//
		MDataHandle output = data.outputValue(attrOutput, &status );
		CHECK_MSTATUS( status );
		output.set( format );

	} else {
		return MS::kUnknownParameter;
	}

	return MS::kSuccess;
}
예제 #22
0
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;
}
예제 #23
0
MStatus HesMeshNode::compute( const MPlug& plug, MDataBlock& data )
{
	MStatus stat;
	
	MPlug pnames(thisMObject(), ameshname);
	const unsigned numMeshes = pnames.numElements();
    
	MString cacheName =  data.inputValue( input ).asString();
	std::string substitutedCacheName(cacheName.asChar());
	EnvVar::replace(substitutedCacheName);
	
	MArrayDataHandle meshNameArray = data.inputArrayValue( ameshname );
	MArrayDataHandle meshArry = data.outputArrayValue(outMesh, &stat);
	
    bool hesStat = false;
	if( plug.array() == outMesh ) {
		const unsigned idx = plug.logicalIndex();
		if(BaseUtil::IsImporting)
            hesStat = true;
        else {
            if(idx == 0) 
                AHelper::Info<std::string>(" hes mesh open file ", substitutedCacheName );
            hesStat = BaseUtil::OpenHes(substitutedCacheName, HDocument::oReadOnly);
        }
		
		if(!hesStat) {
			AHelper::Info<std::string >("hes mesh cannot open file ", substitutedCacheName);
			return MS::kFailure;
		}
        
        meshNameArray.jumpToElement(idx);
		const MString meshName = meshNameArray.inputValue().asString();
		
        if(!BaseUtil::HesDoc->find(meshName.asChar())) {
            AHelper::Info<MString>(" hes cannot find mesh ", meshName );
            return MS::kFailure;
		}
        
		meshArry.jumpToElement(idx);
		MDataHandle hmesh = meshArry.outputValue();

		HPolygonalMesh entryMesh(meshName.asChar() );
        
        APolygonalMesh dataMesh;
		entryMesh.load(&dataMesh);
        entryMesh.close();
        
        MFnMeshData dataCreator;
		MObject outMeshData = dataCreator.create(&stat);
			
		if( !stat ) {
			MGlobal::displayWarning("hes mesh cannot create " + meshName);
			return MS::kFailure;
		}
		
        AHelper::Info<MString>(" hes init mesh ", meshName);
		HesperisPolygonalMeshCreator::create(&dataMesh, outMeshData);

		hmesh.set(outMeshData);
	    
		data.setClean(plug);
		
		if( (idx+1)>=numMeshes ) {
			if(!BaseUtil::IsImporting) {
                AHelper::Info<std::string>(" hes mesh close file ", substitutedCacheName );
				BaseUtil::CloseHes();
			}
		}
	} 
	else {
		return MS::kUnknownParameter;
	}

	return MS::kSuccess;
}
예제 #24
0
// COMPUTE ======================================
MStatus gear_rollSplineKine::compute(const MPlug& plug, MDataBlock& data)
{

	MStatus returnStatus;
	// Error check
    if (plug != output)
        return MS::kUnknownParameter;


	// Get inputs matrices ------------------------------
	// Inputs Parent
	MArrayDataHandle adh = data.inputArrayValue( ctlParent );
	int count = adh.elementCount();
	if (count < 1)
		return MS::kFailure;
	MMatrixArray inputsP(count);
	for (int i = 0 ; i < count ; i++){
		adh.jumpToElement(i);
		inputsP[i] = adh.inputValue().asMatrix();
	}

	// Inputs
	adh = data.inputArrayValue( inputs );
	if (count != adh.elementCount())
		return MS::kFailure;
	MMatrixArray inputs(count);
	for (int i = 0 ; i < count ; i++){
		adh.jumpToElement(i);
		inputs[i] = adh.inputValue().asMatrix();
	}

	adh = data.inputArrayValue( inputsRoll );
	if (count != adh.elementCount())
		return MS::kFailure;
	MDoubleArray roll(adh.elementCount());
	for (int i = 0 ; i < count ; i++){
		adh.jumpToElement(i);
		roll[i] = degrees2radians((double)adh.inputValue().asFloat());
	}

	// Output Parent
	MDataHandle ha = data.inputValue( outputParent );
	MMatrix outputParent = ha.asMatrix();
	
    // Get inputs sliders -------------------------------
    double in_u = (double)data.inputValue( u ).asFloat();
    bool in_resample = data.inputValue( resample ).asBool();
    int in_subdiv = data.inputValue( subdiv ).asShort();
    bool in_absolute = data.inputValue( absolute ).asBool();
	
    // Process ------------------------------------------
    // Get roll, pos, tan, rot, scl
    MVectorArray pos(count);
    MVectorArray tan(count);
	MQuaternion *rot;
	rot = new MQuaternion[count];
    MVectorArray scl(count);
	double threeDoubles[3];
	for (int i = 0 ; i < count ; i++){
		MTransformationMatrix tp(inputsP[i]);
		MTransformationMatrix t(inputs[i]);
		pos[i] = t.getTranslation(MSpace::kWorld);
		rot[i] = tp.rotation();

		t.getScale(threeDoubles, MSpace::kWorld);
		scl[i] = MVector(threeDoubles[0], threeDoubles[1], threeDoubles[2]);
		tan[i] = MVector(threeDoubles[0] * 2.5, 0, 0).rotateBy(t.rotation());
	}
	
    // Get step and indexes
    // We define between wich controlers the object is to be able to
    // calculate the bezier 4 points front this 2 objects
	double step = 1.0 / max( 1, count-1.0 );
	int index1 = (int)min( count-2.0, in_u/step );
	int index2 = index1+1;
	int index1temp = index1;
	int index2temp = index2;
	double v = (in_u - step * double(index1)) / step;
	double vtemp = v;
	
   // calculate the bezier
   MVector bezierPos;
   MVector xAxis, yAxis, zAxis;
   if(!in_resample){
      // straight bezier solve
      MVectorArray results = bezier4point(pos[index1],tan[index1],pos[index2],tan[index2],v);
      bezierPos = results[0];
      xAxis = results[1];
   }
   else if(!in_absolute){
      MVectorArray presample(in_subdiv);
      MVectorArray presampletan(in_subdiv);
      MDoubleArray samplelen(in_subdiv);
      double samplestep = 1.0 / double(in_subdiv-1);
      double sampleu = samplestep;
      presample[0]  = pos[index1];
      presampletan[0]  = tan[index1];
      MVector prevsample(presample[0]);
      MVector diff;
      samplelen[0] = 0;
      double overalllen = 0;
      MVectorArray results(2);
      for(long i=1;i<in_subdiv;i++,sampleu+=samplestep){
         results = bezier4point(pos[index1],tan[index1],pos[index2],tan[index2],sampleu);
         presample[i] = results[0];
         presampletan[i] = results[1];
		 diff = presample[i] - prevsample;
		 overalllen += diff.length();
         samplelen[i] = overalllen;
         prevsample = presample[i];
      }
      // now as we have the
      sampleu = 0;
      for(long i=0;i<in_subdiv-1;i++,sampleu+=samplestep){
         samplelen[i+1] = samplelen[i+1] / overalllen;
         if(v>=samplelen[i] && v <=  samplelen[i+1]){
            v = (v - samplelen[i]) / (samplelen[i+1] - samplelen[i]);
			bezierPos = linearInterpolate(presample[i],presample[i+1],v);
			xAxis = linearInterpolate(presampletan[i],presampletan[i+1],v);
            break;
         }
      }
   }
   else{
      MVectorArray presample(in_subdiv);
      MVectorArray presampletan(in_subdiv);
      MDoubleArray samplelen(in_subdiv);
      double samplestep = 1.0 / double(in_subdiv-1);
      double sampleu = samplestep;
      presample[0]  = pos[0];
      presampletan[0]  = tan[0];
      MVector prevsample(presample[0]);
      MVector diff;
      samplelen[0] = 0;
      double overalllen = 0;
      MVectorArray results;
      for(long i=1;i<in_subdiv;i++,sampleu+=samplestep){
         index1 = (int)min(count-2,sampleu / step);
         index2 = index1+1;
         v = (sampleu - step * double(index1)) / step;
         results = bezier4point(pos[index1],tan[index1],pos[index2],tan[index2],v);
         presample[i] = results[0];
         presampletan[i] = results[1];
		 diff = presample[i] - prevsample;
		 overalllen += diff.length();
         samplelen[i] = overalllen;
         prevsample = presample[i];
      }
      // now as we have the
      sampleu = 0;
      for(long i=0;i<in_subdiv-1;i++,sampleu+=samplestep){
         samplelen[i+1] = samplelen[i+1] / overalllen;
         if(in_u>=samplelen[i] && in_u <= samplelen[i+1]){
            in_u = (in_u - samplelen[i]) / (samplelen[i+1] - samplelen[i]);
			bezierPos = linearInterpolate(presample[i],presample[i+1],in_u);
			xAxis = linearInterpolate(presampletan[i],presampletan[i+1],in_u);
            break;
         }
      }
   }

   
	// compute the scaling (straight interpolation!)
	MVector scl1 = linearInterpolate(scl[index1temp], scl[index2temp],vtemp);

	// compute the rotation!
	MQuaternion q = slerp(rot[index1temp], rot[index2temp], vtemp);
	yAxis = MVector(0,1,0);
	yAxis = yAxis.rotateBy(q);
	
	// use directly or project the roll values!
	// print roll
	double a = linearInterpolate(roll[index1temp], roll[index2temp], vtemp);
	yAxis = yAxis.rotateBy( MQuaternion(xAxis.x * sin(a/2.0), xAxis.y * sin(a/2.0), xAxis.z * sin(a/2.0), cos(a/2.0)));
	
	zAxis = xAxis ^ yAxis;
	zAxis.normalize();
	yAxis = zAxis ^ xAxis;
	yAxis.normalize();

	// Output -------------------------------------------
	MTransformationMatrix result;

	// translation
	result.setTranslation(bezierPos, MSpace::kWorld);
	// rotation
	q = getQuaternionFromAxes(xAxis,yAxis,zAxis);
	result.setRotationQuaternion(q.x, q.y, q.z, q.w);
	// scaling
	threeDoubles[0] = 1;
	threeDoubles[0] = scl1.y;
	threeDoubles[0] = scl1.z;
	result.setScale(threeDoubles, MSpace::kWorld);

	MDataHandle h = data.outputValue( output );
	h.setMMatrix( result.asMatrix() * outputParent.inverse() );

	data.setClean( plug );


	return MS::kSuccess;
}