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). can be renamed to. Also comment out the  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, instead of. It takes a set of indices that refer to the vertices array. With, 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  instead of.

We can tell OpenGL to draw our cube in :

We use  to grab the buffer size. This way, we don't have to declare.

= Enabling depth =

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

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: This will also take care of our aspect ratio issue.
 * 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)

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.

History note: OpenGL 1.x had two built-in matrices, accessible through  and. Here we're replacing those, plus we're adding a camera :)

Let's add our code in the  function, where we updated the   uniform in the previous tutorial. We'll pass a  uniform instead.

Start: at the beginning of each phase, we have an identity matrix, that does no transformation at all, created using.

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:

and  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 :

We've made the traditional flying rotating cube!

= Window resize =

To support sizing the SDL2 window, you can check for s: