# Transposed inverted matrix for normal transformation

## Recommended Posts

Hi there. There is one obscure comment in directx's documentation, there it is: ************** D3DXVec3TransformNormal Function ... Remarks If you transform a normal by a non-affine matrix, the matrix you pass to this function should be the transpose of the inverse of the matrix you would use to transform a coordinate. *************** Well, I dont get the point of using the transposed inverted matrix to transform a normal, whereas the matrix itself suits well for transforming the vertice. However, when I also use the matrix itself to transform the normal, the results are indeed incorect. In fact, they happen to be, sometimes, but not all the time. Probably when i dont use an affine matrix. I understand why not using an affine transform can mess up the normals, but why would inverting and transposing give better results ? Is there someone out ther to give me a bit of explanations or point tosome resource. "Hi-level" maths welcome. (linear algebra and all that stuff i can handle, well I think I can :p )

##### Share on other sites
Hunker down and read this. (Specifically, the "transforming normals" section.)

##### Share on other sites
Transforming normals, nice images and derivation.

Something to play with:

struct TestNormalTransform {  TestNormalTransform() {    Mat3 tm(true); // Construct as identity    tm.print();    tm.y.y = 1.5f; // Scale along y axis.    Mat3 rot(~Vec3(0,0,1),rDegToRad(15.f));#if 1    Mat3 tm2 = tm ^ rot; // Apply rotation followed by scale.#else    Mat3 tm2 = rot ^ tm; // Apply scale followed by rotation.#endif    tm2.print();    Mat3 tm3 = tm2.inverseCopy().transposedCopy(); // Compute inverse followed by transpose.    tm3.print();    Mat3 tm4 = tm3 ^ tm3.inverseCopy(); // Verify proper inverse (result should be identity).    tm4.print();    Vec3 v(1,1,0);    v.normalize();    v.print();    v = tm3 ^ v;  // Normal transformation. tm3 dots (transforms) v    v.print();    Vec3 v2(-1,1,0);    v2.normalize();    v2 = tm2 ^ v2; // Point transformation.    flt na = v.dot(v2);    lprintf("Normal - point angle (should be zero): %f\n",na);    Vec3 nv = ~v; // normalized copy    flt angle = rRadToDeg(rAtan2(nv.y,nv.x)); // In must cases, the angle will change as well (when scale is present).    lprintf("x %f y %f z %f v %f a %f\n",tm3.x.length(),tm3.y.length(),tm3.z.length(),v.length(),angle);  }} testNormalTransform;

Any time scale is involved, the normal must be normalized, as its length will change in most cases. The normal angle relative to a point on the surface of the object will remain orthogonal.

[Edited by - John Schultz on March 6, 2006 5:18:38 PM]

##### Share on other sites
Mathematically, it is correct to use the transpose of the inverse. The articles above show why. But since the transposed inverse of a rotation matrix (orthonormal, no scale or translation) is the same as the original, you can normally use the original, instead of computing the transposed inverse.

##### Share on other sites
Quote:
 Original post by JohnBoltonMathematically, it is correct to use the transpose of the inverse. The articles above show why. But since the transposed inverse of a rotation matrix (orthonormal, no scale or translation) is the same as the original, you can normally use the original, instead of computing the transposed inverse.

if I get your point, DirectX documentation is erronous. Indeed, almost all transformations that ever happen in our 3D virtual world are affine transformations (rotating, scaling, translating) since they preserve some properties of the object they transform (namely parallelism)

However, only a few of these transformations's matrix (which are all affine matrix) verify the property that T(M-1) = M, as you stated, only pure rotation matrix.

Or I missed something...

##### Share on other sites
Quote:
Original post by janta
Quote:
 Original post by JohnBoltonMathematically, it is correct to use the transpose of the inverse. The articles above show why. But since the transposed inverse of a rotation matrix (orthonormal, no scale or translation) is the same as the original, you can normally use the original, instead of computing the transposed inverse.

if I get your point, DirectX documentation is erronous. Indeed, almost all transformations that ever happen in our 3D virtual world are affine transformations (rotating, scaling, translating) since they preserve some properties of the object they transform (namely parallelism)

However, only a few of these transformations's matrix (which are all affine matrix) verify the property that T(M-1) = M, as you stated, only pure rotation matrix.

Or I missed something...

If you use scale, you'll need to use the transposed inverse (and normalize your normals after transformation). Additionally (depending on your pipeline implementation), you cannot apply translation to your normals.

##### Share on other sites
Normally in computer graphics points are represented by (x y z 1) and normals are represented by (x y z 0). That last coordinate is just used to allow translations to be performed with matrix multiplication. Since it is 0 in the normals, the normals are not translated by a translation matrix. Therefore as long as the matrix is only rotation and translation, it will transform normals correctly.

## Create an account

Register a new account

• ## Partner Spotlight

• ### Forum Statistics

• Total Topics
627664
• Total Posts
2978522

• 10
• 10
• 12
• 22
• 13