Page MenuHome

Python api for exporting tangent space normals through script.
Closed, ResolvedPublicPATCH


This patch provides a posibility to export indexed tangents
and normals from blender using the python api.

The normals exporting provided too, because the python API
only gives access to the unconditionally averaged/smooth normals.

To install:
After patching, copy the 'weldmesh' folder from archive into '//blender/intern'.
The weldmesh is a free welding library, provided by Morten Mikkelsen. Much thanks to him!

Sample exporting script for writing tangents, normals and tangent's indices per face to file
is providing as "".
There also a sample blend file with simple model and generated normal map.

The patch is adding new python collections and classes.
For more info, look to 'readme.txt' file in archive.

Event Timeline

Your patch has all white space stripped. No one is going to be able to review this patch.

Oops, I'm really sorry for that. Maybe it's because I've created this patch in linux system where line endings
is coded in different way.
However, I've re-upload the patch with right line endings. Hope that now it must be correct.

Many thanks for hint!

Hmm interesting, how to remove the old one from attachments?
The right one is: 'export_tangents_from_python_patch.patch'

note, please dont configure your editor to strip whitespace

Hi, sorry to keep on about details but I cant apply this patch, could you re-make it without white space edits please?

attached errors, failing that you could say the revision you diffed against. a developer can update to that revision - apply patch, remove whitespace edits, update to recent revision - but this is not nice to have to do ontop of patch review.

Okay. So now I've updated latest blender sources. Seems that revision 42468.
And I've fixed white spaces (I think) in files according to 'FILED' places in 'err.txt' you're sent.

I edited blender sources using CodeBlocks IDE and compiles it with cmake from console
and I didn't knew that it may be those problems with this IDE. Sorry for the inconvenience.

Now I uploaded a patch and archive with other stuff.
Can you please try to patch this one. Hope this'll go.


As an artist who has never complied a C program before, I have been trying all day to get Blender to compile so I can test out this patch. If I can get Blender to actually build, I would love to experiment with the exposed tangent and binormal information. This seems vital in exporting the correct data for a game engine that uses entirely precomputed vertex data. If not from this patch, access to the tangent information via the Python API would add significant strength to Blender when it comes to synchronizing tangent space normal maps between the art application and an external game engine. I hope something for this is added to trunk soon.

Okay, I eventually did get Blender compiling and managed to clean up the files damaged during patching. Uploaded a txt file containing information about what I had to fix manually, and what I then an error during actual compiling - within rna_mesh.c.

If anyone wishes to investigate the errors in rna_mesh.c, I have included a new patch based on the cleanup I made to the originally patched files (export_tangents_from_python_patch2.patch). The .patch file itself still appears quite messy, and this is my first time creating such a file, but it at least applies to a clean blender source quickly and without the errors I was getting before. I am using TortoiseSVN however, so results may vary for more advanced users...?

I will probably prod at this a bit more but am afraid the actual code is beyond my skill level and understanding.


I'm glad that you've found idea of my patch useful.
I've looked into txt file with errors, and to help you review the patch I recreated it with latest svn revision (43228)
Try reverse all changes in TortoiseSvn and to apply new patch then.

Hope it helps.

I've compiled and tested patch in 'gcc 4.6.1' only.
So tell me please if compiling errors appears.

Oh, sorry.
Does those errors still appears after last patch?
And which compiler did you use?

However, I will try to build patch with Visual C++

Thanks - I was able to patch the source at revision 43228 with your new .patch file without any problems, which is good. However, the errors when compiling with scons+msvc2008express commandline are still the same as before (rna_mesh.c complaints regarding the use of StructRNA).

Tried using cmake+msvc2008express solution file, and the build fails here also:

111>LINK : fatal error LNK1104: cannot open file '..\..\lib\Debug\bf_rna.lib'

With similar warnings as scons earlier in the build log:

I'm building 32bit on a 64bit OS, since msvc2008express does not allow 64bit builds as far as I know. Base Blender does build fine, but the changes this patch makes to rna_mesh.c are causing problems. Since you say you can get it to compile, I wonder if this is an issue related to the Visual C++ compiler?

I've installed VisualStudioExpress and compiled rna_mesh.c with cmake+VC9 and seems I've resolved the errors.
Problem was in the variables declaration syntax between pure C and C++ standards, which seems didn't critical in gcc compiler.
So I made a new patch, please try this one.

For some strange reasons I failed to build all blender trunk with VC.
I hope there's no more errors but let me know if you have any.

Can you make sure this also works with the bmesh branch?
Campbell is "considering" putting this in but doesn't have time to adapt it to bmesh himself.

