Editing UV shells

Hello,
so I have come a problem, how to edit/query UV shells.
Basicaly, i want to do 2 things:

1.normalize each shell so it occupies 0-1 UV range. Additionaly I might want to move each next shell by +1.0 in U, so the shells don't overlap but are aligned in a row in UVView
2.cut the mesh, so each shell becomes separate object

If I could get no.2, then it would be possible to do no.1

Problem lies in getting a list of shells somehow... Is it doable in MEL, or should I go API route instead ?

thanks !

polyNormalizeUV -normalizeType 0 -preserveAspectRatio on ;
polyMultiLayoutUV -lm 1 -sc 0 -rbf 0 -fr 1 -ps 0.2 -l 1 -psc 0 -su 1 -sv 1 -ou 0 -ov 0;

Problem lies in getting a list of shells somehow... Is it doable in MEL, or should I go API route instead ?

You dont iterate trough things like this in mel mostly, just not how or maya or mel is used. The purpose of everything uin maya is to become a node so you make use of nodes instead. Doing manual moves wouldnt work out in all cases since there may or may not be a dataset to put the data into. Thats why mayas using nodes.

This is not exactly the kind of programming people actually are taught to do in school. Its teh sort f thing you do in the real world, where you dont go around reinventing the wheel

I needed to do something similar to my uv shells, so i brute forced my way through it...joojaa will probably scold me, this does get really slow on big objects...
I needed to check the size of each UV size to see if exceeded a certain length/width in UV space (we compress UV coords on export, so a single shell can't be larger than 32 units across).

Basically, start with a single face, expand to the shell, remove the list from the list of total faces on your object.

while ( size($flattenList) > 0 )
  {

   // select the first face in the list, we'll grab it's UV shell.
   select -r $flattenList[0];

   // set up the selection constraints to expand the selection to UV shells.
   polySelectConstraint -type 0;
   polySelectConstraint -shell 1 -border 0 -mode 2;

   // store off the list of faces that belong to the UV shell
   string $sel[] = ls -sl -flatten;

   // turn the selection constraint off
   polySelectConstraint -sh 0 -bo 0 -m 0;

   // remove these faces from the original list of faces.
   $flattenList = stringArrayRemoveExact($sel, $flattenList);

thanks Jojaa, it's close, but not there yet.
It does not strech each shell to fit 0-1 space. (I assume you meant polyNormalizeUV -normalizeType 1, otherwise it busts UVmap into separate faces)

Theres nothing wrong in brute forcing if the tool is right and you can get by with it, The main problem here is that this is a O(n^2) algorithm with a lot of overhead. It can be improved in mel but not much.

Ou can do this more elegantly with api calls at O(n) and with 100-1000 speedier loops, with not much more programming overhead.

OTH, i do use simple brute forces fi its not critical. The problem with these kinds of things is that they tend to become backbones of tool sets.

you can take preserve off then it fits as good as it can into the square.

-normalizeType 1, otherwise it busts UVmap into separate faces

it does? wait lets see... no thats not what i meant. MAybe my test geo was a bit bad hmm...

Ok thisis easy to do quite fast all you nee dto know is how many shells athere really are, now thats not entirely trivial to do unfortunately. The brute foce method could be used but agian dont rely on it. Its realtively easy to do in the pai but not entirely trivial tough.

allright, here it goes. it was easier than I expected, thanks to python dictionary.
Just select you geometry and run it. Every shell will be normalized to 0-1, aligned along U, and extracted to separate mesh.

import maya.cmds as cmds
import maya.mel as mel
import string

#extract index from name like that: pCube|pCubeShape.map[666]
def extractIndex(path):
    bracePos= path.rfind("[")
    return string.atoi(path[bracePos+1:-1])

#returns a list of uv shells, where each shell is represented by exactly one UV point
def mfGetUVShells(shape):
    shells= {}
    uvCount= cmds.polyEvaluate(shape, uv=1)
    allUVs= range(uvCount)
    uv= 0
    uvMax= allUVs[-1]
    while(uv<=uvMax):
        #select uv shell
        cmds.select(shape + ".map[" + str(uv) + "]")
        mel.eval("polySelectBorderShell 0")
        uvs_names= cmds.ls(sl=1, l=1, fl=1)
        #get indices of selected uvs
        uvs= map(extractIndex, uvs_names)

        #remove this shell's uvs from further inspection
        for u in uvs:
            if(u in allUVs):
                allUVs.remove(u)
        shells[uvs[0]]= 1
        if(not len(allUVs)):    break

        #reset range
        uv= allUVs[0]
        uvMax= allUVs[-1]

    # go home
    return shells.keys()

#layouts shells ina U-Row
def RowLayoutShells(shape, shells):
    offset= 0;
    for shell in shells:
        cmds.select(shape + ".map[" + str(shell) + "]")
        mel.eval("polySelectBorderShell 0")
        cmds.polyNormalizeUV(normalizeType=1, preserveAspectRatio= 1)
        cmds.polyEditUV(relative=1, u=offset)
        offset += 1

#split each shell into separate mesh
def BustShellsIntoObjects(shape, shells):
    copyL= cmds.duplicate(shape)
    shape= copyL[0]
    for shell in shells:    
        cmds.select(shape + ".map[" + str(shell) + "]")
        mel.eval("polySelectBorderShell 0")
        cmds.select(cmds.polyListComponentConversion(tf=1))#convert to faces
        cmds.polyChipOff(dup=1,ch=0,kft=1)
    cmds.polySeparate(shape, rs=0)

def RowLayoutShellsSL():
    sl= cmds.ls(sl=1, l=1)
    for o in sl:
        shells= mfGetUVShells(o)
        print "Shells count: " + str(len(shells))
        RowLayoutShells(o, shells)
        BustShellsIntoObjects(o, shells)

RowLayoutShellsSL()

Yes you can do this in mel too.. However the removal is also a loop. So inadvartenly its not specifically bttre then the bruteforce loop trough things many times.

PS: didnt we allready do thgis removal for your script once, rg?../../../users/rgkovach/forums../../../users/rgkovach/forums../../../users/rgkovach/forums

"didnt we allready do thgis removal for your script once, rg?"

Not sure what you mean, but I guess that was not me :slight_smile:

No i was talking to rgkovach, because i seem to remeber doing a remove form list thing to him once to speed the unnecceserly loops away.

yes i believe so, the struct of the final script ended up as described above...
it only needs to go through the list of faces once, no? each time hte shell is expanded all those faces are removed from the list, so it skips large number of faces each loop?

Yeah tahts what i tought. Sprry working on my memroy more athen my reading. Well mayas normal interface is not antirely optimal for this, mainly because shells as such arent defined in th core of the code so they cat be accessed without excessive work on the part of the user. In any case  even in mayas api you can not get completely linear but close.