Files
MetaBox/Scripts/Modeling/Edit/LDMT/ldmt_moveOverlapUVOut.py
2025-04-17 04:52:48 +08:00

361 lines
12 KiB
Python

# About ####################
# Auther: Liu Dian
# Email: xgits@outlook.com
# Website: www.xgits.com
# Version: Pro
# License: GPL
import maya.cmds as cmds
import maya.mel as mel
import maya.api.OpenMaya as om2
def getUVEdgeDic(sel):
selList = om2.MSelectionList()
selList.add(sel)
selPath = selList.getDagPath(0)
selMesh = om2.MFnMesh(selPath)
selVtxIter = om2.MItMeshVertex(selPath)
selEdgeIter = om2.MItMeshEdge(selPath)
selFaceIter = om2.MItMeshPolygon(selPath)
uvid_uv = [] # generate {uvid:[u,v],} from MFnMesh.getUVs()
vtxid_uvid = []
edgeid_vtxid = []
edgeid_uvid = [] #edgeid_vtxid + vtxid_uvid
faceid_edgeid = []
faceid_uvid = []
edgeid_faceid = [] #faceid_edgeid reverse
uvedgeid_uvid = [] # get { uvedgeid: [uvid1, uvid2]} On border
uvid_usi = selMesh.getUvShellsIds()
uvid_usi = uvid_usi[1]
uvArray = selMesh.getUVs()
for i in range(len(uvArray[0])):
uvid_uv.append([uvArray[0][i],uvArray[1][i]])
while not selVtxIter.isDone(): #get {[[uvid1,uvid2],...]}
vtxid_uvid.append(list(set(selVtxIter.getUVIndices())))
selVtxIter.next()
while not selEdgeIter.isDone(): #get edge to vtx
edgeid_vtxid.append([selEdgeIter.vertexId(0),selEdgeIter.vertexId(1)])
edgeid_faceid.append(selEdgeIter.getConnectedFaces())
selEdgeIter.next()
for edgeid in range(len(edgeid_vtxid)): # get {[[uvid1,uvid2,uvid3],...]}
vtx0 = edgeid_vtxid[edgeid][0]
vtx1 = edgeid_vtxid[edgeid][1]
edgeid_uvid.append(vtxid_uvid[vtx0] + vtxid_uvid[vtx1])
while not selFaceIter.isDone(): # get {[[uvid1,uvid2,uvid3,uvid4], ...] }
verts = selFaceIter.getVertices()
faceid_edgeid.append(selFaceIter.getEdges())
uvids=[]
for index in range(len(verts)):
uvids.append(selFaceIter.getUVIndex(index)) #necessary for uvedgeid
faceid_uvid.append(uvids)
selFaceIter.next()
for edgeid in range(len(edgeid_faceid)):
faceids = edgeid_faceid[edgeid]
edgeuvids = set(edgeid_uvid[edgeid])
numface = len(faceids)
if numface == 1: #OnBorder
uvids = faceid_uvid[faceids[0]]
uvedgeid_uvid.append(list(edgeuvids.intersection(uvids)))
continue
elif numface == 2:
uvidsA = faceid_uvid[faceids[0]]
uvidsB = faceid_uvid[faceids[1]]
intersectUV = list(set(uvidsA).intersection(uvidsB))
intersectUV_len = len(intersectUV)
if intersectUV_len<2:
if intersectUV_len == 1:
for uv in edgeuvids:
if uv == intersectUV[0]:
continue
elif uv in uvidsA or uv in uvidsB:
uvedgeid_uvid.append([intersectUV[0],uv])
else:
uvedgeid_uvid.append(list(edgeuvids.intersection(uvidsA)))
uvedgeid_uvid.append(list(edgeuvids.intersection(uvidsB)))
else:
print("Cleanup mesh first!!!!")
usi_uvid = {}
usi_uvidOnBord = {}
usi_uvedgeidOnBord = {}
usi_bb = {}
for uvid in range(len(uvid_usi)):
usi = uvid_usi[uvid]
if usi in usi_uvid:
usi_uvid[usi].append(uvid)
else:
usi_uvid[usi] = [uvid]
for uvedgeid in range(len(uvedgeid_uvid)):
usi = uvid_usi[uvedgeid_uvid[uvedgeid][0]]
if usi in usi_uvedgeidOnBord:
usi_uvedgeidOnBord[usi].append(uvedgeid)
else:
usi_uvedgeidOnBord[usi] = [uvedgeid]
for usi in usi_uvedgeidOnBord:
edgeids = usi_uvedgeidOnBord[usi]
uvsOnBord = []
for edgeid in edgeids:
uvsOnBord = uvsOnBord + uvedgeid_uvid[edgeid]
usi_uvidOnBord[usi] = list(set(uvsOnBord))
for usi in usi_uvidOnBord:
umin = 1
umax = 0
vmin = 1
vmax = 0
for uvid in usi_uvidOnBord[usi]:
u = uvid_uv[uvid][0]
v = uvid_uv[uvid][1]
if u < umin:
umin = u
if u > umax:
umax = u
if v < vmin:
vmin = v
if v > vmax:
vmax = v
usi_bb[usi] = [[umin,umax],[vmin,vmax]]
usi_bbarea = {}
for i in range(len(usi_uvid)): #get {usi:area,} from usi_bb
usi_bbarea[i] = abs(usi_bb[i][0][1]-usi_bb[i][0][0])*abs(usi_bb[i][1][1]-usi_bb[i][1][0])
bbarea_usi = sorted(zip(usi_bbarea.values(), usi_bbarea.keys())) # get [(minarea, usi0),...,( maxarea, usi99)]
bbarea_usi.reverse()
uvedgeid_uv = []
for uvedgeid in range(len(uvedgeid_uvid)):
uvidA = uvedgeid_uvid[uvedgeid][0]
uvidB = uvedgeid_uvid[uvedgeid][1]
uA = uvid_uv[uvidA][0]
vA = uvid_uv[uvidA][1]
uB = uvid_uv[uvidB][0]
vB = uvid_uv[uvidB][1]
if vB >= vA:
uvedgeid_uv.append([[uA,vA],[uB,vB]])
else:
uvedgeid_uv.append([[uB,vB],[uA,vA]])
return usi_uvid, uvid_uv, uvedgeid_uvid, usi_uvidOnBord, usi_uvedgeidOnBord, usi_bb, bbarea_usi, uvedgeid_uv
def getFacesHaveNoUV(sel):
selList = om2.MSelectionList()
selList.add(sel)
selPath = selList.getDagPath(0)
selVtxIter= om2.MItMeshVertex(selPath)
faceidWithNoUV = []
faceWithNoUV = []
while not selVtxIter.isDone():
if selVtxIter.numUVs()==0:
faceidWithNoUV += selVtxIter.getConnectedFaces()
selVtxIter.next()
faceidWithNoUV = list(set(faceidWithNoUV))
for faceid in faceidWithNoUV:
faceWithNoUV+=[sel+'.f['+str(faceid)+']']
return faceWithNoUV
def LD_moveOverlapUVOut():
TOLERANCE = 4
p = 10**TOLERANCE
selForSkip = cmds.ls(sl=1)
sel = cmds.ls(sl=1,o=1)
if selForSkip != sel:
selUVidForSkip = cmds.polyListComponentConversion(selForSkip,tuv=1)
selUVidForSkip = cmds.ls(selUVidForSkip,fl=1)
else:
selUVidForSkip = []
sel = sel[0]
faceWithNoUV = getFacesHaveNoUV(sel)
if faceWithNoUV !=[]:
cmds.select(faceWithNoUV,r=1)
cmds.warning("Some Faces have no UVs!")
return
uvDic = getUVEdgeDic(sel) #uvDic[6]
usi_uvid = uvDic[0]
uvid_uv = uvDic[1]
uvedgeid_uvid = uvDic[2]
usi_uvidOnBord = uvDic[3]
usi_uvedgeidOnBord = uvDic[4]
usi_bb = uvDic[5]
bbarea_usi = uvDic[6]
uvedgeid_uv = uvDic[7]
uvNotPass = set() # len(uvNotPass) Filter out stacking uvs
skipList = set()
skipListTemp = set()
intersectList = {}
usi_uvidOnBord_final = {}
usi_uvedgeidOnBord_final = {}
# prepare
for tupleA in range(len(bbarea_usi)):
usiA = bbarea_usi[tupleA][1]
skipListTemp.add(usiA)
# fast detect
bb_uminA = usi_bb[usiA][0][0]
bb_umaxA = usi_bb[usiA][0][1]
bb_vminA = usi_bb[usiA][1][0]
bb_vmaxA = usi_bb[usiA][1][1]
for tupleB in range(len(bbarea_usi)):
usiB = bbarea_usi[tupleB][1]
#faset detect
bb_uminB = usi_bb[usiB][0][0]
bb_umaxB = usi_bb[usiB][0][1]
bb_vminB = usi_bb[usiB][1][0]
bb_vmaxB = usi_bb[usiB][1][1]
if bb_uminA > bb_umaxB or\
bb_umaxA < bb_uminB or\
bb_vminA > bb_vmaxB or\
bb_vmaxA < bb_vminB :
continue
if usiB in skipListTemp:
continue
if ifUVShellStack(usiA,usiB,usi_bb, p):
skipList.add(usiB)
skipListTemp.add(usiB)
elif ifUVShellIntersect(usiA,usiB,usi_uvedgeidOnBord, uvedgeid_uv, usi_bb):
skipListTemp.add(usiB)
skipList.add(usiB)
elif ifUVShellContain(usiA,usiB,usi_uvedgeidOnBord,usi_uvidOnBord,uvedgeid_uv,uvid_uv):
skipList.add(usiB)
skipListTemp.add(usiB)
uvidsToMove = []
uvNamesToMove = set()
# calculate final list
for usi in skipList:
uvidsToMove += usi_uvid[usi]
for uvid in uvidsToMove:
uvNamesToMove.add(sel+'.map['+str(uvid)+']')
for index in range(len(selUVidForSkip)):
selUVidForSkip[index] = selUVidForSkip[index].split('.')[1]
selToSkip = []
for uvName in uvNamesToMove:
uvName = uvName.split('.')[1]
if uvName in selUVidForSkip:
selToSkip.append(sel+'.'+uvName)
for i in selToSkip:
uvNamesToMove.remove(i)
uvNamesToMove = list(uvNamesToMove)
cmds.polyEditUV(uvNamesToMove,u=1)
def ifUVShellStack(usiA, usiB, usi_bb, p):
# fast filter
usiA_umin = float(int(usi_bb[usiA][0][0] * p))/p
usiB_umin = float(int(usi_bb[usiB][0][0] * p))/p
if not usiA_umin == usiB_umin:
return 0
usiA_umax = float(int(usi_bb[usiA][0][1] * p))/p
usiA_vmin = float(int(usi_bb[usiA][1][0] * p))/p
usiA_vmax = float(int(usi_bb[usiA][1][1] * p))/p
usiB_umax = float(int(usi_bb[usiB][0][1] * p))/p
usiB_vmin = float(int(usi_bb[usiB][1][0] * p))/p
usiB_vmax = float(int(usi_bb[usiB][1][1] * p))/p
if usiA_umax == usiB_umax and usiA_vmin == usiB_vmin and usiA_vmax == usiB_vmax:
return 1
return 0
def ifUVShellIntersect(usiA, usiB, usi_uvedgeidOnBord, uvedgeid_uv, usi_bb):
for edgeA in usi_uvedgeidOnBord[usiA]:
ax = uvedgeid_uv[edgeA][0][0]
ay = uvedgeid_uv[edgeA][0][1]
bx = uvedgeid_uv[edgeA][1][0]
by = uvedgeid_uv[edgeA][1][1]
# fast filter
abx = [ax,bx]
aby = [ay,by]
if bx<ax:
abx = [bx,ax]
if by<ay:
aby = [by,ay]
# bound filter
bb_usiB = usi_bb[usiB]
bb_uminB = bb_usiB[0][0]
bb_umaxB = bb_usiB[0][1]
bb_vminB = bb_usiB[1][0]
bb_vmaxB = bb_usiB[1][1]
if abx[0] > bb_umaxB or\
abx[1] < bb_uminB or\
aby[0] > bb_vmaxB or\
aby[1] < bb_vminB:
continue
for edgeB in usi_uvedgeidOnBord[usiB]:
cx = uvedgeid_uv[edgeB][0][0]
cy = uvedgeid_uv[edgeB][0][1]
dx = uvedgeid_uv[edgeB][1][0]
dy = uvedgeid_uv[edgeB][1][1]
# fast filter
cdx = [cx,dx]
cdy = [cy,dy]
if dx<cx:
cdx = [dx,cx]
if dy<cy:
cdy = [dy,cy]
if abx[0] > cdx[1] or\
abx[1] < cdx[0] or\
aby[0] > cdy[1] or\
aby[1] < cdy[0]:
continue
x1 = bx - ax
y1 = by - ay
x2 = cx - ax
y2 = cy - ay
cross1 = x1*y2-x2*y1
x2 = dx - ax
y2 = dy - ay
cross2 = x1*y2-x2*y1
x1 = dx - cx
y1 = dy - cy
x2 = ax - cx
y2 = ay - cy
cross3 = x1*y2-x2*y1
x2 = bx - cx
y2 = by - cy
cross4 = x1*y2-x2*y1
if (cross1*cross2 <= 0 and cross3*cross4<=0):
return 1
return 0
def ifUVShellContain(usiA,usiB,usi_uvedgeidOnBord,usi_uvidOnBord,uvedgeid_uv,uvid_uv):
uvid = usi_uvidOnBord[usiB][0]
intersects = 0
ray_u = uvid_uv[uvid][0]
ray_v = uvid_uv[uvid][1]
for edge in usi_uvedgeidOnBord[usiA]:
u0 = uvedgeid_uv[edge][0][0]
v0 = uvedgeid_uv[edge][0][1]
u1 = uvedgeid_uv[edge][1][0]
v1 = uvedgeid_uv[edge][1][1]
if (v1 >= ray_v and v0 < ray_v):
if ((u0-ray_u)*(v1-ray_v)-(v0-ray_v)*(u1-ray_u)) < 0:
intersects += 1
if intersects%2 == 1:
return 1
return 0
# checkUVBleed_0()
# cProfile.run('checkUVBleed_0()')