DGL
https://delphigl.com/forum/

normals in vertex shader with opengl3.x
https://delphigl.com/forum/viewtopic.php?f=20&t=8900
Seite 1 von 1

Autor:  noeska [ Mo Dez 28, 2009 16:04 ]
Betreff des Beitrags:  normals in vertex shader with opengl3.x

Is there a best way for normals in glsl?

E.g. on modifying the brick shader from the orange book i stumbled upon this line:
Code:
  1.     vec3 tnorm      = normalize(gl_NormalMatrix * gl_Normal);

So with opengl 3.x we no longer have gl_NormalMatrix so better provide my own. And have a look on the delphigl wiki on the go:
Code:

But i do not fully understand it, eg:
Code:
  1. for (unsigned int i=0;i<3;i++)
  2.             for (unsigned int j=0;j<3;j++)
  3.               m_NormalMatrix[i*3+j]=tnmat[i*3+j]/d;
  4.           return tnmat;

What is the endresult? tnmat or m_NormalMatrix?
But when using it with the following in the vertex shader:
Code:
  1.     vec3 tnorm      = normalize(normalMatrix * normal);

Some sides of the cube look to dark e.g. are pitch black.
This is how my normal matrix and determinant code looks like:
Code:
  1.  
  2. type
  3.   GLMatrix4 = array[0..15] of GLfloat; // 4x4 Matrix type
  4.   GLMatrix3 = array[0..8] of GLfloat; // 3x3 Matrix type
  5.  
  6. function determinant(const amatrix: GLmatrix3): GLFloat;
  7. begin
  8.   result := amatrix[0]*((amatrix[4]*amatrix[8])-(amatrix[5]*amatrix[7]))
  9.           - amatrix[1]*((amatrix[3]*amatrix[8])-(amatrix[5]*amatrix[6]))
  10.           + amatrix[2]*((amatrix[3]*amatrix[7])-(amatrix[4]*amatrix[8]))
  11. end;
  12.  
  13. procedure normalMatrix(var aresult: GLmatrix3; const modelviewmatrix: GLmatrix4);
  14. var
  15.   tnmat : GLmatrix3;
  16.   m_NormalMatrix  : GLmatrix3;
  17.   d     : GLfloat;
  18.   i,j   : GLuint;
  19. begin
  20.   //Kopiere den Rotations- und Skalierungsanteil aus der Modelview Matrix.
  21.   for i:=0 to 2 do
  22.     for j:=0 to 2 do
  23.       m_NormalMatrix[i*3+j]:=modelviewmatrix[i*4+j];
  24.  
  25.   //Inverse mit Hilfe der Determinante berechnen und Transponieren in einem Schritt(im Fall der Rotationsmatrix
  26.   //ist es nicht wichtig in welcher Reihenfolge Transponieren und Determinieren geschehen.)
  27.  
  28.   d:=Determinant(m_NormalMatrix);
  29.   tnmat[0]:=m_NormalMatrix[4]*m_NormalMatrix[8]-m_NormalMatrix[5]*m_NormalMatrix[7];
  30.   tnmat[3]:=m_NormalMatrix[5]*m_NormalMatrix[6]-m_NormalMatrix[3]*m_NormalMatrix[8];
  31.   tnmat[6]:=m_NormalMatrix[3]*m_NormalMatrix[7]-m_NormalMatrix[4]*m_NormalMatrix[6];
  32.  
  33.   tnmat[1]:=m_NormalMatrix[2]*m_NormalMatrix[7]-m_NormalMatrix[5]*m_NormalMatrix[8];
  34.   tnmat[4]:=m_NormalMatrix[0]*m_NormalMatrix[8]-m_NormalMatrix[2]*m_NormalMatrix[6];
  35.   tnmat[7]:=m_NormalMatrix[1]*m_NormalMatrix[6]-m_NormalMatrix[1]*m_NormalMatrix[7];
  36.  
  37.   tnmat[2]:=m_NormalMatrix[1]*m_NormalMatrix[5]-m_NormalMatrix[2]*m_NormalMatrix[4];
  38.   tnmat[5]:=m_NormalMatrix[2]*m_NormalMatrix[3]-m_NormalMatrix[0]*m_NormalMatrix[5];
  39.   tnmat[8]:=m_NormalMatrix[0]*m_NormalMatrix[4]-m_NormalMatrix[1]*m_NormalMatrix[3];
  40.  
  41.   for i:=0 to 2 do
  42.     for j:=0 to 2 do
  43.       m_NormalMatrix[i*3+j]:=tnmat[i*3+j]/d;
  44.  
  45.   aresult := tnmat; //or should it be m_NormalMatrix?
  46. end;
  47.  

Going away from that i decided to use something more simple:
Code:
  1.     vec3 tnorm      = (modelViewMatrix*vec4(normal, 0.0)).xyz;

And everything looks like i expect it to be.

So is there somthing wrong with my code? Or can i always use the last regarding to normals or is a normalmatrix a must need?

Autor:  Coolcat [ Mo Dez 28, 2009 16:32 ]
Betreff des Beitrags:  Re: normals in vertex shader with opengl3.x

Probably that method should return m_NormalMatrix ;)

