Looking for suggestions for fast UDIM Detection

Skip to first unread message


May 1, 2015, 2:37:06 AM5/1/15
to python_in...@googlegroups.com
Hey everyone,

I've been brute force checking UV coords to determine what UDIMs any selected object(s) are using, but my simple python query for all UVs and checking each of their coords is painfully slow and in some cases unusable in scenes my team will be working with. 

Do any of you have any snippets of python / python api code that can efficiently return a large list of occupied UDIMs from selected object? 

Appreciate any help you may be able to offer, thanks!


Anthony Tan

May 1, 2015, 8:34:48 AM5/1/15
to python_in...@googlegroups.com
Just wondering, what order of magnitude are we talking about here? A million UVs per object? More? Just my naive python snippet I was just playing with now works okayishly on things at the 100,000 size, is a bit laggy at 1,000,000 and probably would explode at one order up. 
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Chad Fox

May 1, 2015, 9:01:10 AM5/1/15
to python_in...@googlegroups.com

Million certs max. Mostly were working with some scenes that have 500000ish

Thanks for asking.

Chad Fox

May 1, 2015, 9:01:54 AM5/1/15
to python_in...@googlegroups.com

Ug.. Verts .. Damn auto correct :p

Anthony Tan

May 1, 2015, 9:10:04 AM5/1/15
to python_in...@googlegroups.com
Hm, okies, lemme have a play tonight and i'll see how i go. I'm guessing to date you're just doing something like selecting the object, using pymel/maya.cmds/API to dump all the UVs and sort etc etc?

Janos Hunyadi

May 1, 2015, 12:01:12 PM5/1/15
to python_in...@googlegroups.com
If all the uv's are inside a certain UDIM (so not overlapping to multiple UDIMs) you could just take first UV of each object, and check where it is in UV space, and convert that to UDIM space.


Chad Fox

May 1, 2015, 12:08:06 PM5/1/15
to python_in...@googlegroups.com
Hey Janos, yeah that would be awesome, but it's definitely not the case on most of the assets/environments we're working with.

Anthony, thank you for your help. Yeah currently I'm using cmds to loop through every UV then checking which UDIM it's in and adding that UDIM value to a list if it's not already in the list. Clunky. I was trying hard to find out how to perhaps get a list of all uv shells to then loop through their bounding boxes with the same idea in mind, but Ive so far been unable to determine how to do that.



You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.


May 1, 2015, 12:43:18 PM5/1/15
to python_in...@googlegroups.com
I do as Janos suggested, worked quite well and pretty fast.  We had quite heavy props from speed tree and it wasn't that bad

def getMeshUVBounds(mapName, mesh):
mesh = pCore.PyNode(mesh)
uList, vList = mesh.getUVs(mapName)
if not uList:
uList = [0]
if not vList:
vList = [0]
return [[min(uList), min(vList)], [max(uList), max(vList)]]

def getMeshUVBoundsAsUDIM(mapName, mesh):
udimMap = range(1001, 1011)
bounds = getMeshUVBounds(mapName, mesh)
minU, maxV = int(math.trunc(bounds[0][0])), int(round(bounds[1][1] + 0.5))
return udimMap[minU] + (10 * (maxV - 1))

def isUDIMOverlappingBoundaries(mapName, mesh):
bounds = getMeshUVBounds(mapName, mesh)
if int(bounds[0][0]) == int(bounds[1][0]) and int(bounds[0][1]) == int(bounds[1][1]):
return False
return True

Chad Vernon

May 1, 2015, 4:27:26 PM5/1/15
to python_in...@googlegroups.com
If speed is your main issue, you could write it in C++.

Anthony Tan

May 1, 2015, 10:24:59 PM5/1/15
to python_in...@googlegroups.com
Thought I'd just target the uv query to see if that can be sped up any, or where a bottleneck would be (can't imagine it's converting UV to UDIM coordinates, that's almost a one-liner).
So yes, taking three approaches, PyMEL/getUVs feels manageable out to say, 2-300k UVs, but does feel sluggish at 4-500k. Maya.cmds is just diabolical - that's also because I'm not very good with it and I'm 100% sure i'm doing it a horrible way, but the API is fine through to a million at which point I figured it was Fast Enough.
One thing I'd point out with my API approach - I've just done the bare minimum to get a result - I'd trust PyMEL over my implementation of UV grabbing until I did some more testing, wouldn't be surprised if there are issues I'm glossing over in this test scenario that PyMEL handles correctly, and I don't handle at all.
Just using a polysphere with 1000x200 subdivs to give me ~200k UVs, my numbers were roughly 4s for maya.cmds, 0.4s for pymel, and 0.001 for the API. The API approach scales decently as well, while I could've sworn pymel didn't have a linear growth pattern. (my local machine, Maya 2013x64/SP2)
checking pSphereShape1 for 1 iterations
maya.cmds    : 3.95910561149
PyMel        : 0.344888150405
OpenMaya/API : 0.00120376245754
(for 201199 uvs):
The figures above are just for grabbing the UVs and not processing them, but depending on what cases you want to trap, the UV/UDIM thing didn't feel expensive at the ranges you were quoting (out to 500k) using my naive approach of testing every coordinate and building up a set, so I didn't investigate that too much further. If you wanted to do things by-shell i have a feeling API is going to be where you want to head.
(Here's my code dump, scuse the mess but you should be able to execute the thing as it stands to replicate my results once you create a polySphere or similar to play with)
import timeit
mesh_string = 'pSphereShape1'
timer_iterations = 1
# pymel version
import pymel.core as pm
def pymel_getuvs(mesh_string):
    """return a list of two lists, idx 0 is U, idx 1 is V"""
    mesh = pm.PyNode(mesh_string)
    uvs = mesh.getUVs()
    return uvs
# mc version
import maya.cmds as mc
def mc_getuvs(mesh_string):
    """return a list of (u,v) tuples"""
    x = mc.getAttr(mesh_string+'.uvpt', multiIndices=True)  # determine UV idxs
    uvs = []
    for i in x:
        # probably quite a naive way to iterate through an object's UVs. I don't
        # use maya.cmds much
        uvs += mc.getAttr('{mesh_string}.uvpt[{idx}]'.format(idx=i, mesh_string=mesh_string))
    return uvs
# OpenMaya version
import maya.OpenMaya as om
def om_getuvs(mesh_string):
    """return a list of two lists, idx 0 is U, idx 1 is V"""
    # Y'know it's really weird to think of malloc-ing in python..
    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)
    return [u,v]
def uv_to_udim(u,v):
    '''return UDIM tile corresponding to UV coord
    NOTE:very poorly defined response on edges..
    import math
    return int( 1000+(math.floor(u)+1)+(math.floor(v)*10))
# the zip function itself is a bit slow
def equivalence(pymel_result, mc_result, om_result):
    pm_uv = zip(pymel_result[0], pymel_result[1])
    om_uv = zip(om_result[0], om_result[1])
    for i,x in enumerate(pm_uv):
        if pm_uv[i] != om_uv[i]:
            raise ValueError('pm != om')
        elif pm_uv[i] != mc_result[i]:
            raise ValueError('pm != mc')
    print "OK"
print "checking {mesh} for {it} iterations".format(mesh = mesh_string, it = timer_iterations)
print "maya.cmds    :",
t = timeit.Timer(stmt=lambda:mc_getuvs(mesh_string))
print t.timeit(timer_iterations)
print "PyMel        :",
t = timeit.Timer(stmt=lambda:pymel_getuvs(mesh_string))
print t.timeit(timer_iterations)
print "OpenMaya/API :",
t = timeit.Timer(stmt=lambda:om_getuvs(mesh_string))
print t.timeit(timer_iterations)
print "---------------"
print "(for {n} uvs)".format(n=len(om_getuvs(mesh_string)[0]))
print "---------------"
print "DONE"
uvs = om_getuvs(mesh_string)
udim_list = set()
for x in xrange(0,len(uvs[0])):
    udim_list.add( uv_to_udim(uvs[0][x],uvs[1][x]))       
print udim_list
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Chad Fox

May 3, 2015, 2:48:31 AM5/3/15
to python_in...@googlegroups.com
Thanks Anthony. I'll review and test out your code drop on Monday. As a side note, 500k uvs was unfortunately too sluggish for us, perhaps it's something to do with our environments or machines, but it wasn't resonable. God forbid someone runs my script with the UV editor open. Might as well pack up for the day :P

Anyways. Thanks again!


Anthony Tan

May 4, 2015, 2:18:24 AM5/4/15
to python_in...@googlegroups.com
Don't thank me til it works :D I'm doing all of this in such a non-production setup so I'm almost certainly working in a best-case scenario, but yes, let me know how you go and if you want feel free to bounce me a scene or your existing code and I'll have a go with it here to see if anything jumps out at me -  it'll stop me from wasting time with my day off playing with a useless box and setting electronics on fire via poor soldering technique..


Oct 14, 2017, 2:58:30 PM10/14/17
to Python Programming for Autodesk Maya
Hi Ive been trying to write my own UDIM helper Script and came across this page. I was wondering If anyone is continuing the development of this ?

Roy Nieterau

Feb 19, 2021, 7:18:46 AMFeb 19
to Python Programming for Autodesk Maya
Old topic - needed something similar today and only found this topic after. This is the prototype I got to: https://gist.github.com/BigRoy/60883eff23f73a34c4671395b32d858d

Note that unlike the code samples above mine doesn't go over individual uvs but uses the bounding boxes of UV shells to compute the UDIM tiles.
Side effect of that is that it will detect UDIM tiles if it's encompassed in a UV faces and all points are outside of it (very rare case in practice!).
However, my code will fail to detect 'empty tiles' if a single UV shell goes over tile boundaries like circling around it.

It is however, faster for much higher vertex/uv counts.

Also, the code snippets above in this thread can be faster even with Maya Python API 2.0. I'll add that as a comment on my gist too.
Reply all
Reply to author
0 new messages