//-----------------------------------------------------------------------------// 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; }}