Okay, I will try to adopt it. Now, I have started downloading bmesh branch from svn.

By the way. Although I'm tested the patch and I think it exports tangents from a CD_TANGENT layer in correct way, there's one
problem I've found some time ago, maybe you can help me understand it.

If, before exporting mesh, I perform the "Minimize Stretch" procedure (Ctrl+V in the UV/Image editor), then in my
game I get a little crumpled-looking faces (those ones which edges is too long relative to other edges).
But in the blender render and in the GLSL view, all faces is looks good no matter how much I Minimized stretch on those faces.

If I do not performing the "Minimize Stretch" procedure, all seems looks correct.

I've not mentioned this before, because I thought that maybe the shader in my game is doing some wrong TBN transformation or something else,
and I waited for somebody tested this patch too.

So what do you think, maybe there something else I might to do with the CD_TANGENT layer's data before or after welding it?

ok. any existing issues will obviously have to be solved before this can be checked in.
Did you follow the pixel shader implementation? -->

No, I didn't. I just calculated TBN matrix and transformed light and eye vectors by TBN matrix in the vertex shader.
And then used interpolated and normalized tangent space light and eye vectors in the pixel shader.

Yep, that might be my problem.
Instead of this I should transform light and eye normals directly in the pixel shader, with corresponding
with "the pixel shader implementation".

Thanks, I'll try to do in that way.

no you should not transform light and eye vector at all. Transform the normal out of tangent space to the light and view vector. Don't transform the light and view vector.

Ok! I think I finally start to understand). I'll try.

If you want to keep it simple for the first test do the lighting in object space. Transform the eye position and the light position into object space in C/C++ and pass these to the pixel shader. The pixel shader then makes the light direction and the view direction from these and the surface position.

I rewrote my shader and now it works absolutely nice!
Thanks, my problem resolved!

Also I adapted the patch to bmesh branch and tested it. All seems correct.
And I made a new patch for it from latest svn revision (43283).

Nice work! I managed to get the non-bmesh patch to compile at revision 43228, but the test script failed due to not finding mesh.tangent_space at line 68. Of course, I may have simply missed something during the patching process, since I am still new to this. However, I have gotten the latest bmesh patch (revision 43283) to work fine! Compiled fine and the test export python script works, building 32bit blender on a 64bit Windows7 using cmake+msvc2008.

Right now, I am attempting to revise the export script for the game engine I'm working with to make use of the bmesh data (I have noticed UVs are different). Of course, this has nothing to do with the patch... but after that, I should be able to export correct normal, tangent and bitangent data to file, matching the calculations used in blender's baking and viewport. :D


Yes, I've noticed different UVs too.
And in case you did't found how to get them yet,
they accessed in same way, but through "mesh.tessface_uv_textures"
instead of "mesh.uv_textures".

Unfortunately, I can't find the data in tessface_uv_textures. uv_loop_layers has it, uv coords accessible via[i].uv, with three values for each triangle indexed in the order of faces. So if you had an n-sided polygon in bmesh, the sequence in the uv loop would be of length n.

The problem I'm having right now is trying to get my export script to write this data accurately. I should state again that I'm not really a programmer at all, I simply have some python knowledge, and have not done much scripting in Blender before. I have found out that tangent_space.faces are indexed differently than a mesh's faces normally are, which I assume is a necessary part of the mikktspace calculation.

What is the difference between the ordering in tangent_space.vertices and the index values accessible via tangent_space.faces[n].vertices[n]? At the moment, this export script I'm attempting to modify for bmesh and MeshTangentSpace info is exporting normal faces and uv loop info, while applying tangent information from the data added by this patch. I've realized this is wrong, and that I probably need to export the faces from MeshTSFaces data as well as the vertex info.

So here's my question: since the faces in MeshTSFaces are ordered differently, how am I supposed to synchronize this to the uv loop information in the regular mesh data? Sorry if there is an obvious answer to this, I'm really not the best person for the job of testing this. I simply care very much about getting the correct data exported, and am determined to get it right if possible with the additional data your patch provides.

Hmm, uv coords via '[i].uv' is not work in my case :)
Maybe thing is that we are gets our mesh data in the different ways.

I gets my vertices positions from 'mesh.vertices' witch is an array of unique mesh vertices,
and 'mesh.faces' is an array with face obj, that have 3 or 4 (triangle or quad) indexes for unique vertices from 'mesh.vertices'.

The unique vertices 'mesh.tangent_space.faces[n].vertices[n]' is can not be indexed in same order with 'mesh.vertices[n]', because
there might be more than one tangent and normal vectors per each of the face's vertex.

