## OpenGL|ES tutorials - Follows NeHe track.

Apprentice
Posts: 13
Joined: 2008.10
Post: #10
Well, sorry it took a while. I was busy, hope you enjoy lesson 5. Also, please feel free to download the PDF versions of these lessons from my site. The links are in the initial post. Enjoy!

Drawing 3D models that rotate
Today we will look into the creation of 3D models for both the Pyramid and the Cube from the NeHe tutorials. This will take a divergent step away from what we are used to doing. We are going to create our 5 points for our triangle and create an index list along the same way that GLGravity did.
Code:
```const GLfloat triVerticies[] = { 0.0f, 1.0f, 0.0f,            // 0 - top of the triangle -1.0f, -1.0f,  0.0f,        // 1 - SouthWest corner B+-----+G 1.0f, -1.0f,  0.0f,        // 2 - SouthEast corner  | \ / |                 //                R 1.0f, -1.0f, -1.0f,        // 3 - NorthEast corner  | / \ | -1.0f, -1.0f, -1.0f        // 4 - NorthWest corner G+-----+B };```
This array shows how we set up our pyramid along with a color guide to help us order our index list. Something to keep in mind is that the order of our vertexes in the index must correspond to the order of the colors in the color array. We also need a count of our indexes, this is the total indexes in triIndexes including the number at the front.
Code:
```// We need the number of vertexes we will be rendering, this is 16 const GLint triIndexCount = 16; // List our indexes. The first number is the number of indexes in our face // Followed by the RGB faces. these correspond to the order of the tricolors array. // Keep that in mind as you order your indexes. const GLfloat triIndexes[] = { //  #, R, G, B     3, 0, 1, 2,        // front face - top, sw, se     3, 0, 3, 2,        // right face - top, ne, se     3, 0, 3, 4,        // back face - top, ne, nw     3, 0, 1, 4        // left face - top, sw, nw }```
Later you will see that we change from glDrawArrays to glDrawElements. Because of this we also need to modify our triColor array. This array now corresponds to each color in our index list. Because we have 5 points, we now need 5 arrays. Our top point is red, points 1 and 3 are green, and points 2 and 4 are blue. So here is our new color array.
Code:
```// Each color is associated with a specific vertex in the index list now. GLubyte triColors[] = { 255, 0, 0,    // Red 0,255,0,    // Green 0, 0, 255,    // Blue 0,255,0,        // Green 0, 0, 255    // Blue };```
Lastly the only thing to change is to remove glDrawArrays and add in the new code to make use of glDrawElements. Like so:
Code:
```    for(int i = 0; i < triIndexCount; i += triIndexes[i] + 1)     {         glDrawElements(GL_TRIANGLES, triIndexes[i], GL_UNSIGNED_SHORT, &triIndexes[i+1]);     }```

