Published using Google Docs
naMirrorUV.txt

/*

naMirrorUV.mel  v1.1.0

Purpose: Mirror Texture Map

Author: Nathaniel Anozie

ogbonnawork at gmail dot com

nathanielanozie dot blogspot dot com

Acknowledgement: Bryan Ewert (xyz2 dot net), where i learned that one vertex could map to lots of uvs

Tested on 4000 vtx character in Maya 2008

To use Mirror Texture Map

-source 'naMirrorUV.mel'

-select uv-shell to mirror

-type 'naMirrorTextureMap()'

*/

/////given a vertex return the mapped vertex faces

/*

in uv texturing, not all vertex faces are mapped, mapping may be left till later

this takes care of finding which vertex faces are mapped/with uv

*/

global proc string[] getMappedVertexFaceArrayFromVertex(string $vtx)

{

    string $result[];

    string $vertexFaces[] = getVertexFaceArrayFromVertex($vtx);

   

    for($i=0; $i<size($vertexFaces); $i++)

    {

        string $uv[] = `polyListComponentConversion -fvf -tuv $vertexFaces[$i]`;

        if(size($uv) == 1){

            $result[size($result)] = $vertexFaces[$i];

        }

    }

    return $result;

}

/////given a vertex get the vertex faces for it all separated returns and empty array if nothing found

/*

used for uv mapping, since a vertex can be associated with multple faces

there should be one to one mapping between vertex face and a uv and

not a vertex and a uv

*/

global proc string[] getVertexFaceArrayFromVertex(string $vtx)

{

    string $sel[] = `ls -sl`;

    string $result[];

    string $vtxFaceArrayRangeCondensed[] = `polyListComponentConversion -fv -tvf $vtx`;

    if(size($vtxFaceArrayRangeCondensed) > 0)

    {

        select -cl;

        select -r $vtxFaceArrayRangeCondensed;

        $result = `filterExpand -sm 70 -expand true`;

        select -r $sel;    

    }

   

    return $result;

}

/////given vertex face return 1 if has uv, 0 if doesn't, and empty array otherwise

/*

in uv texturing, to help with knowing if a vertex face has a mapped uv

*/

global proc int[] isVtxFaceWithUV(string $_vtxFace)

{

    int $result[];

    string $vtxFace = $_vtxFace;

   

    $uvVertex = `polyListComponentConversion -fvf -tuv $vtxFace`;

   

    if(size($uvVertex) > 0)

    {

        if(size($uvVertex) == 1)

        {

            $result[0] = 1;

        }

        else

        {

            if(size($uvVertex) == 0)

            {

                $result[0] = 0;    

            }

        }  

    }

   

    return $result;

}

/////get mapped vtxFaces given selected and mirrored vertices no vertex faces excluded

/////first element can be a selected vertex or a mirrored vertex (check this)

/*

because automatic mapping and cylindrical mapping map vertex faces differently

i ran into two mapped (mirrored) vertices with identical number of vertex faces

having different number of vertex faces mapped

*/

global proc string[] getMappedVtxFaces(string $arg, string $selVtx, string $mirrorVtx)

{

    string $result[];

   

   

    //get all mapped faces for mirrored vertex

    string $mirroredVtxFacesWithMap[] = getMappedVertexFaceArrayFromVertex($arg);

   

   

    //take away those vfaces we dont have mapped for both selected and mirrored vface

    int $endArray[] = getMaxNumberVtxFacesMappedForSelectedAndMirror($selVtx, $mirrorVtx);

    if(size($endArray)>0){

        int $end = $endArray[0];

        for($i=0; $i<$end; $i++){ $result[size($result)] = $mirroredVtxFacesWithMap[$i];}

    }

    return $result;

}

/////

/*

because automatic mapping and cylindrical mapping map vertex faces differently

i ran into two mapped (mirrored) vertices with identical number of vertex faces

having different number of vertex faces mapped

here we take the min number of both and return that number

*/

global proc int[] getMaxNumberVtxFacesMappedForSelectedAndMirror(string $selVtx, string $mirrorVtx)

