Tuesday, July 23, 2013

Using Maya Api to Print Difference in Vertex Positions Part II (blendshape application)

Happy Tuesday,

Building on an earlier post. Here I show how the simple printing of vertex differences can be useful to help make tweaks of a blendshape after seeing the blendshape fully active. Hope this is helpful. The formula I used here is basically:
result = unposed - ( posed - sculpted )

Then when the result, and posed are fully on of blendhshape we get the edited sculpted pose we want.

cheers,
-Nate

/**@file makeCorrectiveCmd.cpp 
@note select posed,sculpted, then unposed polygon and type in mel -- makeCorrectiveCmd; currently it changes unposed to be a corrective
@author Nathaniel O. Anozie (ogbonnawork at gmail dot com)
@note Modify at your own risk

@note date created: 07/23/2013

*/

//last updated: 07/23/2013 -- added initial release   result = unposed(third) - [ posed(first) - sculpted(second) ]

//remove space after <, was put so didnt dissapear here
#include < maya/MSimple.h>
#include < maya/MGlobal.h>
#include < maya/MSelectionList.h>
#include < maya/MDagPath.h>
#include < maya/MFnMesh.h>
#include < maya/MItMeshVertex.h>
#include < maya/MPoint.h>


DeclareSimpleCommand( makeCorrectiveCmd, "Nathaniel Anozie", "1.0");


MStatus makeCorrectiveCmd::doIt( const MArgList& )
{

    MStatus stat;
    
    //------get the required polygons selected
    MSelectionList selList;
    stat = MGlobal::getActiveSelectionList(selList);
    MString errorMsg = "Error select posed,sculpted, then unposed polygon !!!\n";
    if(MS::kSuccess != stat){
        MGlobal::displayError(errorMsg);
        return stat;
    }
   
    //need certain number of things
    if( selList.length() != 3 ){
        MGlobal::displayError(errorMsg);
        return stat;
    }
    
    //make sure selected are polygons, needed to tell the number of vertices of polygon
    MDagPath firstPath; //hold path
    stat = selList.getDagPath(0, firstPath);
    if(MS::kSuccess != stat){
        MGlobal::displayError(errorMsg);
        return stat;
    }
    if( firstPath.hasFn(MFn::kMesh) ){}
    else{
        MGlobal::displayError(errorMsg);
        return MS::kFailure;        
    }
    
    MDagPath secondPath; 
    stat = selList.getDagPath(1, secondPath);
    if(MS::kSuccess != stat){
        MGlobal::displayError(errorMsg);
        return MS::kFailure;
    }
    if( secondPath.hasFn(MFn::kMesh) ){}
    else{
        MGlobal::displayError(errorMsg);
        return MS::kFailure;        
    }    
    
    MDagPath thirdPath; 
    stat = selList.getDagPath(2, thirdPath);
    if(MS::kSuccess != stat){
        MGlobal::displayError(errorMsg);
        return MS::kFailure;
    }
    if( thirdPath.hasFn(MFn::kMesh) ){}
    else{
        MGlobal::displayError(errorMsg);
        return MS::kFailure;        
    }    
    //--------
    
    
    //---make sure selected have identical number of vertices, kind of like making sure they have same topology but not really
    //first poly data
    int firstNumVtx; //hold number of vertices
    MFnMesh firstMeshFn( firstPath ); //make and set function set used to get vertex info
    firstNumVtx = firstMeshFn.numVertices();
    MGlobal::displayInfo(MString("Poly Number of Vertices Are:")+firstNumVtx+"\n");
    
    //second poly data
    int secondNumVtx; //hold number of vertices
    MFnMesh secondMeshFn( secondPath ); //make and set function set used to get vertex info
    secondNumVtx = secondMeshFn.numVertices();
    
    if(firstNumVtx != secondNumVtx){
        MGlobal::displayError("Requires Identical Number Vtx of Selected!!!\n");
        return MS::kFailure; 
    }
    
     
    //third poly data
    int thirdNumVtx; //hold number of vertices
    MFnMesh thirdMeshFn( thirdPath ); //make and set function set used to get vertex info
    thirdNumVtx = thirdMeshFn.numVertices();
    
    if(firstNumVtx != thirdNumVtx){
        MGlobal::displayError("Requires Identical Number Vtx of Selected!!!\n");
        return MS::kFailure; 
    }
    
    //---
    
    
    //---all is good so store local positions for both selected things
    
    //result data
    MPoint* result;//will hold the result
    delete [] result;
    result = new MPoint[firstNumVtx];

    //first vertex data
    MPoint* firstLocalVtxPositions;
    delete [] firstLocalVtxPositions;
    firstLocalVtxPositions = new MPoint[firstNumVtx];
    MObject firstVtx; //hold each vertex
    int i = 0; //hold index we will use soon

    MItMeshVertex firstVtxIter( firstPath, firstVtx, &stat);
    if( MS::kSuccess == stat ){
        i=0;
        
        for( ; !firstVtxIter.isDone(); firstVtxIter.next() ){
              firstLocalVtxPositions[i] =  firstVtxIter.position( MSpace::kObject); //local space
              i++;
        }
    }
    else{
        MGlobal::displayError("Vertex Iterator Error!!!\n");
        return stat;        
    }
    
    //second vertex data
    MPoint* secondLocalVtxPositions;
    delete [] secondLocalVtxPositions;
    secondLocalVtxPositions = new MPoint[secondNumVtx];
    MObject secondVtx;
    MItMeshVertex secondVtxIter( secondPath, secondVtx, &stat);
    if( MS::kSuccess == stat ){
        i=0;
        for( ; !secondVtxIter.isDone(); secondVtxIter.next() ){
              secondLocalVtxPositions[i] =  secondVtxIter.position( MSpace::kObject); //local space 
              i++;
        }
    }
    else{
        MGlobal::displayError("Vertex Iterator Error!!!\n");
        return stat;        
    }    
    

    //-----
    
    
    //compute result
    i = 0;
    MPoint a;
    MPoint b;
    MPoint diff;
    for( i = 0; i < firstNumVtx; i++)
    {
        a = firstLocalVtxPositions[i];
        b = secondLocalVtxPositions[i];
        //first poly minus second poly
        //if used MPoint minus MPoint would get an MVector a little more to do
        diff.x = a.x - b.x; 
        diff.y = a.y - b.y;
        diff.z = a.z - b.z;
        result[i] = diff;
         
        MGlobal::displayInfo(MString("Vtx Differences Are:") + diff.x + "," + diff.y + "," + diff.z + "\n");
    }

    
    
    //compute new pose
    MObject thirdVtx;
    MItMeshVertex thirdVtxIter( thirdPath, thirdVtx, &stat);
    if( MS::kSuccess == stat ){
        i=0;
        MPoint pnt;
        MPoint newPnt;
        diff.x = 0.0;
        diff.y = 0.0;
        diff.z = 0.0;
        for( ; !thirdVtxIter.isDone(); thirdVtxIter.next() ){
              //new unposed = [ posed(first) - sculpted(second) ] + unposed(third)
              pnt = thirdVtxIter.position( MSpace::kObject);
              diff = result[i];
              //newPnt.x = diff.x + pnt.x;
              //newPnt.y = diff.y + pnt.y;
              //newPnt.z = diff.z + pnt.z;
              newPnt.x = pnt.x - diff.x;
              newPnt.y = pnt.y - diff.y;
              newPnt.z = pnt.z - diff.z;   
              
              stat = thirdVtxIter.setPosition( newPnt, MSpace::kObject);
              if( MS::kSuccess != stat ){
                  MGlobal::displayError("Error setting Vertex\n -- Exiting!!!\n");
                  return stat;        
              }              
              i++;
        }
    }
    else{
        MGlobal::displayError("Vertex Iterator Error!!!\n");
        return stat;        
    }

    
    return stat;
    
}


Inspired by Christian Breitling (b-ling dot com) and Chad Vernon (chadvernon dot com)