in roboschool/cpp-household/glsl/nv_math.inl [1636:1707]
inline matrix3<T> tangent_basis(const vector3<T>& v0, const vector3<T>& v1, const vector3<T>& v2, const vector2<T>& t0, const vector2<T>& t1, const vector2<T>& t2, const vector3<T> & n)
{
matrix3<T> basis;
vector3<T> cp;
vector3<T> e0(v1.x - v0.x, t1.s - t0.s, t1.t - t0.t);
vector3<T> e1(v2.x - v0.x, t2.s - t0.s, t2.t - t0.t);
cp = cross(e0,e1);
if ( fabs(cp.x) > nv_eps)
{
basis.a00 = -cp.y / cp.x;
basis.a10 = -cp.z / cp.x;
}
e0.x = v1.y - v0.y;
e1.x = v2.y - v0.y;
cp = cross(e0,e1);
if ( fabs(cp.x) > nv_eps)
{
basis.a01 = -cp.y / cp.x;
basis.a11 = -cp.z / cp.x;
}
e0.x = v1.z - v0.z;
e1.x = v2.z - v0.z;
cp = cross(e0,e1);
if ( fabs(cp.x) > nv_eps)
{
basis.a02 = -cp.y / cp.x;
basis.a12 = -cp.z / cp.x;
}
// tangent...
T oonorm = T(1) / sqrtf(basis.a00 * basis.a00 + basis.a01 * basis.a01 + basis.a02 * basis.a02);
basis.a00 *= oonorm;
basis.a01 *= oonorm;
basis.a02 *= oonorm;
// binormal...
oonorm = T(1) / sqrtf(basis.a10 * basis.a10 + basis.a11 * basis.a11 + basis.a12 * basis.a12);
basis.a10 *= oonorm;
basis.a11 *= oonorm;
basis.a12 *= oonorm;
// normal...
// compute the cross product TxB
basis.a20 = basis.a01*basis.a12 - basis.a02*basis.a11;
basis.a21 = basis.a02*basis.a10 - basis.a00*basis.a12;
basis.a22 = basis.a00*basis.a11 - basis.a01*basis.a10;
oonorm = T(1) / sqrtf(basis.a20 * basis.a20 + basis.a21 * basis.a21 + basis.a22 * basis.a22);
basis.a20 *= oonorm;
basis.a21 *= oonorm;
basis.a22 *= oonorm;
// Gram-Schmidt orthogonalization process for B
// compute the cross product B=NxT to obtain
// an orthogonal basis
basis.a10 = basis.a21*basis.a02 - basis.a22*basis.a01;
basis.a11 = basis.a22*basis.a00 - basis.a20*basis.a02;
basis.a12 = basis.a20*basis.a01 - basis.a21*basis.a00;
if (basis.a20 * n.x + basis.a21 * n.y + basis.a22 * n.z < T(0))
{
basis.a20 = -basis.a20;
basis.a21 = -basis.a21;
basis.a22 = -basis.a22;
}
return basis;
}