Finally not,

I'm still playing to find a correct way to compute good tangents... but no way... for each technique a model fail to be rendered correctly !

To test I use 3 models and a "tangent shader" (I can provide the obj or the blender model if someone is interested):

- Lego man

- RS8 model

- Cornell box with 2 spheres

I have use several techniques for now :

- Precomputed techniques : where I compute all the tangents once (preprocessing)

- Live computation

I have try to mix all theses methods, but no way... I can render all my models without problems !

If someone has more information about the right way of doing this... ??

*Pre-computation*
- Code from the assimp library :

http://assimp.svn.sourceforge.net/viewv ... iew=markup
- Code from

http://www.terathon.com/code/tangent.html
- Code from NVidia NVMeshMender.cc :

http://www.koders.com/cpp/fid2F46C590DE ... FFED3.aspx
*Live computation methods : based on the N vector*
Code: Select all

```
void GetOrthonormalBasis(clVector3 N, clDualVector3* TnBiT)
{
N = normalize(N);
clVector3 up = (clVector3)(0.f, 1.f, 0.f);
if (fabs(dot(up, N)) > 0.8f)
up = (clVector3)(1.f, 0.f, 0.f);
TnBiT->v1 = normalize(cross(up, N));
TnBiT->v2 = normalize(cross(N, TnBiT->v1));
}
```

Code: Select all

```
void GetOrthonormalBasis(const clVector3 v0, clDualVector3* dv)
{
if (fabs(v0.x) > fabs(v0.y))
{
float invLen = 1.f / sqrt(v0.x * v0.x + v0.z * v0.z);
dv->v1.x = -v0.z * invLen;
dv->v1.y = 0.f;
dv->v1.z = v0.x * invLen;
}
else
{
float invLen = 1.f / sqrt(v0.y * v0.y + v0.z * v0.z);
dv->v1.x = 0.f;
dv->v1.y = v0.z * invLen;
dv->v1.z = -v0.y * invLen;
}
dv->v2 = cross(v0, dv->v1);
}
```

Code: Select all

```
void GetOrthonormalBasis(clVector3 N, clDualVector3* TnBiT)
{
// Reference:
//
// Hughes, J. F., and Moller, T. Building an Orthonormal Basis from a Unit Vector.
// Journal of Graphics Tools 4, 4 (1999), 33-35.
// http://www.cs.brown.edu/research/pubs/pdfs/1999/Hughes-1999-BAO.pdf
// Compute u so that it is orthogonal to n.
if (fabs(N.x) < fabs(N.y))
{
if (fabs(N.x) < fabs(N.z))
{
// N.x is the smallest component.
TnBiT->v1.x = 0.f;
TnBiT->v1.y = -N.z;
TnBiT->v1.z = N.y;
}
else
{
// N.z is the smallest component.
TnBiT->v1.x = -N.y;
TnBiT->v1.y = N.x;
TnBiT->v1.z = 0.f;
}
}
else
{
if (fabs(N.y) < fabs(N.z))
{
// N.y is the smallest component.
TnBiT->v1.x = -N.z;
TnBiT->v1.y = 0.f;
TnBiT->v1.z = N.x;
}
else
{
// N.z is the smallest component.
TnBiT->v1.x = -N.y;
TnBiT->v1.y = N.x;
TnBiT->v1.z = 0.f;
}
}
// u is orthogonal to n, but not unit-length. Normalize it.
TnBiT->v1 = normalize(TnBiT->v1);
// Compute v.
TnBiT->v2 = cross(TnBiT->v1, N);
}
```

*Live computation methods : based on the uv coordinates*
Code: Select all

```
if (!isnan(vp0.Tex.u))
{
// Compute deltas for triangle partial derivatives of normal
float du1 = vp1.Tex.u - vp0.Tex.u;
float du2 = vp2.Tex.u - vp0.Tex.u;
float dv1 = vp1.Tex.v - vp0.Tex.v;
float dv2 = vp2.Tex.v - vp0.Tex.v;
float determinant = du1 * dv2 - dv1 * du2;
if (determinant != 0.f)
{
float invdet = 1.f / determinant;
clVector3 dp1 = vp1.P - vp0.P;
clVector3 dp2 = vp2.P - vp0.P;
clVector3 dpdu = (dv2 * dp1 - dv1 * dp2) * invdet;
rayHit->T = normalize(cross(rayHit->Ng, dpdu));
return;
}
}
```