- In this lecture
we are going to talk more about OpenGL,
making the mytest1 program
that you saw a couple of lectures ago
more complicated
to introduce more of the functionalities of OpenGL.
This segment talks about basic geometry set up.
The way we will do this is start with the mytest1 program
and gradually add code to take you though a squence
of steps that makes it more ambitious.
At the end of this lecture,
we will first have program mytest2
that has a teapot like you can see
with four pillars and where the teapot can animate,
and finally we will add texturing and lighting as well.
Let me show you the demo of the program.
So here I can move into and out of the screen
like I could previously,
and I can also animate my teapot.
Let me also show you the code for this.
In fact I have a DEMO variable here.
In this case I will now set it to zero to start
a basic program similar to mytest1.
I quit this program by hitting escape.
I compile my program
and now if I run this,
I see that I have just a single plane,
a single white plane.
I can zoom in and out as before.
The only changes from the earlier demo
a couple of lectures back in mytest1
was that I changed the floor to all white.
I have also added new globals for the teapot location
which is -0.5,
that is the left end of the screen in x,
where it starts its animation.
And animate is equal to zero,
says whether to animate the teapot or not
which is initially zero.
And of course my DEMO variable.
The other globals are what we saw previously.
I will now show you the basic geometry
set up for the cubes or pillars and colors.
First let me review the geometry set up in general.
The number of objects is equal to 2
because you have the floor and the cubes.
The number of buffers for objects is equal to 3
corresponding to the vertices, colors and indices.
In addition we will have four colors
for the four colors of the cubes
corresponding to the four pillars.
We now define a number of vertex array objects,
in this case is not just the number of objects
but it is also the number of colors
because we have to account for these four colored cubes
and a separate vertex array object for the teapot.
We now define the number of buffers
which includes the number of colors and the teapot buffers.
Objects,
with the object ID, the primitive type of the object,
the number of elements in the object.
Then we define for the teapot a vector of vertices, of normals
for the teapot,
for lighting calculations
and the indices for the teapot.
If you are interested in more details
about the teapot definition,
please look in the appropriate header files.
We also define the modelviewStack,
which is just a vector of mat4 matrices.
We will push and pop on to this stack.
We now define an enum for the vertices,
colors and elements,
corresponding to the arrays for the object.
We have an enum for the floor in the cube
and we define the floor vertices.
Note that the floor is at Z = 0
so the vertices just correspond to X = .5,
Y = .5,
and X = -.5
and Y is -.5
and finally X is .5,
Y is -.5.
The colors,
since it's a uniform white floor
are simply RGB equal to (1,1,1).
The indices for the floor correspond
to the indices for the triangles
and these are just defined as two triangles for the floor.
For later purposes we'll also define the texture coordinates.
The texture coordinates go between 0 and 1,
not -.5 and .5.
We now define the cube geometry for the pillars.
First, I define the width and the height,
which correspond to the width of the pillar
and the height of the pillar.
Then I have this cube color (_cubecol) which is with an underscore.
It's with an underscore because it just defines
the uniform color for the four cubes:
red, green,
blue and yellow,
which is red and green.
Later on when I'm initializing the cube,
I'll have cube color (cubecol) without the underscore,
which for each vertex of the corresponding cube
will just set it to the uniform color
in _cubecol.
I then define the eight vertices for the cube,
where I define the lower plane
with Z is equal to zero first
and then the upper plane with Z is equal to height second.
And notice that the coordinates
are given by plus or minus width.
I initalize this cube color,
which is for each of the eight vertices:
what is its RGB color?
We'll define it later.
And I specify the cube indices,
which is two triangles for each of the six faces,
so 12 triangles for the bottom,
top, left,
front, right
and back faces.
Here is my Initialize Geometry function.
This is just the basic Initialize Geometry function,
it's the same thing
that was used for the plane in mytest1.
It takes as input the vertex array,
the color array and the elements,
as well as their sizes and the type,
which is GL_TRIANGLES.
It defines an offset,
which is object ID times the number of buffers per object,
binds the vertex array,
corresponding to the object.
It binds the buffer corresponding to the vertices plus offset,
so it takes in the buffer data,
uses layout location 0 for the vertices,
enables the corresponding attribute,
which will be passed later to the shaders,
and sets the data appropriately.
This is the VertexAttribPointer,
for example,
saying that you have three floating point numbers
for each vertex,
corresponding to X,
Y and Z.
You bind the buffer for the colors next.
You specify the buffer data.
You use layout location 1 for the colors,
enable the VertexAttribArray and set the vertex attribute.
Summarizing we use location 0 for the vertices,
location 1 for the colors.
Finally, you bind
the buffer corresponding to the elements of the indices.
You set the buffer data.
You specify the primitive type,
which will be GL_TRIANGLES.
You specify the number of elements
and then you do this glBindVertexArray of zero
to prevent further modification of this vertex array object
which is not desired.
We now come to the interesting function,
which is initalizing the cubes
where you have the same geometry for each cube
but it has different colors.
Again, you take as input
the object, the vertices,
the indices and the type.
First we define the outer loop over the number of colors.
This outer loop is the four colors,
or correspondingly,
it is the four pillars.
The next element says "For int j=0; j < 8"
that is the vertices
and the final element k = 0;
k < 3 is the RGB color.
Now notice this line which sets the cube color
for each of the vertices in RGB
to the corresponding uniform color
in _cubecol for that value of 'i'
in (i = 0 ; i < ncolors)
and the 'k' is just the RGB color
So that will be set, for each of the number of colors to red,
green, blue
and yellow in this case.
Notice that this happens for each element
in the outer loop,
which is each of the four pillars
or each of the four colors.
We now bind the vertex array,
corresponding to object + i.
So, object will be the object corresponding to the cube,
but you have different vertex array objects
for each of the different pillars.
That's why I'm saying object + i.
The offset is just
the object * numperobj as before
because the offset will be used for the vertices.
Recall that the geometry is the same for all of the cubes.
However, the colors are different for all of the cubes
and that's why I also define the base
as the number of objects times number per object
because after that each buffer will correspond
to a different color.
The first step is to bind the buffer corresponding
to the vertices for the cube.
That's why we said Vertices + offset.
You get the buffer data
and you use layout location 0 for the vertices.
You enable the vertex attribute array.
You set the vertex attribute pointer.
The interesting thing is what happens with colors
and in this case you're binding the buffer
at base + i because the colors are stored
after vertices color elements vertices color elements for the floor and the cube.
But then I have a sequence of buffers for just the color
and that's what base + i is doing.
After that the standard commands for buffer data
and enabling the VertexAtttribAarray(1)
and its VertexAttribPointer
so you can store layout location 1 for the colors.
We now go to the elements.
Again, Elements + offset;
the elements are the same for all of the four pillars
or all of the four cubes.
You set the buffer data for them,
you specify the primitive type,
the number of elements and then you unbind the vertex array.
In init,
this is what happens.
There is an initobject command for the floor,
which is just
the standard initobject we saw earlier in mytest1
a couple of lectures ago.
But then there is a separate initcubes command
for the cube which will initialize the four cubes
of the four pillars,
each with different colors.
And then there is a loadteapot command,
which we will not be talking about here
but if you are interested you can look below the hood,
which initializes and sets up the teapot.
We'll not talk about how you draw with and without colors.
You may first be interested
in the standard drawobject command
which just binds the vertex array for the object
and draws the elements corresponding to the primitive type
of the object.
The number of elements that the object,
in this case we are using
the UNSIGNED_BYTEs for the elements and then I unbind.
For drawing with color it's very simple,
I simply say object + color,
object in this case would be cube
and color would be the pillar number.
So 0 would be red,
then green, blue, yellow.
And apart from that it's exactly
the same as the drawobject command.
So, I just bind the appropriate vertex array object
and finally I load the teapot.