Last active
August 12, 2024 01:47
-
-
Save Liametc/5231abe1df3e5e541353fe84a6055064 to your computer and use it in GitHub Desktop.
Check polygon normals in maya using python api 2.0
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 maya.api.OpenMaya as om | |
import maya.cmds | |
import time | |
def is_normal_reversed(poly, mesh): | |
""" | |
Check the normal faces in or out of the model by doing a simple ray cast and | |
count results. Evens face out, odds face in. | |
This is costly, so we're only doing it for the first poly. Everything else is | |
compared to this. | |
:param MItMeshPolygon poly: The current poly face. | |
:param MFnMesh mesh: The current mesh object. | |
:returns: :class:`bool` True = normal reversed | |
""" | |
space = om.MSpace.kWorld | |
center = om.MFloatPoint(poly.center(space=space)) | |
normal = om.MFloatVector(poly.getNormal(space=space)) | |
point = center + (normal*0.001) # has to be just off the surface to not get current poly | |
hit_count = 0 | |
hit_nothing = False | |
while not hit_nothing: | |
point, _, face_id, _, _, _ = mesh.closestIntersection(point, normal, space, 10000, False) | |
if face_id == -1: | |
hit_nothing = True | |
break | |
point = point + (normal*0.001) | |
hit_count += 1 | |
return bool(hit_count & 1) | |
def check_polygon_normals(objects, select_faces=False, select_objs=False): | |
""" | |
Check the normals of a polygon. | |
Uses technique defined in http://www.dillonbhuff.com/?p=30 | |
where we check the winding of the vertices against it's neighbour. | |
If any group of two vertices match the order of another group of two, | |
the winding is opposite and he normals face in different directions. | |
We do a better check on the first normal to make sure it's correct. | |
:param list objects: List of object names to check. | |
:param bool select_faces: Select faces with incorret normals. | |
:param bool select_objs: Select objects with incorrect normals | |
""" | |
start = time.time() | |
mSel = om.MSelectionList() | |
map(mSel.add, objects) | |
selection = om.MItSelectionList(mSel) | |
incorrect_polys = om.MSelectionList() | |
while not selection.isDone(): | |
dag = selection.getDagPath() | |
mesh = om.MFnMesh(dag) | |
poly = om.MItMeshPolygon(dag) | |
visited = set([0]) | |
incorrect = set([]) | |
if is_normal_reversed(poly, mesh): | |
incorrect.add(poly.index()) | |
while not poly.isDone(): | |
current = poly.index() | |
vertices = mesh.getPolygonVertices(current) | |
connected_faces = poly.getConnectedFaces() | |
main_count = len(vertices) | |
for face in connected_faces: | |
if face in visited: | |
continue | |
visited.add(face) | |
face_verts = mesh.getPolygonVertices(face) | |
vert_count = len(face_verts) | |
is_different = False | |
matched = False | |
for indexA in range(main_count): | |
indexB = (indexA + 1) % main_count | |
for vert_indexA in range(vert_count): | |
vert_indexB = (vert_indexA + 1) % vert_count | |
matching_verts = all(( | |
vertices[indexA] == face_verts[vert_indexA], | |
vertices[indexB] == face_verts[vert_indexB] | |
)) | |
if matching_verts: | |
is_different = True | |
break | |
# face is incorrect if winding is different compared to correct face | |
# or is the same and an incorrect face | |
if is_different: | |
if current not in incorrect: | |
incorrect.add(face) | |
elif current in incorrect: | |
incorrect.add(face) | |
poly.next(0) # docs says this doesn't take an input, running says otherwise. Input does nothing | |
if incorrect: | |
if select_objs: | |
incorrect_polys.add(dag) | |
if select_faces: | |
for face in incorrect: | |
incorrect_polys.add("{}.f[{}]".format(dag, face)) | |
print("found incorrect polys on {}: {!r}".format(dag, sorted(incorrect))) | |
selection.next() | |
duration = time.time() - start | |
print('ran in: {:.0f}m {:0>2.0f}s'.format(duration // 60, duration % 60)) | |
if select_faces or select_objs: | |
om.MGlobal.setActiveSelectionList(incorrect_polys) | |
# how to run | |
#check_polygon_normals(maya.cmds.ls(geometry=True), select_faces=True, select_objs=False) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment