Skip to content

ComputeTangentFrame

Chuck Walbourn edited this page Jun 18, 2015 · 11 revisions

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 link

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

For Use

  • Universal Windows Platform apps
  • Windows desktop apps
  • Windows 11
  • Windows 10
  • Windows 8.1
  • Xbox One
  • Xbox Series X|S
  • Windows Subsystem for Linux

Architecture

  • x86
  • x64
  • ARM64

For Development

  • Visual Studio 2022
  • Visual Studio 2019 (16.11)
  • clang/LLVM v12 - v18
  • GCC 10.5, 11.4, 12.3
  • MinGW 12.2, 13.2
  • CMake 3.20

Related Projects

DirectX Tool Kit for DirectX 11

DirectX Tool Kit for DirectX 12

DirectXTex

DirectXMath

Tools

Test Suite

Content Exporter

DxCapsViewer

See also

DirectX Landing Page

Clone this wiki locally