Friday, November 7, 2014

Tips Using Maya Api to help Modeling -- Print Vertex Normal

Hi,

I was thinking about writing a couple tools that will greatly speed up some modeling areas regarding spirally loops, closing one off edgeloops, and helping with cleaning unneeded edgeloops.

Here are some rough results using MEL. Basically i use pick walk direction to select edges.
//assume mesh  y up, x mesh left side, z front mesh
//select first edge loop at top of mesh
int $times = 15;

//selects edges that it thinks we should delete
//doesnt check times
//assumes to select every other edge loop
string $result[] = {};
for($i = 0; $i < $times; $i++){
string $loop[] = `pickWalk -d right -type edgeloop`;//traverses us up to bottom of mesh
if( fmod($i,2) == 0 ){ $result = stringArrayCatenate($result,$loop); }
}
select -r $result;


Here are some doodles i made today looking at the normal vector of a vertex.  One reason this can come in handy in these modeling challenges is it allows to get an idea of whether parts of mesh are facing in generally the same direction.  So if the mesh is rather smooth, and we are interested in fixing a sub part that is a simple shape like cylindrical using normal can help tell us what edges/vertices are likely to be facing in a similar direction. Here's something i wrote that just prints the normals of all neighboring faces of a vertex. Here are some images: In one of the images you can see how i reproduced one of the result values by using locators and a nurbs curve and setting the end locator to the plugins result position.  Its shown that the normals returned can be visualized on the mesh. Here's the c++ code i wrote:
/**@file printVertexNormalCmd.cpp
@brief v1.0.0 printVertexNormalCmd;   //print all selected vertices normals relative to surface
@author Nathaniel O. Anozie (ogbonnawork at gmail dot com)
@bug no edge support, no release yet, using Maya macros msimple
@note -- this has some useful info on: getting vertices from selection, MVectorArray and MVector for Normals
@note -- great examples to study: Autodesk api example:
@note -- convertVerticesToEdgesCmd.cpp -- stuff on accessing selected vertices
@note -- apiMeshCreator.cpp (line 428) -- stuff on vertex normals
*/

//Flags:
//
//
//
//

//testing with msimple(remove space before maya)
#include < maya/MSimple.h>

//needed
#include < maya/MGlobal.h>
#include < maya/MDagPath.h>
#include < maya/MItSelectionList.h>
#include < maya/MItMeshVertex.h>
#include < maya/MVectorArray.h>

DeclareSimpleCommand(printVertexNormal, "Great_DAY", "1.0");

MStatus printVertexNormal::doIt(const MArgList& )
{
    MStatus status;
    
    MGlobal::displayInfo("Great Day\n");

    //will be used for normal stuff
    //MVectorArray normals;
    
    //get selected vertex, will need the mesh name, using iterators to get at vertices
    MSelectionList sel;
    MGlobal::getActiveSelectionList(sel);

    MDagPath meshDag;//path to mesh, assuming using same mesh for all selected verts
    MObject selListComponent, ourVtxComponent;
    //make sure only going through selected vertices
    //before using actual vertex selected need to go from selection list to component to vertex
    for( MItSelectionList selListIter(sel,MFn::kMeshVertComponent); !selListIter.isDone(); selListIter.next() )
    {
        //print the vertex name, needs path to mesh
        selListIter.getDagPath(meshDag,selListComponent);
        MString mesh = meshDag.fullPathName();
        if(!selListComponent.isNull()){
            //now we get to deal with actual vertex using our mesh
            for( MItMeshVertex vtxIter(meshDag,selListComponent); !vtxIter.isDone();vtxIter.next())
            {
                //print vertex selected
                MString vertexName = mesh+".vtx["+vtxIter.index(0)+"]";
                MGlobal::displayInfo("Great We Have a Vertex to get Normal from\n");
                MGlobal::displayInfo(vertexName+"\n");
                MVectorArray normalArray;
                status = vtxIter.getNormals(normalArray,MSpace::kWorld);//dont think need MFnMesh
                //i think get 4 or 3 sets of world positions trios for each face touching vertex
                // kObject if wanted positions relative to object
                //McheckErr(status,"Problem getting Normal\n");
                if(!status){status.perror("Problem getting Normal\n");return status;}
                //print each normal of faces using vertex
                MGlobal::displayInfo("///\n");
                for(int j = 0; j< normalArray.length(); j++)
                {
                    MVector normal;
                    normal = normalArray[j];
                    MGlobal::displayInfo(MString("")+normal[0]+","+normal[1]+","+normal[2]+"\n");
                    //probably want to save these and return one trio for the average normal weight 1/numberNeighborFaces
                }
                MGlobal::displayInfo("///\n");
            }
        }else{
            MGlobal::displayError("Please select a Vertex\n");
        }
    }
    
    return MS::kSuccess;
}



//notes
                //probably need function set that gives vertex normal, and what it needs from vertex iterator
                //MVectorArray.append(MVector),   MFnMesh .getVertexNormal( int , MVector), MFnMesh(MObject)
                //?? 
                //MVector normal;
                //MVectorArray.append

Some generally api tips:
--Make use of Maya's included sample api script tutorials.   I highly recommend writing a short terminal line command that can search through api examples for a keyword giving back their line numbers.
--start as simple as possible (like i began this by first gaining confidence from the hello world command sample)

cheers,
Nate