/*! SLMesh::calcTangents computes the tangent and bi-tangent per vertex used for GLSL normal map bumb mapping. The code and mathematical derivation is in detail explained in: http://www.terathon.com/code/tangent.html */ void SLMesh::calcTangents() { if (P && N && Tc) { // allocat tangents delete[] T; T = new SLVec4f[numV]; // allocate temp arrays for tangents SLVec3f* T1 = new SLVec3f[numV * 2]; SLVec3f* T2 = T1 + numV; memset(T1, 0, numV * sizeof(SLVec3f) * 2); for (SLuint m = 0; m < numM; ++m) { for (SLuint f = 0; f < M[m].numF; ++f) { // Get the 3 vertex indexes SLushort iVA = F[M[m].startF + f].iA; SLushort iVB = F[M[m].startF + f].iB; SLushort iVC = F[M[m].startF + f].iC; float x1 = P[iVB].x - P[iVA].x; float x2 = P[iVC].x - P[iVA].x; float y1 = P[iVB].y - P[iVA].y; float y2 = P[iVC].y - P[iVA].y; float z1 = P[iVB].z - P[iVA].z; float z2 = P[iVC].z - P[iVA].z; float s1 = Tc[iVB].x - Tc[iVA].x; float s2 = Tc[iVC].x - Tc[iVA].x; float t1 = Tc[iVB].y - Tc[iVA].y; float t2 = Tc[iVC].y - Tc[iVA].y; float r = 1.0F / (s1*t2 - s2*t1); SLVec3f sdir((t2*x1 - t1*x2) * r, (t2*y1 - t1*y2) * r, (t2*z1 - t1*z2) * r); SLVec3f tdir((s1*x2 - s2*x1) * r, (s1*y2 - s2*y1) * r, (s1*z2 - s2*z1) * r); T1[iVA] += sdir; T1[iVB] += sdir; T1[iVC] += sdir; T2[iVA] += tdir; T2[iVB] += tdir; T2[iVC] += tdir; } } for (SLuint i=0; i < numV; ++i) { // Gram-Schmidt orthogonalize T[i] = T1[i] - N[i] * N[i].dot(T1[i]); T[i].normalize(); // Calculate temp. bitangent and store its handedness in T.w SLVec3f bitangent; bitangent.cross(N[i], T1[i]); T[i].w = (bitangent.dot(T2[i]) < 0.0f) ? -1.0f : 1.0f; } delete[] T1; } }