Page 1 of 1

Using OpenGL/GLUT to Create 3D Scenes Part 3 Rate Topic: ***** 1 Votes

#1 xPurplex  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 10
  • View blog
  • Posts: 93
  • Joined: 17-June 09

Posted 28 July 2009 - 06:33 PM

Assumptions

I assume that you know basic C++ and have read and understand all previous lessons.

How Translations Work

So, how do translations work? Well, generally, we only move one thing....the origin. Yes, the origin. Alright, here we go. Every point in OpenGL has two seperate coordinates. By this, I mean a point can be at (3, 5, 2) and (-7, 1, 5) at the same time. How? Well, there are two types of coordinates. These are global and actual. Global coordinates never change for a particular point (the global origin never changes in any way), but actual coordinates are constantly changing. Still with me? If not, go back and read over again. The actual origin can be changed through functions such as glTranslatef(), glRotatef(), and glScalef(). Take a look at this diagram:

Attached Image

The red dot is the actual origin. The global origin is where the X and Y axes meet. Because the actual origin is in the same place as the global origin, the actual and global are the same for the point at (2 , -1).

Attached Image

Here the actual (above) and global (below) origins are in different places, so the point over to the right has two different coordinates pairs (we are ignoring the Z axis and coordinates at the moment for simplicity's sake).

But...what if I want to make different objects move seperately? For instance what if I wanted to make something spin clockwise as another spins counterclockwise as another doesn't spin but goes around the perimeter of the window? Well, for this we use our good friends, glPushMatrix() and glPopMatrix(). glPushMatrix() saves the transformation state and glPopMatrix() restores it. Quick, look in the mirror! Does your face look like this: :blink:? Relax, a transformation state is just (more or less) what state the actual origin is in. We save and restore it so that we can make certain transformations only affect certain things.


The Code
[size=2]
#include <gl/glut.h>

using namespace std;

int angle = 0;

void init(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(600, 600);
	glutCreateWindow("First Look at Motion");
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_COLOR_MATERIAL);
	glClearColor(0.7f,0.0f,1.0f,1.0f);
}

void handleResize(int w, int h) 
{
	glViewport(0, 0, w, h);
	
	glMatrixMode(GL_PROJECTION);
	
	glLoadIdentity();
	gluPerspective(45.0,				
				   (double)w / (double)h, 
				   1.0,				   
				   200.0);				
}

void draw()
{
	 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	 glMatrixMode(GL_MODELVIEW);
	 glLoadIdentity();


We start this code out the same as ever, except we add in a new variable, angle.
glTranslatef(0.0f, 0.0f, -5.0f); //Move foward 5 units
	 glPushMatrix(); //Save transformation state


Here we just move foward 5 units then save the transformation state. The translation is not really necessary, but I like (x, y, 0) much better than (x, y, -5).
glScalef(0.5f, 0.5f, 0.5f); //Scale by .5 in all directions
	 glRotatef(angle, 0.0f, 0.0f, 1.0f); //Rotate on Z axis
	 
	 glTranslatef(0.0f, -3.0f, 0.0f); //Move to center of square
	 glRotatef(angle, 0.0f, 0.0f, 1.0f); //Rotate on Z axis


The square was a bit big in the last lesson, so I scaled it down to half it's original size. Note, we aren't really doing anything to the square, just scaling the actual origin so that it has an effect on the square. We then rotate the square on it's Z axis, around the global origin (0, 0, 0). Then, we move the actual origin to the center of the square, where we rotate it again.
glBegin(GL_QUADS);

	 glColor3f(0.85, 0.25, 0.25);
	 glVertex3f(-0.5f, -0.5f, 0.0f);
	 glVertex3f(0.5f, -0.5f, 0.0f);
	 glVertex3f(0.5f, 0.5f, 0.0f);
	 glVertex3f(-0.5f, 0.5f, 0.0f);
	 
	 glEnd();
	 
	 glPopMatrix(); //Restore transformation state
	 glPushMatrix(); //Save transformation state


We draw the square, same as always, followed by a call to both glPopMatrix() and glPushmatrix(). This is just restoring and saving the original transformation state so that the transformations will not have an effect on the triangle.
Note: calls to glPopMatrix() and glPushMatrix() cannot be called within calls to glBegin() and glEnd().
glRotatef(angle*3, 0.0f, 1.0f, 0.0f); //Rotate on Y axis


this rotates the triangle on it's Y axis. The "*3" is just to make it spin 3 times faster than normal.
glBegin(GL_TRIANGLES);
	 
	 glColor3f(1.0, 0.6, 0.0);
	 glVertex3f(0.0f, 0.5f, 0.0f);
	 glColor3f(0.5, 0.5, 1.0);
	 glVertex3f(-0.5f, -0.5f, 0.0f);
	 glColor3f(1.0, 1.0, 1.0);
	 glVertex3f(0.5f, -0.5f, 0.0f);
	 
	 glEnd();
	 
	 glPopMatrix(); //Restore transformation state
	 
	 glutSwapBuffers(); 
}


To finish our draw() function, we draw the triangle, restore the transformation state, and send the scene to the screen.
void update(int value) {
	//Makes motion continuous
	angle += 1;
	if (angle > 360) {
		angle = 0;
	}
	
	glutPostRedisplay(); //Redraw scene
	
	glutTimerFunc(5, update, 0); //Call update in 5 milliseconds
}


Here is our function to cause continuous motion. We add to the angle, change it to 0 if it becomes to high, and redraw the scene. We also call update again (horray for recursion!) in 5 milliseconds.
int main(int argc, char** argv) {
	init(argc, argv); 
	
	glutDisplayFunc(draw);
	glutReshapeFunc(handleResize);
	glutTimerFunc(5, update, 0); //Call update 5 milliseconds after program starts
	
	glutMainLoop();
	return 0; 
}


Same as always, except for a call to update 5 milliseconds after the program starts.

I can't show you a picture of the output , but I highly recommend that you paste the code into a project and run it. It's actually pretty cool :P

The next lesson will include:
-3D shapes
-Lighting
-User input

Is This A Good Question/Topic? 0
  • +

Page 1 of 1