Normals

We need to explain “normals” .Normals are important for OpenGL shaders. There is a good explanation on shaders in the following link:

http://www.opengl-tutorial.org/beginners-tutorials/tutorial-8-basic-shading/

Even so; maybe an example is better the following is an image that uses the information provided by the normal node vectors, whereas the next one no.

Description: C:\Users\root\Desktop\SharpGLDemos\SimpleScene\SharpGLWinformsApplication4\bin\Debug\file.bmp

Description: C:\Users\root\Desktop\SharpGLDemos\SimpleScene\SharpGLWinformsApplication4\bin\Debug\file.bmp

This code already includes a normals calculator from the nodes and triangles. How do we calculate the normals?

The normals are vectors that go out of the plane, in this case the triangle. In each triangle, we calculate two vectors by subtracting the direction from Vertex0 and Vertex1, then Vertex0 and Vertex2.  Then, we make the cross product from those vectors.

The cross product of 2 vectors gives the perpendicular direction to those vectors (normal direction).  

Description: C:\Users\root\Desktop\SharpGLDemos\SimpleScene - with Normals\SharpGLWinformsApplication4\bin\Debug\file.bmp

Then, we normalize this vector to give it a length of one en each direction or in code:

double[] temp1 = new double[3]; //vector 1

double[] temp2 = new double[3]; //vector 2

 

for (int j = 0; j < 3; j++)

{

temp1[j] = (Nodes[Triangles[i, 0], j] - Nodes[Triangles[i, 1], j]);

temp2[j] = (Nodes[Triangles[i, 0], j] - Nodes[Triangles[i, 2], j]);

}

 

double[] nv = Cross(temp1, temp2);

double n = Norm(nv);

 

for (int j = 0; j < 3; j++)

{

nv[j] = nv[j] / n;

}

In other words, to get an orthogonal vector is to take a cross product.  So, if we could find two vectors that we knew were in the plane and took the cross product of these two vectors we know that the cross product would be orthogonal to both the vectors. 

However, since both the vectors are in the plane the cross product would then also be orthogonal to the plane. To make a vector orthogonal to a plane we need 3 points in the plane; which is easy for a triangle. Once we calculated the normals for each triangle, is easy to calculate the normal in each point. The normal will be the average of all the normals that have that point.

The code will be:

gl.Begin(OpenGL.GL_TRIANGLES);

            for (int i = 0; i < Triangles.GetLength(0); i++)

            {

               

                float x;

                float y;

                float z;

 

                x = (float)Nodes[Triangles[i, 0], 0];

                y = (float)Nodes[Triangles[i, 0], 1];

                z = (float)Nodes[Triangles[i, 0], 2];

 

                gl.Normal(

                    (float)Normals[Triangles[i, 0], 0],

                    (float)Normals[Triangles[i, 0], 1],

                    (float)Normals[Triangles[i, 0], 2]

                    );

 

                gl.Vertex(x, y, z);

 

                x = (float)Nodes[Triangles[i, 1], 0];

                y = (float)Nodes[Triangles[i, 1], 1];

                z = (float)Nodes[Triangles[i, 1], 2];

 

                gl.Normal(

                    (float)Normals[Triangles[i, 1], 0],

                    (float)Normals[Triangles[i, 1], 1],

                    (float)Normals[Triangles[i, 1], 2]

                    );

 

                gl.Vertex(x, y, z);

 

                x = (float)Nodes[Triangles[i, 2], 0];

                y = (float)Nodes[Triangles[i, 2], 1];

                z = (float)Nodes[Triangles[i, 2], 2];

 

                gl.Normal(

                   (float)Normals[Triangles[i, 2], 0],

                   (float)Normals[Triangles[i, 2], 1],

                   (float)Normals[Triangles[i, 2], 2]

                   );

                gl.Vertex(x, y, z);

            }

            gl.End();

We added some functions that are very useful for science and projects. First the geometry is scaled so the camera angle is fixed, but can translate. The geometry is fixed but the angle can be modified. With the left button in the mouse you can rotate the figure. The wheel in the mouse will make a zoom, there are some keys activated please look at the code.

Pressing Format will change the shader into wireframe:

Description: C:\Users\root\Desktop\SharpGLDemos\SimpleScene\SharpGLWinformsApplication4\bin\Debug\file.bmp

This is the “Save” function:

OpenGL gl = openGLControl.OpenGL;

 

    byte[] pixels = new byte[3 * openGLControl.Width* openGLControl.Height];

 

    gl.ReadPixels(0, 0, openGLControl.Width, openGLControl.Height, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, pixels);

 

 

    Bitmap bmp = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);

    System.Drawing.Imaging.BitmapData data =

        bmp.LockBits(this.ClientRectangle, System.Drawing.Imaging.ImageLockMode.WriteOnly,

                     System.Drawing.Imaging.PixelFormat.Format24bppRgb);

    gl.ReadPixels(0, 0, openGLControl.Width, openGLControl.Height,OpenGL.GL_BGR, OpenGL.GL_UNSIGNED_BYTE, data.Scan0);

 

    bmp.UnlockBits(data);

    bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);

 

    bmp.Save("file.bmp");

“Reset” will be reset the model and the view matrix to the original. If the right button of the mouse is pressed it will give the information of the Node in the geometry, and the selected node. This is the code:

OpenGL gl=openGLControl.OpenGL;

 

    int[] viewport=new int[4];

    double[] modelview = new double[16];

    double[] projection = new double[16];

    double winX, winY, winZ;

 

    byte[] p = new byte[4];   

 

 

    //glGetDoublev( GL_MODELVIEW_MATRIX, modelview );

    gl.GetDouble(OpenGL.GL_MODELVIEW_MATRIX,modelview);

 

    //glGetDoublev( GL_PROJECTION_MATRIX, projection );

    gl.GetDouble(OpenGL.GL_PROJECTION_MATRIX, projection);

   

    //glGetIntegerv( GL_VIEWPORT, viewport );

    gl.GetInteger(OpenGL.GL_VIEWPORT,viewport);

 

    winX = (double)x;

    winY = (double)viewport[3] - (double)y;

    //winY = -(double)y;

    //glReadPixels( x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );

 

 

    gl.ReadPixels(x, Convert.ToInt16(winY), 1, 1, OpenGL.GL_DEPTH_COMPONENT, OpenGL.GL_FLOAT, p);

    float temp = 0.0f;

 

    temp = System.BitConverter.ToSingle(p, 0);

 

 

    

    winZ = temp;

 

    double posX = 0;

    double posY = 0;

    double posZ = 0;

 

    gl.UnProject(winX, winY, winZ, modelview, projection, viewport, ref posX, ref posY, ref posZ);

 

 

    double[] CVector3 = gl.UnProject(winX, winY, winZ);

 

    CVector3 = new double[3] { posX , posY , posZ};

 

    return CVector3;

Once we used UnProject, we multiply this values by the model matrix to get the right x,y,z by the mouse. In other words, change from view to world coordinates.

  position = multMV(getTranspose(matrixModel), position);

Why is this useful? In several projects I found the necessity to be able to point to a specified point or triangle in the geometry to either modify or to know its properties. With this code we are able to do that. In the next tutorial we will show how to display values in 3d.