So, all what is matter is that number of faces: 'len(mesh.faces)' and number of tangent faces 'len(mesh.tangent_space.faces)' are
the same.

Then for each face we can get 3 (or 4 in case of quads) actual unique vertex positions from 'mesh.vertices[n]' and actual
unique vertex normal and tangent vectors from 'mesh.tangent_space.vertices[n]'.

If, for example, we want to get unindexed vertex data for drawing or else, we do
Like that:

currFace = 0
currVert = 0
while currFace < len(mesh.faces):

while currVert < len(mesh.faces[currFace].vertices):

vertUV =[currFace].uv[ currVert ]
vertNormal = mesh.tangent_space.vertices[ mesh.tangent_space.face[currFace].vertices[currVert] ].normal
vertTangent = mesh.tangent_space.vertices[ mesh.tangent_space.face[currFace].vertices[currVert] ].tangent
vertPos = mesh.vertices[ mesh.face[currFace].vertices[currVert] ].co

currVert += 1

currFace += 1

And, don't forget to check if is not None before.

But to export mesh data properly, we should export indexed unique data either from 'mesh.vertices[n]' and from 'mesh.tangent_space.vertices[n]' (2 arrays), and
also to export indexes for each face's 'vertex from mesh.face[n].vertices[n]' and 'mesh.tangent_space.face[n].vertices[n]'.

We need to export unique vertices and indexes to them separately because in that way we save a lot of memory.

This is the way I do my exporting, sorry if my explanation is not very straight :)

This is really great and a much needed addition to the blender python API, especially for game development with proprietary mesh file types!

Revision 43228 compiled right away with your patch using MinGW and Scons for me.
I'd love to have it in the just released 2.62 stable version, would it be possible to get an updated patch for that if it's not too much of a hassle?

No problem!
I made a new patch for blender revision (44231)
Thanks for testing it!

In case anyone need a patch for the latest revision after bmesh branch was merged.
I made a new patch for blender revision (44851)

Is there an updated patch for the merged trunk?


Not yet, but I think the last created r44851 patch may work fine for latest revision.
At least, I used it for r45704 without a conflicts in files.

However I will check today if it works correctly and create a patch for latest revision.

I've checked the patch, it seems works correctly.
But I've noticed that in the python API, accessing mesh's faces syntax was changed from "mesh.faces[]" to "mesh.tessfaces[]".

So I changed the syntax for my part of the api in the similar way.
I.e. from "mesh.tangent_space.faces[]" to "mesh.tangent_space.tessfaces[]".

I made a new patch for blender revision (46064)
Also I re-uploaded a sample exporting script that works with "tess" prefix.


Hi there, thanks for the great work! Just one note: I had to manually merge the changes for source/blender/blenkernel/intern/mesh.c with the latest patch 46064 to get it to compile with blender-2.63a-release version. I have created a patch for this too, tried to upload this (did not seem to work). Should I send the file to someone or do i need to wait until i can upload files?

For me the patch seems to work well, although I only tested it with a few examples so far.

Any estimate when the patch will be merged into the trunk or when it will show up in release version? I think it would be very helpful for many people in the community. Keep up the good work and thanks again!


Hi, Sebastian!
I glad that it work and useful for you. And thank you for reviewing it and for the updated patch!
I don't really know is there a possibility to upload files with a comments to a patch tracker, but you can
send your patch on my email (see in Personal Information) and I'll upload it for you from my account.
Or I can try to compile blender-2.63a-release in this days by myself and will also make updated patch.

I'm not sure when the patch will be merged into the trunk, lets hope the developers will found a time for it soon :)


I've uploaded a patch for blender-2.63a-release version (r46548) updated by Sebastian.
It seems work correctly also with latest svn revision (r46644).


Have updated a patch.

I've uploaded a patch for blender-2.64a-release version (r51232).

I have tested the patches for r46548 and r51232. They work.

Eugene I really think you should contact Campbell and get this patch included.
If you get the dialogue going I am certain that will lead to getting your work included.
I have seen others bitch about blender not allowing you to get the tangent spaces via the python api
so you're not the only one.

Hi Morten, ok, I will contact Cambell about it.

I had a look over the patch, while there is nothing especially wrong with the patch, Im not so happy to have all this data added into blenders meshes, but maybe we just accept it, its not _that_ bad.
It just seems like the change has to be done in an intrusive way, but this is really a limit in how we are currently using RNA/DNA, and that RNA doesnt make so much sense for this functionality.

