<p>In Normal Mapping, you want to go to "Tangent Space", that is the space where the center of the coordinate system is your Vertex (/Fragment). Just like you go from Model Space to World Space and from World Space to Eye Space, you can go to Tangent Space with a matrix multiplication.</p>

<p>In Tangent Space, the vector $n_T=\left(\begin{array}{c}0\\0\\1\end{array}\right)$ is always the Normal - since you read the normal $n_N$ out of the Normal Map in your Fragment Shader, you will obviously not use $n_T$ but $n_N$ for lighting calculations and this choice of $n_N$ rather than $n_T$ brings about the nice effect normal mapping has.</p>

<p>What's a bit special is that every vertex has its own Tangent Space, which is why you need the tangent, bitangent$^1$ and (geometry) normal of every vertex to construct your TBN matrix.</p>

<p>So much for theory - since you didn't really ask about that specifically, I assume you understand this (otherwise just edit your question).</p>

<blockquote>
  <p>by the way, I'm not sure I visualize why the LearnOpenGL tutorial doesn't use vec4(modelSpaceVec, 1); I'm not sure what either value would represent or how it would change the results. I assume this just a property of normals that we always represent them with a w of 0, but I don't get why it applies to the tangent and bitangent</p>
</blockquote>

<p>Vectors in general are represented with a $0$ in the $w$ coordinate. If you look into a translation matrix, you will notice that the last row is the one that moves points around. For vectors, this is not a wanted behaviour - a vector is the same, no matter where, since it is a direction. So to avoid "translating" a vector, you set the $w$ coordinate to $0$. Since your tangent and bitangent vectors are vectors, the $w$ coordinate is $0$ here as well. </p>

<blockquote>
  <p>But more importantly, I don't understand the modelMatrix * ... part of the equation.</p>
</blockquote>

<p>Using the the model matrix $M$ at this point is correct in <em>most</em> cases - but not all of them. The normal matrix $N$ is (as the answer you linked correctly said) the inverse transpose of the model matrix. But, since normals are vectors, you don't need a 4x4 matrix, a 3x3 matrix is just fine. And if you leave out that translation part, and you scale the same amount in all three coordinates, then the transpose of your model matrix is the same as the inverse of your model matrix. Therefore you get:</p>

<p>$
N = (M^{-1})^T = (M^T)^T = M
$</p>

<p>And that is why in most cases (i.e. everytime you use the same scaling in every coordinate) the normal matrix is the same as the model matrix.</p>

<blockquote>
  <p><code>vec3 worldSpaceVec = inverse(transpose(modelMatrix)) * modelSpaceVec;</code></p>
</blockquote>

<p>This is correct, however</p>

<blockquote>
  <p><code>vec3 worldSpaceVec = inverse(transpose(mvpMatrix)) * modelSpaceVec;</code></p>
</blockquote>

<p>this is not correct. Once you have transformed your normals into world space, you <em>need to</em> use the same view and projection matrix as before. Your view matrix brings your viewer into the origin (or rather it moves everything such that your viewer is the origin), inverse transposing this doesn't make sense (and similarly it doesn't make sense for the projection matrix. plus, the order in matrix multiplications is important, which is the next problem... don't do it ;-) )</p>

<p>Now, since you know that the model matrix <em>may</em> be the same as the normal matrix, you can (mathematically correctly) just go with the inverse transpose of the model matrix. Obviously this costs quite a lot of performance, especially inverting a matrix is costly. It is therefore more efficient to just go with the model matrix.</p>

<blockquote>
  <p>In other words, should the tangent and bitangent vectors of a vertex be converted from one space to another using the same transformation matrix as the vertex's normal vector, and if so, why?</p>
</blockquote>

<p>Unlike normals, tangent and bitangent vectors should be transformed with the model matrix, independently of the whether the normal matrix equals the modal matrix. A normal is always supposed to be perpendicular to a surface, and that's why simply taking the model matrix may be incorrect - in some cases the normal matrix would not be perpendicular to the surface anymore. Tangents however are always "lying" on the surface, so if you rotate a surface, the tangent must be rotated the same way to still "lie" on the surface.</p>

<hr>

<p>$^1$ Sometimes this is called <em>binormal</em>, however Eric Lengyel explains why this is an incorrect term in <a href="http://www.mathfor3dgameprogramming.com/" rel="nofollow noreferrer">Mathematics for 3D Game Programming and Computer Graphics</a>.</p>

CC BY-SA 4.0
2018-05-03T07:13:29.853Z
"since you didn't really ask about that specifically, I assume you understand this" I do, but the added context is nice :) Thanks for this very thorough answer! Just to make sure I understood, you're saying that the only case where the inverse transpose isn't redundant is when, say, a mesh is being rescaled on one axis but not the others? Follow up question: if I do want to calculate the normals in camera space (for instance, to avoid floating point rounding errors), how do I do it? Would using `inverse(transpose(modelViewMatrix))` be enough?
Narrateur du chaos
CC BY-SA 4.0
2018-05-03T07:17:57.270Z
`he inverse transpose isn't redundant is when, say, a mesh is being rescaled on one axis but not the others?` there is also the shearing transformation and i am not sure about that, but i doubt it leads to normal matrix = model matrix. but in general, that's the most likely case to brake equality. `if I do want to calculate the normals in camera space` you can do lighting in world space - you will need to transform your lighting and viewing vectors to world space and then to tangent space, but otherwise it doesn't matter.still, the view matrix part is wrong,it's just the `modelMatrix` you want
Tare
CC BY-SA 4.0
2018-05-03T06:52:28.357Z
2018-05-03T07:02:19.550Z
2018-05-03T07:02:19.550Z
Tare
<p>I'd like to understand how the process of building the "tangent space" matrix for <a href="https://en.wikipedia.org/wiki/Normal_mapping" rel="nofollow noreferrer">normal mapping</a> works. I'm following several tutorials, and other stackexchange questions, but I'm unfamiliar with the math involved, and a lot of resources seem to be telling me "just do this and it'll work".</p>

<hr>

<p>According to <a href="https://learnopengl.com/Advanced-Lighting/Normal-Mapping" rel="nofollow noreferrer">the LearnOpenGL tutorial</a>, you should build your tangent space matrix with the following code:</p>

<pre><code>vec3 T = normalize(vec3(model * vec4(aTangent,   0.0)));
vec3 B = normalize(vec3(model * vec4(aBitangent, 0.0)));
vec3 N = normalize(vec3(model * vec4(aNormal,    0.0)));
mat3 TBN = mat3(T, B, N)
</code></pre>

<p>The first three lines are variations of:</p>

<pre><code>vec3 worldSpaceVec = normalize(vec3(modelMatrix * vec4(modelSpaceVec, 0)));
</code></pre>

<p>Other implementations I've seen do:</p>

<pre><code>vec3 worldSpaceVec = normalize(mat3(modelMatrix) * modelSpaceVec);
</code></pre>

<p>(by the way, I'm not sure I visualize why the LearnOpenGL tutorial doesn't use <code>vec4(modelSpaceVec, 1)</code>; I'm not sure what either value would represent or how it would change the results. I assume this just a property of normals that we always represent them with a <code>w</code> of 0, but I don't get why it applies to the tangent and bitangent)</p>

<p>But more importantly, I don't understand the <code>modelMatrix * ...</code> part of the equation. According to <a href="https://computergraphics.stackexchange.com/a/1506/8660">this answer</a>, normals are bivectors, a different type of data which is represented by a row matrix instead of a column matrix (that is, bivectors are $\begin{bmatrix} x &amp; y &amp; z \end{bmatrix}$ where vectors are$\begin{bmatrix} x \\ y \\ z \end{bmatrix}$).</p>

<p>If my understanding is correct, then normals are of a different type than regular vectors, just like kilograms and liters are similar but different types; and they need to be treated differently in regard to transformations. So why does the tutorial use:</p>

<pre><code>vec3 worldSpaceVec = normalize(vec3(modelMatrix * vec4(modelSpaceVec, 0)));
</code></pre>

<p>and not</p>

<pre><code>vec3 worldSpaceVec = inverse(transpose(modelMatrix)) * modelSpaceVec;
</code></pre>

<p>or even</p>

<pre><code>vec3 worldSpaceVec = inverse(transpose(mvpMatrix)) * modelSpaceVec;
</code></pre>

<p>?</p>

<p>In other words, should the tangent and bitangent vectors of a vertex be converted from one space to another using the same transformation matrix as the vertex's normal vector, and if so, why?</p>

CC BY-SA 4.0
2018-05-03T08:36:39.503Z
FYI The w=0 part is for all directions. Stuff that you don't want to have translation affect.
ratchet freak
<transformations><matrix><normal-mapping>
How do I build my tangent space matrix?
Narrateur du chaos
# How do I build my tangent space matrix?

(Asked by: username_0 on 2018-05-03)

I'd like to understand how the process of building the "tangent space" matrix for [normal mapping](https://en.wikipedia.org/wiki/Normal_mapping) works. I'm following several tutorials, and other stackexchange questions, but I'm unfamiliar with the math involved, and a lot of resources seem to be telling me "just do this and it'll work".

---

According to [the LearnOpenGL tutorial](https://learnopengl.com/Advanced-Lighting/Normal-Mapping), you should build your tangent space matrix with the following code:

```
vec3 T = normalize(vec3(model * vec4(aTangent,   0.0)));
vec3 B = normalize(vec3(model * vec4(aBitangent, 0.0)));
vec3 N = normalize(vec3(model * vec4(aNormal,    0.0)));
mat3 TBN = mat3(T, B, N)

```

The first three lines are variations of:

```
vec3 worldSpaceVec = normalize(vec3(modelMatrix * vec4(modelSpaceVec, 0)));

```

Other implementations I've seen do:

```
vec3 worldSpaceVec = normalize(mat3(modelMatrix) * modelSpaceVec);

```

(by the way, I'm not sure I visualize why the LearnOpenGL tutorial doesn't use `vec4(modelSpaceVec, 1)`; I'm not sure what either value would represent or how it would change the results. I assume this just a property of normals that we always represent them with a `w` of 0, but I don't get why it applies to the tangent and bitangent)

But more importantly, I don't understand the `modelMatrix * ...` part of the equation. According to [this answer](https://computergraphics.stackexchange.com/a/1506/8660), normals are bivectors, a different type of data which is represented by a row matrix instead of a column matrix (that is, bivectors are $\begin{bmatrix} x & y & z \end{bmatrix}$ where vectors are$\begin{bmatrix} x \\ y \\ z \end{bmatrix}$).

If my understanding is correct, then normals are of a different type than regular vectors, just like kilograms and liters are similar but different types; and they need to be treated differently in regard to transformations. So why does the tutorial use:

```
vec3 worldSpaceVec = normalize(vec3(modelMatrix * vec4(modelSpaceVec, 0)));

```

and not

```
vec3 worldSpaceVec = inverse(transpose(modelMatrix)) * modelSpaceVec;

```

or even

```
vec3 worldSpaceVec = inverse(transpose(mvpMatrix)) * modelSpaceVec;

```

?

In other words, should the tangent and bitangent vectors of a vertex be converted from one space to another using the same transformation matrix as the vertex's normal vector, and if so, why?

**Tags:** transformations, matrix, normal-mapping

> **Comments:**
> **username_1**: FYI The w=0 part is for all directions. Stuff that you don't want to have translation affect.  

---

## 1 answers

### Answer by username_2 on 2018-05-03. Score: 1 | Accepted answer

In Normal Mapping, you want to go to "Tangent Space", that is the space where the center of the coordinate system is your Vertex (/Fragment). Just like you go from Model Space to World Space and from World Space to Eye Space, you can go to Tangent Space with a matrix multiplication.

In Tangent Space, the vector $n\_T=\left(\begin{array}{c}0\\0\\1\end{array}\right)$ is always the Normal - since you read the normal $n\_N$ out of the Normal Map in your Fragment Shader, you will obviously not use $n\_T$ but $n\_N$ for lighting calculations and this choice of $n\_N$ rather than $n\_T$ brings about the nice effect normal mapping has.

What's a bit special is that every vertex has its own Tangent Space, which is why you need the tangent, bitangent$^1$ and (geometry) normal of every vertex to construct your TBN matrix.

So much for theory - since you didn't really ask about that specifically, I assume you understand this (otherwise just edit your question).

> by the way, I'm not sure I visualize why the LearnOpenGL tutorial doesn't use vec4(modelSpaceVec, 1); I'm not sure what either value would represent or how it would change the results. I assume this just a property of normals that we always represent them with a w of 0, but I don't get why it applies to the tangent and bitangent

Vectors in general are represented with a $0$ in the $w$ coordinate. If you look into a translation matrix, you will notice that the last row is the one that moves points around. For vectors, this is not a wanted behaviour - a vector is the same, no matter where, since it is a direction. So to avoid "translating" a vector, you set the $w$ coordinate to $0$. Since your tangent and bitangent vectors are vectors, the $w$ coordinate is $0$ here as well.

> But more importantly, I don't understand the modelMatrix \* ... part of the equation.

Using the the model matrix $M$ at this point is correct in *most* cases - but not all of them. The normal matrix $N$ is (as the answer you linked correctly said) the inverse transpose of the model matrix. But, since normals are vectors, you don't need a 4x4 matrix, a 3x3 matrix is just fine. And if you leave out that translation part, and you scale the same amount in all three coordinates, then the transpose of your model matrix is the same as the inverse of your model matrix. Therefore you get:

$
N = (M^{-1})^T = (M^T)^T = M
$

And that is why in most cases (i.e. everytime you use the same scaling in every coordinate) the normal matrix is the same as the model matrix.

> `vec3 worldSpaceVec = inverse(transpose(modelMatrix)) * modelSpaceVec;`

This is correct, however

> `vec3 worldSpaceVec = inverse(transpose(mvpMatrix)) * modelSpaceVec;`

this is not correct. Once you have transformed your normals into world space, you *need to* use the same view and projection matrix as before. Your view matrix brings your viewer into the origin (or rather it moves everything such that your viewer is the origin), inverse transposing this doesn't make sense (and similarly it doesn't make sense for the projection matrix. plus, the order in matrix multiplications is important, which is the next problem... don't do it ;-) )

Now, since you know that the model matrix *may* be the same as the normal matrix, you can (mathematically correctly) just go with the inverse transpose of the model matrix. Obviously this costs quite a lot of performance, especially inverting a matrix is costly. It is therefore more efficient to just go with the model matrix.

> In other words, should the tangent and bitangent vectors of a vertex be converted from one space to another using the same transformation matrix as the vertex's normal vector, and if so, why?

Unlike normals, tangent and bitangent vectors should be transformed with the model matrix, independently of the whether the normal matrix equals the modal matrix. A normal is always supposed to be perpendicular to a surface, and that's why simply taking the model matrix may be incorrect - in some cases the normal matrix would not be perpendicular to the surface anymore. Tangents however are always "lying" on the surface, so if you rotate a surface, the tangent must be rotated the same way to still "lie" on the surface.

---

$^1$ Sometimes this is called *binormal*, however Eric Lengyel explains why this is an incorrect term in [Mathematics for 3D Game Programming and Computer Graphics](http://www.mathfor3dgameprogramming.com/).

> **Comments:**
> **username_0**: "since you didn't really ask about that specifically, I assume you understand this" I do, but the added context is nice :) Thanks for this very thorough answer! Just to make sure I understood, you're saying that the only case where the inverse transpose isn't redundant is when, say, a mesh is being rescaled on one axis but not the others? Follow up question: if I do want to calculate the normals in camera space (for instance, to avoid floating point rounding errors), how do I do it? Would using `inverse(transpose(modelViewMatrix))` be enough?  
> **username_2**: `he inverse transpose isn't redundant is when, say, a mesh is being rescaled on one axis but not the others?` there is also the shearing transformation and i am not sure about that, but i doubt it leads to normal matrix = model matrix. but in general, that's the most likely case to brake equality. `if I do want to calculate the normals in camera space` you can do lighting in world space - you will need to transform your lighting and viewing vectors to world space and then to tangent space, but otherwise it doesn't matter.still, the view matrix part is wrong,it's just the `modelMatrix` you want  

---

