[PYMEL] seeking help in getting uv location and map name


#1

I just stated learning pymel. I have been trying to put together some code to get uv coordinates and map id from selected objects. The goal is to use the UV info to do a uv range test which then I can selected uvs within the specified UV tile.

my current issue is I have no idea how to get .map information of selected meshes which corresponds to the uv coordinates (uList, vList)


import pymel.core as pm
import maya.cmds as cmds

    def getUVcord():
         my_object = pm.ls(sl=True)[0]
         uList,vList = my_object.getUVs()
         return uList, vList
    
    def getUVmap():
         selectedUVs = cmds.polyEditUV(query = True)
         return selectedUVs '''what I really need is to get the .map of the mesh selected'''



#2

To get the .maps for the selected uv’s you can just do:

pm.selected(fl=True)

If you just need the ids, then you could do:

ids = [m.index() for m in pm.selected(fl=True)]

You can get the uv coords as a list of tuples like this.

geo = pm.PyNode(‘pPlane1’)
geoShape = geo.getShape(ni=True)
uvs = [(u,v) for u,v in zip(*geoShape.getUVs())]

And then you could get the coords of your selected uv’s like this:

uvs_selected = [uvs[i] for i in ids]

Two things to consider: 1. a mesh can have multiple uv sets. 2. using pymel for these type of component level operations can be slow. Maya.cmds may be faster, and there are also OpenMaya methods that are way faster. It depends on what you are doing though. Let me know if you need more info.

David


#3

very informative, Im gona try it out when I get the chance. Thanks a lot for the help djx.

so I take it that zip is suppose to combine the u and the v into one list ?

I assumed the pymel was at least faster than maya.cmds in terms of getting uv coordinates. Because when I was researching methods on how to query uv coordinates with a reasonable speed, I came across this thread Fast UDIM detection where the author was trying to code a fast UDIM tile detection function. He did a test on grabbing UVs from a polysphere with 1000x200 subdivision with 3 methods: maya.cmds , PyMel, OpenMaya/API. Out of all of them OpenMaya/API was the fastest, then Pymel was second and maya.cmds was last.
I understand that OpenMaya/API is the fastest. But Im not skilled enough to integrate both into one code.

this was the code that I was trying to alter, but failed in getting it to give me a list that corresponds to the .map[ID]

not sure if its just me, but both Pymel and openmaya seems to be more stricter in syntax. I have so much problems troubleshooting syntax errors when the documentations dont give examples.


import maya.OpenMaya as om
def om_getuvs(mesh_string):
    """return a list of two lists, idx 0 is U, idx 1 is V"""
    selection_list = om.MSelectionList()
    mObject_holder = om.MObject()    
    u = om.MFloatArray()             
    v = om.MFloatArray()
    function_set = om.MFnMesh()
 
    # for a note on why this, instead of a flat selection_list.add.
    om.MGlobal.getSelectionListByName(mesh_string, selection_list)
    iterator = om.MItSelectionList(selection_list)
    iterator.getDependNode(mObject_holder)
    function_set.setObject(mObject_holder)
    function_set.getUVs(u,v)
    return [u,v]


#4

With regards to the speed comparison, the author of those tests admits he doesn’t really know maya.cmds very well and does it in a “horrible” way. He is iterating through every uv and doing a mc.getAttr - which is always going to be slow. If you did the same iteration with pymel it would probably be even slower. Generally you will find the overhead of casting things to pymel classes is what makes it a bit (or alot) slower, depending on what you are doing. Dont get me wrong. I use pymel all the time because the object oriented methods I find really useful. You just need to keep in mind that often component based stuff can get slow.

I’ll have a proper look at your code later when I have more time.

David


#5

hi djx, so I tried using the code you provided. I modified it to get uv .map and uv coordinate from selected object instead of selected uvs. As anticipated, I ran into errors. This is what it gave me

Error: line 1: TypeError: file E:\Autodesk_2015\Maya2015\Python\lib\site-packages\pymel\util\utilitytypes.py line 436: index() takes at least 1 argument (0 given)

import pymel.core as pm
import maya.cmds as cmds

selObj = pm.ls(sl=True)
ids = [m.index() for m in selObj]
geo = pm.PyNode(selObj)
geoShape = geo.getShape(ni=True)
uvs = [(u,v) for u,v in zip(*geoShape.getUVs())]
uvSel = [uvs[i] for i in ids] 

#6

pm.ls(sl=True), or more explicitly pm.selected(), always return a list of the selected objects as PyNodes. You can either iterate through the list or just grab the first one as follows:

geo = pm.selected()[0]

If you had selected an object, geo will now be the transform node. As such you cannot get the ids like you attempted. But you just need to know the number of uvs.

numUvs = geo.numUvs()

In fact you dont even need to know that… You can simply get the uvs from the object.

geoShape = geo.getShape(ni=True)
uvs = [(u,v) for u,v in zip(*geoShape.getUVs())]

uvs is a list of tuples in order of their map ids.

So your script would simply be:

geo = pm.selected()[0]
geoShape = geo.getShape(ni=True)
uvs = [(u,v) for u,v in zip(*geoShape.getUVs())]
for i, (u,v) in enumerate(uvs):
    print '%s.map[%i] = (%f, %f)'%(str(geo),i,u,v)


David


#7

djx: Thanks David for the code you posted. It works great.

now with the code that you provided, I tried to modify it to do a uv range test and then storing into a buffer which the “.map” that lies within the range will be selected.

import pymel.core as pm 
import maya.cmds as cmds 
minU = 0 
minv = 0 
maxU = 1 
maxV = 1 
geo = pm.selected()[0] 
geoShape = geo.getShape(ni=True) 
uvs = [(u,v) for u,v in zip(*geoShape.getUVs())] 
tmpBuffer = []
        for i, (u,v) in enumerate(uvs): 
            if uvs[0] > (minU,minV) and uvs[0] < (maxU,maxV):
                 tmpBuffer.append("%s.map[%i]" % (str(geo)) 
            if tmpBuffer : 
                 pm.select(tmpBuffer, r=1) 
                 ConvertSelectionToUVShell

i thought that this would work but it gave me a line 1 invalid syntax error. How would i fix this?


#8

with the help of my friend.

I manage to get the basic code working. :slight_smile:

import pymel.core as pm
import maya.cmds as cmds

minU = 0
minV = 0
maxU = 1
maxV = 1
geo = pm.selected()[0]
geoShape = geo.getShape(ni=True)
uvs = [(u,v) for u,v in zip(*geoShape.getUVs())]
tmpBuffer = []
for i, (u,v) in enumerate(uvs):
    if uvs[0] > (minU,minV) and uvs[0] < (maxU,maxV):
        tmpBuffer.append("%s.map[%i]" % (str(geo),i))
    
pm.select(tmpBuffer, r=1)
pm.runtime.ConvertSelectionToUVShell()

next step is to get it to work with multiple objects selected