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$ – MarcClintDion Feb 22 '15 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 '15 at 13:52

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 '15 at 13:25
  • $\begingroup$ Jerryno; CoDEmanX: face.loop_indices Duly noted: thank you! $\endgroup$ – Tom Telos Feb 22 '15 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 K. Jan 21 '17 at 15:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.