PDA

View Full Version : Obtaining normal Matrix for 1.3+ shader



Zylzyl
01-10-2014, 06:32 PM
Hello.

I am porting code to work with GLSL >=1.3 shaders.
The gl_NormalMatrix built-in uniform, among others, is deprecated and unsupported in GLSL 1.3 and above.
However, OGL, to my understand, still calculates matrices when using the traditional functions such as glTransformf(), glPushMatrix(), etc.

I have the following code to get these and inject them to my uniforms, but there is no GL definition for normal matrix. Why is this missing, or is it called differently?


void setUniforms() {

GLfloat m[16];

glGetFloatv(GL_MODELVIEW_MATRIX, &m[0]);
glUniformMatrix4fv(modelViewMatrixLoc, 1, GL_FALSE, &m[0]);

glGetFloatv(GL_PROJECTION_MATRIX, &m[0]);
glUniformMatrix4fv(projectionMatrixLoc, 1, GL_FALSE, &m[0]);

// Error: GL_NORMAL_MATRIX is not a thing. :-(
glGetFloatv(GL_NORMAL_MATRIX, 1, GL_FALSE, &m[0]);
glUniformMatrix4fv(normalMatrixLoc, 1, GL_FALSE, &m[0]);
}

So yeah, must I really calculate this by myself now?

Thanks in advance!

Alphaomega86
01-11-2014, 09:08 AM
Hey,

Yes, you have to "calculate" the normal matrix by your own. But this is really easy.
The model matrix a 4x4 matrix. All you have to do now is just convert the Model matrix to a simple 3x3 matrix.
This is because the normals do not need a translation or a scale factor. All they need is the models rotation.

Model matrix e.g.:


1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1


this will become:


1 0 0
0 1 0
0 0 1


That's all, hope this will help you ;)

- Daniel

Zylzyl
01-11-2014, 09:19 AM
I don't get why they pretty much force people to implement their own matrix stack now, rofl.

Anyway, I can see truncating the translation column, but scale matrices can affect more than just the bottom row, as far as I know at least. Also scales will (can) affect normals, but in a different manner.

I don't use scales, so thank God.


void setUniforms() {

GLfloat m[16];

glGetFloatv(GL_PROJECTION_MATRIX, &m[0]);
glUniformMatrix4fv(projectionMatrixLoc, 1, GL_FALSE, &m[0]);

glGetFloatv(GL_MODELVIEW_MATRIX, &m[0]);
glUniformMatrix4fv(modelViewMatrixLoc, 1, GL_FALSE, &m[0]);

// Error: GL_NORMAL_MATRIX is not a thing. :-(
//glGetFloatv(GL_NORMAL_MATRIX, 1, GL_FALSE, &m[0]);

// HACKHACK: As long as we don't do scale transformations (which we don't) we will be fine doing just this.
m[12] = 0;
m[13] = 0;
m[14] = 0;
glUniformMatrix4fv(normalMatrixLoc, 1, GL_FALSE, &m[0]);
}

I hope I will get away with doing just that. Only other geometric data I will have to transform manually are light positions, so I should be fine for now.

In any case, thanks for letting me know.

chbaker0
01-11-2014, 10:17 PM
Yes, you have to "calculate" the normal matrix by your own. But this is really easy.
The model matrix a 4x4 matrix. All you have to do now is just convert the Model matrix to a simple 3x3 matrix.
This is because the normals do not need a translation or a scale factor. All they need is the models rotation.
l

It is a little more than that, actually. First you can just reduce it to a 3x3 matrix as you said, but then you must take its inverse, then transpose it (or fitting called, the inverse transpose). Changing it to 3x3 only removes the translation factor. I can't explain the reasoning behind this better than this (http://arcsynthesis.org/gltut/Illumination/Tut09%20Normal%20Transformation.html)


I don't get why they pretty much force people to implement their own matrix stack now, rofl.


The idea is to separate actual graphics related stuff (i.e. lights, transformations, fog, etc) from the API, so you are just dealing with the data. That way, how you format and use your data is totally up to you, and you write your code and shaders accordingly.

On another note, check out the GLM library (http://glm.g-truc.net/0.9.5/index.html) to replace the matrix math functions that have been deprecated, and check out the Unofficial OpenGL SDK (http://glsdk.sourceforge.net/docs/html/index.html), where you can find a matrix stack implementation if you must use one.

Jesse
01-15-2014, 11:41 AM
It is a little more than that, actually. First you can just reduce it to a 3x3 matrix as you said, but then you must take its inverse, then transpose it (or fitting called, the inverse transpose). Changing it to 3x3 only removes the translation factor. I can't explain the reasoning behind this better than this (http://arcsynthesis.org/gltut/Illumination/Tut09%20Normal%20Transformation.html)
There's no need to do an inverse transpose all the time. The website you linked to mentions they are using non-uniform scaling and rotations. He mentions this on the same page:


One more thing to note before we move on. Doing the inverse-transpose is only really necessary if you are using a non-uniform scale. In practice, it's actually somewhat rare to use this kind of scale factor. We do it in these tutorials, so that it is easier to build models from simple geometric components.

A rotation is certainly orthogonal. By mathematical induction, the product of any finite number of orthogonal matrices is again orthogonal--so rotations are not really a problem. As the author says, a non-uniform scale will require the inverse-transpose so there's nothing we can do about those.

A uniform scale, however, won't require the inverse-transpose. To see this, note that a uniform scale is not orthogonal. Consider this: is the transpose of a uniform scale equal to its inverse? No, unless it is the identity matrix. So it appears that we may need to compute the inverse-transpose for this case after all. Since the scale is uniform, however, the transform only affects the magnitude of the normal vectors but not the direction. So re-normalizing the normals will work in this special case and so we avoid computing the inverse-transpose.