Making an Octahedron move in 3D

Hello, I am very fresh and new to OpenGL, and programming overall for the most part. I have had some assistance with classmates in this project I am doing, and I feel I have made some great headway, but there is something I am missing, or not seeing, or just forgetting about… that is making my idle animation function not work. Before I show you the code, I know I only have it set for the x and y and not z yet, but I figure I mine as well get those two going before I even need to delve into the z space. The idea behind the project was to make an octahedron in 3d space, and have it move around the box, adjusting angle as it came in contact with the boundaries. All with having materials and lighting around it. The materials and lighting are for the most part completed, but this animation has me in a snag. So please, tips, hints and helpful advice is greatly appreciated. Thanks.

octahedron.h


#include <GL/glut.h>

GLfloat pos[2];		//x,y
GLfloat dir[2];		//dx,dy
GLint rot;		//degrees

/**********************************************************/
/* Material */
/**********************************************************/

struct Material {
  GLfloat ambient[4];
  GLfloat diffuse[4];
  GLfloat specular[4];
  GLfloat shiny;
};
typedef struct Material Material;

struct Point{
	GLfloat x;
	GLfloat y;
	GLfloat z;
};
typedef struct Point Point;

Material WhatIsBrass(void);
Material WhatIsWhiteShiny(void);
Material WhatIsRedPlastic(void);

#define Brass WhatIsBrass()
#define WhiteShiny WhatIsWhiteShiny()
#define RedPlastic WhatIsRedPlastic()

void SetMaterial(Material m);

octahedron.cpp


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <GL/glut.h>
#include <math.h>
#include "octahedron.h"

#define PI 3.14159265

GLsizei ww = 700, wh = 700;
GLdouble orthoX = 700, orthoY = 700;
GLint wcx = 180, wcy = 180;
int xTrack, yTrack;					//tracks mouse movement
int moveX, moveY;					//possibly used later for animation

float rotSpeed[2];					//to be possibly used later for automatic rotation

bool tracking = false;				//true when left mouse is held down

double rotation[2] = {0,0};			//keeps track of current rotation

GLfloat vertices[6][3] =	{{0,1,0}, 
							{0,-1,0}, 
							{0,0,1}, 
							{1,0,0}, 
							{-1,0,0}, 
							{0,0,-1}};
GLubyte octaIndices[24] =	{0,2,3,     //face indices
							 0,2,4,
							 0,5,4,
							 0,5,3,
							 1,2,4,
							 1,2,3,
							 1,5,3,
							 1,5,4};



//calculate the norm from three points
//could be optimized a bit
Point norm(GLfloat a[3], GLfloat b[3], GLfloat c[3])
{
	GLfloat v1[3] = {a[0] - c[0], a[1] - c[1], a[2] - c[2]};
	GLfloat v2[3] = {b[0] - c[0], b[1] - c[1], b[2] - c[2]};
	//(a2b3 &#8722; a3b2, a3b1 &#8722; a1b3, a1b2 &#8722; a2b1)
	Point n = {(v1[1] * v2[2]) - (v1[2] * v2[1]),
		(v1[2] * v2[0]) - (v1[0] * v2[2]),
		(v1[0] * v2[1]) - (v1[1] * v2[0])};

	return n;
}

//calculate normal of each face, draw the face
//for some reason the normal of each odd face points inwards, so they are negated
void drawOcta(void){
	GLfloat x,y;
	int i = 0;
	Point n;
	for(i; i < 8; i++){
		//glColor3ub(colors[i * 3],colors[i * 3 + 1],colors[i * 3 + 2]);
		
		n = norm(vertices[octaIndices[i*3 + 1]], vertices[octaIndices[i*3 + 2]], vertices[octaIndices[i*3]]);

		if(i % 2 == 0)
			glNormal3f(n.x, n.y, n.z);

		else
			glNormal3f(- n.x, - n.y, - n.z);
		
		glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, &octaIndices[i*3]);

	}


}


void ani() {

GLfloat x,y;
int i, j, k;
GLfloat pos[2];		//x,y,z
GLfloat dir[2];		//dx,dy,dz
GLint rot;		//degrees

int neg;

pos[0] = (GLfloat) x - (ww/2 - orthoX/2);
pos[1] = (GLfloat) y - (wh/2 - orthoX/2);

	//randomly set x direction (rand between -2.2 and 2.2, abs value >= .2)

	if(rand()%2 == 1) neg = 1;
	else neg = -1;
	dir[0] = .2 * neg + (float)(rand() % 100) *.02 * neg;

	//randomly set y direction (rand between -2.2 and 2.2, abs value >= .2)

	if(rand()%2 == 1) neg = 1;
	else neg = -1;
	dir[1] = .2 * neg + (float)(rand() % 100) *.02 * neg;
	rot = (GLint)(rand()%180);


		
		//randomly set rotation if hits a boundary
		for(k=0; k < 20; k++){
		if (pos[0] + (ww/2 - orthoX/2) > ww/2 + 149)  {
			if(dir[0] > 0) dir[0] = - dir[0];
			rot = (GLint)(rand()%180);
		}
		if (pos[0] + (ww/2 - orthoX/2) < ww/2 - 149) {
			if(dir[0] < 0) dir[0] = - dir[0];	
			rot = (GLint)(rand()%180);
		}
		if (pos[1] + (wh/2 - orthoY/2) > wh/2 + 149)  {
			if(dir[1] > 0) dir[1] = - dir[1];
			rot = (GLint)(rand()%180);
		}
		if (pos[1] + (wh/2 - orthoY/2) < wh/2 - 149) {
			if(dir[1] < 0) dir[1] = - dir[1];
			rot = (GLint)(rand()%180);
		}
		
		}

		//displaceX += dirX * 5.0; displaceY += dirY * 3.0;
		for (i = 0; i < 20000; i++) 
			for (j = 0; j < 200; j++) ;
		glutPostRedisplay ( );

}




/**********************************************************/
/* Material */
/**********************************************************/

Material WhatIsBrass(void)
     /* brass material */
{
  Material thisIsIt =
    {{0.33, 0.22, 0.03, 1.0},
     {0.78, 0.57, 0.11, 1.0},
     {0.99, 0.91, 0.81, 1.0},
     27.8};

  return thisIsIt;
}

Material WhatIsWhiteShiny(void)
{
  Material thisIsIt =
    {{1.0, 1.0, 1.0, 1.0},
     {1.0, 1.0, 1.0, 1.0},
     {1.0, 1.0, 1.0, 1.0},
     100.0};

  return thisIsIt;
}

Material WhatIsRedPlastic(void)
{
  Material thisIsIt =
    {{0.3, 0.0, 0.0, 1.0},
     {0.6, 0.0, 0.0, 1.0},
     {0.8, 0.6, 0.6, 1.0},
     32.0};

  return thisIsIt;
}


void SetMaterial(Material m)
     /* sets the current material */
{
  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, m.ambient);
  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, m.diffuse);
  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, m.specular);
  glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, m.shiny);
}

void display() {
	

	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	
	//store view matrix
	glPushMatrix();
	glMatrixMode (GL_MODELVIEW);
	glLoadIdentity();
	
	//lights off
	glDisable(GL_LIGHT0);
	//apply rotation
	glRotated(rotation[1], 1.0, 0.0, 0.0);
	glRotated(rotation[0], 0.0, 1.0, 0.0);


	//black lines
	//use the commented out code below to make a box around the octahedron
	glColor3ub(0, 0, 0);
	glBegin(GL_LINE_STRIP);
		glVertex3f(-4,-4,-4);
		glVertex3f(-4,4,-4);
		glVertex3f(-4,4,4);
		glVertex3f(-4,-4,4);
		glVertex3f(-4,-4,-4);
		glVertex3f(4,-4,-4);
		glVertex3f(4,4,-4);
		glVertex3f(4,4,4);
		glVertex3f(4,-4,4);
		glVertex3f(4,-4,-4);
	glEnd();
	glBegin(GL_LINES);
		glVertex3f(-4, 4, -4);
		glVertex3f(4, 4, -4);
		glVertex3f(-4, 4, 4);
		glVertex3f(4, 4, 4);
		glVertex3f(-4, -4, 4);
		glVertex3f(4, -4, 4);
	glEnd();
	



	//lights on
	glEnable(GL_LIGHT0);

	//glEnable(GL_LIGHT1);    but not this light


	

	SetMaterial(RedPlastic);
	drawOcta();
	
	//recover viewing matrix
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	
	glFlush();
	glutSwapBuffers();


}

//left mouse toggles tracking bool
void mouse(int button, int state, int x, int y) {

	if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
		tracking = true;

	}
	if(button == GLUT_LEFT_BUTTON && state == GLUT_UP) {

		tracking = false;
	}
	
}

//tracks mouse position while mouse button is being held
void mouseTrackActive(int x, int y) {
	

		if(tracking == true){

			rotation[0] = rotation[0] + .7*(x - xTrack);
			if (rotation[0] >= 360) rotation[0]-=360;
			rotation[1] = rotation[1] + .7*(y - yTrack);
			if (rotation[1] >= 360) rotation[1]-=360;
		}

		xTrack = x;
		yTrack = y;
		glutPostRedisplay();
	}

//tracks mouse position while mouse button not being held
//essential to remain consistent with active mouse function
void mouseTrackPassive(int x, int y){

		xTrack = x;
		yTrack = y;
		glutPostRedisplay();
}

