Search code examples
pythonmayamaya-api

re-ordering polygon face index in maya


I have been wrestling with a problem in Maya for a while, and I cannot find a solution either on or off this site. I made the account so I could pose a direct question to the community and hope to get an answer.

The problem is thus: During modeling, the face index (e.g obj.f[0]) gets jumbled up as a matter of course. I need to re-order that face index sequentially from a user specified start point. This is to put the faces into a selection list. (Maya will put the list based on the face_index number, which is not what we want) To clarify, the face index does not need to be changed itself. It just needs to go into a list properly.

What I did so far: I was able to write some code that will do the selection for a strip of polygons. The face selected gets converted into a list of edges and Maya then searches for faces that shares the same edge and appends that to a new list in order. This works easy in a strip because only one edge is shared for the neighbouring face. Pseudo-code is:

select geo
select start face and make new_list
converts geo_sel into list
for geo_sel_face in geo_sel:
    convert to edge
    for new_list_face in new_list:
        convert to edge
        if edge in geo_sel_face in new_list_face:
            ordered_list.append(geo_sel_face)

Something like that. Of course the code completely breaks when dealing with a full surface like a plane, since there are at least two edges shared with other faces.

What this is used for: I wrote a script to basically plant grass (or any other type of geometry) across a surface. The original script looks for face centers and plants the grass, or what have you, on the face center. It will also constrain orientation to normals. However, the indexing is jumbled up, and doing additional work that requires a proper index becomes impossible. It would help a lot in data management if the list is human-readable rather than machine readable, which is why I'm searching for a way to do this.

Lastly: I've tried to look for a solution but there doesn't seem any to be found for a full surface. Perhaps I need to think about this from another angle, and would deeply appreciate any help or inspiration from the community.

Thank you for your time!


Solution

  • There's not a perfectly reliable way to do what you're asking, since faces don't have a reliable independent identity -- and since it can be very tricky to come up with a mapping that actually makes sense to the computer even though it's obvious to us.

    The easy thing to do is to use a dedicated UV map to contain your ordering information. If it's something that involves human decision making you could actually just ask the artists to produce a name UV map and use the UV centroids of your faces as the ordering elements. Something like this will give you a mapping between UV face centers and face indices:

    def uv_centroids(mesh, map = 'map1'):
        results = dict()
        for f in range(cmds.polyEvaluate(mesh, f=True)):
            cmds.select("%s.f[%s]" % (mesh, f), r = True)
            uu, vv = cmds.polyEvaluate(  bc2=True, uvs=map)
            uu = sum(uu) / 2.0
            vv =sum(vv) / 2.0
            results[uu,vv] = f
        return results
    

    since the face-centers are just tuples, using sort() on the dictionary keys will rank them first by U and then by V:

    # example with a default plane
    uv_dict  = uv_centroids('pPlane1')    
    ordered = uv_dict.keys()
    ordered.sort()
    for k in ordered:
        print k, uv_dict[k]
    
    # prints out the keys and faces ordered 0,10,20... 1, 11, 21.... etc
    

    While the UV's are as fragile as the indices under ordinary modelling conditions, they are a pretty simple to re-create and allow the artists to make some choices about flow and order. You may even be able to project an old mapping onto a new mesh using TransferAttributes.