Suppose you have a mesh; you go into Edit mode, set Transform Orientation to Normal, show 3D manipulator widget, Pivot Point = Active Element, face select mode, and then you select any one face: immediately you will see a blue arrow representing the face normal, and also a red and a green arrow representing the face's tangent and bitangent.

What is the most straightforward way to refer to said tangent and bitangent vectors from a Python script? The API documentation confuses me with loops and uv's, yet, clearly, Blender assigns a tangent and bitangent to each face without hesitation!

  • $\begingroup$ I believe what you are looking for is 'calc_tangents'. elysiun.com/forum/… $\endgroup$ Feb 22, 2015 at 7:54
  • $\begingroup$ Thank you, gentlemen! To me, each face has a single loop that defines the perimeter, hence defines the face itself. But the API speaks of multiple loops, each with a single vertex?? Average, fine; thank you. But Blender surely has a tangent and bitangent already stored and associated with each face, as evidenced by the instantaneous appearance of those little XYZ arrows when Transform Orientation = Normal. Isn't that so? $\endgroup$
    – Tom Telos
    Feb 22, 2015 at 13:52

1 Answer 1


You access tangents and bitangents from MeshLoops:

import bpy
me = bpy.context.active_object.data

# tangents have to be pre-calculated
# this will also calculate loop normal

# loop faces
for face in me.polygons:
    # loop over face loop
    for vert in [me.loops[i] for i in face.loop_indices]:
        tangent = vert.tangent
        normal = vert.normal
        bitangent = vert.bitangent_sign * normal.cross(tangent)

To get tangent and bitangent of some face you need to average tangents and bitangents of every vertex in that face loop.

  • $\begingroup$ There is a convenience attribute on polygons you can use to loop over face loops: face.loop_indices. It's already a range object. for vert in [me.loops[i] for i in face.loop_indices]: should suffice. $\endgroup$
    – CodeManX
    Feb 22, 2015 at 13:25
  • $\begingroup$ Jerryno; CoDEmanX: face.loop_indices Duly noted: thank you! $\endgroup$
    – Tom Telos
    Feb 22, 2015 at 18:57
  • $\begingroup$ I made this test comparing normals coming from the loops and the ones that are stored in me.vertices[x].normal, and they are different. Shouldn't those be exactly the same? I've made a separate question here blender.stackexchange.com/questions/71356/… $\endgroup$
    – Greg
    Jan 21, 2017 at 15:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .