/*! Rotates the object so that it's forward vector is pointing towards the 'target' point. Default forward is -Z. The 'relativeTo' parameter defines in what space the 'target' parameter is to be interpreted in. */ void SLNode::lookAt(const SLVec3f& target, const SLVec3f& up, SLTransformSpace relativeTo) { SLVec3f pos = translation(); SLVec3f dir; SLVec3f localUp = up; if (relativeTo == TS_world && _parent) { SLVec3f localTarget = _parent->updateAndGetWMI() * target; localUp = _parent->updateAndGetWMI().mat3() * up; dir = localTarget - translation(); } else if (relativeTo == TS_object) dir = _om * target - translation(); else dir = target - translation(); dir.normalize(); SLfloat cosAngle = localUp.dot(dir); // dir and up are parallel and facing in the same direction // or facing in opposite directions. // in this case we just rotate the up vector by 90° around // our current right vector // @todo This check might make more sense to be in Mat3.posAtUp if (fabs(cosAngle-1.0) <= FLT_EPSILON || fabs(cosAngle+1.0) <= FLT_EPSILON) { SLMat3f rot; rot.rotation(-90.0f, right()); localUp = rot * localUp; } _om.posAtUp(pos, pos+dir, localUp); needUpdate(); }
/*! 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; } }