{

    int $result[];

    //get all mapped faces for selected vertex

    string $selectedVtxFacesWithMap[] = getMappedVertexFaceArrayFromVertex($selVtx);

    string $mirroredVtxFacesWithMap[] = getMappedVertexFaceArrayFromVertex($mirrorVtx);

   

    int $min = min(size($selectedVtxFacesWithMap),size($mirroredVtxFacesWithMap));

    if($min >= 0){ $result[0] = $min; }

   

    return $result;

}

/////given lots of vertices selected cut the uv shell of it

/*

in uv mapping to help texture artist, mirrored shell should

be cut up so that the individual uvs can be moved

*/

global proc cutUVShellFromVtxSelection(string $vtxArray[])

{

    string $edges[] = `polyListComponentConversion -fv -te $vtxArray`;

    if(size($edges) > 0){

        polyMapCut -ch 1 $edges;

    }

}

/////given one/or more user selected uv-shells, made through the uv texture editor mirror the uv-shell

/*

user can select individual uv's but enough have to be selected to make up at least one face

*/

global proc naMirrorTextureMap()

{

    string $sel[] = `ls -sl`;

   

    //if user selected a shell then

    //this wont be empty

    string $mapSelected[] = `filterExpand -sm 35 -expand true`;

   

    //make sure we have an actual map selected

    if(size($mapSelected) > 0){

       

        //get vertices selected by using mask for vertices to get expanded form of selection

        string $vertsSelectedShort[] = `polyListComponentConversion -fuv -tv $mapSelected`;

       

        //many of these vertices may be involved in

        //multiple uv shells and later

        //mirroring would cause mirroring of uv's that are not part of the shell we want mirrored

        //i think mirroring vertex faces would be a better idea (check this)        

       

        select -cl;

        select -r $vertsSelectedShort;

        string $expandedVSel[] = `filterExpand -sm 31 -expand true`;

        select -r $sel;

       

        //by making reselection but this time vertices we ensure mirror vertices correspond to selected vertex      

        string $vertsSelected[] = $expandedVSel;

        select -cl;

        select -r $vertsSelected;

        string $mirroredVerts[] = naMirrorSelectedVerts();

       

       

        if(size($mirroredVerts) > 0 ){

           

            //this is where we do the auto uv maps for the mesh on opposite side of selected

            //that side should probably not have any uvs already, this doesn't check that to make sure

            //Then we cut the map, after cut ex: vtx 1 (whose original value is vtx 92) could link to many uvs uv 5, 7, 9

            //where to move uv 5,7,9, we move them using vertex faces

           

           

            //no other vertices should be involved in projection

            //other than the mirrored vertices

            string $polyName[] = getPolyFromComponent($sel[0]);

            string $allVtx[] = getVtxFromPoly($polyName[0]);

            select -r $allVtx;

            string $vertsNonMirror[] = stringArrayRemove( $mirroredVerts, $allVtx);

           

           

            //for automapping the opposite of user's mesh

            //make sure no overlap faces between mirror and selected

            string $autoMappedFaces[];

            $autoMappedFaces = faceArrayRemoveFromVtx($vertsNonMirror,$mirroredVerts);

            if(size($autoMappedFaces) > 0){

                polyAutoProjection -ch 0 -lm 0 -pb 0 -ibd 1 -cm 0 -l 2 -sc 1 -o 1 -p 6 -ps 0.2 -ws 1 $autoMappedFaces;

            }

           

           

            //uvs can be moved individually without having ovewrapping because

            //lots of possible clumping for automap

            cutUVShellFromVtxSelection($mirroredVerts);

           

           

           

            //loop verts of selected

            int $i=0;

           

            //check speed

            //3 functions called with every vertex, these functions sometimes call other functions

            //moveUVToMirrorPosition

            //getSelectedVtxFaces       //calls getMappedVertexFaceArrayFromVertex, getMaxNumberVtxFacesMappedForSelectedAndMirror

            //getMirrorVtxFaces         //calls getMappedVertexFaceArrayFromVertex, getMaxNumberVtxFacesMappedForSelectedAndMirror

           

           

            string $movedUV[];//will tell us which uvs were in fact moved by code

            /*

            we need this because automap may add uvs that we cannot move, so we want to remove these

            from the texture editor.

            */

           

            for($i=0; $i<size($vertsSelected); $i++)

            {

               

                string $selVtx = $vertsSelected[$i];

                string $mirrorVtx = $mirroredVerts[$i];

               

               

                /////from two vertices, one on one side of mesh, and another a mirror of it

                /////this tries to move the uv's of one side to match the uv's user made on the other side

                //moveUVToMirrorPosition($vertsSelected[$i],$mirroredVerts[$i]);

               

                /*

                we are going to move a uv in the uv coordinate space

                we are going to move each uv associated with a vertex face --check this

                this is a brief example

                weve got uv map 5, map 9 , map 12  the user mapped already

                weve got uv map 3, map 2, map 24 as the code auto mapped part that should match with user part

                this moves in uv coordinates, all the code automapped uvs to corresponding user mapped uvs

                */

               

                /*

                //get all mapped faces for selected vertex that has corresponding for mirrored vertex

                //im confused shouldn't everything be mapped, probably can just put a vtx to face conversion

                //maybe this is useful if something went wrong in auto map part but i dont think that is likely

                */

                /*

                //why do we go vtx-vtxface-map

                //and not vtx - map

                */

               

                //string $selectedVtxFacesWithMap[] = getMappedVertexFaceArrayFromVertex($selVtx);

                //string $mirroredVtxFacesWithMap[] = getMappedVertexFaceArrayFromVertex($mirrorVtx);

               

                string $selectedVtxFacesWithMap[] = getMappedVtxFaces($selVtx,      $selVtx, $mirrorVtx);

                string $mirroredVtxFacesWithMap[] = getMappedVtxFaces($mirrorVtx,   $selVtx, $mirrorVtx);

               

                ///i want to see if went directly from vtx to uv what would we get

                //string $uvFromSelectedVtx[] = `polyListComponentConversion -fv -tuv $selVtx`;

                //string $uvFromMirrorVtx[] = `polyListComponentConversion -fv -tuv $mirrorVtx`;

                ///

               

                //most of the time we probably will be mirroring across the u or horizontal direction in map space

                //here is where we say that if wanted to mirror across v we would use {1,-1} for mirror direction

                float $mapMirrorDirection[] = {-1,1};    

               

                //for non perfect mirror and or/ mirrored faces not mapped

                //or gaps mesh these may not be equal so we check that

                //mirrored and selected vertex have same number of vertex faces

                if(size($selectedVtxFacesWithMap) == size($mirroredVtxFacesWithMap) ){

                   

                   

                   

                   

                    //loop selected vface

                    int $i=0;

                    string $mirroredNameUV[];

                    string $selectedNameUV[];

                    for($i=0; $i<size($selectedVtxFacesWithMap); $i++)

                    {

                        //do the moving in coordinate system for mirrored item

                        $mirroredNameUV = `polyListComponentConversion -fvf -tuv $mirroredVtxFacesWithMap[$i]`;

                        $selectedNameUV = `polyListComponentConversion -fvf -tuv $selectedVtxFacesWithMap[$i]`;

     

                        float $uvPos[] = `polyEditUV -query $selectedNameUV[0]`;

                        float $uPos = ($mapMirrorDirection[0])*$uvPos[0];

                        float $vPos = ($mapMirrorDirection[1])*$uvPos[1];

                       

                       

                        //if we are using user selected uv shell

                        //and not other uved uv shells that user didn't select

                        //we go ahead and move

                       

                        //default to assume uv is not from user selected shell

                        int $isUVFromUserSelectedShell = 0;

                       

                        $isUVFromUserSelectedShell = stringArrayContains($selectedNameUV[0],$mapSelected);

                       

                        if( $isUVFromUserSelectedShell == 1  ){

                           

                            //movement

                            polyEditUV -r false -u $uPos -v $vPos $mirroredNameUV[0];

                           

                            //save moved uv

                            $movedUV[size($movedUV)] = $mirroredNameUV[0];

                        }//end if check for uv

                       

                    }

                    //end loop vface

                   

                   

                   

                }

               

                else

                {

                    error("cannot mirror uvs, please check mesh placement and/or vtx positions...");

                }

               

               

            }//end vertex loop

           

           

           

           

            ////remove extra uvs automapped by code for cleanup

            //first select all automapped mirrored vtx faces uvs  

            string $autoMappedUV[] = `polyListComponentConversion -ff -tuv $autoMappedFaces`;

           

            select -cl;

            select -r $autoMappedUV;

            //now we want selected to be the non moved uvs

            //we use toggle so we unselect what was already selected

            select -tgl $movedUV;

           

            //we are left with uvs that were not moved and we wish to delete

            string $unMovedUVMirror[] = `ls -sl`;

           

            //need this check the function does not except empty arguments

            if(size($unMovedUVMirror) > 0){            

                polyMapDel -ch 0 $unMovedUVMirror;

            }

           

            //merge uvs for cleanup

            string $uvMirror[] = `polyListComponentConversion -fv -tuv $mirroredVerts`;

            //no construction history for speed increase

            polyMergeUV -d 0.01 -ch 0 $uvMirror;

           

           

           

        }

    }//end if

    else{

        print("please select a uv-shell");

    }

   

   

    //restore user selection

    select -r $sel;    

}

