TangentSpaceVectors的创建

来源:互联网 发布:数控锥度螺纹编程实例 编辑:程序博客网 时间:2024/06/06 02:03
//-----------------------------------------------------------------------------// 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;    }}