int main(int argc, char **argv) {
	GLfloat lightPos1[] = {0.0, 10.0, 0.0, 0.0};

    /* yellow light */
    GLfloat diffuse1[] = {1.0, 1.0, 0.75, 1.0};
    GLfloat specular1[] = {0.8, 0.8, 0.4, 1.0};
    GLfloat ambient1[] = {0.6, 0.6, 0.6, 1.0};

	GLfloat lightPos2[] = {0.0, 1.0, -1.0, 0.0};

    GLfloat diffuse2[] = {0.4, 0.4, 0.4, 1.0};
    GLfloat specular2[] = {0.0, 0.0, 0.0, 1.0};
    GLfloat ambient2[] = {0.05, 0.05, 0.05, 0};

    /* background light */
    GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };

	glutInit (&argc, argv);
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB| GLUT_DEPTH);
	glutInitWindowSize (ww, wh);
	glutInitWindowPosition (wcx, wcy);
	glutCreateWindow ("Octahedron");
	glutDisplayFunc(display);


	glMatrixMode (GL_PROJECTION);
	glViewport (0,0, ww, wh);
	glLoadIdentity ( );
	glOrtho (-8.0, 8.0, -8.0, 8.0, -8.0, 8.0);
	glFrustum(-10.0, 10.0, -10.0, 10.0, -10.0, 10.0);
	//glMatrixMode (GL_MODELVIEW);
	glutIdleFunc(ani);
	glutMotionFunc(mouseTrackActive);
	glutPassiveMotionFunc(mouseTrackPassive);
	glutMouseFunc(mouse);
	glEnable(GL_DEPTH_TEST);
	glEnableClientState(GL_VERTEX_ARRAY);

	//color handled mostly by materials + light
	//glEnableClientState(GL_COLOR_ARRAY);
	//glColorPointer(3,GL_UNSIGNED_BYTE, 0, &colors);
	glVertexPointer(3, GL_FLOAT, 0, &vertices);
	glShadeModel(GL_FLAT);
    glEnable(GL_LIGHTING);
    glEnable(GL_NORMALIZE);
    
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
    /* set a low background light such that objects in the scene
       can be seen at all */
    
	glClearColor (1.0, 1.0, 1.0, 1.0);	   /*white background */

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glLightfv(GL_LIGHT0, GL_POSITION, lightPos1);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse1);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular1);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient1);
	glLightfv(GL_LIGHT1, GL_POSITION, lightPos2);
    glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse2);
    glLightfv(GL_LIGHT1, GL_SPECULAR, specular2);
    glLightfv(GL_LIGHT1, GL_AMBIENT, ambient2);
	glutMainLoop();
}

If I was to take the time to compile and run your code, what would it show right now (i.e. as posted)?

It shows a octahedron in the middle of a 3D box, standing stationary, no movement whatsoever. You can move the box around and see it from all angles, but… just no movement

I was able to compile and run your program. I get the red octagon, inside a wireframe box. Both objects can be rotated by dragging the mouse around. Nice! Like you said the octagon doesn’t move. It doesn’t move because none of the quantities being computed in the ‘ani’ function are in any way applied to the octagon. You must explicitly move the octagon using glTranslate (called before drawOcta) with parameters that are computed in ‘ani’. An easy way to do this is with global variables. Maybe that’s what moveX and moveY are for? I get the impression that you copied this code from some other application and are trying to make it animate an octagon. Nothing wrong with that. Another tip - you’ll have to surround the glTranslate and drawOcta call with Push and PopMatrix calls. Good luck.

Well you are correct, it is not all completely my code, it is a project I am doing with a partner, whom needless to say is far better at programming than I. He created the octagon and movement by dragging the mouse around, I created the materials and the lights. The last part is mine as well, which is making the animation work.

Thanks for the tips about using glTranslate, I will give it a whirl and see what I can do. But if I am going to need this in z space as well, should I made moveX, moveY, and moveZ? and where exactly would I call the move calls in the glTranslate function?

Add moveZ to the line near the top of your file where moveX and moveY are declared. I suggest changing that declaration from ‘int’ to ‘float’.

Replace your drawOcta() call with what’s below -


   glPushMatrix ();
      glTranslatef (moveX, moveY, moveZ);
      drawOcta();
   glPopMatrix ();

Inside your ‘ani’ function you have to compute the values of moveX, moveY, and moveZ. I’m not going to try to figure out what’s going on in that function. That’s your job. I’d suggest commenting out most of it for the time being and writing a very simple version that makes the Octohedron move slowly in the X direction only (i.e. compute moveX, set moveY and moveZ to zero). When you have X motion under control, go on to Y and Z.

Good luck.

okay I’ll get right on that. Thanks a lot MaxH.