/////remove vertex items (faces) from the second string array

/*

here is a helpful tool to find what faces of input is shared and remove the shared faces from the returned faces

*/

global proc string[] faceArrayRemoveFromVtx(string $item[],string $list[])

{

    string $sel[] = `ls -sl`;  

   

    //return saveFaces minus removeFaces

    string $result[];

    string $saveFaces[];    

    string $removeFaces[];

   

    //convert vertex input into faces

    string $saveExpandedFaces[] = `polyListComponentConversion -fv -tf $list`;

    select -cl;

    select -r $saveExpandedFaces;

    $saveFaces = `filterExpand -sm 34 -expand true`;

    select -r $sel;

   

    //print "save faces";

    //print $saveFaces;

   

    //get what faces should be removed

    string $removeExpandedFaces[] = `polyListComponentConversion -fv -tf $item`;

    select -cl;

    select -r $removeExpandedFaces;

    $removeFaces = `filterExpand -sm 34 -expand true`;    

    select -r $sel;    

   

    if(size($saveFaces) > 0){    

        if( size($removeFaces) > 0){

            //find what faces of input is shared and remove the shared faces from the returned faces

            string $intersector = `stringArrayIntersector`;

            stringArrayIntersector -edit -intersect $saveFaces $intersector;

            stringArrayIntersector -edit -intersect $removeFaces $intersector;

            string $shareOneOrMoreVtxFaces[] = `stringArrayIntersector -query $intersector`;

            deleteUI $intersector;

           

            $result = stringArrayRemove( $shareOneOrMoreVtxFaces, $saveFaces);

           

        }

        else{

            //dont remove any faces

            $result = $saveFaces;

        }

    }

   

   

    return $result;

}

