@aken2046 here is the script I wrote. It was meant to remove tris on a very specific kind of mesh. The script works by selecting one mesh object and running the script. Here is the test object I used when testing it:
And here is the script itself (below). It’s very much a work in progress and not thoroughly tested. I was trying to get the script to unfold the UV’s in a more sophisticated way, which I managed to have working, but I commented out those sections at the bottom.
Give it a try. I am curious to know how you would like to use it. Maybe I could help modify it to suit your needs.
import maya.cmds as cmds
import math
def mergeVertices( obj ):
# merge vertices
cmds.polyMergeVertex( obj, d=0.0001, am=1, ch=1 )
def getPoles( obj ):
# get all vertices in the object
verts = cmds.polyListComponentConversion( obj, toVertex=True )
# flatten the list
verts = cmds.ls( verts, flatten=True )
# create a list to hold the number of edges connected to each vertex
edgeCounts = []
# create a list to hold the poles
poles = []
# create a variable to hold highest number of edges
mostEdges = 0
# for each vertex
for v in verts :
# get the edges connected to it and store them in a list
edges = cmds.polyListComponentConversion( v, toEdge=True )
# flatten the list
edges = cmds.ls( edges, flatten=True )
# add the number of edges to a list
edgeCounts.append( len(edges) )
# if the vertex has more edges than the edge count
if len(edges) > mostEdges :
# set the new edge count
mostEdges = len(edges)
# for each vertex
for i in range( len(verts) ) :
# if the vertex has an equal or greater number of edges connected to it than the maximum
if edgeCounts[i] >= mostEdges :
# add the vertex to the poles list
poles.append( verts[i] )
# return the poles list
return poles
def getCenterUvShell( obj ) :
# get all vertices in the object
verts = cmds.polyListComponentConversion( obj, toVertex=True )
# flatten the list
verts = cmds.ls( verts, flatten=True )
# get the middle vertex
middleVert = verts[ int( math.floor( len(verts) / 2 ) ) ]
# get the center uv shell
centerUvShell = cmds.polyListComponentConversion( middleVert, toUV=True, uvShell=True )
# convert to vertices
#centerUvShell = cmds.polyListComponentConversion( centerUvShell, toVertex=True )
# flatten the list
centerUvShell = cmds.ls( centerUvShell, flatten=True )
# return the cap edge list
return centerUvShell
def getCapEdgesFromShell( shell ) :
capEdges = cmds.polyListComponentConversion( shell, toEdge=True, border=True )
# flatten the list
capEdges = cmds.ls( capEdges, flatten=True )
# return the cap edge list
return capEdges
def walkAlongEdgeFromVertex( edges, vertex, steps ) :
# convert the edges to a list of vertices
lvEdges = cmds.polyListComponentConversion( edges, toVertex=True )
# flatten the list
lvEdges = cmds.ls( lvEdges, flatten=True )
# convert to a set
svEdges = set( lvEdges )
# add the vertex to its own set
sVertex = set( [vertex] )
# set next vertex
nextVert = vertex
# create a mask set
svMask = set()
# loop begin
for i in range(steps) :
leExpand = cmds.polyListComponentConversion( nextVert, toEdge=True )
# convert the edges to vertices
lvExpand = cmds.polyListComponentConversion( leExpand, toVertex=True )
# flatten the list
lvExpand = cmds.ls( lvExpand, flatten=True )
# convert to a set
svExpand = set( lvExpand )
# get intersection of the expanded verts with the edges
svTwoEdges = svExpand.intersection( svEdges )
# first index
if i==0 :
# remove the vertex from the set
svOuterVerts = svTwoEdges.difference( sVertex )
# use the first as the next vertex
nextVert = list( svOuterVerts )[0]
# add the expanded set to the mask set
svMask = svMask.union(svExpand)
# other indexes
else :
#two edges - mask
nextVert = list( svTwoEdges.difference( svMask ) )[0]
# add the expanded set to the mask set
svMask = svMask.union(svExpand)
cmds.select( nextVert )
return nextVert
def deleteTrisFromUv ( uvs, seamEdge ) :
# defines a value to not delete an edge based on whether the u or v values of two uvs in question are within this threshold
keepTol = 0.0001
# define edges to exclude
sEdgeExclude = set( seamEdge )
# user selects a set of uvs
uvSelection = uvs
# store the edges to delete in a list
edgesToDelete = list()
# for all uvs in the selection
for uv in uvSelection :
# set the first uv
uv1 = uv
# get the uv value
uv1Val = cmds.polyEditUV( uv1, query=True )
# get the adjacent edges
adjEdges = cmds.polyListComponentConversion( uv1, toEdge=True )
# get the adjacent uvs
adjUvs = cmds.polyListComponentConversion( adjEdges, toUV=True )
# select the uvs
cmds.select( adjUvs )
# remove the first uv from the selection
cmds.select( uv1, deselect=True )
# set the adjacent uvs
adjUvs = cmds.ls( selection=True, flatten=True )
# for the adjacent uvs
for xy in adjUvs :
# set the second uv
uv2 = xy
# get the uv values
uv2Val = cmds.polyEditUV( uv2, query=True )
# if the first and second uvs don't match within a given tolerance
if abs( uv1Val[0] - uv2Val[0] ) > keepTol and abs( uv1Val[1] - uv2Val[1] ) > keepTol : # proceed to delete the edge between
# get the vertices
verts = cmds.polyListComponentConversion( uv1, uv2, toVertex=True )
# flatten the list
verts = cmds.ls( verts, flatten=True )
#newVert = cmds.polyListComponentConversion( uv2, toVertex=True )
# get the edge
edge = cmds.polyListComponentConversion( verts[0], verts[1], toEdge=True, internal=True )
# convert to set
sEdge = set( edge )
# exclude the uv shell border
sEdge = sEdge.difference( sEdgeExclude )
# edit the edge variable
edge = list(sEdge)
# add the edge to the list
edgesToDelete.extend(edge)
# exit the loop
#break
# delete all edges in the list
cmds.polyDelEdge( edgesToDelete, cv=False )
def getSeamEdgeFromShell ( shell ) :
# declare variables
minU = float()
maxU = float()
tol = 0.001
uvSeam = []
# select the shell
cmds.select( shell )
# select only the border uvs
mel.eval( 'PolySelectTraverse 3' )
# store the uv border
uvBorder = cmds.ls ( selection=True, flatten=True )
# clear the selection
cmds.select ( clear=True )
# select the uv border
cmds.select ( uvBorder )
# print
#print (uvBorder)
# for each border uv
for i in range( len( uvBorder) ) :
# get the u and v values
uvVal = cmds.polyEditUV( uvBorder[i], query=True )
# for the first uv
if ( i==0 ) :
# set minU and maxU
minU = uvVal[0]
maxU = uvVal[0]
# for all other uvs
else :
# if the u value is less than minU
if ( uvVal[0] < minU ) :
# set minU
minU = uvVal[0]
# if the u value is greater than maxU
if ( uvVal[0] > maxU ) :
# set maxU
maxU = uvVal[0]
# for each border uv
for uv in uvBorder :
# get the u and v values
uvVal = cmds.polyEditUV( uv, query=True )
# if the uv is aligned with minU or maxU
if ( ( ( uvVal[0] < ( minU + tol ) ) and ( uvVal[0] > ( minU - tol ) ) ) or ( ( uvVal[0] < ( maxU + tol ) ) and ( uvVal[0] > ( maxU - tol ) ) ) ) :
# add the uv to the list
uvSeam.append( uv )
eUvSeam = cmds.polyListComponentConversion( uvSeam, toEdge=True, internal=True )
return eUvSeam
def getCapFaces( stroke, shell ) :
# convert the stroke to uvs
lStrokeUv = cmds.polyListComponentConversion( stroke, toUV=True )
# flatten the list
lStrokeUv = cmds.ls( lStrokeUv, flatten=True )
# store them in a set
sStrokeUv = set( lStrokeUv )
# store the center shell in a set
sShellUv = set( shell )
# get the difference of the two
sCapUv = sStrokeUv.difference( sShellUv )
# convert to a list
lCapUv = list( sCapUv )
# convert the uvs to faces
faces = cmds.polyListComponentConversion( lCapUv, toFace=True )
# flatten the list
faces = cmds.ls( faces, flatten=True )
# return
return faces
def planarMapUv( faces ) :
# planar map faces
cmds.polyProjection( faces, type="Planar", ibd=True, kir=True, md="x" )
def quadrangulateWithAngle( faces, angle ) :
cmds.polyQuad( faces, a=angle, kgb=True, ktb=True, khe=False, ws=True )
def getCapSeamFromEdge( seamEdges, shell ) :
# select the edges
cmds.select( seamEdges )
# set selection type to edges
#cmds.selectType( pe=True )
# select contiguous edges
cmds.polySelectConstraint( pp=4, m2a=30.0, m3a=90.0, t=0x8000 )
# store the contiguous edges in a list
lCntgEdges = cmds.ls( selection=True, flatten=True )
# store the contiguous edges in a set
sCntgEdges = set( lCntgEdges )
# store the seam edges in a set
#sSeamEdges = set( seamEdges )
# convert the shell to edges
lShellEdges = cmds.polyListComponentConversion( shell, toEdge=True )
# flatten the list
lShellEdges = cmds.ls( lShellEdges, flatten=True )
# convert to a set
sShellEdges = set( lShellEdges )
# get the difference
sCapEdges = sCntgEdges.difference( sShellEdges )
# store them in a list
lCapEdges = list( sCapEdges )
# return
return lCapEdges
def cutAndUnfold( edges, faces ) :
# cut
cmds.polyMapCut( edges )
# unfold
cmds.u3dUnfold( faces, ite=8, p=0, bi=1, tf=1, ms=1024, rs=0 )
def moveAndSew( edges ) :
# move and sew uv edges
cmds.polyMapSewMove( edges, lps=0 )
def unfoldAndLayout( obj ) :
# unfold
cmds.u3dUnfold( obj, ite=8, p=0, bi=1, tf=1, ms=1024, rs=0 )
# layout
cmds.u3dLayout( obj, res=256, scl=1 )
# get the selected object
sel = cmds.ls( selection=True )
# create a variable to hold the stroke
stroke = sel[0]
# merge verts on the stroke
mergeVertices( stroke )
#poles = getPoles( stroke )
# define the main uv shell
shell = getCenterUvShell( stroke )
# define the seam edges
seamEdges = getSeamEdgeFromShell( shell )
# delete tris
deleteTrisFromUv( shell, seamEdges )
'''
# define the cap faces
capFaces = getCapFaces( stroke, shell )
# planar map the cap faces
planarMapUv( capFaces )
# re-define the main uv shell
shell = getCenterUvShell( stroke )
# re-define the seam edges
seamEdges = getSeamEdgeFromShell( shell )
# define the cap seam
capSeam = getCapSeamFromEdge( seamEdges, shell )
# cut and unfold the cap
cutAndUnfold( capSeam, capFaces )
# delete tris on the cap faces
quadrangulateWithAngle( capFaces, 1.0 )
# re-define the cap faces
#capFaces = getCapFaces( stroke, shell )
# get the cap edges
capEdges = getCapEdgesFromShell ( shell )
# move and sew the edges
moveAndSew( capEdges )
# unfold and layout
unfoldAndLayout( stroke )
'''
# test the selection
#cmds.select( capEdges )
'''
deleteTrisFromUv( shell, seamEdges )
quadrangulateWithAngle( capFaces, 1.0 )
'''
'''
capEdges = getCapEdgesFromShell ( shell )
seamPoint = walkAlongEdgeFromVertex( capEdges, poles[0], 3 )
'''