We're now going to discuss basic OpenGL matrix stacks and transforms. So let me first summarize the OpenGL vertex transformations. Recall that you start with the object in object coordinates, and here you have the (x y z w) coordinates and homogeneous coordinates.
Then you define the ModelView matrix, which includes the object transformations, to place the objects properly in the world. As well as the glm::lookAt command, which you've implemented in homework 1. Then you go through the projection matrix, which goes from 3D to 2D, which is usually glm::perspective. So the shaded boxes are what you've already implemented in homework 1, and also in homework 2.
That gives you the eye coordinates used for lighting, and then you go to the perspective divide or dehomogenization.
You have clip coordinates, and you can clip to the -1 to 1 range, then you can do the perspective divide or dehomogenization, you get normalized device coordinates, and then you do a viewport transform so it finally appears in the window. To do all of these transforms, of course, you need some kind of matrix operations. In particular, you need matrix stacks.
And this is very important for hierarchically defined figures such as the human body. You might consider the face, the torso. So you might define the torso initially. You might translate and scale to place the face, the hands, the legs, so forth.
In old OpenGL, matrix stacks were defined for you with things like glPushMatrix, glPopMatrix, glLoad, glMultMatrixf.
In fact, in the demo program that I have given out, which is mytest2, you use the old style stack.
However, things have changed in a number of different ways. Nowadays in C++, the standard template library includes a stack type. In fact, if you use the glm::mat4 for matrices, you can just plug mat4 into a stack. And therefore, the current recommendation is to just use STL stacks which are managed yourself. And therefore, all of this ModelView matrix, push/pop is really deprecated.
In homework 2, to understand the way the stack works, you should really manage it yourself. In the directions for homework 2, we explain a little bit about the STL library for stacks. You can of course also look this up online. It's very well documented.
For homeworks 1 and 2, you write your own transformation code for translate, scale and rotate. Of course, in old style OpenGL, commands are provided for these purposes, like glScale, glRotate and glTranslate, and their equivalent glm commands, but you are supposed to write it yourself in homework 1 and 2.
Be careful of OpenGL conventions. In the old style, you right multiply the current matrix. And this leads to a difference in code where the last transformation in the code is actually the first one that's applied. And glm operators largely follow this convention. But this is a bit different from the standard mathematical convention, and leads to column versus row order. And so you have to be careful.
gluLookAt, and its instantiation as glm::lookAt, is just like a matrix in any other type of matrix. And like any other transform, it affects the ModelView matrix. Therefore you specify it after you've specified the transforms to the objects, so in code it comes first, in the actual operation it comes last.
So why is all of this, the exact location of gluLookAt, not an issue for gluPerspective? Because gluPerspective affects the projection matrix stack, which usually doesn't have anything else on it, while gluLookAt affects the ModelView matrix that has camera positioning, but also has object motion.
So let's talk about drawing the pillars. This is old style OpenGL. In new OpenGL you would manage the stack yourself and use STL commands to pop and push. Look at the way in which this is written. This is a very powerful idiom in OpenGL. We first specify the matrix mode to be the ModelView matrix. Then we come to the first pillar.
And notice this command between push and pop matrix. That's because anything you do within these doesn't affect what follows next. So, it's very common that you keep whatever is in the stack at this point. Which may be gluLookAt, which may be other object transformations. You push that on the stack, do your translation to draw your pillar, pop out. And so, you have the transforms within this push/pop block.
So here, you translate to a particular location on the screen. You draw this cube. And the zero refers to a color. So in this case it's red. So similarly you go to the next color, and you go to the next location.
We can also talk about the third and fourth pillars, again, different colors for the cube and different locations in the scene.
So we are now ready to do a demo. And let me bring in my source code again. Now, let me first say a little bit about this demo. So this will be demo 1, which will include the white plane that we saw earlier. And will also include the pillars. One question I'm going to ask you once I start the demo is, does the order of drawing matter? So what happens if I move the floor after the pillars in the code versus moving it before. So think about that while I set up this demo.
So once again, I'm showing you my actual text editing environment, and my compilation environment. And all I'm going to do is to change this to 1. If you look at the code, it includes a number of lines, right? So I'll just show this to you.
So it includes lines like if DEMO is greater than or equal to 2, then do so. So if DEMO is greater than 0, then I actually draw my first, second, third and fourth pillars, which is just the code that I just showed you on this slide. So let's try to make the program.
Again the makefile is fairly standard. And, now let me run this.
So here I have the program, you can see that I have the plane and I have the pillars. And this looks really good.
So here, you see that it appears in the way it's supposed to appear, with the plane below and the pillars on top. Let's now change the order of drawing. So let's see again what we did here. We drew the object FLOOR, and then we drew the object for the pillars.
So one thing we can do is come down. So here is, does the order of drawing matter? What happens if I draw the ground after the pillars? And I'll change this to actually draw the floor here. So I haven't really changed anything. I'm still drawing the pillars, I'm still drawing the floor. Only thing is, I'm now drawing the floor after I draw the pillars. So think about whether that should lead to any change in the program.
Output, and let me make the program again, and let me run it. So now notice, notice what's going on. You see that the floor was drawn after the pillars and therefore the pillars come first and then the floor comes after them. Intuitively it make sense. It's just, we're drawing objects in the order in which I specified them.
However, that might not be the desired behavior that you want.