//Used for finding nodes like skinning blendshape etc

//for getting selections like get vertices from a polygon selection

//Last Modified: Nov 23, 2011

//By: Nathaniel Anozie ogbonnwork at gmail dot com

////given string array of node and node type return array for name first occurence of node type

/*

    /////

    string array of node

    ex: [blendNode, tweakNode, shapeNode]

   

    string node type: tweak, blendShape

    /////

*/

global proc string[]

getFirstHasNodeType(string $nodeArray[], string $nodeType)

{

    string $result[];

    int $i= 0;

    string $tempType;//store node type of loop element,cleared on every step

    //loop nodes of input

   

    for ($i=0;$i< size($nodeArray); $i++)

    {

        $tempType = `nodeType $nodeArray[$i]`;

        //if found matching node return it

        if( $tempType == $nodeType  )

        {

            $result[0] = $nodeArray[$i];

            break;

        }

    }

 

    return $result;

}

/////return vertices given a polygon selection

/*

often user may need to user vertices from a polygon selection

this script helps with returning that

*/

global proc string[]

getVtxFromPoly(string $poly)

{

    string $result[];

    string $sel[] = `ls -sl`;

   

    //will be altering user scene

    //with constaint command

    //so added check necessary

    if(`objExists $poly`){

        print "hii";

        select -cl;

        select -r $poly;

        polySelectConstraint -type 0x0001 -shell true -m 3;//mode no constraint used

        string $expanded[] = `ls -sl`;

        $result = `filterExpand -sm 31 -expand true`;

        polySelectConstraint -shell false;

        select -cl;

        select -r $sel;

    }

    else

    {

        warning("no poly exists");

    }

    return $result;

}

/*

naMirrorSelectedVerts.mel  v1.0.1

Last Modified: November 14, 2011

Author: Nathaniel Anozie

ogbonnawork at gmail dot com

nathanielanozie dot blogspot dot com

Purpose: Mirror selected vertices

Supports Low Poly Meshes ex < 10000 verts on a side

Tested on mirroring about 9000 verts which took about 150 seconds

*/

/////given selected vertices return list of thier mirrored vertex

/*

    //assumes nearestPointOnMesh plugin loaded

*/

global proc string[] naMirrorSelectedVerts()

{  

    print(`date -time`+"\n");

    string $_verts[] = `ls -sl`;

    string $mVerts[]; //for each input vtx corresponding mirrored vtx    

   

    if(size($_verts)>0){

        //string $verts[] = expandComponentArray($_verts);  

        string $verts[] = `filterExpand -sm 31 -expand true`;

        string $nearestFace[];  //nearest face to each mirrored vtx

        int $mDirect[] = {-1,1,1}; //mirror in x direction

       

        //get shape for mesh that has these verts

        string $polyNameArray[] = getPolyFromComponent($verts[0]);

        string $polyName = $polyNameArray[0];

        string $shapes[] = `listRelatives - shapes $polyName`;

        string $shape = $shapes[0];

       

       

        //this will be able to tell given a point what is nearest face to it

        string $near = "nearNodeForNAMirrorUV";

        createNode nearestPointOnMesh -n $near;

        connectAttr -f ($shape+".outMesh") ($near+".inMesh");

       

       

        int $i = 0;    

        //loop over verts

        for($i=0; $i<size($verts); $i++){

           

            float $selPos[] = `xform -q -t -ws $verts[$i]`;

           

            //get mirrored position for each slected vtx

            float $mPosX = $mDirect[0]*$selPos[0];

            float $mPosY = $mDirect[1]*$selPos[1];

            float $mPosZ = $mDirect[2]*$selPos[2];

           

            //we give it the point

            setAttr ($near+".inPositionX") ($mPosX);

            setAttr ($near+".inPositionY") ($mPosY);

            setAttr ($near+".inPositionZ") ($mPosZ);

            //we get the mirrored face

            string $nearestFaceId = `getAttr $near (".nearestFaceIndex")`;

           

            $nearestFace[$i] = $polyName+".f"+"["+$nearestFaceId+"]";

            string $mirrorVtx[] = getClosestVertToPos($nearestFace[$i],{$mPosX,$mPosY,$mPosZ});

            $mVerts[$i] = $mirrorVtx[0];

           

           

            //print($mVerts[$i]);

        }

        //end loop

       

        //delete created nodes

        delete($near);

       

        select -r $_verts;

    }

   

    print(`date -time`+"\n");

    return($mVerts);

}

/////given face and a world position get the closest vertex of face to that position

/*

    string name of face ex: "pCube1.f[2]"

    float 3 element array ex: {0.5,0.5,0.5}

*/

global proc string[] getClosestVertToPos(string $_face, float $wpos[] )

