(MEL)UDIM uv layout script WIP


#1

heres part of the script that ive been working on if anyone is interested. Essentially what its suppose to do is select the UDIM patch user specifies. For example if user say select 1001 UDIM (u1_v1) uv, it will select all the uvs within the UDIM tile boundary. Its using PolySelectconstraint as the backbone for the uv selection. Unfortunately, due to the inaccuracy of the maximum distance boundary, I had to do a lot of testing for the limits. Also In my findings, because its distance based on a specified point in the u and v space. It selects uvs in a radial falloff. Therefore I have to run it in several passes to select the uvs near the corner of the uv tile.


global proc selectUDIMPatch(){
    polySelectConstraint -m 3 -t 0x0010 -d 1 -dp 0.5 0.5 0 -db 0 0.5;
    string $Cnstpass1[] = `ls -sl -fl`; //center limit
    polySelectConstraint -m 3 -t 0x0010 -d 1 -dp 0.75 0.75 0 -db 0 0.25;
    string $Cnstpass2[] = `ls -sl -fl`; //top right center limit
    polySelectConstraint -m 3 -t 0x0010 -d 1 -dp 0.9 0.9 0 -db 0 0.1;
    string $Cnstpass3[] = `ls -sl -fl`; //top right small limit 
    polySelectConstraint -m 3 -t 0x0010 -d 1 -dp 0.1 0.9 0 -db 0 0.1;
    string $Cnstpass4[] = `ls -sl -fl`; //top left small limit 
    polySelectConstraint -m 3 -t 0x0010 -d 1 -dp 0.1 0.1 0 -db 0 0.1;
    string $Cnstpass5[] = `ls -sl -fl`; //botton left limit
    polySelectConstraint -m 3 -t 0x0010 -d 1 -dp 0.99 0.99 0 -db 0 0.01;
    string $Cnstpass6[] = `ls -sl -fl`; //tiny right limit
    polySelectConstraint -m 3 -t 0x0010 -d 1 -dp 0.05 0.05 0 -db 0 0.01;
    string $Cnstpass7[] = `ls -sl -fl`; //tiny left limit
    resetPolySelectConstraint;
    string $storedUV[];
    string $strAryA, $strAryB;
        for( $i=1; $i<6; ++$i){
            $strAryA = ("$Cnstpass" + $i);
            $strAryB = ("$Cnstpass" + ($i+1));
            $storedUVs[] = stringArrayCatenate($strAryA,$strAryB);// combine all the string arrays into one
            }
            string $finalUVs[] = stringArrayRemoveDuplicates $storedUVs; // remove duplicate of uvs due to overlap
select $finalUVs;
}
selectUDIMPatch;

unfortunately when I run it I get this error.

// Error: $storedUVs[] = stringArrayCatenate($strAryA,$strAryB);
//
// Error: Line 22.24: Syntax error //
// Error: string $finalUVs[] = stringArrayRemoveDuplicates $storedUVs;
//
// Error: Line 24.71: Invalid use of Maya object “stringArrayRemoveDuplicates”. //

maybe there is a better way to combine the string arrays into one?? Anyone have some suggestion

Thanks


#2

First error is the []. Leave them out.
$storedUVs = stringArrayCatenate($strAryA,$strAryB);

Second error is the function call. Either use () or ``.

string $finalUVs[] = stringArrayRemoveDuplicates $storedUVs;

or

string $finalUVs[] = stringArrayRemoveDuplicates($storedUVs);

As for the design of the code… Using python might be a good start. But erither way, once you have the uvs in a big array, you can iterate through and test whether they are in-side a bounding box. The radial thing seems a bit awkward to say the least.

David


#3

Hi David, Thanks for the reply.

I changed the lines to what you suggested. but this comes up.

// Error: $storedUVs = stringArrayCatenate($strAryA,$strAryB);
//
// Error: Line 23.63: Cannot cast data of type string to string[]. //
// Error: string $finalUVs[] = stringArrayRemoveDuplicates $storedUVs;
//
// Error: Line 25.73: “$storedUVs” is an undeclared variable. //
// Error: //
// Error: Line 27.0: Syntax error //


