MStatus SwirlDeformer::deform( MDataBlock& block, MItGeometry &iter, const MMatrix &localToWorld, unsigned int geomIndex ) { MStatus stat; MDataHandle envData = block.inputValue( envelope ); float env = envData.asFloat(); if( env == 0.0 ) // Deformer has no effect return MS::kSuccess; MDataHandle matData = block.inputValue( deformSpace ); MMatrix mat = matData.asMatrix(); MMatrix invMat = mat.inverse(); MDataHandle startDistHnd = block.inputValue( startDist ); double startDist = startDistHnd.asDouble(); MDataHandle endDistHnd = block.inputValue( endDist ); double endDist = endDistHnd.asDouble(); MPoint pt; float weight; double dist; double ang; double cosAng; double sinAng; double x; double distFactor; for( iter.reset(); !iter.isDone(); iter.next() ) { weight = weightValue( block, geomIndex, iter.index() ); if( weight == 0.0f ) continue; pt = iter.position(); pt *= invMat; dist = sqrt( pt.x * pt.x + pt.z * pt.z ); if( dist < startDist || dist > endDist ) continue; distFactor = 1 - ((dist - startDist) / (endDist - startDist)); ang = distFactor * M_PI * 2.0 * env * weight; if( ang == 0.0 ) continue; cosAng = cos( ang ); sinAng = sin( ang ); x = pt.x * cosAng - pt.z * sinAng; pt.z = pt.x * sinAng + pt.z * cosAng; pt.x = x; pt *= mat; iter.setPosition( pt ); } return stat; }
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; }
MStatus identityNode::deform( MDataBlock& block, MItGeometry& iter, const MMatrix& /*m*/, unsigned int multiIndex) // // Method: deform // // Description: "Deforms" the point with an identity transformation // // 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; // Iterate through each point in the geometry. // for ( ; !iter.isDone(); iter.next()) { MPoint pt = iter.position(); // Perform some calculation on pt. // ... // Set the final position. iter.setPosition(pt); } return returnStatus; }
MStatus offset::deform( MDataBlock& block, MItGeometry& iter, const MMatrix& /*m*/, unsigned int multiIndex) // // Method: deform // // Description: Deform the point with a squash 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; // Envelope data from the base class. // The envelope is simply a scale factor. // MDataHandle envData = block.inputValue(envelope, &returnStatus); if (MS::kSuccess != returnStatus) return returnStatus; float env = envData.asFloat(); // Get the matrix which is used to define the direction and scale // of the offset. // MDataHandle matData = block.inputValue(offsetMatrix, &returnStatus ); if (MS::kSuccess != returnStatus) return returnStatus; MMatrix omat = matData.asMatrix(); MMatrix omatinv = omat.inverse(); // iterate through each point in the geometry // for ( ; !iter.isDone(); iter.next()) { MPoint pt = iter.position(); pt *= omatinv; float weight = weightValue(block,multiIndex,iter.index()); // offset algorithm // pt.y = pt.y + env*weight; // // end of offset algorithm pt *= omat; iter.setPosition(pt); } return returnStatus; }
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; }
MStatus DucttapeMergeDeformer::deform( MDataBlock& block, MItGeometry& iter, const MMatrix& m, unsigned int multiIndex) { MStatus status; MDataHandle envData = block.inputValue(envelope,&status); const float env = envData.asFloat(); if(env < 1e-3f) return status; if(multiIndex == 0) { if(m_inputGeomIter) { delete m_inputGeomIter; m_inputGeomIter = NULL; } MDataHandle hmesh = block.inputValue(ainmesh); MItGeometry * aiter = new MItGeometry( hmesh, true, &status ); if(!status) { AHelper::Info<int>("DucttapeMergeDeformer error no geom it", 0); return status; } m_inputGeomIter = aiter; } if(!m_inputGeomIter) return status; MPoint pd; MVector dv; for (; !iter.isDone(); iter.next()) { if(m_inputGeomIter->isDone() ) return status; float wei = env * weightValue(block, multiIndex, iter.index() ); if(wei > 1e-3f) { pd = iter.position(); dv = m_inputGeomIter->position() - pd; pd = pd + dv * wei; iter.setPosition(pd); } m_inputGeomIter->next(); } return status; }
// 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; }
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; }
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 }
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 )); }
MStatus tm_noisePerlin::deform( MDataBlock& block, MItGeometry& iter, const MMatrix& /*m*/, unsigned int /*multiIndex*/) { MStatus status = MS::kSuccess; // It's a fake data access try to workaround strange behavior on x86_64 linux systems... MDataHandle dummyData = block.inputValue(dummy,&status); MDataHandle lev_MampData = block.inputValue(lev_Mamp,&status); McheckErr(status, "Error getting lev_Mamp data handle\n"); double _lev_Mamp = lev_MampData.asDouble(); MDataHandle lev_MfreqData = block.inputValue(lev_Mfreq,&status); McheckErr(status, "Error getting lev_Mfreq data handle\n"); double lev_Mfreq = lev_MfreqData.asDouble(); MDataHandle levelsData = block.inputValue(levels,&status); McheckErr(status, "Error getting frequency data handle\n"); short levels = levelsData.asShort(); MDataHandle scaleData = block.inputValue(scale,&status); McheckErr(status, "Error getting scale data handle\n"); double scale = scaleData.asDouble(); MDataHandle scaleAmpXData = block.inputValue(scaleAmpX,&status); McheckErr(status, "Error getting scaleAmpX data handle\n"); double scaleAmpX = scaleAmpXData.asDouble(); MDataHandle scaleAmpYData = block.inputValue(scaleAmpY,&status); McheckErr(status, "Error getting scaleAmpY data handle\n"); double scaleAmpY = scaleAmpYData.asDouble(); MDataHandle scaleAmpZData = block.inputValue(scaleAmpZ,&status); McheckErr(status, "Error getting scaleAmpZ data handle\n"); double scaleAmpZ = scaleAmpZData.asDouble(); MDataHandle scaleFreqXData = block.inputValue(scaleFreqX,&status); McheckErr(status, "Error getting scaleFreqX data handle\n"); double scaleFreqX = scaleFreqXData.asDouble(); MDataHandle scaleFreqYData = block.inputValue(scaleFreqY,&status); McheckErr(status, "Error getting scaleFreqY data handle\n"); double scaleFreqY = scaleFreqYData.asDouble(); MDataHandle scaleFreqZData = block.inputValue(scaleFreqZ,&status); McheckErr(status, "Error getting scaleFreqZ data handle\n"); double scaleFreqZ = scaleFreqZData.asDouble(); MDataHandle variationData = block.inputValue(variation,&status); McheckErr(status, "Error getting variation data handle\n"); double variation = variationData.asDouble(); MDataHandle envData = block.inputValue(envelope,&status); McheckErr(status, "Error getting envelope data handle\n"); double env = envData.asDouble(); MDataHandle amplitudeData = block.inputValue(amplitude,&status); McheckErr(status, "Error getting amplitude data handle\n"); double amplitude = amplitudeData.asDouble(); MDataHandle frequencyData = block.inputValue(frequency,&status); McheckErr(status, "Error getting frequency data handle\n"); double frequency = frequencyData.asDouble(); amplitude = amplitude * scale; frequency = frequency * 0.01 / scale; for ( ; !iter.isDone(); iter.next()) { MPoint pt = iter.position(); vector noisePnt; noisePnt.x = 0; noisePnt.y = 0; noisePnt.z = 0; double l_amp = amplitude; double x = scaleFreqX * pt.x * frequency; double y = scaleFreqY * pt.y * frequency; double z = scaleFreqZ * pt.z * frequency; for( int lev = 0; lev < levels; lev++) { x *= lev_Mfreq; y *= lev_Mfreq; z *= lev_Mfreq; vector lev_Pnt = INoise::noise4d_v(x, y, z, variation); noisePnt.x += lev_Pnt.x * l_amp; noisePnt.y += lev_Pnt.y * l_amp; noisePnt.z += lev_Pnt.z * l_amp; l_amp *= _lev_Mamp; } pt.x += noisePnt.x * scaleAmpX; pt.y += noisePnt.y * scaleAmpY; pt.z += noisePnt.z * scaleAmpZ; iter.setPosition(pt); } return status; }
MStatus AlembicCurvesDeformNode::deform(MDataBlock &dataBlock, MItGeometry &iter, const MMatrix &localToWorld, unsigned int geomIndex) { // get the envelope data float env = dataBlock.inputValue(envelope).asFloat(); if (env == 0.0f) { // deformer turned off return MStatus::kSuccess; } // update the frame number to be imported double inputTime = dataBlock.inputValue(mTimeAttr).asTime().as(MTime::kSeconds); MString &fileName = dataBlock.inputValue(mFileNameAttr).asString(); MString &identifier = dataBlock.inputValue(mIdentifierAttr).asString(); // check if we have the file if (fileName != mFileName || identifier != mIdentifier) { mSchema.reset(); if (fileName != mFileName) { delRefArchive(mFileName); mFileName = fileName; addRefArchive(mFileName); } mIdentifier = identifier; // get the object from the archive Abc::IObject iObj = getObjectFromArchive(mFileName, identifier); if (!iObj.valid()) { MGlobal::displayWarning("[ExocortexAlembic] Identifier '" + identifier + "' not found in archive '" + mFileName + "'."); return MStatus::kFailure; } AbcG::ICurves obj(iObj, Abc::kWrapExisting); if (!obj.valid()) { MGlobal::displayWarning("[ExocortexAlembic] Identifier '" + identifier + "' in archive '" + mFileName + "' is not a Curves."); return MStatus::kFailure; } mSchema = obj.getSchema(); } if (!mSchema.valid()) { return MStatus::kFailure; } { ESS_PROFILE_SCOPE("AlembicCurvesDeformNode::deform readProps"); Alembic::Abc::ICompoundProperty arbProp = mSchema.getArbGeomParams(); Alembic::Abc::ICompoundProperty userProp = mSchema.getUserProperties(); readProps(inputTime, arbProp, dataBlock, thisMObject()); readProps(inputTime, userProp, dataBlock, thisMObject()); // Set all plugs as clean // Even if one of them failed to get set, // trying again in this frame isn't going to help for (unsigned int i = 0; i < mGeomParamPlugs.length(); i++) { dataBlock.outputValue(mGeomParamPlugs[i]).setClean(); } for (unsigned int i = 0; i < mUserAttrPlugs.length(); i++) { dataBlock.outputValue(mUserAttrPlugs[i]).setClean(); } } // get the sample SampleInfo sampleInfo = getSampleInfo(inputTime, mSchema.getTimeSampling(), mSchema.getNumSamples()); // check if we have to do this at all if (mLastSampleInfo.floorIndex == sampleInfo.floorIndex && mLastSampleInfo.ceilIndex == sampleInfo.ceilIndex) { return MStatus::kSuccess; } mLastSampleInfo = sampleInfo; // access the camera values AbcG::ICurvesSchema::Sample sample; AbcG::ICurvesSchema::Sample sample2; mSchema.get(sample, sampleInfo.floorIndex); if (sampleInfo.alpha != 0.0) { mSchema.get(sample2, sampleInfo.ceilIndex); } Abc::P3fArraySamplePtr samplePos = sample.getPositions(); Abc::P3fArraySamplePtr samplePos2; if (sampleInfo.alpha != 0.0) { samplePos2 = sample2.getPositions(); } // iteration should not be necessary. the iteration is only // required if the same mesh is attached to the same deformer // several times float blend = (float)sampleInfo.alpha; float iblend = 1.0f - blend; unsigned int index = 0; for (iter.reset(); !iter.isDone(); iter.next()) { index = iter.index(); // MFloatPoint pt = iter.position(); MPoint pt = iter.position(); MPoint abcPos = pt; float weight = weightValue(dataBlock, geomIndex, index) * env; if (weight == 0.0f) { continue; } float iweight = 1.0f - weight; if (index >= samplePos->size()) { continue; } bool done = false; if (sampleInfo.alpha != 0.0) { if (samplePos2->size() == samplePos->size()) { abcPos.x = iweight * pt.x + weight * (samplePos->get()[index].x * iblend + samplePos2->get()[index].x * blend); abcPos.y = iweight * pt.y + weight * (samplePos->get()[index].y * iblend + samplePos2->get()[index].y * blend); abcPos.z = iweight * pt.z + weight * (samplePos->get()[index].z * iblend + samplePos2->get()[index].z * blend); done = true; } } if (!done) { abcPos.x = iweight * pt.x + weight * samplePos->get()[index].x; abcPos.y = iweight * pt.y + weight * samplePos->get()[index].y; abcPos.z = iweight * pt.z + weight * samplePos->get()[index].z; } iter.setPosition(abcPos); } return MStatus::kSuccess; }
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; }
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; }
/*! * Description: Deform the point using the Sederberg-Parry FFD 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 ffdPlanar::deform( MDataBlock& block, MItGeometry& iter, const MMatrix& /*m*/, unsigned int multiIndex ) { MStatus status = MS::kSuccess; // Determine the displacement lattice points. MDataHandle row1Data = block.inputValue( latticeRow1, &status ); MCheckErr( status, "Error getting r1 data handle\n" ); MVector row1Vector = row1Data.asVector(); MDataHandle row2Data = block.inputValue( latticeRow2, &status ); MCheckErr( status, "Error getting r2 data handle\n" ); MVector row2Vector = row2Data.asVector(); MDataHandle row3Data = block.inputValue( latticeRow3, &status ); MCheckErr( status, "Error getting r3 data\n" ); MVector row3Vector = row3Data.asVector(); // Determine the envelope (this is a global scale factor for the deformer). MDataHandle envData = block.inputValue(envelope,&status); MCheckErr(status, "Error getting envelope data handle\n"); float env = envData.asFloat(); // Generate the FFD lattice. MVector lattice[FFD_LATTICE_POINTS_S][FFD_LATTICE_POINTS_T][FFD_LATTICE_POINTS_U] = { // Since dimensions known ahead of time, generate array now. { // x = 0 { MVector(0.f, row1Vector.x, 0.f), MVector(0.f, row1Vector.y, .5f), MVector(0.f, row1Vector.z, 1.f) }, // y = 0 }, { // x = 1 { MVector(.5f, row2Vector.x, 0.f), MVector(.5f, row2Vector.y, .5f), MVector(.5f, row2Vector.z, 1.f) }, // y = 0 }, { // x = 2 { MVector(1.f, row3Vector.x, 0.f), MVector(1.f, row3Vector.y, .5f), MVector(1.f, row3Vector.z, 1.f) }, // y = 0 } }; MBoundingBox boundingBox; status = getBoundingBox( block, multiIndex, boundingBox ); MCheckErr( status, "Error getting bounding box\n" ); MTransformationMatrix transform = getXyzToStuTransformation( boundingBox ); MMatrix transformMatrix = transform.asMatrix(); MMatrix inverseMatrix = transform.asMatrixInverse(); // Iterate through each point in the geometry. for ( ; !iter.isDone(); iter.next() ) { MPoint pt = iter.position(); MPoint ptStu = pt * transformMatrix; MPoint deformed = getDeformedPoint( ptStu, lattice ) * inverseMatrix; if ( env != 1.f ) { MVector diff = deformed - pt; deformed = pt + env * diff; } iter.setPosition( deformed ); } return status; }
MStatus mapBlendShape::deform(MDataBlock& data, MItGeometry& itGeo, const MMatrix& localToWorldMatrix, unsigned int geomIndex) { MStatus status; // get the blendMesh MDataHandle hBlendMesh = data.inputValue( aBlendMesh, &status ); CHECK_MSTATUS_AND_RETURN_IT( status ); MObject oBlendMesh = hBlendMesh.asMesh(); if (oBlendMesh.isNull()) { return MS::kSuccess; } MFnMesh fnMesh( oBlendMesh, &status ); CHECK_MSTATUS_AND_RETURN_IT( status ); MPointArray blendPoints; fnMesh.getPoints( blendPoints ); // get the dirty flags for the input and blendMap bool inputGeomClean = data.isClean(inputGeom, &status); bool blendMapClean = data.isClean(aBlendMap, &status); if (!blendMapClean) { lumValues.reserve(itGeo.count()); } MDoubleArray uCoords, vCoords; MVectorArray resultColors; MDoubleArray resultAlphas; uCoords.setLength(1); vCoords.setLength(1); bool hasTextureNode; bool useBlendMap = data.inputValue(aUseBlendMap).asBool(); float blendMapMultiplier = data.inputValue(aBlendMapMultiplier).asFloat(); if (blendMapMultiplier<=0.0) { useBlendMap = false; } if (useBlendMap) { hasTextureNode = MDynamicsUtil::hasValidDynamics2dTexture(thisMObject(), aBlendMap); } float env = data.inputValue(envelope).asFloat(); MPoint point; float2 uvPoint; float w, lum; for ( ; !itGeo.isDone(); itGeo.next() ) { lum = 1.0; if (useBlendMap) { if (!blendMapClean) { fnMesh.getUVAtPoint(blendPoints[itGeo.index()], uvPoint); if (hasTextureNode) { uCoords[0] = uvPoint[0]; vCoords[0] = uvPoint[1]; MDynamicsUtil::evalDynamics2dTexture(thisMObject(), aBlendMap, uCoords, vCoords, &resultColors, &resultAlphas); lum = float(resultColors[0][0]); } lumValues[itGeo.index()] = lum; } else { lum = lumValues[itGeo.index()]; } } point = itGeo.position(); w = weightValue( data, geomIndex, itGeo.index() ); point += (blendPoints[itGeo.index()] - point) * env * w * lum * blendMapMultiplier; itGeo.setPosition( point ); } return MS::kSuccess; }
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; }
// // Deform computation // MStatus jhMeshBlur::deform( MDataBlock& block,MItGeometry& iter,const MMatrix& m,unsigned int multiIndex) { MStatus returnStatus; // Envelope float envData = block.inputValue(envelope, &returnStatus).asFloat(); CHECK_MSTATUS(returnStatus); if(envData == 0) return MS::kFailure; /* VARIABLES */ //float factor = block.inputValue(aShapeFactor, &returnStatus).asFloat(); float fStrength = block.inputValue(aStrength, &returnStatus).asFloat(); CHECK_MSTATUS(returnStatus); if (fStrength == 0) return MS::kFailure; float fThreshold = block.inputValue(aTreshhold, &returnStatus).asFloat(); CHECK_MSTATUS(returnStatus); float fW = 0.0f; // weight float fDistance; fStrength *= envData; double dKracht = block.inputValue(aInterpPower, &returnStatus).asDouble(); CHECK_MSTATUS(returnStatus); double dDotProduct; // Dotproduct of the point bool bTweakblur = block.inputValue(aTweakBlur, &returnStatus).asBool(); CHECK_MSTATUS(returnStatus); bool bQuad = block.inputValue(aQuadInterp, &returnStatus).asBool(); CHECK_MSTATUS(returnStatus); MTime inTime = block.inputValue(aTime).asTime(); int nTijd = (int)inTime.as(MTime::kFilm); MFloatVectorArray currentNormals; // normals of mesh MFnPointArrayData fnPoints; // help converting to MPointArrays MFloatVector dirVector; // direction vector of the point MFloatVector normal; // normal of the point MPointArray savedPoints; // save all point before edited MMatrix matInv = m.inverse(); // inversed matrix MPoint ptA; // current point (iter mesh) MPoint ptB; // previous point (iter mesh) MPoint ptC; // mesh before previous point (iter mesh) // get node, use node to get inputGeom, use inputGeom to get mesh data, use mesh data to get normal data MFnDependencyNode nodeFn(this->thisMObject()); MPlug inGeomPlug(nodeFn.findPlug(this->inputGeom,true)); MObject inputObject(inGeomPlug.asMObject()); MFnMesh inMesh(inputObject); inMesh.getVertexNormals(true, currentNormals); // get the previous mesh data MPlug oldMeshPlug = nodeFn.findPlug(MString("oldMesh")); MPlug oldMeshPositionsAPlug = oldMeshPlug.elementByLogicalIndex((multiIndex*4) + 0); MPlug oldMeshPositionsBPlug = oldMeshPlug.elementByLogicalIndex((multiIndex*4) + 1); MPlug oldMeshPositionsCPlug = oldMeshPlug.elementByLogicalIndex((multiIndex*4) + 2); // cache for tweak mode MPlug oldMeshPositionsDPlug = oldMeshPlug.elementByLogicalIndex((multiIndex*4) + 3); // cache for tweak mode // convert to MPointArrays MObject objOldMeshA; MObject objOldMeshB; MObject objOldMeshC; // cache MObject objOldMeshD; // cache oldMeshPositionsAPlug.getValue(objOldMeshA); oldMeshPositionsBPlug.getValue(objOldMeshB); oldMeshPositionsCPlug.getValue(objOldMeshC); // cache oldMeshPositionsDPlug.getValue(objOldMeshD); // cache fnPoints.setObject(objOldMeshA); MPointArray oldMeshPositionsA = fnPoints.array(); fnPoints.setObject(objOldMeshB); MPointArray oldMeshPositionsB = fnPoints.array(); fnPoints.setObject(objOldMeshC); MPointArray oldMeshPositionsC = fnPoints.array(); // cache fnPoints.setObject(objOldMeshD); MPointArray oldMeshPositionsD = fnPoints.array(); // cache // If mesh position variables are empty,fill them with default values if(oldMeshPositionsA.length() == 0 || nTijd <= 1){ iter.allPositions(oldMeshPositionsA); for(int i=0; i < oldMeshPositionsA.length(); i++) { // convert to world oldMeshPositionsA[i] = oldMeshPositionsA[i] * m; } oldMeshPositionsB.copy(oldMeshPositionsA); oldMeshPositionsC.copy(oldMeshPositionsA); // cache oldMeshPositionsD.copy(oldMeshPositionsA); // cache } // get back old date again if (bTweakblur == true) { // restore cache oldMeshPositionsA.copy(oldMeshPositionsC); oldMeshPositionsB.copy(oldMeshPositionsD); } iter.allPositions(savedPoints); for(int i=0; i < savedPoints.length(); i++) { // convert points to world points savedPoints[i] = savedPoints[i] * m; } // Actual Iteration through points for (; !iter.isDone(); iter.next()){ // get current position ptA = iter.position(); // get old positions ptB = oldMeshPositionsA[iter.index()] * matInv; ptC = oldMeshPositionsB[iter.index()] * matInv; fDistance = ptA.distanceTo(ptB); fW = weightValue(block,multiIndex,iter.index()); if (fDistance * (fStrength*fW) < fThreshold && fThreshold > 0){ iter.setPosition(ptA); } else { // aim/direction vector to calculate strength dirVector = (ptA - ptB); // (per punt) dirVector.normalize(); normal = currentNormals[iter.index()]; dDotProduct = normal.x * dirVector.x + normal.y * dirVector.y + normal.z * dirVector.z; if(bQuad == true){ MVector vecA(((ptB - ptC) + (ptA - ptB)) / 2); vecA.normalize(); MPoint hiddenPt(ptB + (vecA * fDistance) * dKracht); ptA = quadInterpBetween(ptB, hiddenPt, ptA, (1 - fStrength * fW) + (linearInterp(dDotProduct, -1, 1) * (fStrength * fW) ) ); } else { MPoint halfway = (ptA - ptB) * 0.5; MPoint offset = halfway * dDotProduct * (fStrength*fW); ptA = ptA - ((halfway * (fStrength*fW)) - offset); // + (offset * strength); } // set new value iter.setPosition(ptA); } } if(bTweakblur == false){ oldMeshPositionsD.copy(oldMeshPositionsB); oldMeshPositionsC.copy(oldMeshPositionsA); oldMeshPositionsB.copy(oldMeshPositionsA); oldMeshPositionsA.copy(savedPoints); // Save back to plugs objOldMeshA = fnPoints.create(oldMeshPositionsA); objOldMeshB = fnPoints.create(oldMeshPositionsB); objOldMeshC = fnPoints.create(oldMeshPositionsC); objOldMeshD = fnPoints.create(oldMeshPositionsD); oldMeshPositionsAPlug.setValue(objOldMeshA); oldMeshPositionsBPlug.setValue(objOldMeshB); oldMeshPositionsCPlug.setValue(objOldMeshC); oldMeshPositionsDPlug.setValue(objOldMeshD); } return returnStatus; }
// COMPUTE ====================================== MStatus gear_slideCurve2::deform( MDataBlock& data, MItGeometry& iter, const MMatrix &mat, unsigned int mIndex ) { MStatus returnStatus; // Inputs --------------------------------------------------------- // Input NurbsCurve // Curve MFnNurbsCurve crv( data.inputValue( master_crv ).asNurbsCurve() ); MMatrix m = data.inputValue(master_mat).asMatrix(); // Input Sliders double in_sl = (double)data.inputValue(slave_length).asFloat(); double in_ml = (double)data.inputValue(master_length).asFloat(); double in_position = (double)data.inputValue(position).asFloat(); double in_maxstretch = (double)data.inputValue(maxstretch).asFloat(); double in_maxsquash = (double)data.inputValue(maxsquash).asFloat(); double in_softness = (double)data.inputValue(softness).asFloat(); // Init ----------------------------------------------------------- double mstCrvLength = crv.length(); int slvPointCount = iter.exactCount(); // Can we use .count() ? int mstPointCount = crv.numCVs(); // Stretch -------------------------------------------------------- double expo = 1; if ((mstCrvLength > in_ml) && (in_maxstretch > 1)){ if (in_softness != 0){ double stretch = (mstCrvLength - in_ml) / (in_sl * in_maxstretch); expo = 1 - exp(-(stretch) / in_softness); } double ext = min(in_sl * (in_maxstretch - 1) * expo, mstCrvLength - in_ml); in_sl += ext; } else if ((mstCrvLength < in_ml) && (in_maxsquash < 1)){ if (in_softness != 0){ double squash = (in_ml - mstCrvLength) / (in_sl * in_maxsquash); expo = 1 - exp(-(squash) / in_softness); } double ext = min(in_sl * (1 - in_maxsquash) * expo, in_ml - mstCrvLength); in_sl -= ext; } // Position -------------------------------------------------------- double size = in_sl / mstCrvLength; double sizeLeft = 1 - size; double start = in_position * sizeLeft; double end = start + size; double tStart, tEnd; crv.getKnotDomain(tStart, tEnd); // Process -------------------------------------------------------- double step = (end - start) / (slvPointCount - 1.0); MPoint pt; MVector tan; while (! iter.isDone()){ double perc = start + (iter.index() * step); double u = crv.findParamFromLength(perc * mstCrvLength); if ((0 <= perc) && (perc <= 1)) crv.getPointAtParam(u, pt, MSpace::kWorld); else{ double overPerc; if (perc < 0){ overPerc = perc; crv.getPointAtParam(0, pt, MSpace::kWorld); tan = crv.tangent(0); } else{ overPerc = perc - 1; crv.getPointAtParam(mstPointCount-3.0, pt, MSpace::kWorld); tan = crv.tangent(mstPointCount-3.0); tan.normalize(); tan *= mstCrvLength * overPerc; pt += tan; } } pt *= mat.inverse(); pt *= m; iter.setPosition(pt); iter.next(); } return MS::kSuccess; }
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 ); }
MStatus vxCacheDeformer::deform( MDataBlock& block, MItGeometry& iter, const MMatrix& m, unsigned int multiIndex) { MStatus returnStatus; MDataHandle envData = block.inputValue(envelope,&returnStatus); float env = envData.asFloat(); if(env == 0) return returnStatus; double time = block.inputValue( frame ).asTime().value(); MDataHandle inPathData = block.inputValue( path ); MString str_path = inPathData.asString(); MDataHandle inMinFrmData = block.inputValue( aminframe ); int minfrm = inMinFrmData.asInt(); MDataHandle inMaxFrmData = block.inputValue( amaxframe ); MDataHandle inFrmStepData = block.inputValue( aframestep ); int frmstep = inFrmStepData.asInt(); if( time < minfrm ) time = minfrm; int frame_lo = minfrm + int(time-minfrm)/frmstep*frmstep; int frame_hi = frame_lo+frmstep; if( strlen( str_path.asChar() ) > 0 ) { char filename[256]; sprintf( filename, "%s.%d.mcf", str_path.asChar(), frame_lo ); FMCFMesh mesh; if(mesh.load(filename) != 1) { MGlobal::displayError( MString("Failed to open file: ") + filename ); return MS::kFailure; } int lo_n_vertex = mesh.getNumVertex(); vertexArray.clear(); vertexFArray.clear(); XYZ tp; for(unsigned int i = 0; i < mesh.getNumVertex(); i++) { mesh.getVertex(tp, i); vertexArray.append( MPoint( tp.x, tp.y, tp.z ) ); } if( time > frame_lo ) { sprintf( filename, "%s.%d.mcf", str_path.asChar(), frame_hi ); if(mesh.load(filename) != 1) MGlobal::displayError( MString("Failed to open file: ") + filename ); else if(mesh.getNumVertex() == lo_n_vertex) { XYZ tp; for(unsigned int i = 0; i < mesh.getNumVertex(); i++) { mesh.getVertex(tp, i); vertexFArray.append( MPoint( tp.x, tp.y, tp.z ) ); } double alpha = double(time-frame_lo) / (double)frmstep; for(unsigned int i = 0; i < mesh.getNumVertex(); i++) { vertexArray[i] = vertexArray[i] + ( vertexFArray[i] - vertexArray[i] )*alpha; } } } // iterate through each point in the geometry // for ( ; !iter.isDone(); iter.next()) { MPoint pt = iter.position(); pt = pt + (vertexArray[iter.index()] - pt)*env; iter.setPosition(pt); } } return returnStatus; }