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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
//Code written in C# -Adds Tangent Data To Supplied Mesh 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; } |
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