I - Introduction
Hello fellow life forms!
In today’s post, we take a look at the theory needed for understanding the famous tangent-space mapping, which is the basis for most meso-scale rendering techniques. This post is not intended to be an in-depth mathematical treatment of tangent space, manifolds, mappings or anything like that. It is intended to lay the groundwork in a reasonable manner, so that when I mention Tangent Space or something related to it, you can easily visualize what I mean.

So, let’s start by defining what we mean by Tangent Space (in a loose manner): let be a real vector space related to point on an object. We call it a Tangent Space when such a space contains all possible tangent directions passing through . Think about a sphere : at each point we can define three vectors: one along the horizontal, one into the horizon and another along the vertical, such that they tell how much we walk in each of those directions; if we combine these, we walk tangent to the sphere. If you are used to a little Calculus, you already know these vectors are nothing more than partial derivatives along , and , respectively. We call the combination of these vectors the Gradient and it defines the tangent plane at each point . And yes, it is the same you see in ML, Optimization and Physics. Thus, mathematically, we have:
Well, I believe that with this little introduction you were able to at least get a feel for what a tangent space is! I took a more continuous route to give the example, but in this series we’re gonna stick exclusively to discrete objects, i.e. triangles. Continuous methods are useful and are the right tool for other mathematical models [1], but we aren’t going to look at those here! So, let’s see how we can represent our Tangent Space in terms of vertices and triangles only.
II - Tangent Space
Look at the figure below. Assume we have a discrete sphere (in blue) and a plane (in red); we can define a general vertex along with two vectors and , the tangent and bitangent (the term binormal is a mistake [2]), respectively, such that:
BEWARE! in (3) is the set notation for and, not the wedge product from Grassmann algebra.

III - Calculating the Tangent and Bi-Tangent Vectors

OK! Without further ado, let’s get down to the math! This is what you are here for, right? Look at figure 2, above. Assume we have a generic vertex inside our triangle, let’s call it , such that:
Equation (6) is nothing more than a vector inside our triangle defined in terms of as the starting point for the tail and the tip ending at some generic point (inside the triangle!) with coordinates . Let’s plug in to see what we get:
If you are still not convinced, now would be a good moment to stop, grab a piece of paper and a pen and draw the geometry!
Rearranging equation (6), we get:
Adding on both sides, we have:
Applying (7) to both and :
Wait a minute … We now have a 2x2 system of equations:
Let’s see what we know about it! We already know the values of both and . We also know , , and , they are given! So… what are we left with? Yeah! You guessed it! It is and . Solving it using Cramer’s Rule, we get:
So, there you go! We now have two vectors and that follow all the constraints we established in section II. We are done then, right? Well… not exactly. You may have noticed that at no point did I mention the vectors and . So, what’s up with that? Well, as it turns out, and do not represent the tangent vectors for a vertex in tangent space, but instead they represent the tangent vectors for a triangle in texture-space! Let’s see how we can fix that.
IV - Practical Considerations
-> First, we must go from a triangle to a vertex. To do so, we must first analyze a vertex and what is adjacent to it. If you look at a peak vertex, you can see that it represents (approximately) a region in which we should have a smooth surface. Thus, to correctly represent the information present at this point, we must average the information of all triangles that share this vertex :

-> Second, after the previous process of smoothing the vertices and then linearly interpolating them for pixel shader consumption, we lose property (4) from section II. Therefore, we should also use the Gram–Schmidt process to keep our vectors perpendicular to each other!
Finally! We now have two vectors and , such that all properties from section II are preserved and we can safely use them to transform between world/object and tangent spaces for our needed calculations. But this is a topic for the next post! See you there, bye!
Live long and prosper!!!
References
1 - (1978)Simulation of Wrinkled Surfaces - Jim Blinn - Association for Computing Machinery, Inc.
2 - (2011)Mathematics for 3D Game Programming and Computer Graphics, Third Edition - Eric Lengyel - Cengage Learning PTR