Sanity check - Need help with no-nonsense tangents for simple procedural objects..

I have tried reading up on tangents, but the only resources I can find are either pages full of matrix formulas or long source codes for general purpose tangent calculations. What I need is to generate very simple tangents - preferably without out all the overhead a general purpose solutions brings.

What I need boils down to two different kinds of geometry:

a) Simple primitives with sharp edges (i.e. a cube, a plane, a tetrahedron etc.). I assume I’ll be splitting the vertices on the sharp edges.

b) Strips/Grids with smooth edges.

Some really simple cases:

a) Let’s go with something extremely simple: 2 triangles forming a quad. Let’s assume the texture u,v coordinates are (0,0) in the top left corner and (1,1) in the bottom right corner of the quad. What would the tangent be for each of the four corners?

b) Let’s go with a grid of quads (of 2 triangles) making up a simple terrain. I assume I need to average up the surrounding grid points to find the average tangent, but isn’t that already done with the normals from RecalculateNormals()?

Are the follow assumptions correct?

  • The tangent vector is usually orthogonal (90 degrees) to the normal vector?

  • The tanget vector is rotated so it lines up with the 2D coordinates of u and v?

  • The tangent needs to be specified in object space?

  • The tangent vector consists up 4 components, the last being either 1 or -1?

Also… Do I want to use the normals from RecalculateNormals() before I make the tangents? Or is it better to call Recalc afterwards? (or create the normals myself)

I found an example that closely match my b) category from Unity’s Procedural example (heightmap generator):

    var uvScale = Vector2 (1.0 / (width - 1), 1.0 / (height - 1));
    var sizeScale = Vector3 (size.x / (width - 1), size.y, size.z / (height - 1));
    
    for (y=0;y<height;y++)
    {
        for (x=0;x<width;x++)
        {
            var pixelHeight = heightMap.GetPixel(x, y).grayscale;
            var vertex = Vector3 (x, pixelHeight, y);
            vertices[y*width + x] = Vector3.Scale(sizeScale, vertex);
            uv[y*width + x] = Vector2.Scale(Vector2 (x, y), uvScale);

            // Calculate tangent vector: a vector that goes from previous vertex
            // to next along X direction. We need tangents if we intend to
            // use bumpmap shaders on the mesh.
            var vertexL = Vector3( x-1, heightMap.GetPixel(x-1, y).grayscale, y );
            var vertexR = Vector3( x+1, heightMap.GetPixel(x+1, y).grayscale, y );
            var tan = Vector3.Scale( sizeScale, vertexR - vertexL ).normalized;
            tangents[y*width + x] = Vector4( tan.x, tan.y, tan.z, -1.0 );
        }
    }

With a little refactoring for clarity the last 4 lines become:

var hL = heightMap.GetPixel(x-1, y).grayscale;
var hR =  heightMap.GetPixel(x+1, y).grayscale;
var tan1 = Vector3(2, hR - hL, 0);
var tan = Vector3.Scale(sizeScale,tan1).normalized;
tangents[y*width + x] = Vector4( tan.x, tan.y, tan.z, -1.0 );

I don’t get exactly what their scaling is about, but at least the code is pretty straightforward. :slight_smile:

I guess tangents for triangles with either flat or sharp angles are even simpler to calculate using the above mehtod.

http://forum.unity3d.com/threads/38984-How-to-Calculate-Mesh-Tangents

–Eric