However, if that doesn't work, you may try this Java code:
Code:
  1. public double _00, _01, _02, _03;
  2. public double _10, _11, _12, _13;
  3. public double _20, _21, _22, _23;
  4. public double _30, _31, _32, _33;
  5.  
  6. public Matrix33d getNormalMatrix() {
  7.     double det = _00 * (_22*_11 - _21*_12)
  8.                - _10 * (_22*_01 - _21*_02)
  9.                + _20 * (_12*_01 - _11*_02);
  10.     return new Matrix33d(
  11.          (_22*_11 - _12*_21) / det, -(_22*_10 - _12*_20) / det,  (_21*_10 - _11*_20) / det,
  12.         -(_22*_01 - _02*_21) / det,  (_22*_00 - _02*_20) / det, -(_21*_00 - _01*_20) / det,
  13.          (_12*_01 - _02*_11) / det, -(_12*_00 - _02*_10) / det,  (_11*_00 - _01*_10) / det
  14.     );
  15. }


Zitat:
Going away from that i decided to use something more simple:
Code:
  1. vec3 tnorm = (modelViewMatrix*vec4(normal, 0.0)).xyz;

And everything looks like i expect it to be.

That will work only in a (common) special case: The upper left part of your modelViewMatrix needs to be orthonormal. The NormalMatrix is the transpose of the inverse of modelViewMatrix. So, if modelViewMatrix is orthonormal, you can invert it just by transposing it. The transpose of the transpose is again the matrix you started with.
The upper left part of your modelViewMatrix is orthonormal, if modelViewMatrix does ONLY contain rotation and/or translation, NO scaling or shearing.

Autor:  noeska [ Mo Dez 28, 2009 20:32 ]
Betreff des Beitrags:  Re: normals in vertex shader with opengl3.x

both m_normalmatrix and tmat give wrong results making some faces of my cube black.

while looking at your java example i discovered at typo in my determinant code. The last 8 should have been a 6.
But as it turned out that was not the solution.
Ok then further with the java example and compare that with the normalmapmatrix calculation itself.
A quick comparision tells met that there are differences, so on with the hard job of renumbering the indices.
Now i have the following source:
Code:
  1.  
  2. function determinant(amatrix: GLmatrix3): GLFloat;
  3. begin
  4.   result := amatrix[0]*(amatrix[8]*amatrix[4]-amatrix[5]*amatrix[7])
  5.           - amatrix[1]*(amatrix[8]*amatrix[3]-amatrix[5]*amatrix[6])
  6.           + amatrix[2]*(amatrix[7]*amatrix[3]-amatrix[4]*amatrix[6]);
  7. end;
  8.  
  9. procedure normalMatrix(var aresult: GLmatrix3; modelviewmatrix: GLmatrix4);
  10. var
  11.   tnmat : GLmatrix3;
  12.   m_NormalMatrix  : GLmatrix3;
  13.   d     : GLfloat;
  14.   i,j   : GLuint;
  15. begin
  16.   //Kopiere den Rotations- und Skalierungsanteil aus der Modelview Matrix.
  17.   for i:=0 to 2 do
  18.     for j:=0 to 2 do
  19.       m_NormalMatrix[i*3+j]:=modelviewmatrix[i*4+j];
  20.  
  21.   //Inverse mit Hilfe der Determinante berechnen und Transponieren in einem Schritt(im Fall der Rotationsmatrix
  22.   //ist es nicht wichtig in welcher Reihenfolge Transponieren und Determinieren geschehen.)
  23.  
  24.   d:=Determinant(m_NormalMatrix);
  25.   tnmat[0]:=(m_NormalMatrix[4]*m_NormalMatrix[8]-m_NormalMatrix[5]*m_NormalMatrix[7])/d;
  26.   tnmat[3]:=-(m_NormalMatrix[1]*m_NormalMatrix[8]-m_NormalMatrix[2]*m_NormalMatrix[7])/d;
  27.   tnmat[6]:=(m_NormalMatrix[1]*m_NormalMatrix[5]-m_NormalMatrix[4]*m_NormalMatrix[2])/d;
  28.  
  29.   tnmat[1]:=-(m_NormalMatrix[8]*m_NormalMatrix[3]-m_NormalMatrix[5]*m_NormalMatrix[6])/d;
  30.   tnmat[4]:=(m_NormalMatrix[8]*m_NormalMatrix[0]-m_NormalMatrix[2]*m_NormalMatrix[6])/d;
  31.   tnmat[7]:=-(m_NormalMatrix[5]*m_NormalMatrix[0]-m_NormalMatrix[3]*m_NormalMatrix[2])/d;
  32.  
  33.   tnmat[2]:=(m_NormalMatrix[7]*m_NormalMatrix[3]-m_NormalMatrix[6]*m_NormalMatrix[4])/d;
  34.   tnmat[5]:=-(m_NormalMatrix[7]*m_NormalMatrix[0]-m_NormalMatrix[6]*m_NormalMatrix[1])/d;
  35.   tnmat[8]:=(m_NormalMatrix[4]*m_NormalMatrix[0]-m_NormalMatrix[3]*m_NormalMatrix[1])/d;
  36.  
  37.   aresult := tnmat;
  38. end;
  39.  


And this actualy seems to work ... (at least i do not get pitch black sides anymore ;-) )

Autor:  noeska [ Mo Dez 28, 2009 22:32 ]
Betreff des Beitrags:  Re: normals in vertex shader with opengl3.x

The complete example: http://www.noeska.net/downloads/ogl3brick.zip

Seite 1 von 1 Alle Zeiten sind UTC + 1 Stunde
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/