Some maya api questions (multiple iterators)

how do most people deal with working around c++ references when there needed as arguments with the api, trying to work with the fnMesh::getPolygonUV method but it requires float references for both the U and the V values that it outputs, so there is really nothing i can do with existing python data types that wont give me a type error.

i tried messing around with the mscriptUtil like this.


                scriptUtilU = om.MScriptUtil()
                scriptUtilV = om.MScriptUtil()

                uPtr = scriptUtilU.asFloat()
                vPtr = scriptUtilV.asFloat()

                fnMesh.getPolygonUV(polyId, vertId, vPtr, uPtr)

but that didn’t work at all

I think you are a missing a couple of things. Check out my friend’s post on working with C++ pointers in Python http://www.kiaran.net/?p=205

ya thanks, i got the pointers working fine now, seems odd that it needs a pointer or a reference, for such a small piece of data that could be passed directly.

been trying to work with the getPolygonUV method of fnmesh but have been hitting a few problems, this is what i have been trying.


import maya.OpenMaya as om
import sys

#get mSelection List
sel = om.MSelectionList()
om.MGlobal.getActiveSelectionList(sel)

#MItSelectionList iteritor for meshes
#filter with mfn class
iterMesh = om.MItSelectionList(sel, om.MFn.kGeometric)

# create pointer and var objects
triCount = om.MIntArray()
triVerts = om.MIntArray()

u_util = om.MScriptUtil()
u_util.createFromDouble(0.0)
uPtr = u_util.asFloatPtr()

v_util = om.MScriptUtil()
v_util.createFromDouble(0.0)
vPtr = v_util.asFloatPtr()

vertPos = om.MPoint()
vertNrm = om.MVector()

# selection iterator
while not iterMesh.isDone():
    dagPath = om.MDagPath()
    iterMesh.getDagPath(dagPath)
    fnMesh = om.MFnMesh(dagPath)

    fnMesh.getTriangles(triCount, triVerts)

    # Zips the list of verts into triplets: [[0, 1, 2], [2, 1, 3],...]
    vertzip = zip(*[iter(triVerts)] * 3)
    # Groups the triplets into n-length lists based on the number of tris per-poly from triCount
    start = 0
    vertids = []
    for num in triCount:
        next = start + num
        vertids.append(vertzip[start:next])
        start = next

    for polyId, tris in enumerate(vertids):
        # print 'Poly id: %d' % polyId
        for triNum, vertIds in enumerate(tris):
            # print 'Triangle: %d' % triNum
            print >> sys.stderr, 'defaultmat'

            for vertId in vertIds:
                fnMesh.getPoint(vertId, vertPos)
                fnMesh.getFaceVertexNormal(polyId, vertId, vertNrm)
                fnMesh.getPolygonUV(polyId, vertId, uPtr, vPtr)
                # print out data
                print >> sys.stderr, vertPos.x, vertPos.y, vertPos.z,
                print >> sys.stderr, vertNrm.x, vertNrm.y, vertNrm.z,
                uvsU = u_util.getFloat(uPtr)
                uvsV = v_util.getFloat(vPtr)
                print >> sys.stderr, uvsU, uvsV
    iterMesh.next()

the data im getting back defiantly looks like uv coordinates, but it stops early, and fails on the 8th vertex it tries to process. with the error

# Error: RuntimeError: (kInvalidParameter): No element at given index #

from the docs on it, i would have assumed that it would work in a similar way to the getFaceVertexNormal method that works perfect atm, so i can olny assume im not that the polygonid and vertex index it wants are different from what i was giving it and different from what the other commands like getFaceVertexNormal want.

You are correct that getPolygonUV wants a different vertex id.

Most methods in MFnMesh that operate on a vertex id expect an object-relative/global vertex id (so the same id you’d see in the script editor when you select a vertex). getFaceVertexNormal is this way; in the docs for it:

[in] vertexIndex The object-relative (mesh-relative/global) vertex index

getPolygonUV takes a face-relative/local vertex id:

[in] vertexIndex The face-relative (local) vertex id to examine

getTriangles returns object-relative vertex ids. I’m pretty new to API stuff and not sure what the most efficient way to deal with that conversion is (or if you can assume that getTriangles vertices are in the same order as the face’s vertex order). There may be a better way of approaching the overall script that gives you the data you want up front instead of (feeling like you’re) jumping through hoops/conversions to get it. There are so many different ways to do things in the API and being new to it I have a hard time knowing which methods are efficient/safe/etc :frowning:

ya thanks for the info didn’t know it was expecting the numbers from just the 1 tri.

