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
@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