#### Archived

This topic is now archived and is closed to further replies.

# transforming vertex normals

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

## Recommended Posts

okay, i need to do a little explaining first. I''m building a simple software rasterizer and an accompanying API that is modeled off of OpenGL (a very basic version of OpenGL). It''s coming along pretty well so far. I have a rotating cube in the screen that''s being lit by three different kinds of lights. It also has point sampled textures applied to it. The front end code looks very very similar to OpenGL. It''s kind of neat! Things left to do with the API are to include the option for bilinear texture filtering, fix some issues with clipping against the near plane, add support for a simple zbuffer, add support for alpha blending... there''s a lot left to do. but i''m having a LOT of fun with the project. And I''m learning a lot too, always a plus. Okay, here''s where I''m having a problem. I am running into a very strange error with this rotating cube demo. I know that I''m dealing with an orthogonal ModelView matrix, so the vertex normals can be transformed by the same matrix used on the vertices themselves (according to Eric Lengyel''s "Mathematics for 3D Game Programming and Computer Graphics", awesome book btw). So rather than go through the trouble of having to create an inverse transpose matrix of the current MV matrix every time it''s modified, i just use the MV matrix. The front, back, left, and right faces are illuminated correctly (with gouraud shading, it''s cool). However, the top and bottom faces are being illuminated. I''ve looked over a printout of the current MV matrix and the current normal the normals for the top and bottom face are not being transformed correctly. Here''s an example of the printout: CurrentNormal=[0.000000, 1.000000, 0.000000, 1.000000, ] MODEL_VIEW= 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 -4.000000 0.000000 0.000000 0.000000 1.000000 INV_MODEL_VIEW= 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 CurrentNormal=[0.000000, 1.000000, 0.000000, 1.000000, ] MODEL_VIEW= 1.000000 0.000000 0.000000 0.000000 0.000000 0.999550 0.029995 0.000000 0.000000 -0.029995 0.999550 -4.000000 0.000000 0.000000 0.000000 1.000000 INV_MODEL_VIEW= 1.000000 0.000000 0.000000 0.000000 0.000000 0.999550 0.029995 0.000000 0.000000 -0.029995 0.999550 0.000000 0.000000 0.000000 0.000000 1.000000 CurrentNormal=[0.000000, 0.999550, -0.029995, 1.000000, ] MODEL_VIEW= 1.000000 0.000000 0.000000 0.000000 0.000000 0.998201 0.059964 0.000000 0.000000 -0.059964 0.998201 -4.000000 0.000000 0.000000 0.000000 1.000000 INV_MODEL_VIEW= 1.000000 0.000000 0.000000 0.000000 0.000000 0.998201 0.059964 0.000000 0.000000 -0.059964 0.998201 0.000000 0.000000 0.000000 0.000000 1.000000 CurrentNormal=[0.000000, 0.998201, -0.059964, 1.000000, ] MODEL_VIEW= 1.000000 0.000000 0.000000 0.000000 0.000000 0.995953 0.089879 0.000000 0.000000 -0.089879 0.995953 -4.000000 0.000000 0.000000 0.000000 1.000000 INV_MODEL_VIEW= 1.000000 0.000000 0.000000 0.000000 0.000000 0.995953 0.089879 0.000000 0.000000 -0.089879 0.995953 0.000000 0.000000 0.000000 0.000000 1.000000 CurrentNormal=[0.000000, 0.995953, -0.089879, 1.000000, ] Note that the INV_MODEL_VIEW matrix is the same as the modelview except for the translation portion, i just have separate matrices for correctness. In this example, the top face is being rotated forward (out of the screen, so as to become visible). The z-coordinate of the vertex normal should become more positive, which would be the same as pointing out of the screen. But, it''s going in the opposite direction. Note that the transpose of the transformation matrix would transform the normal in the correct way. Well, to make a long story short, i tried using the transpose of the MV matrix and the inverse transpose, but neither technique worked correctly. I''ve poured over all the code and even gone through all the calculations by hand. Everything is mathematically correct but the numbers aren''t what they should be. So there must be something wrong with the technique I''m using? I''m sorry if this post is vague. The problem involves a lot of code and is kind of complicated in and of itself. Thanks in advance for any help or advice you can give me. I''m all out of ideas. -Justin

##### Share on other sites
I'm not quite sure I follow your listing, are those normals pre or post transform or a mix? Are they supposed to be homogenous? (in which case the w coordinate must be 0, you don't want them translated) Or is that trailing 1 the length?

I'm pretty sure (but I haven't gone through it) that your technique should be working correctly.

[edited by - JuNC on August 17, 2003 6:04:17 PM]

##### Share on other sites
hey JuNC. the initial normal is [0.0, 1.0, 0.0, 1.0] and all the normals in the listing are post transformation by the INV_MODEL_VIEW matrix.

I know, i can''t figure out why my technique isn''t working. it''s messed. I''m so confused haha.

##### Share on other sites
Here''s what I think (though I might be wrong).

You can''t use a matrix that has a translation to transform your normals, the matrix that transforms the normal must be purely a rotation. If you translate the normal, and then normalize it, you probably won''t notice that you''ve done something wrong, but the direction that the normal points will be completely wrong.

So you know where to find the translation part of a matrix, right? Its the top 3 entries on the right side (which includes the -4 on the modelview matrix in your example). So, try transforming the normal with the translation set to 0 and see if that works.

