This project has moved and is read-only. For the latest updates, please go here.
Generates per-vertex tangent and bi-tangent information

HRESULT ComputeTangentFrame(
   _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces,
   _In_reads_(nVerts) const XMFLOAT3* positions,
   _In_reads_(nVerts) const XMFLOAT3* normals,
   _In_reads_(nVerts) const XMFLOAT2* texcoords, _In_ size_t nVerts, 
   _Out_writes_opt_(nVerts) XMFLOAT3* tangents,
   _Out_writes_opt_(nVerts) XMFLOAT3* bitangents );

HRESULT ComputeTangentFrame(
   _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces,
   _In_reads_(nVerts) const XMFLOAT3* positions,
   _In_reads_(nVerts) const XMFLOAT3* normals,
   _In_reads_(nVerts) const XMFLOAT2* texcoords, _In_ size_t nVerts, 
   _Out_writes_opt_(nVerts) XMFLOAT3* tangents,
   _Out_writes_opt_(nVerts) XMFLOAT3* bitangents );

HRESULT ComputeTangentFrame(
   _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces,
   _In_reads_(nVerts) const XMFLOAT3* positions,
   _In_reads_(nVerts) const XMFLOAT3* normals,
   _In_reads_(nVerts) const XMFLOAT2* texcoords, _In_ size_t nVerts, 
   _Out_writes_opt_(nVerts) XMFLOAT4* tangents,
   _Out_writes_opt_(nVerts) XMFLOAT3* bitangents );

HRESULT ComputeTangentFrame(
   _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces,
   _In_reads_(nVerts) const XMFLOAT3* positions,
   _In_reads_(nVerts) const XMFLOAT3* normals,
   _In_reads_(nVerts) const XMFLOAT2* texcoords, _In_ size_t nVerts, 
   _Out_writes_opt_(nVerts) XMFLOAT4* tangents,
   _Out_writes_opt_(nVerts) XMFLOAT3* bitangents );

HRESULT ComputeTangentFrame(
   _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces,
   _In_reads_(nVerts) const XMFLOAT3* positions,
   _In_reads_(nVerts) const XMFLOAT3* normals,
   _In_reads_(nVerts) const XMFLOAT2* texcoords, _In_ size_t nVerts, 
   _Out_writes_(nVerts) XMFLOAT4* tangents );

HRESULT ComputeTangentFrame(
   _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces,
   _In_reads_(nVerts) const XMFLOAT3* positions,
   _In_reads_(nVerts) const XMFLOAT3* normals,
   _In_reads_(nVerts) const XMFLOAT2* texcoords, _In_ size_t nVerts, 
   _Out_writes_(nVerts) XMFLOAT4* tangents );

Parameters

The normals parameter can be computed from the mesh indices and vertex positions using ComputeNormals.

The tangents can be optionally returned as a 4-vector where the .w component indicates 'handedness' which allows for an easy reconstruction of the bi-tangent in the shader.

float3 normal : NORMAL0
float4 tangent : TANGENT0

...

float3 tan1 = tangent.xyz;
float3 tan2 = cross( normal, tangent.xyz ) * tangent.w;

Remark

Note that bi-normal is another common term used for bi-tangent, although technically a bi-normal only applies in 2D and not 3D. The Direct3D HLSL semantic name for the bi-tangent is BINORMAL.

Due to the C++ overload resolution rules, if you want to call ComputeTangentFrame for only the binormal output and not the tangent output, you need to use an explicit cast on the nullptr parameter:

std::unique_ptr<XMFLOAT3[]> bitangents( new XMFLOAT3[ nVerts ] );

if ( FAILED( ComputeTangentFrame( &mesh->indices.front(), nFaces,
   pos.get(), normals.get(), texcoords.get(), nVerts,
   static_cast<XMFLOAT3*>(nullptr), bitangents.get() ) ) )
   // Error

Example

std::unique_ptr<WaveFrontReader<uint16_t>> mesh( new WaveFrontReader<uint16_t>() );

if ( FAILED( mesh->Load( L"test.obj" ) ) )
   // Error

if ( mesh->hasNormals )
   // Skip next computation

size_t nFaces = mesh->indices.size() / 3;
size_t nVerts = mesh->vertices.size();

std::unique_ptr<XMFLOAT3[]> pos( new XMFLOAT3[ nVerts ] );
for( size_t j = 0; j < nVerts; ++j )
   pos[ j ] = mesh->vertices[ j ].position;

std::unique_ptr<XMFLOAT3[]> normals( new XMFLOAT3[ nVerts ] );

if ( FAILED( ComputeNormals( &mesh->indices.front(), nFaces,
   pos.get(), nVerts, CNORM_DEFAULT, normals.get() ) ) )
   // Error

if ( !mesh->hasTexcoords )
   // Skip next computation

std::unique_ptr<XMFLOAT2[]> texcoords( new XMFLOAT2[ nVerts ] );
for( size_t j = 0; j < nVerts; ++j )
   texcoords[ j ] = mesh->vertices[ j ].textureCoordinate;

std::unique_ptr<XMFLOAT3[]> tangents( new XMFLOAT3[ nVerts ] );
std::unique_ptr<XMFLOAT3[]> bitangents( new XMFLOAT3[ nVerts ] );

if ( FAILED( ComputeTangentFrame( &mesh->indices.front(), nFaces,
   pos.get(), normals.get(), texcoords.get(), nVerts,
   tangents.get(), bitangents.get() ) ) )
   // Error

Further Reading

Lengyel, Eric. "Computing Tangent Space Basis Vectors for an Arbitrary Mesh". Terathon Software 3D Graphics Library, 2001
http://www.terathon.com/code/tangent.html

Mittring, Martin. "Triangle Mesh Tangent Space Calculation". Shader X^4 Advanced Rendering Techniques, 2006

Last edited Nov 20, 2014 at 7:58 PM by walbourn, version 16