Sign in to follow this  

Transposed inverted matrix for normal transformation

This topic is 4304 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Quote:
Original post by JohnBolton
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.


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 this post


Link to post
Share on other sites
Quote:
Original post by janta
Quote:
Original post by JohnBolton
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.


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 this post


Link to post
Share on other sites
Guest Anonymous Poster
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.

Share this post


Link to post
Share on other sites

This topic is 4304 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this