Thats all there is to it. Now we have a rotating pyramid with multicolors.
Now we are ready to draw our cube. But first we need to add the cube data.
Code:
`    GLfloat                    rquad;`
Once we have that set we are finally going to set the depth buffer, otherwise we will be looking at a very weird cube.
Go into AppController.m and go to the setupView function. After the size variable but before we go into projection mode add the following.
Code:
`    glEnable(GL_DEPTH_TEST);                        // Enables Depth Testing`
This allows OpenGL to do testing for which faces are physically in front of others. OpenGL has a glClearDepth function, but OpenGL|ES removed this function as well and just assumes you want to clear the entire buffer.
Code:
`    rquad = 0.0f;`
Now that we have cleared our buffer, now we need to tell the clear function when to actually clear it so it can recalculate the face order. To do this we add a flag to glClear in the drawView function. Replace the old one with this new one:
Code:
```    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ```
There, now we are clearing our depth buffer every frame.
Ok, everything is now in place we can focus on drawing our cube.
Here I need to introduce a few things that we normally aren't used to seeing as OpenGL usually goes. Because we are using GL_VERTEX_ARRAY and GL_COLOR_ARRAY to draw our triangle, we need to clean up when we are done by disabling these. Right after we finish our drawElement for loop, we need to disable these, in case we don't use them in further draw methods.
Code:
```glDisableClientState(GL_VERTEX_ARRAY);     glDisableClientState(GL_COLOR_ARRAY);```
Its good to clean up your client states after you are done drawing (later you can comment these out and see how it affects the cube ~_*)
So, now you are wondering, how to I draw a cube. Well here goes. We begin by adding some new code after the state disabling.
Code:
```const GLfloat cubeVertices[] = { -1.0f, 1.0f, 1.0f,    // 0, Top Left Front Of The Cube           4+-----+5 1.0f, 1.0f, 1.0f,    // 1, Top Right Front Of The Cube           /|    /| 1.0f,-1.0f, 1.0f,    // 2, Bottom Right Front Of The Cube          / |7  / | -1.0f,-1.0f, 1.0f,    // 3, Bottom Left Front Of The Cube        0+-----+1 +6 -1.0f, 1.0f,-1.0f,    // 4, Top Left Back Of The Cube             |     |  / 1.0f, 1.0f,-1.0f,    // 5, Top Right Back Of The Cube         |     | / 1.0f,-1.0f,-1.0f,    // 6, Bottom Right Back Of The Cube        3+-----+2 -1.0f,-1.0f,-1.0f    // 7, Bottom Left Back Of The Cube }; // We need the number of faces we will be rendering, this is 6 faces, 5 values per face int cubeIndexCount = 30; const GLushort cubeIndexes[] = {     4, 0, 1, 4, 5, // Top     4, 3, 2, 7, 6, // Bottom     4, 0, 1, 3, 2, // Front     4, 4, 5, 7, 6, // Back     4, 0, 4, 3, 7, // Left     4, 1, 5, 2, 6  // Right }; const GLubyte cubeColors[] = {     3,   0, 255,   0, // Top - Green     3, 255, 125,   0, // Bottom - Orange     3, 255,   0,   0, // Front - Red     3, 255, 255,   0, // Back - Yellow     3,   0,   0, 255, // Left - Blue     3, 255,   0, 255  // Right - Violet };     glLoadIdentity();                                    // Reset The Current Modelview Matrix     glTranslatef(0.0f,-2.0f,-6.0f);                        // Move Down 2.0 Units And Into The Screen 6.0     glRotatef(rquad,1.0f,1.0f,1.0f);                        // Rotate The Cube On all 3 axises```
Next, like before we set up our vertex pointer.
Code:
```    glVertexPointer(3, GL_FLOAT, 0, cubeVertices);     glEnableClientState(GL_VERTEX_ARRAY);```
Notice that we aren't doing anything with the color array, this is why we turned it off after our last drawing completed. Instead we will be using glColor4f as part of the for loop you will see next. Now the syntax might seem a little strange to newer programmers who have never seen a for loop work with more than 1 variable. Here goes.
Code:
```    for(int i = 0, j = 0; i < cubeIndexCount; i += cubeIndexes[i] + 1, j += cubeColors[j] + 1)     {         glColor4f(cubeColors[j+1], cubeColors[j+2], cubeColors[j+3], 0.0);         glDrawElements(GL_TRIANGLE_STRIP, cubeIndexes[i], GL_UNSIGNED_SHORT, &cubeIndexes[i+1]);         }```
The for loop initializes 2 variables, i and j. 'i' is used for the cube indexes like the triangles before, but j is used to control the cube colors. The middle of the for loop is the same, only 1 ending type. The last part is 2 increment phases, we need to increment 'i' by the number of indexes we have to advance, but j needs to be incremented by the number of colors we are using. Notice the comma to seperate the 2 statements in each section of the for loop. Neat huh?
Ok, like before, we are using a Vertex array, so we need to disable the client state after we finish drawing, do that now.
Code:
`    glDisableClientState(GL_VERTEX_ARRAY);`
Lastly we added that new rotate variable for the cube so we will decrement it to make it spin a different direction.
Code:
```    rquad-=0.75f;     if( rquad < -360.0f)     {         rquad += 360.0f;     }```
Thats all there is to it. Go ahead and compile and run the code and check out our nice new rotating cube.

