Antonio Antonio - 1 month ago 26
Python Question

Overlapping vertices in maya

I want to find all vertices that have distance smaller than

0.0003
and return them as a list. I use the following algorithm but is quite slow for a big scene. Do you have any tips on improving the speed?

listOfAllMesh = cmds.ls(geometry=True,type="mesh")
overlapping = []
for meshToCek in listOfAllMesh:
listOFVertex=[]
cmds.select(meshToCek)
mel.eval("ConvertSelectionToVertices")
AllVertexes = cmds.ls(selection=True, flatten=True)
listOFVertex.append(AllVertexes[0])
Flag=False
for VertexToCek in AllVertexes[1:]:
c1=cmds.xform(VertexToCek, q=True, os=True, a=True, t=True)
for cek in listOFVertex:
c2=cmds.xform(cek, q=True, os=True, a=True, t=True)
distance = math.sqrt(math.pow(c2[0] - c1[0], 2) + math.pow(c2[1] - c1[1], 2) + math.pow(c2[2] - c1[2], 2))
if distance<0.0003:
overlapping.append(VertexToCek)
overlapping.append(cek)
Flag=True
if not Flag:
listOFVertex.append(VertexToCek)
Flag=False
return overlapping

Answer

I hope I understand it correctly that you're trying to test an object's vertices against itself!

A few things I can think of that may be slowing down your code:

xform will likely be a slower way to get a point's position.

distance = math.sqrt(math.pow(c2[0] - c1[0], 2) + math.pow(c2[1] - c1[1], 2) + math.pow(c2[2] - c1[2], 2)) This may be another culprit. Usually when calculating distances, it's the square root that will slow it down. One way to get around it would be to calculate the squared distance instead, so you avoid having to use math.sqrt at all.

cmds.select(meshToCek)
mel.eval("ConvertSelectionToVertices")

This probably doesn't slow it down much but to get the vertices in memory may be better.

I tried doing a mostly strictly maya api approach, and the performance seems better. Maybe there's a better way to optimize, but we got some progress here!

import maya.cmds as cmds
import maya.OpenMaya as OpenMaya


def mfn_mesh_generator():
    selection_list = OpenMaya.MSelectionList()
    for mesh in cmds.ls(l=True, geometry=True,type="mesh"):
        selection_list.add(mesh)

    for i in range(selection_list.length()):    
        dag_path = OpenMaya.MDagPath()
        selection_list.getDagPath(i, dag_path)

        mfn_mesh = OpenMaya.MFnMesh(dag_path)
        yield mfn_mesh


def get_overlapping_vertices(mfn_mesh, threshold=0.0003):
    points_list = OpenMaya.MPointArray()
    mfn_mesh.getPoints(points_list, OpenMaya.MSpace.kWorld)

    overlapping = []

    for i in range(points_list.length()):
        for j in range(points_list.length()):
            if i == j:
                continue

            dist = points_list[i].distanceTo(points_list[j])
            if dist < threshold:
                if i not in overlapping:
                    overlapping.append(i)

                if j not in overlapping:
                    overlapping.append(j)

    return overlapping


for mfn_mesh in mfn_mesh_generator():
    dag_path = OpenMaya.MDagPath()
    mfn_mesh.getPath(dag_path)
    print dag_path.fullPathName()
    get_overlapping_vertices(mfn_mesh)

mfn_mesh_generator is a python generator that you can loop through all MFnMesh objects in the scene. Feel free to change this if you want to collect your meshes in another way (I only did it this way to separate things out and to make it more generic). Luckily the api's MPoint object has a method, distanceTo, to calculate the distance of another MPoint! Also MFnMesh has a method to get all vertices in one swoop with getPoints. This optimizes it a bit than getting them one by one.

With a scene of 5 poly spheres, it came to about 0.667850017548 seconds. The same scene with your method comes out to about 12.1129710674 seconds. A pretty decent boost in speed!

Hope that helps out and gives you some ideas.