Trying to mod the UV-set order by cloning and copying UV-sets

Exporters and engines aside, let’s assume that I manually want to modify the UV set order (indices) in Maya by simply cloning and copying UV sets.
A simple task I thought, but for some reason this code doesn’t work even though the print statements claims it does:

import pymel.core as pm
import copy

sortedList = []
sortedListOrg = []


# Get selection...
selObj = pm.ls(selection=True)[0].getShape()

# ...and query UV set names and indices
uvIndices = pm.polyUVSet(selObj, query=True, allUVSetsIndices=True)
uvNames = pm.polyUVSet(selObj, query=True, allUVSets=True)
uvSetDict = dict(zip(uvNames, uvIndices)) # Create keypairs
sortedList = sorted(uvSetDict, key=uvSetDict.get) # Sorted list
sortedListOrg = copy.copy(sortedList) # Copy

# Flip order in sortedList
sortedList.reverse()

count = 0
while count < len(uvSetDict):
    temp = sortedListOrg[count]
    pm.polyUVSet(
        copy=True,
        newUVSet=temp+"_t",
        uvSet=temp,
    )
    sortedList.append(temp+"_t")
    count += 1
    
    print("Created copy of %s called %s")%(temp, temp+"_t")
    
    
# Copy sets and place them in the correct order
count = 0
dictSize = len(uvSetDict)
while count < dictSize:

    # Copy
    copyIndex = count + dictSize
    
    pm.polyUVSet(
        copy=True,
        newUVSet=sortedListOrg[count],
        uvSet=sortedList[copyIndex],
    )
    
    print("Copied %s to %s")%(sortedList[copyIndex], sortedList[count])
    
    count += 1

Create a cube, clone the UV set. Name the sets A and B (optional ofc).
Move the coords in one of the sets so you can tell the difference between A and B.
Run the code.
Notice that the clone of A isn’t copied into B (and the clone of B isn’t copied into A).
Additionally, there is no construction history suggesting that the copy even took place!!

Why doesn’t this work?

So your problem is that when you are performing the final copy, you’re copying index 2 which would be your A_t into A (which are identical), and then B_t into B (which are also identical).

So if your goal is to just swap the layouts of two sets, you could do something like this:


import pymel.core as pm

original = pm.selected()[0]
# Make a duplicate to work on, so we can see if the swap worked.
sel = original.duplicate()[0]

def swap_uv_sets_by_index(obj, pair):
    index_0, index_1 = pair
    set_names = pm.polyUVSet(obj, q=True, allUVSets=True)
    # Make a temp UVSet that holds a copy of our first set.
    tmp_name = set_names[index_0] + '_tmp'
    pm.polyUVSet(obj, copy=True, newUVSet=tmp_name, uvSet=set_names[index_0])
    # Move the data in our second set, into the first set
    pm.polyUVSet(obj, copy=True, newUVSet=set_names[index_0], uvSet=set_names[index_1])
    # Move the data from our temp set, into our second set
    pm.polyUVSet(obj, copy=True, newUVSet=set_names[index_1], uvSet=tmp_name)
    # Cleanup after ourselves by removing our temp set
    pm.polyUVSet(obj, delete=True, uvSet=tmp_name)

swap_uv_sets_by_index(sel, (0, 1))

If you want to cycle the layouts by a set amount you can try something like this:


import pymel.core as pm

original = pm.selected()[0]
# Make a duplicate to work on, so we can see if the swaps worked.
sel = original.duplicate()[0]

def shift_uv_sets(obj, shift_amount):
    set_names = pm.polyUVSet(obj, q=True, allUVSets=True)
    num_sets = len(set_names)
    if shift_amount == num_sets or num_sets == 1:
        # No need to do the work, the offset will just return our current layout
        return
    swap_pairs = [(i, (i - shift_amount) % num_sets) for i in xrange(num_sets)]

    # Build temp storage
    for index_0, index_1 in swap_pairs:
        tmp_name = set_names[index_1] + '_tmp'
        pm.polyUVSet(obj, copy=True, uvSet=set_names[index_1], newUVSet=tmp_name)
    
    # Swap values from temp, into originals, and cleanup temp
    for index_0, index_1 in swap_pairs:
        tmp_name = set_names[index_1] + '_tmp'
        pm.polyUVSet(obj, copy=True, uvSet=tmp_name, newUVSet=set_names[index_0])
        pm.polyUVSet(obj, delete=True, uvSet=tmp_name)

shift_uv_sets(sel, 2)

I first thought the problem arises from the fact that I copy from sortedListOrg into sortedList when I should be copying from sortedList into sortedList.
Changed that, ran the code and it appeared to be working - but only for 2 sets. When I tried re-arranging this order with multiple sets it all just turned to chaos.

Tested your code and it works. The only thing missing is a rename when the sets are swapped or cycled - but that’s easily fixed.

Thanks a bunch for your help!

keep in mind that while the file is opened in maya, the temp uv set will still occupy an index even after it is deleted. so if you tried to add a new uv set later, it would use index 3 (assuming the first two are index 0 and 1, and the temp set occupied index 2).
to truly free the index used by the temp uv set, you need to re-open the file.

[QUOTE=rgkovach123;27976]keep in mind that while the file is opened in maya, the temp uv set will still occupy an index even after it is deleted. so if you tried to add a new uv set later, it would use index 3 (assuming the first two are index 0 and 1, and the temp set occupied index 2).
to truly free the index used by the temp uv set, you need to re-open the file.[/QUOTE]

Oh wow, that is a bit nuts.
Which probably explains why none of the commands (at least that I could find in my quick scan) that work with UVSets actually use that index value.

hopefully you never have to work in pipeline in considers the index…

also, you can really get yourself stuck if you create a uv set, rename it to “foo”, delete it, then create another new uv set and then try to name it “foo”… bad things happen…