sexta-feira, 18 de outubro de 2013

Export from Maya using a Python script

As you can see or will see in my posts, i´m very used to code using Actionscript to create tools for export coordinates, textures, instructions, etc. But what if i needed to export 3D data? When i discovered that Maya supports python i was very excited to try something with it. So i coded a very simple FPS using lwjgl (opengl and another useful libraries wrapped for java), and a Maya level exporter using python.
The rules for using the exporter are:
- Hitboxes (AABB collision) must be named HitBox on Maya. They can't be transformed (scale, rotate).
- All models need to be triangulated.
- Select everything.
- Copy the textures images to the "texture" folder of the FPS Engine.
- Name the file "map.sam" and save on the "maps" folder.

Grab the source files HERE. It contains an eclipse project of the Java lwjgl fps and the python scripts + maya 2012 scene i used for testing (you will probably need to adjust the textures paths). (Hulk model by 3dregenerator)
Here´s the python exporter code.
import maya.OpenMaya as OpenMaya
import pymel.core as pm
import math

#Function to get the texture name.
def GetFileTextureName(plug):
    connectedPlugs = OpenMaya.MPlugArray()
    plug.connectedTo(connectedPlugs, True, False)
    for k in range(connectedPlugs.length()):
        if (connectedPlugs[k].node().apiType() == OpenMaya.MFn.kFileTexture):
            depNode = OpenMaya.MFnDependencyNode(connectedPlugs[k].node())
            ftn = depNode.findPlug("ftn")
            filepath = str(ftn.asString())
            filesplit = filepath.split('/')
            filename = filesplit[filesplit.__len__()-1]
            return filename
    return "none"
    

selections = OpenMaya.MSelectionList();
#Grab the selections..
OpenMaya.MGlobal.getActiveSelectionList(selections);

print "Total selected objects:", selections.length();

dagpath = OpenMaya.MDagPath()
objeto = OpenMaya.MObject()

#List iterator.
iter = OpenMaya.MItSelectionList(selections);
iter.reset();

maptxt = ''
objtxt = ''
hittxt = ''

while not iter.isDone():
    
    iter.getDagPath(dagpath, objeto);

    print "object:", dagpath.partialPathName();
    
    # HIT HANDLER ==============================
    if "HitBox" in str(dagpath.partialPathName()):
        print "Hit Object detected."
        
        hittxt += '\nobj\n'
        
        #=== WORLD POSITIONING ======================
        trans = OpenMaya.MFnTransform( dagpath );        
        position = trans.getTranslation(OpenMaya.MSpace.kWorld);
        scaleArray = OpenMaya.MScriptUtil()
        scaleArray.createFromList( [0.0, 0.0, 0.0], 3 )
        scale = scaleArray.asDoublePtr()
        trans.getScale(scale)
        rotation = OpenMaya.MEulerRotation();
        trans.getRotation(rotation);
        
        hittxt += '\npart\n'
        hittxt += '\ndiv '
        hittxt += str(position.x);
        hittxt += '\ndiv '
        hittxt += str(position.y);
        hittxt += '\ndiv '
        hittxt += str(position.z);
        hittxt += '\ndiv '
        hittxt += str(math.degrees(rotation.x));
        hittxt += '\ndiv '
        hittxt += str(math.degrees(rotation.y));
        hittxt += '\ndiv '
        hittxt += str(math.degrees(rotation.z));
        hittxt += '\ndiv '
        hittxt += str(OpenMaya.MScriptUtil().getDoubleArrayItem( scale, 0 ));
        hittxt += '\ndiv '
        hittxt += str(OpenMaya.MScriptUtil().getDoubleArrayItem( scale, 1 ));
        hittxt += '\ndiv '
        hittxt += str(OpenMaya.MScriptUtil().getDoubleArrayItem( scale, 2 ));
        #===============================================
        
        hittxt += '\npart\n'
        
        # cache the points
        mesh = OpenMaya.MFnMesh( dagpath );
        
        meshPoints = OpenMaya.MPointArray()
        mesh.getPoints( meshPoints, OpenMaya.MSpace.kObject )
        for i in range( meshPoints.length() ):
            hittxt += '\ndiv '
            hittxt += str(meshPoints[i].x);
            hittxt += '\ndiv '
            hittxt += str(meshPoints[i].y);
            hittxt += '\ndiv '
            hittxt += str(meshPoints[i].z);
        
    # MESH HANDLER ==============================   
    else:
        print "Mesh Object detected."
        
        objtxt += '\nobj\n'
        objtextura = ''
       
        uvs = []
        pts = []
        normals = []
        vertexindices = []      
        
        instanceNumber = dagpath.instanceNumber()
        mesh = OpenMaya.MFnMesh( dagpath );
        
        #=== POSICIONAMENTO NO MUNDO ======================
        trans = OpenMaya.MFnTransform( dagpath );        
        position = trans.getTranslation(OpenMaya.MSpace.kWorld);
        scaleArray = OpenMaya.MScriptUtil()
        scaleArray.createFromList( [0.0, 0.0, 0.0], 3 )
        scale = scaleArray.asDoublePtr()
        trans.getScale(scale)
        rotation = OpenMaya.MEulerRotation();
        trans.getRotation(rotation);
        
        objtxt += '\npart\n'
        objtxt += '\ndiv '
        objtxt += str(position.x);
        objtxt += '\ndiv '
        objtxt += str(position.y);
        objtxt += '\ndiv '
        objtxt += str(position.z);
        objtxt += '\ndiv '
        objtxt += str(math.degrees(rotation.x));
        objtxt += '\ndiv '
        objtxt += str(math.degrees(rotation.y));
        objtxt += '\ndiv '
        objtxt += str(math.degrees(rotation.z));
        objtxt += '\ndiv '
        objtxt += str(OpenMaya.MScriptUtil().getDoubleArrayItem( scale, 0 ));
        objtxt += '\ndiv '
        objtxt += str(OpenMaya.MScriptUtil().getDoubleArrayItem( scale, 1 ));
        objtxt += '\ndiv '
        objtxt += str(OpenMaya.MScriptUtil().getDoubleArrayItem( scale, 2 ));
        #print OpenMaya.MScriptUtil().getDoubleArrayItem( scale, 0 );
        #print math.degrees(rotation.x);
        #==================================================
        
        objtxt += '\npart\n'
        #TEXTURA ========================================
        # Process the materials
        sets = OpenMaya.MObjectArray()
        components = OpenMaya.MObjectArray()
        mesh.getConnectedSetsAndMembers(instanceNumber, sets, components, True)
        for i in range(sets.length()):

            # Current set and component
            set = sets[i]
            component = components[i]
            
            # Maya handles
            fnSet = OpenMaya.MFnSet(set)
            dependencyNode = OpenMaya.MFnDependencyNode(set)
            
            # Get the shaders
            surfaceShaderAttribute = dependencyNode.attribute("surfaceShader");
            surfaceShaderPlug = OpenMaya.MPlug(set, surfaceShaderAttribute)
            
            # Get the connections
            sourcePlugArray = OpenMaya.MPlugArray()
            surfaceShaderPlug.connectedTo(sourcePlugArray, True, False)
            
            if sourcePlugArray.length() == 0:
                continue
            
            # Get the relevant material connection
            sourceNode = sourcePlugArray[0].node()
            materialDepNode = OpenMaya.MFnDependencyNode(sourceNode)
            
            # Process basic material (lambert) parameters
            if sourceNode.hasFn(OpenMaya.MFn.kLambert):
                lambertShader = OpenMaya.MFnLambertShader(sourceNode)
            
            try:
                color = lambertShader.findPlug("color", True)
                objtextura = GetFileTextureName(color)
                break
            except RuntimeError:
                objtextura = "none"
                
            
        print objtextura
        objtxt += '\nsession\n'
        objtxt += objtextura
        #==================================================
               
        #cache the UVs
        UVSets = []
        # Get UV sets for this mesh
        mesh.getUVSetNames( UVSets )
      
        # cache the points
        meshPoints = OpenMaya.MPointArray()
        mesh.getPoints( meshPoints, OpenMaya.MSpace.kObject )        
       
        print "vertices: ", pts.__len__()
        print "uvs: ", uvs.__len__()             
        
        #cache normals for each vtx
        meshNormals = OpenMaya.MFloatVectorArray()
        # normals are per-vertex per-face
        # use MtMeshPolygon.normalIndex() for index
        mesh.getNormals( meshNormals )
        
        for i in range( meshNormals.length() ):
                        
            normals.append(meshNormals[i])
            
        print "normais: ", normals.__len__()
        
        polyIter = OpenMaya.MItMeshPolygon( dagpath, objeto )
        
        pointsarray = []
        indicesarray = []
        normalsarray = []
        uvsarray = []
        
        vindices = []
        indices = []        
        points = {}
        normals = {}
        uniqueIndex = 0

        polyIter.reset();
        while not polyIter.isDone():
            
            polygonVertexIndices = OpenMaya.MIntArray()
            polygonVertexPoints = OpenMaya.MPointArray()
            polygonVertexNormals = OpenMaya.MVectorArray()
            uvSetNames = []
            uvSets = {}
            
            # Get polygon information
            polyIter.getVertices(polygonVertexIndices)
            polyIter.getPoints(polygonVertexPoints, OpenMaya.MSpace.kObject)
            polyIter.getNormals(polygonVertexNormals, OpenMaya.MSpace.kObject)
            polyIter.getUVSetNames(uvSetNames)
            
            Us = OpenMaya.MFloatArray();
            Vs = OpenMaya.MFloatArray();
            
            polyIter.getUVs(Us, Vs, UVSets[0]);
            
            for i in range (Us.length()):
                uvsarray.append(Us[i]);
                uvsarray.append(Vs[i]);
            
            # Get current polygons triangles
            pntAry = OpenMaya.MPointArray()
            intAry = OpenMaya.MIntArray()

            # Get the vertices and vertex positions of all the triangles in the current face's triangulation.
            polyIter.getTriangles(pntAry, intAry, OpenMaya.MSpace.kObject)
            
            for i in range( polygonVertexPoints.length() ):
                pointsarray.append(OpenMaya.MPoint(polygonVertexPoints[i]));
                #print polygonVertexPoints[i].x;
                
            for i in range(polygonVertexIndices.length()):
                indicesarray.append(polygonVertexIndices[i]+uniqueIndex);
                
            for i in range( polygonVertexNormals.length() ):
                normalsarray.append(OpenMaya.MVector(polygonVertexNormals[i]));
            
            uniqueIndex += 1
            polyIter.next();
        
        objtxt += '\nsession\n'
        #for key, value in points.iteritems():
        #print '-------------------'
        for i in range (pointsarray.__len__()):
            objtxt += '\ndiv '
            objtxt += str(pointsarray[i].x);
            objtxt += '\ndiv '
            objtxt += str(pointsarray[i].y);
            objtxt += '\ndiv '
            objtxt += str(pointsarray[i].z);
        
        objtxt += '\nsession\n'
        for i in range( uvsarray.__len__() ):
            objtxt += '\ndiv '
            objtxt += str(uvsarray[i]);
        
        objtxt += '\nsession\n'
        for i in range (normalsarray.__len__()):
            objtxt += '\ndiv '
            objtxt += str(normalsarray[i].x);
            objtxt += '\ndiv '
            objtxt += str(normalsarray[i].y);
            objtxt += '\ndiv '
            objtxt += str(normalsarray[i].z);

        print "FINAL Vertices tamanho", pointsarray.__len__();
        print "FINAL Normais tamanho: ", normalsarray.__len__();
        print "FINAL Uvs tamanho: ", uvsarray.__len__();
        print "FINAL Indices: ", indicesarray
        print "FINAL Total poligonos: ", uniqueIndex
                                
    iter.next();

def saveMap( fileName, fileType):
    
    print fileName;
    
    maptxt = ''
    maptxt += '\ntype\n'+objtxt+'\ntype\n'+hittxt
    mfile = open(fileName, 'w')
    mfile.write(maptxt);
    mfile.close();
   
    return 1

pm.fileBrowserDialog( m=1, fc=saveMap, fl="Some Map File (*.sam),*.sam", ft="Some Map File (*.sam)", om='SaveAs' )

Nenhum comentário:

Postar um comentário