# OpenGL Programming/Modern OpenGL Tutorial 05

Our triangle animation is fun, but we're learning OpenGL to see 3D graphics.
Let's create a cube!

# Adding the 3rd dimension

A cube is 8 vertices in the 3D space (4 points in the front face, 4 in the back face). triangle can be renamed to cube. Also comment out the fade bindings.
Now let's write our cube vertices. We'll position our (X,Y,Z) coordinate system like in this picture. We'll write them so they are related to the center of the object. It's cleaner, and it will allow us to rotate the cube around its center later:
Note: here, the Z coordinate is towards the user. You may find other conventions such as Z towards the top (height) in Blender, but OpenGL's default is Y-is-up.
To see something better than a black mass, we'll also define some colors:
Don't forget the global buffer handles:

# Elements - Index Buffer Objects (IBO)

Our cube has 6 faces. Two faces may share some vertices. In addition we'll write our face as a combination of 2 triangles (so 12 triangles total).
Consequently we'll introduce the concept of elements: we use glDrawElements, instead of glDrawArrays. It takes a set of indices that refer to the vertices array. With glDrawElements, we can specify any order, and even the same vertex several times. We'll store these indices in an Index Buffer Object (IBO).
It is better to specify all faces in a similar way, here counter-clockwise, because it will be important for texture mapping (see next tutorial) and lighting (so triangle normals need to point to the right way).
Note that we used a buffer object again, but with GL_ELEMENT_ARRAY_BUFFER instead of GL_ARRAY_BUFFER.
We can tell OpenGL to draw our cube in render:
We use glGetBufferParameteriv to grab the buffer size. This way, we don't have to declare cube_elements.

# Enabling depth

We now can see the square front face, but to see the other faces of the cube, we need to rotate it. We still can peek by removing one (or both!) of the front face's triangle. :)

# Model-View-Projection matrix

Until now, we've worked with object coordinates, specified around the object's center. To work with multiple objects, and position each object in the 3D world, we compute a transformation matrix that will:
* shift from model (object) coordinates to world coordinates (model->world)
* then from world coordinates to view (camera) coordinates (world->view)
* then from view coordinates to projection (2D screen) coordinates (view->projection)
This will also take care of our aspect ratio issue.
The goal is to compute a global transformation matrix, called MVP, that we'll apply on each vertex to get the final 2D point on the screen.
Note that the 2D screen coordinates are in the [-1,1] interval. There is a 4th non-matrix step to convert these to [0, screen_size], controlled by glViewPort.
History note: OpenGL 1.x had two built-in matrices, accessible through glMatrixMode(GL_PROJECTION) and glMatrixMode(GL_MODELVIEW). Here we're replacing those, plus we're adding a camera :)
Let's add our code in the logic function, where we updated the fade uniform in the previous tutorial. We'll pass a mvp uniform instead.
Start: at the beginning of each phase, we have an identity matrix, that does no transformation at all, created using glm::mat4(1.0f).
Model: we'll push our cube a bit in the background, so it doesn't mix with the camera:
View: GLM provides a re-implementation of gluLookAt(eye, center, up). eye is the position of the camera, center is where the camera is pointed to, and up is the top of the camera (in case it's tilted). Let's center on our object from a bit above, with the camera straight:
Projection: GLM also provides a re-implementation of gluPerspective(fovy, aspect, zNear, zFar). aspect is the screen aspect ratio (width/height) which is horizontal by default and it's axis can be changed by recalculating the vertical field of view using trigonometric math functions when in radians multiplied by the aspect divided by the conditional/original aspect ratio, fovy is the vertical field of view (45° for a common 60° horizontal FOV in 4:3 resolution) that can be zoomed by recalculating the field of view the same way as changing the aspect axis constraint, zNear and zFar are the clipping plane (min/max depth), both positive, zNear usually small not equal to zero. We need to see up to our square, so we can use 10 for zFar:
screen_width and screen_height are new global variables to define the size of the window:
Result:
We can pass it to the shader:
And in the shader:

# Animation

To animate the object, we can simply apply additional transformations before the Model matrix.
To rotate the cube, we can add in logic:
We've made the traditional flying rotating cube!

# Window resize

To support sizing the SDL2 window, you can check for SDL_WINDOWEVENTs:
- Recent stats
< OpenGL Programming