//-----------------------------------------------------------------------------
// Name: createTangentSpaceVectors()
// Desc: Given a vertex (v1) and two other vertices (v2 & v3) which define a
// triangle, this function will return Tangent, BiNormal, and Normal,
// vectors which can be used to define the tangent matrix for the first
// vertex's position (v1).
//
// Args: v1 - vertex 1
// v2 - vertex 2
// v3 - vertex 3
// v1u, v1v - texture-coordinates of vertex 1
// v2u, v2v - texture-coordinates of vertex 2
// v3u, v3v - texture-coordinates of vertex 3
// vTangent - When the function returns, this will be set as the tangent vector
// vBiNormal - When the function returns, this will be set as the binormal vector
// vNormal - When the function returns, this will be set as the normal vector
//
// Note: This function is based on an article by By Jakob Gath and Sbren Dreijer.
// http://www.blacksmith-studios.dk/projects/downloads/tangent_matrix_derivation.php
//------------------------------------------------------------------------------
void createTangentSpaceVectors( vector3f *v1,
vector3f *v2,
vector3f *v3,
float v1u, float v1v,
float v2u, float v2v,
float v3u, float v3v,
vector3f *vTangent,
vector3f *vBiNormal,
vector3f *vNormal )
{
// Create edge vectors from vertex 1 to vectors 2 and 3.
vector3f vDirVec_v2_to_v1 = *v2 - *v1;
vector3f vDirVec_v3_to_v1 = *v3 - *v1;
// Create edge vectors from the texture coordinates of vertex 1 to vector 2.
float vDirVec_v2u_to_v1u = v2u - v1u;
float vDirVec_v2v_to_v1v = v2v - v1v;
// Create edge vectors from the texture coordinates of vertex 1 to vector 3.
float vDirVec_v3u_to_v1u = v3u - v1u;
float vDirVec_v3v_to_v1v = v3v - v1v;
float fDenominator = vDirVec_v2u_to_v1u * vDirVec_v3v_to_v1v -
vDirVec_v3u_to_v1u * vDirVec_v2v_to_v1v;
if( fDenominator < 0.0001f && fDenominator > -0.0001f )
{
// We're too close to zero and we're at risk of a divide-by-zero!
// Set the tangent matrix to the identity matrix and do nothing.
*vTangent = vector3f( 1.0f, 0.0f, 0.0f );
*vBiNormal = vector3f( 0.0f, 1.0f, 0.0f );
*vNormal = vector3f( 0.0f, 0.0f, 1.0f );
}
else
{
// Calculate and cache the reciprocal value
float fScale1 = 1.0f / fDenominator;
vector3f T;
vector3f B;
vector3f N;
T = vector3f((vDirVec_v3v_to_v1v * vDirVec_v2_to_v1.x - vDirVec_v2v_to_v1v * vDirVec_v3_to_v1.x) * fScale1,
(vDirVec_v3v_to_v1v * vDirVec_v2_to_v1.y - vDirVec_v2v_to_v1v * vDirVec_v3_to_v1.y) * fScale1,
(vDirVec_v3v_to_v1v * vDirVec_v2_to_v1.z - vDirVec_v2v_to_v1v * vDirVec_v3_to_v1.z) * fScale1);
B = vector3f((-vDirVec_v3u_to_v1u * vDirVec_v2_to_v1.x + vDirVec_v2u_to_v1u * vDirVec_v3_to_v1.x) * fScale1,
(-vDirVec_v3u_to_v1u * vDirVec_v2_to_v1.y + vDirVec_v2u_to_v1u * vDirVec_v3_to_v1.y) * fScale1,
(-vDirVec_v3u_to_v1u * vDirVec_v2_to_v1.z + vDirVec_v2u_to_v1u * vDirVec_v3_to_v1.z) * fScale1);
// The normal N is calculated as the cross product between T and B
N = crossProduct( T, B );
// Calculate and cache the reciprocal value
float fScale2 = 1.0f / ((T.x * B.y * N.z - T.z * B.y * N.x) +
(B.x * N.y * T.z - B.z * N.y * T.x) +
(N.x * T.y * B.z - N.z * T.y * B.x));
//
// Use the temporary T (Tangent), (B) Binormal, and N (Normal) vectors
// to calculate the inverse of the tangent matrix that they represent.
// The inverse of the tangent matrix is what we want since we need that
// to transform the light's vector into tangent-space.
//
(*vTangent).x = crossProduct( B, N ).x * fScale2;
(*vTangent).y = -(crossProduct( N, T ).x * fScale2);
(*vTangent).z = crossProduct( T, B ).x * fScale2;
(*vTangent).normalize();
(*vBiNormal).x = -(crossProduct( B, N ).y * fScale2);
(*vBiNormal).y = crossProduct( N, T ).y * fScale2;
(*vBiNormal).z = -(crossProduct( T, B ).y * fScale2);
(*vBiNormal).normalize();
(*vNormal).x = crossProduct( B, N ).z * fScale2;
(*vNormal).y = -(crossProduct( N, T ).z * fScale2);
(*vNormal).z = crossProduct( T, B ).z * fScale2;
(*vNormal).normalize();
//
// NOTE: Since the texture-space of Direct3D and OpenGL are laid-out
// differently, a single normal map can't look right in both
// unless you make some adjustments somewhere.
//
// You can adjust or fix this problem in three ways:
//
// 1. Create two normal maps: one for OpenGL and one for Direct3D.
// 2. Flip the normal map image over as you load it into a texture
// object.
// 3. Flip the binormal over when computing the tangent-space
// matrix.
//
// Since the normal map used by this sample was created for Direct3D,
// I've decided to simply flip the binormal.
//
*vBiNormal = *vBiNormal * -1.0f;
}
}
TangentSpaceVectors的创建
最新推荐文章于 2021-02-23 11:13:07 发布