Here are the new functions in their entirety.
SetupView:
Code:
```    const GLfloat            zNear = 0.01,                             zFar = 1000.0,                             fieldOfView = 45.0;     GLfloat                    size;          glEnable(GL_DEPTH_TEST);                        // Enables Depth Testing     //Set the OpenGL projection matrix     glMatrixMode(GL_PROJECTION);     size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);     CGRect rect = view.bounds;     glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size / (rect.size.width / rect.size.height), zNear, zFar);     glViewport(0, 0, rect.size.width, rect.size.height);          //Make the OpenGL modelview matrix the default     glMatrixMode(GL_MODELVIEW);     glLoadIdentity();     // Clears the view with black     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);     rtri = 0.0f;     rquad = 0.0f;```
drawView:
Code:
```const GLfloat triVertices[] = { 0.0f,  1.0f,  0.0f,        // 0 - top of the triangle -1.0f, -1.0f, 1.0f,        // 1 - SouthWest corner B+-----+G 1.0f, -1.0f, 1.0f,        // 2 - SouthEast corner  | \ / |                 //                R 1.0f, -1.0f, -1.0f,        // 3 - NorthEast corner  | / \ | -1.0f, -1.0f, -1.0f        // 4 - NorthWest corner G+-----+B }; // We need the number of faces we will be rendering, this is 16 int triIndexCount = 16; // List our indexes. The first number is the number of indexes in our face // Followed by the RGB faces. these correspond to the order of the tricolors array. // Keep that in mind as you order your indexes. GLushort triIndexes[] = { //  #, R, G, B     3, 0, 1, 2,        // front face - top, sw, se     3, 0, 3, 2,        // right face - top, ne, se     3, 0, 3, 4,        // back face - top, ne, nw     3, 0, 1, 4        // left face - top, sw, nw }; // Each color is associated with a specific vertex in the index list now. GLubyte triColors[] = { 255, 0, 0,    // Red 0,255,0,    // Green 0, 0, 255,    // Blue 0,255,0,        // Green 0, 0, 255    // Blue };     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);     glLoadIdentity();                                    // Reset The Current Modelview Matrix     glTranslatef(0.0f,2.0f,-6.0f);                        // Move Up 2 Units And Into The Screen 6.0     glRotatef(rtri,0.0f,1.0f,0.0f);                        // Rotate The Triangle On The Y axis ( NEW )          glVertexPointer(3, GL_FLOAT, 0, triVertices);     glEnableClientState(GL_VERTEX_ARRAY);     glColorPointer(3, GL_UNSIGNED_BYTE, 0, triColors);     glEnableClientState(GL_COLOR_ARRAY);          for(int i = 0; i < triIndexCount; i += triIndexes[i] + 1)     {         glDrawElements(GL_TRIANGLES, triIndexes[i], GL_UNSIGNED_SHORT, &triIndexes[i+1]);     }     glDisableClientState(GL_VERTEX_ARRAY);     glDisableClientState(GL_COLOR_ARRAY); const GLfloat cubeVertices[] = { -1.0f, 1.0f, 1.0f,            // 0, Top Left Front Of The Cube           4+-----+5 1.0f, 1.0f, 1.0f,            // 1, Top Right Front Of The Cube           /|    /| 1.0f,-1.0f, 1.0f,            // 2, Bottom Right Front Of The Cube          / |7  / | -1.0f,-1.0f, 1.0f,            // 3, Bottom Left Front Of The Cube        0+-----+1 +6 -1.0f, 1.0f,-1.0f,            // 4, Top Left Back Of The Cube             |     |  / 1.0f, 1.0f,-1.0f,            // 5, Top Right Back Of The Cube         |     | / 1.0f,-1.0f,-1.0f,            // 6, Bottom Right Back Of The Cube        3+-----+2 -1.0f,-1.0f,-1.0f            // 7, Bottom Left Back Of The Cube }; // We need the number of faces we will be rendering, this is 6 faces, 5 values per face int cubeIndexCount = 30; const GLushort cubeIndexes[] = {     4, 0, 1, 4, 5, // Top     4, 3, 2, 7, 6, // Bottom     4, 0, 1, 3, 2, // Front     4, 4, 5, 7, 6, // Back     4, 0, 4, 3, 7, // Left     4, 1, 5, 2, 6  // Right }; const GLubyte cubeColors[] = {     3,   0, 255,   0, // Top - Green     3, 255, 125,   0, // Bottom - Orange     3, 255,   0,   0, // Front - Red     3, 255, 255,   0, // Back - Yellow     3,   0,   0, 255, // Left - Blue     3, 255,   0, 255  // Right - Violet };     glLoadIdentity();                                    // Reset The Current Modelview Matrix     glTranslatef(0.0f,-2.0f,-6.0f);                        // Move Down 2 Units And Into The Screen 6.0     glRotatef(rquad,1.0f,1.0f,1.0f);                        // Rotate The Cube On all 3 axises          glVertexPointer(3, GL_FLOAT, 0, cubeVertices);     glEnableClientState(GL_VERTEX_ARRAY);     for(int i = 0, j = 0; i < cubeIndexCount; i += cubeIndexes[i] + 1, j += cubeColors[j] + 1)     {         glColor4f(cubeColors[j+1], cubeColors[j+2], cubeColors[j+3], 0.0);         glDrawElements(GL_TRIANGLE_STRIP, cubeIndexes[i], GL_UNSIGNED_SHORT, &cubeIndexes[i+1]);         }     glDisableClientState(GL_VERTEX_ARRAY);          rtri+=1.0f;     if(rtri > 360.0f)     {         rtri -= 360.0f;     }     rquad-=0.75f;     if(rquad < -360.0f)     {         rquad += 360.0f;     }```
See you next time when we begin to tackle textures!

 Messages In This Thread OpenGL|ES tutorials - Follows NeHe track. - dragagon - Oct 25, 2008, 10:58 PM OpenGL|ES tutorials - Follows NeHe track. - dragagon - Oct 26, 2008, 09:52 PM OpenGL|ES tutorials - Follows NeHe track. - dragagon - Oct 26, 2008, 10:03 PM OpenGL|ES tutorials - Follows NeHe track. - dragagon - Oct 26, 2008, 10:42 PM OpenGL|ES tutorials - Follows NeHe track. - dragagon - Oct 26, 2008, 10:58 PM OpenGL|ES tutorials - Follows NeHe track. - dragagon - Oct 28, 2008, 11:12 AM OpenGL|ES tutorials - Follows NeHe track. - tachykixorz - Oct 28, 2008, 05:28 PM OpenGL|ES tutorials - Follows NeHe track. - XxtraLarGe - Oct 29, 2008, 02:51 AM OpenGL|ES tutorials - Follows NeHe track. - cubeur - Oct 30, 2008, 11:28 PM OpenGL|ES tutorials - Follows NeHe track. - dragagon - Oct 30, 2008 11:39 PM OpenGL|ES tutorials - Follows NeHe track. - miketucker - Nov 5, 2008, 12:31 PM OpenGL|ES tutorials - Follows NeHe track. - Andy1988 - Nov 15, 2008, 08:09 PM OpenGL|ES tutorials - Follows NeHe track. - arekkusu - Nov 16, 2008, 12:33 PM OpenGL|ES tutorials - Follows NeHe track. - Andy1988 - Nov 16, 2008, 12:43 PM OpenGL|ES tutorials - Follows NeHe track. - bronxbomber92 - Nov 16, 2008, 01:59 PM OpenGL|ES tutorials - Follows NeHe track. - nixta - Nov 23, 2008, 05:49 PM OpenGL|ES tutorials - Follows NeHe track. - DubhDevelopment - Nov 24, 2008, 06:38 AM OpenGL|ES tutorials - Follows NeHe track. - JLatte - Nov 24, 2008, 12:25 PM OpenGL|ES tutorials - Follows NeHe track. - Jake - Nov 24, 2008, 08:31 PM OpenGL|ES tutorials - Follows NeHe track. - lightlab - Nov 28, 2008, 05:22 PM OpenGL|ES tutorials - Follows NeHe track. - Michael Kerley - Nov 29, 2008, 01:39 AM OpenGL|ES tutorials - Follows NeHe track. - lightlab - Nov 30, 2008, 08:18 AM OpenGL|ES tutorials - Follows NeHe track. - aceallways - Dec 29, 2008, 09:51 AM OpenGL|ES tutorials - Follows NeHe track. - BJMcKay - Dec 31, 2008, 04:18 PM OpenGL|ES tutorials - Follows NeHe track. - davidB - Jan 4, 2009, 08:30 AM OpenGL|ES tutorials - Follows NeHe track. - sherwing - Jan 6, 2009, 02:18 AM OpenGL|ES tutorials - Follows NeHe track. - nasif_20 - Jan 15, 2009, 10:54 PM OpenGL|ES tutorials - Follows NeHe track. - cmason - Jan 25, 2009, 07:46 PM OpenGL|ES tutorials - Follows NeHe track. - cmason - Jan 26, 2009, 07:13 AM OpenGL|ES tutorials - Follows NeHe track. - cmason - Jan 26, 2009, 07:52 AM OpenGL|ES tutorials - Follows NeHe track. - atlas3650 - Feb 10, 2009, 05:30 PM OpenGL|ES tutorials - Follows NeHe track. - miq01 - Feb 27, 2009, 07:10 AM OpenGL|ES tutorials - Follows NeHe track. - dragagon - Feb 28, 2009, 10:49 PM OpenGL|ES tutorials - Follows NeHe track. - Pega88 - Mar 29, 2009, 08:21 AM OpenGL|ES tutorials - Follows NeHe track. - BreakYman - Apr 6, 2009, 06:25 PM OpenGL|ES tutorials - Follows NeHe track. - steve_mock - Apr 21, 2009, 02:20 PM OpenGL|ES tutorials - Follows NeHe track. - Resrick - Apr 22, 2009, 03:30 PM OpenGL|ES tutorials - Follows NeHe track. - warmi - Apr 24, 2009, 07:14 AM OpenGL|ES tutorials - Follows NeHe track. - steve_mock - Apr 29, 2009, 05:27 AM OpenGL|ES tutorials - Follows NeHe track. - sthaqu - May 19, 2009, 11:10 AM