Skip to content

Instantly share code, notes, and snippets.

@hdlx
Last active September 21, 2023 08:19
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save hdlx/67a97305ffbe284e5f104d8b4f9eb0f2 to your computer and use it in GitHub Desktop.
Save hdlx/67a97305ffbe284e5f104d8b4f9eb0f2 to your computer and use it in GitHub Desktop.
Maya get closest vertex
import maya.api.OpenMaya as om
import maya.cmds as cmds
#returns the closest vertex given a mesh and a position [x,y,z] in world space.
#Uses om.MfnMesh.getClosestPoint() returned face ID and iterates through face's vertices.
def getClosestVertex(mayaMesh,pos=[0,0,0]):
mVector = om.MVector(pos)#using MVector type to represent position
selectionList = om.MSelectionList()
selectionList.add(mayaMesh)
dPath= selectionList.getDagPath(0)
mMesh=om.MFnMesh(dPath)
ID = mMesh.getClosestPoint(om.MPoint(mVector),space=om.MSpace.kWorld)[1] #getting closest face ID
list=cmds.ls( cmds.polyListComponentConversion (mayaMesh+'.f['+str(ID)+']',ff=True,tv=True),flatten=True)#face's vertices list
#setting vertex [0] as the closest one
d=mVector-om.MVector(cmds.xform(list[0],t=True,ws=True,q=True))
smallestDist2=d.x*d.x+d.y*d.y+d.z*d.z #using distance squared to compare distance
closest=list[0]
#iterating from vertex [1]
for i in range(1,len(list)) :
d=mVector-om.MVector(cmds.xform(list[i],t=True,ws=True,q=True))
d2=d.x*d.x+d.y*d.y+d.z*d.z
if d2<smallestDist2:
smallestDist2=d2
closest=list[i]
return closest
@Lirinis
Copy link

Lirinis commented Oct 27, 2018

What if several closest faces are at the same distance? What if several vertices of the face are at the same distance?
It seems to implicitly choose the one with the lowest id in both cases while I would expect to get a list.

@hdlx
Copy link
Author

hdlx commented Nov 14, 2018

You're right. According to the documentation, it seems that MFnMesh.getClosestPoint() can't return a list of point plus face ID tuple. This is one limitation using this technique.

@BigRoy
Copy link

BigRoy commented Feb 5, 2021

Thanks - saved me some time to quickly test a thing.

Here's a quick cleanup/rewrite as thanks!

from maya import cmds
import maya.api.OpenMaya as om
import operator


def getClosestVertex(mesh, pos=(0,0,0)):
    """Return closest vertex and distance from mesh to world-space position [x, y, z].
        
    Uses om.MfnMesh.getClosestPoint() returned face ID and iterates through face's vertices.
    
    Example:
        >>> getClosestVertex("pCube1", pos=[0.5, 0.5, 0.5])
        # (3, 0.0)
        >>> getClosestVertex("pCube1", pos=[0.5, 0.9, 0.5])
        # (3, 0.4)

    Args:
        mesh (str): Mesh node name.
        pos (list): Position vector XYZ
        
    Returns:
        tuple: (vertex index, distance)
    
    """
    pos = om.MPoint(pos)
    sel = om.MSelectionList()
    sel.add(mesh)
    fn_mesh = om.MFnMesh(sel.getDagPath(0))
    
    index = fn_mesh.getClosestPoint(pos, space=om.MSpace.kWorld)[1]  # closest polygon index    
    face_vertices = fn_mesh.getPolygonVertices(index)  # get polygon vertices
    
    vertex_distances = ((vertex, fn_mesh.getPoint(vertex, om.MSpace.kWorld).distanceTo(pos)) 
                         for vertex in face_vertices)
    return min(vertex_distances, key=operator.itemgetter(1))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment