When rendering 3D scenes with transformations applied to the objects, normals have to be transformed with the transposed inverse of the model view matrix. So, with a normal $n$, modelViewMatrix $M$, the transformed normal $n'$ is

$$n' = (M^{-1})^{T} \cdot n $$

When transforming the objects, it is clear that the normals need to be transformed accordingly. But why, mathematically, is this the corresponding transformation matrix?

  • If the model matrix is made of translation, rotation and scale, you don't need to do inverse transpose to calculate normal matrix. Simply divide the normal by squared scale and multiply by model matrix and we are done. You can extend that to any matrix with perpendicular axes, just calculate squared scale for each axes of the matrix you are using instead. I wrote the details in my blog: lxjk.github.io/2017/10/01/Stop-Using-Normal-Matrix.html – Eric Oct 1 '17 at 23:52
up vote 20 down vote accepted

Here's a simple proof that the inverse transpose is required. Suppose we have a plane, defined by a plane equation $n \cdot x + d = 0$, where $n$ is the normal. Now I want to transform this plane by some matrix $M$. In other words, I want to find a new plane equation $n' \cdot Mx + d' = 0$ that is satisfied for exactly the same $x$ values that satisfy the previous plane equation.

To do this, it suffices to set the two plane equations equal. (This gives up the ability to rescale the plane equations arbitrarily, but that's not important to the argument.) Then we can set $d' = d$ and subtract it out. What we have left is:

$$n' \cdot Mx = n \cdot x$$

I'll rewrite this with the dot products expressed in matrix notation (thinking of the vectors as 1-column matrices):

$${n'}^T Mx = n^T x$$

Now to satisfy this for all $x$, we must have:

$${n'}^T M = n^T$$

Now solving for $n'$ in terms of $n$,

$$\begin{aligned}{n'}^T &= n^T M^{-1} \\ n' &= (n^T M^{-1})^T\\ n' &= (M^{-1})^T n\end{aligned}$$

Presto! If points $x$ are transformed by a matrix $M$, then plane normals must transform by the inverse transpose of $M$ in order to preserve the plane equation.

This is basically a property of the dot product. In order for the dot product to remain invariant when a transformation is applied, the two vectors being dotted have to transform in corresponding but different ways.

Mathematically, this can be described by saying that the normal vector isn't an ordinary vector, but a thing called a covector (aka covariant vector, dual vector, or linear form). A covector is basically defined as "a thing that can be dotted with a vector to produce an invariant scalar". In order to achieve that, it has to transform using the inverse transpose of whatever matrix is operating on ordinary vectors. This holds in any number of dimensions.

Note that in 3D specifically, a bivector is similar to a covector. They're not quite the same since they have different units: a covector has units of inverse length while a bivector has units of length squared (area), so they behave differently under scaling. However, they do transform the same way with respect to their orientation, which is what matters for normals. We usually don't care about the magnitude of a normal (we always normalize them to unit length anyway), so we usually don't need to worry about the difference between a bivector and a covector.

  • 2
    awesome explanation. however a bit fast on 2 points, a bit more details would be loved : 1. how do you jump from dot products to matrix products ? 2. between line 2 and 3 of last quoted section, what happens (n is moved from left to right a bit magically to me) – v.oddou Sep 16 '15 at 1:24
  • 4
    1. (a^T)b is the same as dot(a, b) if a and b are column matrices of the same dimension. Try out the math for yourself! 2. (AB)^T = (B^T)(A^T), and (A^T)^T = A For more matrix identities, check out The Matrix Cookbook – Mokosha Sep 16 '15 at 1:30
  • 3
    @v.oddou Yep, Mokosha is right. Dot product can be expressed as multiplying a 1×n matrix (row vector) with a n​×1 matrix (column vector); the result is a 1×1 matrix whose single component is the dot product. The transpose of a column vector is a row vector, so we can write a·b as a^T b. For the second question, transposing a product of matrices is equivalent to transposing the individual factors and reversing their order. – Nathan Reed Sep 16 '15 at 5:42
  • perfect, its all clear without issue now. thanks both. – v.oddou Sep 16 '15 at 6:09
  • @NathanReed (Gosh this takes me back to the early PowerVR days where we modelled most things with planes). It might also be worth mentioning that, for optimisation purposes, if you have a matrix Mr that only contain rotations, (i.e. is orthogonal) then Inverse(Mr) = Transpose(Mr), and so Trans(Inverse(Mr)=_Mr_. You can also take shortcuts with the translation part and if you know the scaling is uniform. FWIW in the SGL PowerVR graphics library, we used to keep booleans to track whether a transformation matrix had these properties to save costs with the normal transformations. – Simon F Sep 16 '15 at 8:32

This is simply because normals are not really vectors! They are created by cross products, which results in bivectors, not vectors. Algebra works much different for these coordinates, and geometric transformation is just one operation that behaves differently.

A great resource for learning more about this is Eric Lengyel's presentation on Grassman Algebra.

  • Normals are also so-called pseudovectors. As a generalization and rule of thumb, everything resulting from a cross product (e.g. planes) will be transformed in a similar fashion. – Matthias Oct 4 '17 at 17:03

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.