##### Share on other sites
Note that Eric uses 3x3 matrices in his description, the 4x4 counterpart of which has zero translation, as previously mentioned.

##### Share on other sites
quote:

hey JuNC. the initial normal is [0.0, 1.0, 0.0, 1.0] and all the normals in the listing are post transformation by the INV_MODEL_VIEW matrix.

If that vector is [x,y,z,w] then it is wrong. Vectors in 3 space *must* have a w of 0. Only (3 space) points have a w of 1. You can either break out two transform routines (one that ignores the final column of the matrix for vectors) like the above two solutions, or store the w's correctly.

[edited by - JuNC on August 18, 2003 5:35:37 AM]

##### Share on other sites
use n = [x,y,z,0], and transform that trough the inverse transpose matrix.

why? i''ve read in some nvidia document why..

"take a look around" - limp bizkit

##### Share on other sites
just a reminder:
to transform vertex normals with matrix that has perspective effect, you need to transform the full plane equation (x,y,z,d), instead of just the normal (x,y,z,0).
see
transform normals

##### Share on other sites
To start with, I took an identity matrix and rotated it on all 45 degrees in each direction I could, x, y, and z.
0.50000 0.50000 -0.70711 0.00000
-0.14645 0.85355 0.50000 0.00000
0.85355 -0.14645 0.50000 0.00000
0.00000 0.00000 0.00000 1.00000
Then I pick a resulting ray, I take the Z one. I just did this to get a normal, that's all, normally(grin) you'll already have the normal before you want to transform it. A normal is a ray, is an axis, or whatever you want to call it.
I load another identity matrix and drop these X Y and Z components for this matrix in to the corresponding position spots.
1.00000 0.00000 0.00000 0.85355
0.00000 1.00000 0.00000 -0.14645
0.00000 0.00000 1.00000 0.50000
0.00000 0.00000 0.00000 1.00000
The transformed normal is 0.85355, -0.14645, 0.50000
I can now multiply this matrix by any rotation matrix, the result should be a properly tranformed normal.
Rotated by -45 degress on the X axis:
1.00000 0.00000 0.00000 0.85355
0.00000 0.70711 -0.70711 -0.45711
0.00000 0.70711 0.70711 0.25000
0.00000 0.00000 0.00000 1.00000
Looks good, as expected, X component doesn't change when rotated about the X axis.

Ok, I'm ready for somebody to tell me how I did this wrong. I already know there MUST be a better way to do it, I just wanted to chime in and hopefully provoke some better answers.

[edited by - wudan on August 18, 2003 4:04:02 PM]

[edited by - wudan on August 18, 2003 4:11:26 PM]

##### Share on other sites
I have no idea what you are talking about

A normal is a vector representing a plane. Rays are something very different (position & direction). You could all it an axis but probably don''t want to.

Explain what you are trying to do and we''ll tell you whats wrong.

quote:

1.00000 0.00000 0.00000 0.85355
0.00000 1.00000 0.00000 -0.14645
0.00000 0.00000 1.00000 0.50000
0.00000 0.00000 0.00000 1.00000
The transformed normal is 0.85355, -0.14645, 0.50000

Explain how you got this. Sounds like something is severely wrong.

##### Share on other sites
"A normal is a vector representing a plane." <-- we'll use this.

So I take "0.85355, -0.14645, 0.50000", a normal, which is a vector representing a plane. I plug those vector values in to the corresponding x, y, and z spots in an identity matrix (along the right hand side, as above), viola, I have a 4x4 matrix representation of that normal/vector.

Then I can rotate the normal through regular matrix transformation, resulting in a transformed normal. As long as I don't get it confused with regular 'worldspace' vectors, and handle it properly, it should be fine, afaik.

Basically, my thinking is, if it is a vector in any sense, I can transform it like a vector.

As I said, I know there is a better way to do this, but that's for somebody else to tell me.

All tolled, it looks like the method that chipmunk is using is correct.

[edited by - wudan on August 19, 2003 9:43:57 AM]

##### Share on other sites
I kinda see how you got there, but I'm not sure why.

Transformation of a point P by a 4X4 matrix M:

 P' = M * P [x']       [x] [y'] = M * [y] [z']       [z] [1]        [1]

Transformation of a normal N by (e.g. the same) 4X4 matrix M:

 N' = (MT)-1 * N [x']        [x] [y'] = (MT)-1 * [y] [z']        [z] [0]         [0]

(I might have the T,-1 inside out)

However, if M is orthogonal then MT = M-1
so (MT)-1 = M and you can do

 N' = M * N

Which is what the OP was trying to do.

[edited by - JuNC on August 19, 2003 11:28:36 AM]

##### Share on other sites
I haven''t read the whole thing but i guess what you might be doing wrong is transforming the normals using the same MV matrix that you are using for vertex transformationg. That''s wrong... i am sure someone have already mentioned it above... you should not TRANSLATE the normals. Only the rotational components of the MV matrix should be used.. ie. ONLY the top-left 3x3 part of the 4x4 matrix. Just leave out the last column and last row of the 4x4 matrix and use the remaining 3x3 matrix.

in OGL vertex shader this is achieved by

DP3 NormalVector.x NormalVector ModelViewMat[0]
DP3 NormalVector.y NormalVector ModelViewMat[1]
DP3 NormalVector.z NormalVector ModelViewMat[2]

Notice.. we r doing a DP3 (3 component dot product).