Created
August 29, 2015 11:18
-
-
Save SEVEZ/642535b8baeaedb02a56 to your computer and use it in GitHub Desktop.
Maya Python script for selecting overlapped and flipped uv polygons
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import math | |
import maya.api.OpenMaya as om | |
from pymel.core import * | |
from pymel.core.datatypes import * | |
def createBoundingCircle(meshfn): | |
"""Parameter: meshfn - MFnMesh | |
Represent a face by a center and radius, i.e. | |
center = [center1u, center1v, center2u, center2v, ... ] | |
radius = [radius1, radius2, ... ] | |
return (center, radius)""" | |
center = [] | |
radius = [] | |
for i in xrange(meshfn.numPolygons): | |
# 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(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)): | |
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(orig): | |
sum = 0.0 | |
num = len(orig)/2 | |
for i in xrange(num): | |
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(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(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 = createBoundingCircle(meshfn) | |
for i in xrange(meshfn.numPolygons): | |
rayb1, face1Orig, face1Vec = 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 = createRayGivenFace(meshfn, j) | |
if not rayb2: continue | |
# Exclude the degenerate face | |
# if(area(face2Orig) < 0.000001): continue; | |
if 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 | |
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 ) | |
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 ) | |
polyUVSet( s, cuv=1, uvSet=str( curUV ) ) | |
oStr += '\n' | |
if ( flipped ==[] and overlapFaces == [] ): | |
oStr = "No problems found!" | |
confirmDialog( button = "Ok", m = oStr, t = "UV check stats" ) | |
else: | |
res = confirmDialog( button = ['Ok','Flipped','Overlaps'], db='Ok', m = oStr, t = "UV check stats" ) | |
if res == 'Flipped': select( flipped, r=1 ) | |
if res == 'Overlaps': select( overlapFaces, r=1 ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment