Thursday, July 18, 2013

Using Maya Api to Print Difference in Vertex Positions Part I

Hi there,

Here is a plugin I wrote as a start for a corrective sculpting tool. It doesn't have undo yet.
I also included some intro api coding tips I wrote. Hope they are helpful.


/**@file printVertexSubtractCmd.cpp 
@note select two polygon and type in mel -- printVertexSubtractCmd; it will print for all vertices in order the vertex first poly minus vertex second poly. (local position difference)
@author Nathaniel O. Anozie (ogbonnawork at gmail dot com)
@note Modify at your own risk

@note date created: 07/18/2013

*/

#include 
#include 
#include 
#include 
#include 
#include 
#include 

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


MStatus printVertexSubtractCmd::doIt( const MArgList& )
{

    MStatus stat;
    
    //------get the two polygons selected
    MSelectionList selList;
    stat = MGlobal::getActiveSelectionList(selList);
    if(MS::kSuccess != stat){
        MGlobal::displayError("Needs two Polygons selected !!!\n");
        return stat;
    }
    //need two things
    if( selList.length() != 2 ){
        MGlobal::displayError("Needs two Polygons selected !!!\n");
        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("Needs two Polygons selected !!!\n");
        return stat;
    }
    if( firstPath.hasFn(MFn::kMesh) ){}
    else{
        MGlobal::displayError("Needs two Polygons selected !!!\n");
        return MS::kFailure;        
    }
    
    MDagPath secondPath; //hold path
    stat = selList.getDagPath(1, secondPath);
    if(MS::kSuccess != stat){
        MGlobal::displayError("Needs two Polygons selected !!!\n");
        return MS::kFailure;
    }
    if( secondPath.hasFn(MFn::kMesh) ){}
    else{
        MGlobal::displayError("Needs two Polygons selected !!!\n");
        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; 
    }
    //---
    
    
    //---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");
    }
    
    
    
    return stat;
    
}


Some intro API coding tips,

1. Taking screengrabs of parts of plugins
take screenshots of particular parts of plugins so they can be accessed for quickly studying later. (example main parts of a command doIt,initializePlugin ..., or node.. create, initialize …)
I made folder for Node, and Commands and in them have all the needed parts labeled sometimes by their function name. Its helpful to have the class declaration and the main use of the function in one place.

2. Finding how to use API function tip
duplicate Autodesk tutorial devkit sample code into a new folder. Then to search for how to use certain function could type in terminal

grep -n 'greatDayThisIscodeLookingFor' *

it gives us all line numbers and files that use the greatDayThisIscodeLookingFor

3. Header tip
after writing command etc, can go through all the objects used and do includes using that objects name with a .h at end. most of the time the header is named the same as when created the object.

4. Using API docs
google search class name to find api docs on all the functions that class has. Sometimes there are even more if the class inherits other functions. Then with the function we need can do the (tip on finding use of function) to see how its used in real examples.

5. Start with DeclareSimpleCommand
When writing first commands use MSimple.h. It helps eliminate alot of extra stuff so can start writing code.

6. template Make File
Have a template make file, there are lots of examples on google. This way just need to change .cpp name … bundle name to compile and build plugin.

7. Finding API Type Constants
To find constants ex: what is local space. First google the class with the function. Then in API docs find the function and read the class that has that argument. Then google that class and open the API docs. It should be easy to find that the local space is kObject.


cheers,
Nate