Normal / Bump Mesh Tangent Generation
Code: The shader needs tangents from your procedural mesh!
If you are generating meshes or importing meshes at runtime you may stumble upon the problem of generating tangents for your mesh. Normal / bumped shaders require that tangent plane basis vectors be calculated for each vertex in your mesh to correctly light or effect your mesh in a consistant manner.
I did some digging and found this code on the unity3d forum (unfortunately their was a slight/tiny error on the c# version) so I thought I would post the working version here for reference. I have also added some ammendments which also apparently calculate bi-normals or bit-tangents should you ever find a need. I believe the code may have originated come from here: Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”. Terathon Software 3D Graphics Library, 2001.
Usage:- TangentSolver(Mesh myMesh); returns void
public void TangentSolver(Mesh mesh) {
Vector3[] tan2 = new Vector3[mesh.vertices.Length];
Vector3[] tan1= new Vector3[mesh.vertices.Length];
Vector4[] tangents = new Vector4[mesh.vertices.Length];
//Vector3[] binormal = new Vector3[mesh.vertices.Length];
for (int a = 0; a < (mesh.triangles.Length); a += 3) {
long i1 = mesh.triangles[a + 0];
long i2 = mesh.triangles[a + 1];
long i3 = mesh.triangles[a + 2];
Vector3 v1 = mesh.vertices[i1];
Vector3 v2 = mesh.vertices[i2];
Vector3 v3 = mesh.vertices[i3];
Vector2 w1 = mesh.uv[i1];
Vector2 w2 = mesh.uv[i2];
Vector2 w3 = mesh.uv[i3];
float x1 = v2.x - v1.x;
float x2 = v3.x - v1.x;
float y1 = v2.y - v1.y;
float y2 = v3.y - v1.y;
float z1 = v2.z - v1.z;
float z2 = v3.z - v1.z;
float s1 = w2.x - w1.x;
float s2 = w3.x - w1.x;
float t1 = w2.y - w1.y;
float t2 = w3.y - w1.y;
float r = 1.0F / (s1 * t2 - s2 * t1);
Vector3 sdir = new Vector3((t2*x1-t1*x2)*r,(t2*y1-t1*y2)*r,(t2*z1-t1*z2)*r);
Vector3 tdir = new Vector3((s1*x2-s2*x1)*r,(s1*y2-s2*y1)*r,(s1*z2-s2*z1)*r);
tan1[i1] += sdir;
tan1[i2] += sdir;
tan1[i3] += sdir;
tan2[i1] += tdir;
tan2[i2] += tdir;
tan2[i3] += tdir;
}
for (int a = 0; a < mesh.vertices.Length; a++) {
Vector3 n = mesh.normals[a];
Vector3 t = tan1[a];
Vector3.OrthoNormalize( ref n, ref t );
tangents[a].x = t.x;
tangents[a].y = t.y;
tangents[a].z = t.z;
// Calculate handedness
tangents[a].w = (Vector3.Dot(Vector3.Cross(n, t), tan2[a]) < 0.0f) ? -1.0f : 1.0f;
//To calculate binormals if required as vector3 try one of below:-
//Vector3 binormal[a] = (Vector3.Cross(n, t) * tangents[a].w).normalized;
//Vector3 binormal[a] = Vector3.Normalize(Vector3.Cross(n, t) * tangents[a].w)
}
mesh.tangents = tangents;
}



3 Comments
Hi Jon,
Just found this bit of code here, looks like it’s exactly what I need.
One thing though, it seems your blog has failed to parse some characters…
It seems to be the lowerThan sign ‘<' …wherever there should be one of those, there is '<'
Just wanted to point it out.
Thanks for this!
Cheers!
Quite right, well spotted… I suppose I better fix it now!
Nice! even the one in my own comment is fixed
BTW, The code worked perfectly! All in all, it took me 5 minutes to get it up and adding tangents to the runtime-loaded meshes. Thanks again!
Cheers