Hey folks, welcome to another new NeHe lesson!
As you might have noticed, static objects are pretty boring after a short time. So lets deal with moving and rotating objects!
Sad as it is, we need to talk about some matrix math here... Don't worry, you just need to understand the principles!
OpenGL uses 2 matrices to calculate the screen position of a vertex. One is the PerspectiveMatrix which takes into account which is the greatest distance at which you still see objects and whether you can look 45° to left and right or have a 180° view, this is called the view angle. We're not changing this here.
What is more important is the ModelViewMatrix, this one moves objects from their object space to world space. glTranslatef alters exactly this matrix. The values you specify to glTranslatef will move all objects you draw (before altering the matrix again) to the amount you specified. If you're familiar with vector math, this is just adding the vector (-1.5, 0.0, -6.0) to each vertex you draw. Or you can imagine you move the camera exactly into the opposite direction.
Another operation is rotating objects around a given angle. Thats what glRotatef does. It takes 4 parameters: the angle (in degree, NOT radians!) and a vector describing the axis around which we want to rotate.
Last but not least there is a scale operation glScalef(x,y,z) which scales your objects in x,y and z direction to the given value, 1.0 leaves them unchanged.
Now you need to take care in which order you apply operations:
Remembering the math lessons at school, you might know that matrix multiplication is not commutative (means A*B != B*A). But (M
rot * M
trans) * V is the same as M
rot * (M
trans * V), where M stands for matrix and V for the vertex we want to translate to its world position.
This means operations we perform on the ModelViewMatrix will be applied to our vertices in reverse order to their order in the code.
Another usefull thing is the matrix stack. OpenGL internally stores the modelview matrix on top of a stack, we can push the current matrix with glPushMatrix() - thereby the current matrix remains the same - we can then apply changes to the matrix and render some polygons, after that we can use glPopMatrix() to restore the last matrix we pushed in there.
In this lesson we now want to create a rotating cube. So we need to define a cube in our init-method.
bool Lesson03::init()
{
if (!m_Window.createWindow(800, 600, 32, false, "Ne(w)He Lesson 3 - A rotating cube"))
{
return false;
}
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
//Create a cube inside our vertex buffer
m_Vertices.push_back(Vertex(-1.0f, -1.0f, 1.0f ));//Vertex
m_Colors.push_back(Vertex(1.0, 0.0, 0.0));//Color
m_Vertices.push_back(Vertex( 1.0f, -1.0f, 1.0f ));
m_Colors.push_back(Vertex(1.0, 0.0, 0.0));
m_Vertices.push_back(Vertex( 1.0f, 1.0f, 1.0f ));
m_Colors.push_back(Vertex(1.0, 0.0, 0.0));
m_Vertices.push_back(Vertex(-1.0f, 1.0f, 1.0f ));
m_Colors.push_back(Vertex(1.0, 0.0, 0.0));
Here you see one of the 6 faces (each a quad) of the cube, the other 5 are exactly the same, only that we're having a fixed x and y coordinate and each one at 1.0 and -1.0.
By the way, the f behind a floating point number indicates that its a float → single precision. Single precision is enough for OpenGL apps.
With the knowledge you've just gained you might want to create a variable for the angle to rotate the cube and increase it every frame (everytime "draw" gets called). Thats exactly what we're going to do:
//Here's where all the drawing happens
void Lesson03::draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix
glTranslatef(0.0f, 0.0f, -8.0f); // Move everything 8 units into the screen
// We rotate the cube around the y axis at an angle of "rot",
// the x-axis of 0.2*rot and z 0.4*rot so we might see each of its sides some time..
glRotatef(m_RotationAngle, 0.2, 1.0, 0.4);
m_RotationAngle += 0.03; //increase the angle so the cube keeps spinning - this value indicates the speed
if(m_RotationAngle > 360.0) //prevent from having an angle greater than a float value can store ^^
{
m_RotationAngle -= 360.0;
}
Last but not least we draw the cube to the screen:
//Now we need to tell OpenGL to use the arrays we filled with data
glEnableClientState(GL_VERTEX_ARRAY); //We want a vertex array
glEnableClientState(GL_COLOR_ARRAY); //and a color array
glVertexPointer(3, GL_FLOAT, 0, &m_Vertices[0]); //All values are grouped to three Floats, we start at the beginning of the array (offset=0) and want to use m_vertices as VertexArray
glColorPointer(3, GL_FLOAT, 0, &m_Colors[0]); //Same here, but use m_colors
glDrawArrays(GL_QUADS, 0, m_Vertices.size()); // The cube consists only of quads, and we have nothing else in our array so we draw all vertices
//Disable using the Vertex and Color array
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_QUADS, 0, m_Vertices.size()); // The cube consists only of quads, and we have nothing else in our array so we draw all vertices
//Disable using the Vertex and Color array
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
As you can see this part is the same as in lesson 2, apart from that we use the size of our vertex array as the number of vertices to be drawn. This works because we dont want to draw other shapes.
Thats it! you've drawn your first 3D cube to the screen! Pretty easy, isn't it?
Caste @ NeHe-Team - May 29, 2008
Currently rated 162 by 1039 people
- Currently 162/5 Stars.
- 1
- 2
- 3
- 4
- 5
EditDownloads
Windows
Linux