Tyler Thornock
Technical Animator
Home Tutorials Tools Rigs About/Resume
Maya – Camera Pivot Under Cursor

One common issue in 3D applications is difficulty having the camera pivot around a specific center of interest. For example, most apps have an option to pivot around the center of the selection, but the selection is not specific enough for larger objects and you end up in some goofy state where your pivot is waaay off, is way to sensitive to movement, or just selecting the vertices to pivot around is too cumbersome and requires you to leave the active tool.

Z-Brush handled this by allowing you to pivot around the surface point under your cursor. The following code will allow you to have your Maya camera pivot around the mesh point under your cursor while remaining in your current tool, I have it assigned to a hotkey. Every 3D app should have a similar implementation, Unreal has notably had terrible camera movement for this type of thing.

from PySide2 import QtGui, QtWidgets
from shiboken2 import wrapInstance
from maya.api import OpenMaya, OpenMayaUI
from maya import OpenMayaUI as OpenMayaUI1

# get the active editor and cursor position
editor = cmds.playblast(activeEditor=True)
camera = cmds.modelEditor(editor, query=True, camera=True)
position = QtGui.QCursor.pos()
editor_widget = wrapInstance(int(OpenMayaUI1.MQtUtil.findControl(editor)), QtWidgets.QWidget)
rel_position = editor_widget.mapFromGlobal(position)

# find what is under the cursor, objects on a templated or referenced layer are ignored
# NOTE: you can temporarily turn off certain types via cmds.modelEditor if you do not want them considered
obj = cmds.hitTest(editor, rel_position.x(), rel_position.y())
if not obj:
    raise Exception('Nothing found under the cursor.')

# see if we have a mesh
sel = OpenMaya.MSelectionList()
sel.add(obj[0])
shape_dag = sel.getDagPath(0)
if not shape_dag.apiType() == OpenMaya.MFn.kMesh:
    raise Exception('Object under cursor is not a mesh, "{}".'.format(obj))

# convert the widget cursor position to a point on the near clip plane and a point on the far clip plane
near_point = OpenMaya.MPoint()
far_point = OpenMaya.MPoint()
view = OpenMayaUI.M3dView.active3dView()
# adjust the Y value since MView works differently
view.viewToWorld(rel_position.x(), view.portHeight() - rel_position.y(), near_point, far_point)

# cast a ray into the mesh to find the point on surface
direction = far_point - near_point
mesh_fn = OpenMaya.MFnMesh(shape_dag)
intersection_info = mesh_fn.closestIntersection(OpenMaya.MFloatPoint(near_point), OpenMaya.MFloatVector(direction), OpenMaya.MSpace.kWorld, 1000000, False)

# now focus the point
point = list(intersection_info[0])[:3]
cmds.viewPlace(camera, lookAt=point)