mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 05:14:40 +01:00
another shot at UV overlapping, wip
This commit is contained in:
parent
685069a9ab
commit
698b0da170
1 changed files with 228 additions and 83 deletions
|
|
@ -3,6 +3,10 @@ from maya import cmds
|
|||
import pyblish.api
|
||||
import pype.api
|
||||
import pype.maya.action
|
||||
import math
|
||||
import maya.api.OpenMaya as om
|
||||
from pymel.core import *
|
||||
from pymel.core.datatypes import *
|
||||
|
||||
|
||||
class ValidateMeshHasOverlappingUVs(pyblish.api.InstancePlugin):
|
||||
|
|
@ -20,94 +24,235 @@ class ValidateMeshHasOverlappingUVs(pyblish.api.InstancePlugin):
|
|||
actions = [pype.maya.action.SelectInvalidAction]
|
||||
optional = True
|
||||
|
||||
def _createBoundingCircle(self, meshfn):
|
||||
""" Parameter: meshfn - MFnMesh
|
||||
Represent a face by a center and radius, i.eself.
|
||||
center = [center1u, center1v, center2u, center2v, ... ]
|
||||
radius = [radius1, radius2, ... ]
|
||||
return (center, radius)
|
||||
"""
|
||||
center = []
|
||||
radius = []
|
||||
for i in xrange(meshfn.numPolygons): # noqa: F405
|
||||
# get uvs from face
|
||||
uarray = []
|
||||
varray = []
|
||||
for j in range(len(meshfn.getPolygonVertices(i))):
|
||||
uv = meshfn.getPolygonUV(i, j)
|
||||
uarray.append(uv[0])
|
||||
varray.append(uv[1])
|
||||
|
||||
# loop through all vertices to construct edges/rays
|
||||
cu = 0.0
|
||||
cv = 0.0
|
||||
for j in range(len(uarray)):
|
||||
cu += uarray[j]
|
||||
cv += varray[j]
|
||||
|
||||
cu /= len(uarray)
|
||||
cv /= len(varray)
|
||||
rsqr = 0.0
|
||||
for j in range(len(varray)):
|
||||
du = uarray[j] - cu
|
||||
dv = varray[j] - cv
|
||||
dsqr = du * du + dv * dv
|
||||
rsqr = dsqr if dsqr > rsqr else rsqr
|
||||
|
||||
center.append(cu)
|
||||
center.append(cv)
|
||||
radius.append(math.sqrt(rsqr))
|
||||
|
||||
return center, radius
|
||||
|
||||
def _createRayGivenFace(self, meshfn, faceId):
|
||||
""" Represent a face by a series of edges(rays), i.e.
|
||||
orig = [orig1u, orig1v, orig2u, orig2v, ... ]
|
||||
vec = [vec1u, vec1v, vec2u, vec2v, ... ]
|
||||
return false if no valid uv's.
|
||||
return (true, orig, vec) or (false, None, None)
|
||||
"""
|
||||
orig = []
|
||||
vec = []
|
||||
# get uvs
|
||||
uarray = []
|
||||
varray = []
|
||||
for i in range(len(meshfn.getPolygonVertices(faceId))):
|
||||
uv = meshfn.getPolygonUV(faceId, i)
|
||||
uarray.append(uv[0])
|
||||
varray.append(uv[1])
|
||||
|
||||
if len(uarray) == 0 or len(varray) == 0:
|
||||
return (False, None, None)
|
||||
|
||||
# loop throught all vertices to construct edges/rays
|
||||
u = uarray[-1]
|
||||
v = varray[-1]
|
||||
for i in xrange(len(uarray)): # noqa: F405
|
||||
orig.append(uarray[i])
|
||||
orig.append(varray[i])
|
||||
vec.append(u - uarray[i])
|
||||
vec.append(v - varray[i])
|
||||
u = uarray[i]
|
||||
v = varray[i]
|
||||
|
||||
return (True, orig, vec)
|
||||
|
||||
def _area(self, orig):
|
||||
sum = 0.0
|
||||
num = len(orig)/2
|
||||
for i in xrange(num): # noqa: F405
|
||||
idx = 2 * i
|
||||
idy = (i + 1) % num
|
||||
idy = 2 * idy + 1
|
||||
idy2 = (i + num - 1) % num
|
||||
idy2 = 2 * idy2 + 1
|
||||
sum += orig[idx] * (orig[idy] - orig[idy2])
|
||||
|
||||
return math.fabs(sum) * 0.5
|
||||
|
||||
def _checkCrossingEdges(self,
|
||||
face1Orig,
|
||||
face1Vec,
|
||||
face2Orig,
|
||||
face2Vec):
|
||||
""" Check if there are crossing edges between two faces.
|
||||
Return true if there are crossing edges and false otherwise.
|
||||
A face is represented by a series of edges(rays), i.e.
|
||||
faceOrig[] = [orig1u, orig1v, orig2u, orig2v, ... ]
|
||||
faceVec[] = [vec1u, vec1v, vec2u, vec2v, ... ]
|
||||
"""
|
||||
face1Size = len(face1Orig)
|
||||
face2Size = len(face2Orig)
|
||||
for i in xrange(0, face1Size, 2):
|
||||
o1x = face1Orig[i]
|
||||
o1y = face1Orig[i+1]
|
||||
v1x = face1Vec[i]
|
||||
v1y = face1Vec[i+1]
|
||||
n1x = v1y
|
||||
n1y = -v1x
|
||||
for j in xrange(0, face2Size, 2):
|
||||
# Given ray1(O1, V1) and ray2(O2, V2)
|
||||
# Normal of ray1 is (V1.y, V1.x)
|
||||
o2x = face2Orig[j]
|
||||
o2y = face2Orig[j+1]
|
||||
v2x = face2Vec[j]
|
||||
v2y = face2Vec[j+1]
|
||||
n2x = v2y
|
||||
n2y = -v2x
|
||||
|
||||
# Find t for ray2
|
||||
# t = [(o1x-o2x)n1x + (o1y-o2y)n1y] /
|
||||
# (v2x * n1x + v2y * n1y)
|
||||
denum = v2x * n1x + v2y * n1y
|
||||
# Edges are parallel if denum is close to 0.
|
||||
if math.fabs(denum) < 0.000001:
|
||||
continue
|
||||
t2 = ((o1x-o2x) * n1x + (o1y-o2y) * n1y) / denum
|
||||
if (t2 < 0.00001 or t2 > 0.99999):
|
||||
continue
|
||||
|
||||
# Find t for ray1
|
||||
# t = [(o2x-o1x)n2x
|
||||
# + (o2y-o1y)n2y] / (v1x * n2x + v1y * n2y)
|
||||
denum = v1x * n2x + v1y * n2y
|
||||
# Edges are parallel if denum is close to 0.
|
||||
if math.fabs(denum) < 0.000001:
|
||||
continue
|
||||
t1 = ((o2x-o1x) * n2x + (o2y-o1y) * n2y) / denum
|
||||
|
||||
# Edges intersect
|
||||
if (t1 > 0.00001 and t1 < 0.99999):
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
def _getOverlapUVFaces(self, meshName):
|
||||
""" Return overlapping faces """
|
||||
faces = []
|
||||
# find polygon mesh node
|
||||
selList = om.MSelectionList()
|
||||
selList.add(meshName)
|
||||
mesh = selList.getDependNode(0)
|
||||
if mesh.apiType() == om.MFn.kTransform:
|
||||
dagPath = selList.getDagPath(0)
|
||||
dagFn = om.MFnDagNode(dagPath)
|
||||
child = dagFn.child(0)
|
||||
if child.apiType() != om.MFn.kMesh:
|
||||
raise Exception("Can't find polygon mesh")
|
||||
mesh = child
|
||||
meshfn = om.MFnMesh(mesh)
|
||||
|
||||
center, radius = self._createBoundingCircle(meshfn)
|
||||
for i in xrange(meshfn.numPolygons): # noqa: F405
|
||||
rayb1, face1Orig, face1Vec = self._createRayGivenFace(
|
||||
meshfn, i)
|
||||
if not rayb1:
|
||||
continue
|
||||
cui = center[2*i]
|
||||
cvi = center[2*i+1]
|
||||
ri = radius[i]
|
||||
# Exclude the degenerate face
|
||||
# if(area(face1Orig) < 0.000001) continue;
|
||||
# Loop through face j where j != i
|
||||
for j in range(i+1, meshfn.numPolygons):
|
||||
cuj = center[2*j]
|
||||
cvj = center[2*j+1]
|
||||
rj = radius[j]
|
||||
du = cuj - cui
|
||||
dv = cvj - cvi
|
||||
dsqr = du * du + dv * dv
|
||||
# Quick rejection if bounding circles don't overlap
|
||||
if (dsqr >= (ri + rj) * (ri + rj)):
|
||||
continue
|
||||
|
||||
rayb2, face2Orig, face2Vec = self._createRayGivenFace(
|
||||
meshfn, j)
|
||||
if not rayb2:
|
||||
continue
|
||||
# Exclude the degenerate face
|
||||
# if(area(face2Orig) < 0.000001): continue;
|
||||
if self._checkCrossingEdges(face1Orig,
|
||||
face1Vec,
|
||||
face2Orig,
|
||||
face2Vec):
|
||||
face1 = '%s.f[%d]' % (meshfn.name(), i)
|
||||
face2 = '%s.f[%d]' % (meshfn.name(), j)
|
||||
if face1 not in faces:
|
||||
faces.append(face1)
|
||||
if face2 not in faces:
|
||||
faces.append(face2)
|
||||
return faces
|
||||
|
||||
@classmethod
|
||||
def _has_overlapping_uvs(cls, node):
|
||||
|
||||
allUvSets = cmds.polyUVSet(q=1, auv=1)
|
||||
# print allUvSets
|
||||
currentTool = cmds.currentCtx()
|
||||
cmds.setToolTo('selectSuperContext')
|
||||
biglist = cmds.ls(
|
||||
cmds.polyListComponentConversion(node, tf=True), fl=True)
|
||||
shells = []
|
||||
overlappers = []
|
||||
bounds = []
|
||||
for uvset in allUvSets:
|
||||
# print uvset
|
||||
while len(biglist) > 0:
|
||||
cmds.select(biglist[0], r=True)
|
||||
# cmds.polySelectConstraint(t=0)
|
||||
# cmds.polySelectConstraint(sh=1,m=2)
|
||||
# cmds.polySelectConstraint(sh=0,m=0)
|
||||
aShell = cmds.ls(sl=True, fl=True)
|
||||
shells.append(aShell)
|
||||
biglist = list(set(biglist) - set(aShell))
|
||||
cmds.setToolTo(currentTool)
|
||||
cmds.select(clear=True)
|
||||
# shells = [ [faces in uv shell 1], [faces in shell 2], [etc] ]
|
||||
overlapFaces = []
|
||||
flipped = []
|
||||
oStr = ''
|
||||
for s in ls(sl=1, fl=1):
|
||||
curUV = polyUVSet(s, q=1, cuv=1)
|
||||
for i, uv in enumerate(polyUVSet(s, q=1, auv=1)):
|
||||
polyUVSet(s, cuv=1, uvSet=uv)
|
||||
of = getOverlapUVFaces(str(s))
|
||||
if of != []:
|
||||
oStr += s + " has " + str(len(of)) + " overlapped faces in uvset " + uv + '\n'
|
||||
overlapFaces.extend(of)
|
||||
|
||||
for faces in shells:
|
||||
shellSets = cmds.polyListComponentConversion(
|
||||
faces, ff=True, tuv=True)
|
||||
if shellSets != []:
|
||||
uv = cmds.polyEditUV(shellSets, q=True)
|
||||
"""
|
||||
# inverted
|
||||
flf = []
|
||||
for f in ls( PyNode( s ).getShape().f, fl=1 ):
|
||||
uvPos = polyEditUV( [ polyListComponentConversion( vf, fvf=1, toUV=1 )[0] for vf in ls( polyListComponentConversion( f, tvf=1 ), fl=1 ) ], q=1 )
|
||||
uvAB = Vector( [ uvPos[2] - uvPos[0], uvPos[3] - uvPos[1] ] )
|
||||
uvBC = Vector( [ uvPos[4] - uvPos[2], uvPos[5] - uvPos[3] ] )
|
||||
if uvAB.cross( uvBC ) * Vector([0, 0, 1]) <= 0: flf.append( f )
|
||||
if flf != []:
|
||||
oStr += s + " has " + str( len( flf ) ) + " inverted faces in uvset " + uv + '\n'
|
||||
flipped.extend( flf )
|
||||
|
||||
uMin = uv[0]
|
||||
uMax = uv[0]
|
||||
vMin = uv[1]
|
||||
vMax = uv[1]
|
||||
for i in range(len(uv)/2):
|
||||
if uv[i*2] < uMin:
|
||||
uMin = uv[i*2]
|
||||
if uv[i*2] > uMax:
|
||||
uMax = uv[i*2]
|
||||
if uv[i*2+1] < vMin:
|
||||
vMin = uv[i*2+1]
|
||||
if uv[i*2+1] > vMax:
|
||||
vMax = uv[i*2+1]
|
||||
bounds.append([[uMin, uMax], [vMin, vMax]])
|
||||
else:
|
||||
return False
|
||||
|
||||
for a in range(len(shells)):
|
||||
for b in range(a):
|
||||
# print "b",b
|
||||
if bounds != []:
|
||||
# print bounds
|
||||
aL = bounds[a][0][0]
|
||||
aR = bounds[a][0][1]
|
||||
aT = bounds[a][1][1]
|
||||
aB = bounds[a][1][0]
|
||||
|
||||
bL = bounds[b][0][0]
|
||||
bR = bounds[b][0][1]
|
||||
bT = bounds[b][1][1]
|
||||
bB = bounds[b][1][0]
|
||||
|
||||
overlaps = True
|
||||
if aT < bB: # A entirely below B
|
||||
overlaps = False
|
||||
|
||||
if aB > bT: # A entirely above B
|
||||
overlaps = False
|
||||
|
||||
if aR < bL: # A entirely right of B
|
||||
overlaps = False
|
||||
|
||||
if aL > bR: # A entirely left of B
|
||||
overlaps = False
|
||||
|
||||
if overlaps:
|
||||
overlappers.extend(shells[a])
|
||||
overlappers.extend(shells[b])
|
||||
else:
|
||||
return False
|
||||
pass
|
||||
|
||||
if overlappers:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
polyUVSet( s, cuv=1, uvSet=str( curUV ) )
|
||||
oStr += '\n'
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue