# Quick Intro to Tangent Space – For 3D Artists

If you’re thinking “I’ve herd of Tangents before”, and you’ve not spent a lot of time animating or learning calculus, then there’s a good chance it’s from *Tangent Space Normal Maps*. In this short I’m going to take a quick look at *tangent space*, and relate it back to the Cross Product.

### What is a Tangent?

A tangent by itself is usually represented as a straight line on a curve – normally on a graph – and represents the *instantaneous rate of change* at that point. For a more complete understanding of tangents, you’d need to spend some time learning introductory Calculus, which is *not* something I’d suggest many artists worry about unless there’s specific interest.

Tangents also apply to 3D meshes, and with tangent space mapping, the tangent is the direction or “flow” of a mesh, representing largest rate of change in an meshes `U`

co-ordinate in texture space.

I’m not going to go into computing the tangent space here, if you want to go down another rabbit hole, here’s a good thread from gamedev.stackexchange explaining directly. But you can think of the `tangent`

as a “forward axis” along a mesh, with the `bitangent`

being the “right” axis, and the `normal`

being the “up” axis.

### MikkTSpace and Tangent Space Normal Maps

The tangent vector is helpful as it gives gives us one of the two base vectors for our tangent space mapping. If we have two perpendicular directions in a 3D space, we can use the Cross Product to calculate the third. It’s common practise, using the `MikkTSpace`

tangent conversion algorithm, covered in Morten Mikkelsen’s thesis here.

When encoding normal maps using Mikkelsen’s algorithm – which has almost become the standard for many 3D programs – only the `normal`

and the `tangent`

are stored. The `bitangent`

, sometimes also known as the `binormal`

, is computed from the Cross Product of the `tangent`

and the `normal`

when the mesh data is loaded by another software package.

The `tangent`

, `bitangent`

, and `normal`

are in essence the co-ordinate system of texture space, like the `XYZ`

of 3D space.

Tangent space normal maps adjust normals *based on the surface tangent*. Thus will look odd when used on a mesh with different surface tangents. This means that we cannot expect a normal map, baked with on mesh, to look right on a different mesh.

Take this small quad, comprised of two triangles. On each triangle we can see the `N`

or normal vector in green, pointing directly away from the triangle’s face. The `T`

or tangent vector is in blue, pointing to the top left in this image, and the `B`

or bitangent vector in red, pointing to the bottom left.

However in the above animated clip you can see how the `TBN`

vectors move and re-orient with the animated plane.

Because the tangent represents the *direction* of the mesh at a given point, if the tangent is incorrect, the normals from the normal map will be pointing in a different direction, and thus odd shading can occur.

Tangent space normal maps store normals based upon the original tangents of the mesh. A normal of `(0,1,0)`

in a normal map doesn’t mean point up in world or object space, it means “Point directly away from the models surface”. So this tangent-space up vector would be an unchanged normal, as this is what the face normal would have been in the first place.

Once the normal map has been decoded, we have a unit vector per pixel, which in the fragment shader we’d *transform into object space*.

The `tangent`

, `bitangent`

, `normal`

matrix, or `TBN Matrix`

is what is the end destination for the tangent space vectors we’ve been looking at. When these are assembled in a matrix, we can then *multiply* our decoded normal vector by this matrix. This *transforms* it, from the flat (tangent) space of our normal map, to the *object* *space* of our mesh. In this case specifically, it just rotates our normal vector to our mesh’s surface.

### To Summarise

This short takes a quick fly-by of tangent space mapping as a supporting component of my Cross Product article. There’s much more to touch on, like linear transforms, but hopefully this provides the start of a foundation.