I'm writing a script to export models from Blender to be used in my custom OpenGL engine. My engine wants vertices to be in a big solid "array of structs" block, with each vertex having the same amount of data, so I can easily load it into a vertex buffer object. I started out by just exporting the positions and normals which was easy, but getting to UVs my job became more complicated, because each "vertex" could have multiple UVs.

My solution was to go over each polygon first, and for each corner of the polygon, store a whole new vertex in a list, then add an index for that vertex. Afterwards, I scan the list of vertices, and eliminate any doubles, fixing indices as appropriate. This works exactly as expected; when only normal and position data is considered the number of vertices is equal to the mesh's original number of vertices, and I don't have to worry about "splitting" to account for UVs and such.

This works great and all until I start looking at tangents. All of a sudden, the number of vertices I end up with seems suspiciously close to the total number of indices, which means that (almost) no two triangles are sharing any vertices between them. Obviously this isn't good enough.

From doing quite a lot of google searching on the issue, it appears that blender calculates tangents on a per-face basis, with no regards whatsoever to indexing, and you're expected to smooth it out yourself. I have not been able to find any answers as to how to smooth them together. An article I found on the subjects suggests that simply averaging them out doesn't work, and recommends using a vertex welder, then links to a 404 and google shows nothing on the subject.

I'm using calc_tangents() to create the tangent data in the first place. I know how to access the calculated tangents of each corner of a polygon. How do I translate this per-corner/per-face data into per-vertex?

P.S., Should I be storing bitangents in my vertex buffer from this stage, or calculate them in the fragment shader? A lot of sources online recommend the latter, but I've read that it shows up incorrectly if the UVs are skewed.


1 Answer 1


How do I translate this per-corner/per-face data into per-vertex?

You get the appropriate vertex of the face loop this way:

import bpy

me = bpy.context.active_object.data

for face in me.polygons:
    # face loops and face vertices are in the same order
    for vert_id, loop_id in zip(face.vertices, face.loop_indices):    
        # this is the loop:
        # this is the vertex in the corner of the loop:

Should I be storing bitangents in my vertex buffer from this stage, or calculate them in the fragment shader?

This depends on what you want to do with your engine. You can trade some memory for faster fragment shader, but you loose a lot of functionality in the future.

If you need any mesh deformations (armature, soft-body,..) you will have to calculate normals, tangents and bitangents on the fly anyway.

  • $\begingroup$ I already know how to access the vertices and face loop of a polygon. The problem is that the tangents of that face loop don't match the tangents of the face loop of neighboring faces, and I want them to. $\endgroup$ Commented Aug 29, 2017 at 9:58
  • $\begingroup$ @HaydnV.Harach They probably don't match because the UV space does not match and that is ok. The tangents are dependent on UV space and you cannot "merge or smooth them together", that would produce incorrect results. More on this is here: opengl-tutorial.org/intermediate-tutorials/… $\endgroup$ Commented Aug 29, 2017 at 10:17
  • $\begingroup$ The number of vertices i have with just UVs and with UVs + tangents doesnt match, though. Adding tangents to the mix, i have over twice as many resulting vertices. $\endgroup$ Commented Aug 29, 2017 at 10:24
  • $\begingroup$ @HaydnV.Harach And is your shading smooth everywhere? You get extra UV vertices where UV seams are, there you get extra tangents but you also get extra tangents on flat edges as vertices on flat edges will have multiple normals. $\endgroup$ Commented Aug 29, 2017 at 10:34
  • $\begingroup$ That seems to have been the problem. I forgot that it was an issue because setting shading to "smooth" or "flat" has no effect on the exported normals. Now, when I export the model as 'smooth', I go from 2815 vertices to 941. Without tangents at all I get 923 vertices, so I'm fairly satisfied with this. Thanks! $\endgroup$ Commented Aug 30, 2017 at 0:09

You must log in to answer this question.

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