{

    string $result[];  

    string $face = $_face;

    string $vertsOfFace[];

   

    string $_vertsOfFace[] = `polyListComponentConversion -ff -tv $face`;//has [2:3] possibly

    $vertsOfFace = expandComponentArray($_vertsOfFace);

    if(size($wpos)==3){

        string $minVertex = $vertsOfFace[0];

        float $minWorldPos[] = `xform -q -t  -ws $minVertex`;

        float $minValue[] = euclidDistance( $minWorldPos, $wpos );

       

        //loop verts of face

        int $i=0;

        string $_minVertex="";

        float $_minWorldPos[];

        float $_minValue[];

       

        for($i=0; $i<size($vertsOfFace); $i++)

        {

            $_minVertex = $vertsOfFace[$i];

            $_minWorldPos = `xform -q -t  -ws $_minVertex`;

            $_minValue = euclidDistance( $_minWorldPos, $wpos );    

           

            //if found a closer point to input position save it

            if( $_minValue[0] < $minValue[0] )

            {

                $minVertex = $_minVertex;

                $minWorldPos = $_minWorldPos;

                $minValue = $_minValue;

            }

            //end if

            clear($_minWorldPos);

            clear($_minValue);

            $_minVertex="";

        }

        //end loop

        $result[0] = $minVertex;  

    }

 

    return $result;

}

/////  given a string array of form name[int:int] unfold name[2:3] into name[2] and name[3]

/*

    /////

    needs string name array of form name[int:int]

*/

global proc string[] expandComponentArray(string $_verts[])

{

    string $result[];  

    string $verts[] = $_verts;

   

    //get expanded form of vertex[int] instead of vertex[int:int]

    int $v = 0;

    string $expanded[];

    for($v=0; $v<size($verts); $v++)

    {

        $expanded = expandComponent($verts[$v]);

        if(size($expanded)>0){

            $result = stringArrayCatenate($result,$expanded);

        }

        //if found [int] add that with no change

        else{

            string $append[];

            $append[0] = $verts[$v];

            $result = stringArrayCatenate($result,$append);

        }

    }    

    return $result;    

}

/////  given a string of form name[int:int] unfold name[2:3] into name[2] and name[3]

/*

    /////

    needs string name of form name[intA:intB], intA < intB

*/

global proc string[] expandComponent( string $_arg )

{

    string $result[];

   

    string $partsNoSemiColon[];

    tokenize($_arg,":",$partsNoSemiColon);

   

    //will unfold name[2:3] into name[2] and name[3]

    if(size($partsNoSemiColon) == 2)

    {

        string $parts[];

        tokenize($_arg,"[",$parts);

        string $polyName = $parts[0];

       

        string $vertsWithBracket = $parts[1];

       

        //now have '[int' and 'int]'

        string $singleBracket[];

        tokenize($vertsWithBracket,":",$singleBracket);

       

        string $startParts[];

        string $endParts[];

        tokenize($singleBracket[0],"[",$startParts);        

        tokenize($singleBracket[1],"]",$endParts);  

       

        int $start=$startParts[0]; //int

        int $end=$endParts[0];   //int

        //loop start to end adding to result

        int $counterInBracket=0;

        string $vertex[];        

        for($counterInBracket = 0; $counterInBracket <= ($end-$start); $counterInBracket++)

        {

            //counter 0,1,2... if start is 5 end is 8 we put in vertex [5+0],[5+1], ...[5+3] or [5],[6],[7],[8]

            $vertex[0] = $polyName+"["+($start+$counterInBracket)+"]";

            $result = stringArrayCatenate($result,$vertex);

        }

       

    }

   

    return $result;

}

////get poly name given any poly component

/*supports any component vtx,face,edge,vFace ..

*/

global proc string[] getPolyFromComponent(string $component)

{

    string $result[];

   

    string $parts[];

    tokenize($component,".",$parts);

    $result[0] = $parts[0];  

    return $result;

}

/////given two vectors return euclidean distance

/*

this is used to find closeness on a mesh

suppose you wanted to know of the vertices of a face

which one is closest this other point, user can

use this to find out

    /////

    needs two float arrays of 3 elements

    /////

*/

global proc float[] euclidDistance(float $a[], float $b[] )

{

    float $result[];

   

    if( (size($a)==3) && (size($b)==3) )

    {

        $result[0] = sqrt( pow(($a[0]-$b[0]),2)+

                            pow(($a[1]-$b[1]),2)+

                            pow(($a[2]-$b[2]),2)

                            );

    }

   

    return $result;

}