Getting tangents for selected vertices in OpenMaya

Hi there. I’m trying to calculate tangent space for a couple of selected vertices (or what I call their “rotation”). To do that I need to get at least normals and tangents and it seems I need to use MFnMesh to do that. However MFnMesh.getTangents(), .getNormals(), .getBinormals() return list of values for every vertex in the shape. Do you know a smart way to extract the data only for vertices in the selection list?

If you’re not opposed to using PyMel, you could do:

import pymel.core as pm
normals = [vert.getNormal() for vert in pm.ls(selection=True, flatten=True)]

Yeah, I know it. But what about tangents?

So I searched through the api documentation for “binormal” because it’s part of what you seem to need, and it’s a less used term than “tangent”.
And it looks like there’s a couple places to get it:
MFnMesh.getBinormals whcih gets all binormals for all faceVertices
MFnMesh.getFaceVertexBinormal which gets the binormal for a faceVertex
MFnMesh.getFaceVertexBinormals which gets all the binormals for a given face
MItMeshFaceVertex.getBinromal which is similar, just on a mesh iterator.

And all these places have equivalent tangent getters.

So it looks like everything is based on the faceVertices. This makes sense to me because the tangent and binormal depends on the uv’s of the mesh, and any vertex on a mesh can have as many uv’s as it has neighboring faces.

From the documentation of MFnMesh.getTangents

The tangent is defined as the surface tangent of the polygon
running in the U direction defined by the uv map.

So, for the vertices in your selection list, you’d have to convert to the list of faces, and get the normals, tangents, and binormals from there.
That will give you multiple coordinate systems per vertex (one per adjacent face), and you’ll have to figure out if you want to just pick one, or if you want to somehow average them.


A possible way to handle this:

Get an MItMeshVertex iterator over your selection set, then for each item in the iterator, MItMeshVertex.getNormal to get the normal. Then MItMeshVertex.getConnectedFaces to just get the connected faces, and store them in a set

Build an MItMeshPolygon iterator over that set of faces, then for each face in that set, get the MItMeshPolygon.getVertices to get the order of the vertices for the polygon. Then use MFnMesh.getFaceVertexTangents to get the tangents for that face.

So with all that looping, you should be able to get all the faceVertex tangents per vertex.
From there, you can pick one tangent, or figure out how to average them.

1 Like