find mostly the problem is that the formate im working with wants the data displayed in a very weird way, which kinda works against how most of these methods work, since say it was just a obj file, it is pretty easy to print vert, normal, and uv lists to file, but more difficulty to work in this example where each tri has it’s own vert, uv and normal lists.

any idea of how to convert to the local per polygon index, only method that seems useful for this is polygonVertexCount so i could just hope things will match up, and do interate over a range of polygonVertexCount, but seems liek a pretty big hack job.

My limited API knowledge dies out there. I don’t know how different return values relate to each other enough to know what you can trust to give you a conversion of global-to-local. You may be better offer using MItMeshPolygon to iterate over the triangles of each polygon.

That being said, from some simple tests I just ran this method seems to work:
MFnMesh.getVertices returns:

[out] vertexCount Vertex count per polygon
[out] vertexList Storage for the vertex list.

Which is the same return as getTriangles except per-polygon, not triangle. As far as I can tell getVertices returns the object-relative vertices in their local order. So if a polygon has 4 vertices and they are [2, 3, 5, 4], you can use their position in that list to determine which local-index each has on that polygon, and then you can loop through the vertices for each triangle on that polygon and find the index of each triangle vert in the corresponding poly’s getVertices list, and you (should) have the local-index of each tri’s vert.

So for example assuming:

getTriangles returns:
triangleCount: [2, 2]
triangleVertices: [0, 1, 2, 2, 1, 3, 2, 3, 4, 4, 3, 5]

and

getVertices returns:
polygonVertexCount: [4, 4]
polygonVertices: [0, 1, 3, 2, 2, 3, 5, 4]

That means that the first polygon has 4 verts [0, 1, 3, 2]; and it has two triangles, with verts [0, 1, 2] and [2, 1, 3].
By looking up the index of each triangle vert in the poly vert list, you get the local index, so that translates to two triangles with [0, 1, 3] and [3, 1, 2] in local-vertex orders

And again, I can’t confirm that this will always hold up (but it makes sense to me that it would), but it’s more just me writing down/brainstorming a little exploration I just did.

Keep posting any progress you have, the more knowledge out there the better.

haven’t updated the thread in a while but i ended up taking a different approach to this problem, and just started using nested iterators for now, and im ignoring the per triangle not per polygon problem and just triangulating the mesh in advanced for now. also if people were curious what this is for is writing out source SMD files, since there are currently no good community maintained ones, and the official one only works on older 32bit maya installs.


    def writer(self, fileObject, optionString, accessMode):
        # get mSelection List
        sel = om.MSelectionList()
        om.MGlobal.getActiveSelectionList(sel)

        iterMesh = om.MItSelectionList(sel, om.MFn.kGeometric)

        vertPos = om.MPoint()
        normal = om.MVector()

        # MscriptUtil shit
        uvList = [0, 0]
        uv_util = om.MScriptUtil()
        uv_util.createFromList(uvList, 2)
        uvPoint = uv_util.asFloat2Ptr()

        # open file
        fullName = fileObject.fullName()
        smd = open(fullName, "w")

        while not iterMesh.isDone():
            dagPath = om.MDagPath()
            iterMesh.getDagPath(dagPath)

            # sel as mObject
            mObj = om.MObject()
            iterMesh.getDependNode(mObj)
            # print >> sys.stderr, 'triangles'  # start of tris list
            print >> smd, 'triangles'  # start of tris list

            # polys iter
            iterPolys = om.MItMeshPolygon(mObj)
            while not iterPolys.isDone():
                # print >> sys.stderr, 'defaultMat'  # Material ID place holder
                print >> smd, 'defaultMat'  # Material ID place holder
                polyMobj = iterPolys.currentItem()

                iterVerts = om.MItMeshFaceVertex(dagPath, polyMobj)
                while not iterVerts.isDone():
                    vertPos = iterVerts.position()
                    iterVerts.getNormal(normal)
                    iterVerts.getUV(uvPoint)

                    print >> smd, 0,  # bone ID place holder
                    print >> smd, vertPos.x, vertPos.y, vertPos.z,
                    print >> smd, normal.x, normal.y, normal.z,
                    uv0 = uv_util.getFloat2ArrayItem(uvPoint, 0, 0)
                    uv1 = uv_util.getFloat2ArrayItem(uvPoint, 0, 1)
                    print >> smd, uv0, uv1
                    iterVerts.next()
                iterPolys.next()
            iterMesh.next()

        smd.close()

next bit to do is kinda working backwards but is figure out the material names on each face.

haven’t looked into it, but it is prolly better due to how data is structured in maya, and for performance so im not calling for the material for each face, to look up all the materials first, than find the faces associated with the material, and do all the above to those faces.

anyone know of a way to grab the material name per polygon of, or perhaps get the materials than make lists of polygons with them.