#4

Looks like you are declaring it as singular

string $storedUV[];

David


#5

Wouldn’t mind seeing what you came up with ?


#6

djx: I wish I had the time to relearn another language. Im just trying to make a tool that works, and mel is the only language I am comfortable with, so thats why im using it.

after trying to get the previous method to work. I had to brute force it, by concatenate each array. Which ended up very slow. So I decided to follow djx suggestion, by using only one polySelectConstraint and then test it against the uv boundingbox. finally storing it into an array. Unfortunately I’ve hit another wall with the syntax :sad:

heres the error message

// Error: //
// Error: Line 19.0: Syntax error //


global proc selectUDIMPatchalt(){ 
    polySelectConstraint -m 3 -t 0x0010 -d 1 -dp 0.5 0.5 0 -db 0 0.7075; // select uv covering the whole tile.
    string $ConstraintSel[] = `ls -sl -fl`; //store initial selection
    int $minU = 0;
    int $minV = 0;
    int $maxU = 1;
    int $maxV = 1;
    string $finalUV[];
    int $uvLoc[];
        for($i = 0; $i < size($ConstraintSel) ; $i++) { //start testing uvs against bounding box
           $uvLoc = `polyEditUV -q -u -v $ConstraintSel`;
               if ($uvLoc[$i] > $minU && $uvLoc[$i] < $maxU && $uvLoc[$i+1] > $minV && $uvLoc[$i+1] < $maxV){
                   $finalUV[$i]= $ConstraintSel[$i];
    }
    print $finalUV;
}

selectUDIMPatchalt;


Falam: Once I have my script more polished I will post it up here. Thanks for taking interest. Here is one part of the script that works well for me so far
Function of the script is to take the user selected uvs and lay them out in the tile it is near.


global proc layoutUDIMuv() {
    ConvertSelectionToUVShell;
    float $UVBBox[] = `polyEvaluate -bc2`;
    float $offsetU = `floor $UVBBox[0]`;
    float $offsetV = `floor $UVBBox[2]`;
    polyMultiLayoutUV -sc 1 -psc 2 -lm 1 -l 2 -ou $offsetU -ov $offsetV -rbf 0;
    }

layoutUDIMuv;



#7

It looks like you are missing a closing ‘}’ on your final if statement in the function call:

if ($uvLoc[$i] > $minU && $uvLoc[$i] < $maxU && $uvLoc[$i+1] > $minV && $uvLoc[$i+1] < $maxV){
   $finalUV[$i]= $ConstraintSel[$i];


Less that great error reporting is a definite downside of MEL.

-ChrisZ


#8

yeh syntax errors isnt very descriptive.

nice catch on the closing curly bracket } . but new syntax error arises Q-Q

somehow the $finalUV is not carrying any value. Im suspecting that there is something wrong with the if statement.


 for($i = 0; $i < size($ConstraintSel) ; $i++) { //start testing uvs against bounding box
           $uvLoc[$i] = `polyEditUV -q -u -v $ConstraintSel`;
               if ($uvLoc[$i] > $minU && $uvLoc[$i] < $maxU)($uvLoc[$i+1] > $minV && $uvLoc[$i+1] < $maxV){
                   $finalUV[$i] = $ConstraintSel[$i];
                    }

EDIT: ok so I manage to solve the syntax error right after writing this post, by removing the ) inside the if statement and just replace it with && inbetween "$maxU and $uvLoc[$i+1] "


global proc selectUDIMPatchalt(){ 
    polySelectConstraint -m 3 -t 0x0010 -d 1 -dp 0.5 0.5 0 -db 0 0.7075; // select uv covering the whole tile.
    resetPolySelectConstraint;
    string $ConstraintSel[] = `ls -sl -fl`; //store initial selection
    int $minU = 0;
    int $minV = 0;
    int $maxU = 1;
    int $maxV = 1;
    string $finalUV[];
    float $uvLoc[];
        for($i = 0; $i < size($ConstraintSel) ; $i++) { //start testing uvs against bounding box
           $uvLoc[$i] = `polyEditUV -q -u -v $ConstraintSel`;
               if ($uvLoc[$i] > $minU && $uvLoc[$i] < $maxU && $uvLoc[$i+1] > $minV && $uvLoc[$i+1] < $maxV){
                   $finalUV[$i] = $ConstraintSel[$i];
                    }
                    print $finalUV;
        }
    
}

selectUDIMPatchalt;

but now I get // Error: line 12: Cannot convert data of type float[] to type float. // …sigh


#9

after some more testing. I was able to get the code to run without any syntax errors or warning. But it still boggles my mind how it ignores my if statement.

  
        if ($Uarray[$L] > $minU && $Uarray[$L] < $maxU && $Varray[$L] > $minV && $Varray[$L] < $maxV){
            $finalUV[size($finalUV)]= $ConstraintSel[$L];

Main code


global proc selectUDIMPatch(){ 
    polySelectConstraint -m 3 -t 0x0010 -d 1 -dp 0.5 0.5 0 -db 0 0.7075; // select uv covering the whole tile.
    resetPolySelectConstraint;
    string $ConstraintSel[] = `ls -sl -fl`; //store initial selection
    int $minU = 0;
    int $minV = 0;
    int $maxU = 1;
    int $maxV = 1;
    string $finalUV[]; //variable for storing UV selection after testing
    int $numUVs = `size $ConstraintSel`;
    float $Uarray[];
    float $Varray[];
    
    for($j = 0; $j < $numUVs; $j++){ //store u into seperate array
       $Uarray = `polyEditUV -q -u`;
       }
       
    for($k = 0; $k < $numUVs; $k++){ //store v into seperate array
       $Varray = `polyEditUV -q -v`;
       }
       
    for($L = 0; $L < $numUVs; $L++){ //testing to see if uvs lies within the tile boundary then storing it
        if ($Uarray[$L] > $minU && $Uarray[$L] < $maxU && $Varray[$L] > $minV && $Varray[$L] < $maxV){
            $finalUV[size($finalUV)]= $ConstraintSel[$L];
        }
    }
    //print $finalUV;
    select -replace $finalUV;
    
}

selectUDIMPatch;



#10

Had some downtime at work recently and wrote a procedure that auto layout selected object uvs in UDIM. I have kinda given up on UDIM patch selection for now, so I will be continue writing other parts of the Tool, and maybe eventually port everything to python.


global proc layoutUDIMautoSel(){
    string $userSel[] = `ls -sl`; 
    int $uvTileCounterU = 0;
    int $uvTileCounterV = 0;
        for($objs in $userSel) {
            string $Facename = ($objs + ".f[li]");
[/li]                polyMultiLayoutUV -sc 1 -l 2 -lm 0 -fr true -ou $uvTileCounterU -ov $uvTileCounterV -psc 2 -ps 1.2 $Facename;
                $uvTileCounterU += 1;
                if ($uvTileCounterU > 9){
                    $uvTileCounterU = 0;
                    $uvTileCounterV += 1;
                }
        }
}

layoutUDIMautoSel;

To use just select a bunch of mesh, run layoutUDIMautoSel;


#11

so I came back to the patch selection proc. and was able to get it to run at a reasonable time. Tested it with 1mil polys and had it run under a min. It still uses polyselectionConstraint as the backbone, then convertSelectionToUVShellBorder command to reduce the amount of uvs that it has to proccess. Now I m trying to add a progressWindow inside the proc to give the User some feedback, but im stuck as to how to implement it properly. Mainly the MaxAmount and where to put the counter. Any help is appreciated


global proc selectUDIMPatch(){ 
    global float $uNum,$vNum;
    convertUDIM;        
    float $uPoint = $uNum + 0.5;
    float $vPoint = $vNum + 0.5;
    polySelectConstraint -m 3 -t 0x0010 -d 1 -dp $uPoint $vPoint 0 -db 0 0.7075; // select uv covering the whole tile.
    ConvertSelectionToUVShellBorder; // convert to uv border to save time and iterations 
    string $preProcessSel[] = `ls -sl -fl`; 
    polySelectConstraint -m 0 -t 0x0010 -d 0 -dp 0 0 0 -db 0 0;// Zero out select Constraint
    resetPolySelectConstraint;
        
    float $minU = $uNum; //
    float $minV = $vNum; ////
    float $maxU = $uNum + 1; //// set boundary
    float $maxV = $vNum + 1; //
    
    string $finalUV[]; //variable for storing UV selection after testing
    int $numUVs = `size $preProcessSel`;
    int $MaxAmount = $numUVs * 2;
    int $pAmount = 0;
    progressWindow
        -title "Selecting UV Patch"
        -maxValue $MaxAmount
        -progress $pAmount
        -status "Selecting: 0%"
        -isInterruptable false;
        
    float $Uarray[]; // using array because I read somewhere that matrix doesn't handle strings. MEL limitation
    float $Varray[];
    float $tempUV[];
    
    for($i = 0; $i < ($numUVs)*2; $i++){
         $tempUV = `polyEditUV -q -u -v $preProcessSel`;
        }
    
    for($j = 0; $j < ($numUVs)*2; $j++){ //store u into seperate array
       $Uarray[size($Uarray)] = $tempUV[$j];
       $j++;
       }

    for($k = 1; $k < ($numUVs)*2; $k++){ //store v into seperate array
       $Varray [size($Varray)] = $tempUV[$k];
       $k++;
       }
       
    for($L = 0; $L < ($numUVs); $L++){ //testing to see if uvs lies within the tile boundary then storing it
        if ($Uarray[$L] > $minU && $Uarray[$L] < $maxU && $Varray[$L] > $minV && $Varray[$L] < $maxV){
            $finalUV[size($finalUV)] = $preProcessSel[$L];
        }
        else{
            continue;
        }
    }
    select -replace $finalUV;
    SelectUVShell;
    //inViewMessage -smg ("UDIM Patch " + $UDIMinput + " Selected") -pos topRight -bkc 0x00000000 -fade;
    progressWindow -endProgress; 
}


#12

Tiny Update:

shift object uvs UDIM style. When you have objects that already have uv layouts but is currently stacked/residing in 0-1 space. This script will auto shift the uvs over while adhering to the UDIM convention.

{
         string $userSel[] = `ls -sl`;
         int $uvTileCounterU = 0;
         int $uvTileCounterV = 0;
             for($objs in $userSel) {
                    string $ObjUVs = ($objs + ".map[*]");
                    polyMoveUV -translateU $uvTileCounterU -translateV $uvTileCounterV $ObjUVs;
                    $uvTileCounterU += 1;
                        if ($uvTileCounterU > 9){
                            $uvTileCounterU = 0;
                            $uvTileCounterV += 1;
                        }
             }
    }

#13

random code dump to keep this thread alive, lol

this local rotates uv shells with partial uv selection. Can be repurpose to work with local scale as well.

global proc rotateUVShells()
{
    ConvertSelectionToUVShell;
    string $uvShellList[] = texGetShells();
    string $flattenList[];
            for ($s in $uvShellList)
                {
                    $flattenList = eval("ls -sl -flatten " + $s);
                    float $UVBBox[] = `polyEvaluate -bc2 $flattenList`;      
                    float $pvtU = ($UVBBox[0] + $UVBBox[1])* 0.5;
                    float $pvtV = ($UVBBox[2] + $UVBBox[3])* 0.5;
                    polyEditUV -pivotU $pvtU -pivotV $pvtV -angle 30 $flattenList;
                }
}

rotateUVShells;