void MeshUtils::calculateVertexTangents( const std::vector< Face >& faces, std::vector< LitVertex >& inOutVertices ) { /** * I used the algorithm from this page: http://www.terathon.com/code/tangent.html. */ uint vertexCount = inOutVertices.size(); Vector* tan1 = new Vector[vertexCount * 2]; Vector* tan2 = tan1 + vertexCount; memset( tan1, 0, vertexCount * sizeof(Vector) * 2 ); Vector sdir, tdir; uint trianglesCount = faces.size(); for ( uint i = 0; i < trianglesCount; ++i ) { const Face& tri = faces[i]; uint i1 = tri.idx[0]; uint i2 = tri.idx[1]; uint i3 = tri.idx[2]; const TVector<3>& v1 = inOutVertices[i1].m_coords; const TVector<3>& v2 = inOutVertices[i2].m_coords; const TVector<3>& v3 = inOutVertices[i3].m_coords; const TVector<2>& w1 = inOutVertices[i1].m_textureCoords; const TVector<2>& w2 = inOutVertices[i2].m_textureCoords; const TVector<2>& w3 = inOutVertices[i3].m_textureCoords; float x1 = v2[0] - v1[0]; float x2 = v3[0] - v1[0]; float y1 = v2[1] - v1[1]; float y2 = v3[1] - v1[1]; float z1 = v2[2] - v1[2]; float z2 = v3[2] - v1[2]; float s1 = w2[0] - w1[0]; float s2 = w3[0] - w1[0]; float t1 = w2[1] - w1[1]; float t2 = w3[1] - w1[1]; float r = (s1 * t2 - s2 * t1); if ( r != 0.0f ) { r = 1.0f / r; sdir.set( (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r ); tdir.set( (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r ); tan1[i1].add( sdir ); tan1[i2].add( sdir ); tan1[i3].add( sdir ); tan2[i1].add( tdir ); tan2[i2].add( tdir ); tan2[i3].add( tdir ); } } Vector vertexNorm, vertexTangent, normTanCross; for ( uint i = 0; i < vertexCount; ++i ) { vertexNorm.load( inOutVertices[i].m_normal ); const Vector& t = tan1[i]; // Gram-Schmidt orthogonalize FastFloat normTan1Dot; normTan1Dot.setNeg( vertexNorm.dot( t ) ); vertexTangent.setMulAdd( vertexNorm, normTan1Dot, t ); vertexTangent.normalize(); // Calculate handedness normTanCross.setCross( vertexNorm, t ); FastFloat handedness; handedness.setSign( normTanCross.dot( tan2[i] ) ); handedness.reciprocal(); vertexTangent.mul( handedness ); // store the results vertexTangent.store( inOutVertices[i].m_tangent ); } delete[] tan1; }