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; }
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 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 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; }
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 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; }