Some things to consider.
- Is this for python or C? --- who uses this? (Im assuming python but we have C++ rna API now too)
... C devs can use mikktspace.c directly, or the tangents from the derived mesh if the headers are included.

- If this is for python only - we could have some function that lets python get the tangents as python lists/tuples/floats/ints - so there is no need to use RNA for access.

... you could treat this a bit different then adding data into DNA - bypass RNA and just allocate a block of tangents which python can access - like we do for bmesh_py_api.c gets freed when python frees.

- The current implementation assumes youll have a mesh - Cycles does this and other areas of blender too, its not so bad but means accessing tangents on derived-mesh-final isnt so simple, it needs converting into a mesh first.

- me->tangent_space can easily get out of sync with the real mesh and is only freed on freeing when freeing the mesh, this means an exporter can allocate a bunch of tangents and theres no obvious way to remove them. (a rna function call may be enough here. though I dont especially like this), this is another advantage of doing this with python data structure - this way the script author needs to make sure the data isnt out of sync, but at least they wont get stale data from another script.

I just have a quick comment regarding the mesh part. The purpose of this patch is to allow people who write python plugins to get hold of the
tangent spaces that were used to bake the normal map. These tangent spaces are always calculated on the DM inside of blender.
So the fact that his patch requires a mesh isn't a problem since the objective is to pass the internal spaces to python.

As for your other comments about design I don't have anything to add. Makes sense.


Yes I think this is for python only.
As an additional goal of this patch was to give access not only to tangents but also for vertex normals in a way as they calculated when rendering.
Because it seem, the python api only gave access to the unconditionally averaged/smooth normals or for faces only.

- About accessing tangents on derived-mesh-final, are you meant that not from every mesh object we can create an derived mesh object?
If so, then yes it is a problem. If no, then I think that anyway any developer who writes an exporting script will do converting mesh anyway (for example to apply the modifiers stack)

- I did freeing tangent_space when freeing the mesh because it seemed most simple way to do. But yes I absolutely agree that there must be a way to clear and refresh it.
How about then to add a couple of methods to it. For example 'tangent_space.refresh()' and 'tangent_space.clear()' (or clean)? Is this will be ok?

I did this through RNA because it the only place in the blender sources where I've found Python data definitions.
Maybe you're right and better to do this functionality through python code. I did not know that it is even possible before. In that case I need to investigate more about it.
But I hope it will be as user friendly as RNA variant.
And also I don't know how difficult it will be to do welding in that case.


All I meant was that tangent space is calculated always in:

DM_add_tangent_layer() inside of DerivedMesh.c

So it's done on a DM.

Hello again.

It's been a while but today I successfully compiled Blender 2.67b (r57415) with the latest version of the attached patch file (export_tangents_patch_blender264a_release(51232).patch).

Are there any updates on integration of the patch into the trunk? The last discussion about this was already half a year ago and the patch already exists since 2011. I would be very happy if I don't need to manually patch each new release of Blender anymore ;)


Like I told you you need to get hold of campbell. Also known as ideasman on irc in #blendercoders.
I don't think anyone with authority is keep track of this tracker and since a lot of people want the tspace export I think it would be a great idea.


Hi all.
I'm sorry for not updating the patch for long period of time. Have almost no time for this now.
Best what I changed in the patch so far is added two functions: 'mesh.tangent_space.clear()' and 'mesh.tangent_space.refresh()'.
Didn't came up with something better than this yet... At least now, user have a way to clear and refresh tangents when mesh is changed.

I've uploaded a patch for blender-2.68a-release version (r59244) (lattest trunk revision).

Hi, I made some minor changes for the patch to work with Blender-2.69 release. Trying to upload to attachments...

Hi there!
Still no progress on getting tangent export Blender it seems. I wanted to say that I did get hold of Campbell (ideasman_42) on IRC in September last year. He told me the patch was "too intrusive" and that they would implement it another way. He said he'd forwarded the request to a guy called Bastien, who apparently was working on game pipeline features at the time. I haven't checked back after that so I'm not sure if any work has been done or what the status is right now. If anyone knows who this Bastien is, I'd be extremely grateful to have some sort of news either way.
I hope there's some progress on this soon. I've been following the discussion for two or three years now, it's a crucial feature for game developers and it's sad that this rather important functionality is still missing from what is otherwise a competent package.


  • Andy

This makes me incredibly happy!
Thank you very much! If it's in the trunk I'll build the latest rev and start looking into it right away. :)

Campbell Barton (campbellbarton) changed the task status from Unknown Status to Resolved.Feb 19 2014, 4:41 AM

Closing since this has been made possible via an alternative patch.