Animation problem [opengl/c]

Started by
5 comments, last by synthetic 14 years, 10 months ago
In a school project I've made I got a ball bouncing inside a box.. but some times the animation is abit weird, its like seeing double.. especialy when the ball is moving fast.. I guess thats natural, but its not moving that fast either.. the animation is done by calling a animation function with glutTimerFunc() every 25 seconds.. the animation function add forces to the ball and calculates the new coordinates and then calles glutPostRedisplay() so the scene is drawn with the ball at the new coordinates.. Is this the right way to animate it? I dont know if you need to see the code, but pasting it here anyway. I've handed it in a month ago so its too late making any changes to it now though..

#include <time.h>
#include <math.h>
#include <gl\glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PI 3.1415926535897932384626433832795
#define true 1
#define false 0
#define X 0
#define Y 1
#define Z 2

//image variables
#define MAXROW	200
#define MAXCOL	320
typedef unsigned char pixel;
typedef char name[15];
name image_file_name;
pixel image_buf[MAXROW*MAXCOL];
pixel image[MAXROW][MAXCOL];
pixel p;
name inf_name = "data\\me.raw";
FILE *inf_handle;
int charin;
int r,c;

//div variables
float bumpPower = 2.0;
int showHelp = false;
char valueStr[30] = "";
int showSplash = false;

//camera variables
int rotation = 0;
const float zDistance = 15;

//physics variables
float gravity = 0.2;
float fluidVisc = 0.01;
float boxFriction = 0.5;
float ballMass = 1.0;

//light variables
int lightOn = true;
float light_pos[] = {0.0, 4.0, 0.0, 0.0};
float LightAmbient[]= {0.5, 0.5, 0.5, 1.0};
float LightDiffuse[]= {1.0, 0.1, 0.1, 1.0};

//ball variables
float ballRadius = 0.5;
float ballPos[] = {0.0, 1.5, 0.0};
float ballDirection[] = {0.0, 0.0, 0.0};

//box variables
const float BOXSIZE = 10;
float boxPos[] = {0.0, 0.0, 0.0};
int boxOutOfPos = false;

//function declerations

//adds drag force to ball using addForce()
void addDrag();
//adds friction force to ball using addForce()
void addFriction();
//applying force to the ball. Projecting the direction vector with the
//force * the direction of the force
void addForce(float force,float direction[]);
//adds gravity force to ball using addForce()
void addGravity();
//running all functions conserning the animation of the scene
void animate(int value);
//bums the left near corner of the box
void bumpLeftNear();
//bumps the left far corner of the box
void bumpLeftFar();
//bumps the right near corner of the box
void bumpRightNear();
//bumps the right far corner of the box
void bumpRightFar();
//moves the camera around the box
void changeView(int angle);
//checking for collisions between the ball and the box
void checkCollision();
//glut display function
void display(void);
//draws the box
void drawBox();
//draws the ball
void drawBall();
//draws the menu
void drawMenu();
//draws the splash screen
void drawSplash();
//get the magnitude of the direction vector
float getMagnitude();
//glut init function
void init(void);
//loads the raw input image
void InputImage();
//glut keyboard function
void keyboard (unsigned char key, int x, int y);
//turns on and of lightening in the scene
void light(int on);
//glut mouse function
void mouse(int button, int state, int x, int y);
//moves the box back to the original position after it has been bumped
void moveBoxBack();
//Prints text to screen
void printText(float x, float y, float z,char str[],void *font);
//glut reshape function
void reshape (int w, int h);
//glut special keyboard function
void (int key, int x, int y);
//normalises a 3d vector
void normalise3dVector(const float v[], float *normal);
//writes the menu text to screen
void writeMenuText();
//write name caption on splash screen
void writeNameCaption();
//writes the new value string to the screen
void writeValueStr();
//main function
int main(int argc, char** argv);

//Function defenitions
void addDrag()
{
	//F=-b*v	,(b = 6*pi*n*r)	,n = fluid viscosity, r=ball radius
	float force = (-(6*PI*fluidVisc*ballRadius) * getMagnitude());
	float direction[] = {0.0, 0.0, 0.0};
	normalise3dVector(ballDirection, direction);
	addForce(force, direction);
}

void addFriction()
{
	//R=u*N       (N = g)
	float force = -(boxFriction * (ballMass * gravity));
	float direction[] = {0.0, 0.0, 0.0};
	normalise3dVector(ballDirection, direction);
	addForce(force, direction);
}

void addForce(float force,float direction[])
{
	int i;
	for(i = X; i <= Z; i++)
		ballDirection = ballDirection + (direction * force);
}

void addGravity()
{
	float force = ballMass * gravity;
	float direction[] = {0.0, 1.0, 0.0};
	addForce(force, direction);
}

void animate(int value)
{
	int i;

	addGravity();
	addDrag();

	for(i = X; i <= Z; i++)
		ballPos -= ballDirection;

	checkCollision();

	if(boxOutOfPos == true)
		moveBoxBack();

	glutPostRedisplay();

	glutTimerFunc(25,animate,0);
}

void bumpLeftFar()
{
	float boxBoundary[] = {BOXSIZE/2 - ballRadius - 0.5,BOXSIZE/2 - ballRadius - 0.5,BOXSIZE/2 - ballRadius - 0.5};
	float direction[] = {0.0, 0.0, 0.0};

	//set y axis direction
	if(ballPos[Y] <= -boxBoundary[Y])
		direction[Y] = 1.0;

	//move box
	boxPos[X] += 0.5;
	boxPos[Y] += 0.5;
	boxPos[Z] += 0.5;
	//Check how much it should move on x-axis
	if(ballPos[X] <= -boxBoundary[X])
		direction[X] = 1.0;
	else if(ballPos[X] >= boxBoundary[X])
		direction[X] = -1.0;
	else if(ballPos[Y] <= -boxBoundary[Y])
			direction[X] = -0.4;

	//Check how much it should move on z-axis
	if(ballPos[Z] <= -boxBoundary[Z])
		direction[Z] = 1.0;
	else if(ballPos[Z] >= boxBoundary[Z])
		direction[Z] = -1.0;
	else if(ballPos[Y] <= -boxBoundary[Y])
			direction[Z] = -0.4;
	addForce(bumpPower / ballMass, direction);
}


void bumpLeftNear()
{
	float boxBoundary[] = {BOXSIZE/2 - ballRadius - 0.5,BOXSIZE/2 - ballRadius - 0.5,BOXSIZE/2 - ballRadius - 0.5};
	float direction[] = {0.0, 0.0, 0.0};

	//set y axis direction
	if(ballPos[Y] <= -boxBoundary[Y])
		direction[Y] = 1.0;

	//move box
	boxPos[X] += 0.5;
	boxPos[Y] += 0.5;
	boxPos[Z] -= 0.5;
	//Check how much it should move on x-axis
	if(ballPos[X] <= -boxBoundary[X])
		direction[X] = 1.0;
	else if(ballPos[X] >= boxBoundary[X])
		direction[X] = -1.0;
	else if(ballPos[Y] <= -boxBoundary[Y])
		direction[X] = -0.4;

	//Check how much it should move on z-axis
	if(ballPos[Z] <= -boxBoundary[Z])
		direction[Z] = -1.0;
	else if(ballPos[Z] >= boxBoundary[Z])
		direction[Z] = 1.0;
	else if(ballPos[Y] <= -boxBoundary[Y])
		direction[Z] = 0.4;

	addForce(bumpPower / ballMass, direction);
}

void bumpRightFar()
{
	float boxBoundary[] = {BOXSIZE/2 - ballRadius - 0.5,BOXSIZE/2 - ballRadius - 0.5,BOXSIZE/2 - ballRadius - 0.5};
	float direction[] = {0.0, 0.0, 0.0};

	//set y axis direction
	if(ballPos[Y] <= -boxBoundary[Y])
		direction[Y] = 1.0;

	//move box
	boxPos[X] -= 0.5;
	boxPos[Y] += 0.5;
	boxPos[Z] += 0.5;
	//Check how much it should move on x-axis
	if(ballPos[X] <= -boxBoundary[X])
		direction[X] = -1.0;
	else if(ballPos[X] >= boxBoundary[X])
		direction[X] = 1.0;
	else if(ballPos[Y] <= -boxBoundary[Y])
			direction[X] = 0.4;

	//Check how much it should move on z-axis
	if(ballPos[Z] <= -boxBoundary[Z])
		direction[Z] = 1.0;
	else if(ballPos[Z] >= boxBoundary[Z])
		direction[Z] = -1.0;
	else if(ballPos[Y] <= -boxBoundary[Y])
		direction[Z] = -0.4;

	addForce(bumpPower / ballMass, direction);
}

void bumpRightNear()
{
	float boxBoundary[] = {BOXSIZE/2 - ballRadius - 0.5,BOXSIZE/2 - ballRadius - 0.5,BOXSIZE/2 - ballRadius - 0.5};
	float direction[] = {0.0, 0.0, 0.0};

	//set y axis direction
	if(ballPos[Y] <= -boxBoundary[Y])
		direction[Y] = 1.0;

	//move box
	boxPos[X] -= 0.5;
	boxPos[Y] += 0.5;
	boxPos[Z] -= 0.5;
	//Check how much it should move on x-axis
	if(ballPos[X] <= -boxBoundary[X])
		direction[X] = -1.0;
	else if(ballPos[X] >= boxBoundary[X])
		direction[X] = 1.0;
	else if(ballPos[Y] <= -boxBoundary[Y])
		direction[X] = 0.4;

	//Check how much it should move on z-axis
	if(ballPos[Z] <= -boxBoundary[Z])
		direction[Z] = -1.0;
	else if(ballPos[Z] >= boxBoundary[Z])
		direction[Z] = 1.0;
	else if(ballPos[Y] <= -boxBoundary[Y])
		direction[Z] = 0.4;

	addForce(bumpPower / ballMass, direction);
}

void changeView(int angle)
{
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
	glTranslatef (0.0, 0.0,(GLfloat) -zDistance);
	glRotatef ((GLfloat)angle, 0.0, 1.0, 0.0);
}

void checkCollision()
{
	float boxBoundary[] = {BOXSIZE/2 - ballRadius, BOXSIZE/2 - ballRadius ,BOXSIZE/2 - ballRadius};
	int i;
	for(i = X; i <= Z; i++)
	{
		//if ball is at the boundary of the box change the ball direction and move the ball
		//back inside the box if its past the border,then add friction from the box to the ball
		if(ballPos <= -boxBoundary)
		{
			ballDirection = -ballDirection;
			ballPos = -boxBoundary;
			addFriction();
		}
		else if(ballPos >= boxBoundary)
		{
			ballDirection = -ballDirection;
			ballPos = boxBoundary;
			addFriction();
		}
	}
}

void display(void)
{
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	//if esc button is pressed show the splash screen otherwise draw the scene
	if(showSplash)
		drawSplash();
	else
	{
		writeValueStr();
		drawBall();
		drawBox();
		//show help menu if f1 is pressed
		if(showHelp)
			drawMenu();
	}

	glutSwapBuffers();
	glFlush();
}

void drawBox()
{
	GLfloat box_mat_amb_diff[] = {0.2,0.2, 0.4};
	GLfloat box_mat_specular[] = {0.5, 0.5, 0.5};
	GLfloat box_mat_shininess[] = {10.0};

	glPushMatrix();
		glColor3f(0.2,0.2, 0.4);
		glMaterialfv(GL_FRONT, GL_SPECULAR, box_mat_specular);
		glMaterialfv(GL_FRONT, GL_SHININESS, box_mat_shininess);
		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, box_mat_amb_diff);

		glTranslatef(boxPos[X],boxPos[Y],boxPos[Z]);
		glScalef(BOXSIZE, BOXSIZE, BOXSIZE);

		glBegin(GL_QUADS);
			//Top Face
			glNormal3f( 0.0, 1.0, 0.0);
			glVertex3f(-0.5,  0.5, -0.5);
			glVertex3f(-0.5,  0.5,  0.5);
			glVertex3f( 0.5,  0.5,  0.5);
			glVertex3f( 0.5,  0.5, -0.5);

			//Bottom Face
			glNormal3f( 0.0, 1.0, 0.0f);
			glVertex3f(-0.5, -0.5, -0.5);
			glVertex3f( 0.5, -0.5, -0.5);
			glVertex3f( 0.5, -0.5,  0.5);
			glVertex3f(-0.5, -0.5,  0.5);
		glEnd();

		glutWireCube(1);
	glPopMatrix();
}

void drawBall()
{
	GLfloat ball_mat_amb_diff[] = {0.2,0.3, 0.0};
	GLfloat ball_mat_specular[] = {1.0, 1.0, 1.0};
	GLfloat ball_mat_shininess[] = {70.0};

	glPushMatrix();
		glColor3f(0.2, 0.3, 0.0);
		glMaterialfv(GL_FRONT, GL_SPECULAR, ball_mat_specular);
		glMaterialfv(GL_FRONT, GL_SHININESS, ball_mat_shininess);
		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ball_mat_amb_diff);

		glTranslatef(ballPos[0],ballPos[1],ballPos[2]);

		glutSolidSphere(ballRadius, 20*((int)ballRadius+1), 20*((int)ballRadius+1));
	glPopMatrix();
}

void drawMenu()
{
		GLfloat helpMenu_mat_amb_diff[] = {0.2, 0.3, 0.3, 0.1};
		glPushMatrix();
			glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, helpMenu_mat_amb_diff);

			glScalef(5,5,5);
			glRotatef ((GLfloat)-rotation, 0.0, 1.0, 0.0);
			glTranslatef(0.0,0.0,1.5);

			glBlendFunc(GL_ONE, GL_SRC_ALPHA);
			glEnable (GL_BLEND);

			glBegin(GL_POLYGON);
				glVertex3f(-1.0f, 1.0f, 0.0f);
				glVertex3f( 1.0f, 1.0f, 0.0f);
				glVertex3f( 1.0f,-1.0f, 0.0f);
				glVertex3f(-1.0f,-1.0f, 0.0f);
			glEnd();

			glDisable(GL_BLEND);

		glPopMatrix();
		writeMenuText();
}

void drawSplash()
{
		int splashOffset = 0;
		changeView(0);
		glPushMatrix();
			for (r = MAXROW-1; r >= 0; r--)
			{
				for (c = 0; c < MAXCOL; c++)
					image_buf[MAXCOL*splashOffset + c] = image[r][c];
				splashOffset++;
			}

			writeNameCaption();

			glRasterPos3f(-3.5, -2.5, 5.0);
			glDrawPixels(MAXCOL, MAXROW, GL_LUMINANCE, GL_UNSIGNED_BYTE, image_buf);
		glPopMatrix();
}

float getMagnitude()
{
	//calculate the value of the vector magnitude: abs(sqrt(x^2 + y^2 + z^2))
	return fabs(sqrt(pow(ballDirection[0],2) + pow(ballDirection[1],2) + pow(ballDirection[2],2)));
}

void init(void)
{
    glShadeModel(GL_SMOOTH);
    glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
    glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
    glEnable(GL_LIGHT0);
	light(true);

	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    glClearColor (0.0, 0.0, 0.0, 0.0);

    glEnable(GL_DEPTH_TEST);
}

void InputImage()
{
    //opens the image file and store it in the image array
	if ((inf_handle = fopen(inf_name, "rb")) == NULL)
    {
        puts("*** Can't open image file !\n ");
        charin = getchar();
        exit(1);
    }

    for ( r = 0; r < MAXROW; r++ )
    {
        for ( c = 0; c < MAXCOL; c++)
        {
            if((charin=fgetc(inf_handle))==EOF)
            {
                printf("***File reading failed! \n");
                charin = getchar();
                exit(1);
            }
            image[r][c] = charin;
        }
    }

   fclose(inf_handle);
}

void keyboard (unsigned char key, int x, int y)
{
	//handles keyboard input. Change the value string if anything values are changed
	switch (key)
	{
		case 'q':
		case 'Q':
			if(boxOutOfPos == false)
			{
				bumpLeftFar();
				boxOutOfPos = true;
			}
			break;

		case 'w':
		case 'W':
			if(boxOutOfPos == false)
			{
				bumpRightFar();
				boxOutOfPos = true;
			}
			break;

		case 'a':
		case 'A':
			if(boxOutOfPos == false)
			{
				bumpLeftNear();
				boxOutOfPos = true;
			}
			break;

		case 's':
		case 'S':
			if(boxOutOfPos == false)
			{
				bumpRightNear();
				boxOutOfPos = true;
			}
			break;

		case 'l':
		case 'L':
			if(lightOn == true)
				light(false);
			else
				light(true);
			break;

		case 'e':
		case 'E':
			gravity += 0.005;
			sprintf(valueStr,"Gravity: %f", gravity);
			break;

		case 'd':
		case 'D':
			gravity -= 0.005;
			sprintf(valueStr,"Gravity: %f", gravity);
			break;

		case 'r':
		case 'R':
			ballMass += 0.1;
			sprintf(valueStr,"Ball mass: %f", ballMass);
			break;

		case 'f':
		case 'F':
			ballMass -= 0.1;
			sprintf(valueStr,"Ball mass: %f", ballMass);
			break;

		case 't':
		case 'T':
			fluidVisc += 0.0005;
			sprintf(valueStr,"Fluid viscosity: %f", fluidVisc);
		break;

		case 'g':
		case 'G':
			fluidVisc -= 0.0005;
			sprintf(valueStr,"Fluid viscosity: %f", fluidVisc);
			break;

		case 'y':
		case 'Y':
			boxFriction += 0.05;
			sprintf(valueStr,"Box Friction: %f", boxFriction);
			break;

		case 'h':
		case 'H':
			boxFriction -= 0.05;
			sprintf(valueStr,"Box Friction: %f", boxFriction);
			break;

		case 'u':
		case 'U':
			bumpPower += 0.5;
			sprintf(valueStr,"bump Power: %f", bumpPower);
			break;

		case 'j':
		case 'J':
			bumpPower -= 0.5;
			sprintf(valueStr,"bump Power: %f", bumpPower);
			break;

		case 'o':
		case 'O':
			gravity = 0.2;
			fluidVisc = 0.01;
			boxFriction = 0.5;
			ballMass = 1.0;
			bumpPower = 2.0;
			ballRadius = 0.5;
			strcpy(valueStr,"Values reset");
			break;

		case 'i':
		case 'I':
			ballRadius += 0.05;
			sprintf(valueStr,"ball radius: %f", ballRadius);
			break;

		case 'k':
		case 'K':
			ballRadius -= 0.05;
			sprintf(valueStr,"ball radius: %f", ballRadius);
			break;

		case 27:
            showSplash = true;
            break;
        default:
            break;
    }
}

void light(int turnOn)
{
	if(turnOn)
	{
		glEnable(GL_LIGHTING);
		lightOn = true;
	}
	else
	{
		glDisable(GL_LIGHTING);
		lightOn = false;
	}
}

void mouse(int button, int state, int x, int y)
{
	if (button == GLUT_LEFT_BUTTON && showSplash == true)
		exit(0);
}

void moveBoxBack()
{
	int i,tmp;

	for(i = X; i <= Z; i++)
	{
		tmp = boxPos * 10;
		if(tmp < 0)
			boxPos += 0.1;
		else
			boxPos -= 0.1;

		if(tmp == 0)
		{
			boxPos = 0.0;
			boxOutOfPos = false;
		}
	}
}

void printText(float x,float y,float z,char str[],void *font)
{
	char *c;

	glRasterPos3f(x,y,z);
	for (c=str; *c != '\0'; c++)
		glutBitmapCharacter(font , *c);
}

void reshape (int w, int h)
{
    glViewport (0, 0, (GLsizei) w, (GLsizei) h);

    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 30.0);

    changeView(0);
}

void specialKeyboard(int key, int x, int y)
{
	//handles special keyboard input that keyboard cannot handle
	switch (key)
	{
		case GLUT_KEY_LEFT:
			rotation = (rotation + 4) % 360;
			changeView(rotation);
			break;

		case GLUT_KEY_RIGHT:
			rotation = (rotation - 4) % 360;
			changeView(rotation);
			break;

		case GLUT_KEY_F1:
			if(showHelp == false)
			{
				showHelp = true;
				glDisable(GL_DEPTH_TEST);
			}
			else
			{
				showHelp = false;
				glEnable(GL_DEPTH_TEST);
			}
	}
}

void normalise3dVector(const float v[], float *normal)
{
	int i;
	float magnitude = getMagnitude(v);
	for(i = X; i <= Z; i++)
	{
		normal = v/magnitude;
	}
}

void writeMenuText()
{
	char helpStr1[] = "Left/Right - move camera";
	char helpStr2[] = "Q/W/A/S - bump bottom corners";
	char helpStr3[] = "L - turn lightening on/off";
	char helpStr4[] = "E/D - adjust gravity up/down";
	char helpStr5[] = "R/F - adjust ball mass up/down";
	char helpStr6[] = "T/G - adjust fluid viscosity up/down";
	char helpStr7[] = "Y/H - adjust box friction up/down";
	char helpStr8[] = "U/J - adjust bump power up/down";
	char helpStr9[] = "I/K - adjust ball radius up/down";
	char helpStr10[] = "O - reset";
	char helpStr11[] = "F1 - show this menu";
	char helpStr12[] = "ESC - Quit";

	GLfloat helpStr_mat_amb_diff[] = {1.0, 0.0, 0.0};

	glPushMatrix();
		glColor3f(1.0, 0.0, 0.0);
		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, helpStr_mat_amb_diff);

		glRotatef ((GLfloat)-rotation, 0.0, 1.0, 0.0);

		printText(-1.5, 1.5 ,12.0, helpStr1,GLUT_BITMAP_TIMES_ROMAN_24);
		printText(-1.5, 1.3 ,12.0, helpStr2,GLUT_BITMAP_TIMES_ROMAN_24);
		printText(-1.5, 1.1 ,12.0, helpStr3,GLUT_BITMAP_TIMES_ROMAN_24);
		printText(-1.5, 0.9 ,12.0, helpStr4,GLUT_BITMAP_TIMES_ROMAN_24);
		printText(-1.5, 0.7 ,12.0, helpStr5,GLUT_BITMAP_TIMES_ROMAN_24);
		printText(-1.5, 0.5 ,12.0, helpStr6,GLUT_BITMAP_TIMES_ROMAN_24);
		printText(-1.5, 0.3 ,12.0, helpStr7,GLUT_BITMAP_TIMES_ROMAN_24);
		printText(-1.5, 0.1 ,12.0, helpStr8,GLUT_BITMAP_TIMES_ROMAN_24);
		printText(-1.5, -0.1 ,12.0, helpStr9,GLUT_BITMAP_TIMES_ROMAN_24);
		printText(-1.5, -0.3 ,12.0, helpStr10,GLUT_BITMAP_TIMES_ROMAN_24);
		printText(-1.5, -0.5 ,12.0, helpStr11,GLUT_BITMAP_TIMES_ROMAN_24);
		printText(-1.5, -0.7 ,12.0, helpStr12,GLUT_BITMAP_TIMES_ROMAN_24);
	glPopMatrix();
}

void writeNameCaption()
{
    char caption[] = "Terje Loe";
    glColor3f(0.0, 0.0, 0.0);

	printText(-0.7, -3.5 ,5.0, caption,GLUT_BITMAP_9_BY_15);
}

void writeValueStr()
{
	GLfloat valueStr_mat_amb_diff[] = {1.0,1.0, 1.0};

	glPushMatrix();
		glColor3f(1.0, 1.0, 1.0);
		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, valueStr_mat_amb_diff);

		glRotatef ((GLfloat)-rotation, 0.0, 1.0, 0.0);

		printText(-1.7, 1.6 ,12.0, valueStr,GLUT_BITMAP_HELVETICA_10);
	glPopMatrix();
}

int main(int argc, char** argv)
{
	//InputImage();
	glutInit(&argc, argv);
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
	glutInitWindowSize (500, 500);
	glutInitWindowPosition (0, 0);
	glutCreateWindow ("Ball in a box");
	init();
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutMouseFunc(mouse);
	glutKeyboardFunc(keyboard);
	glutSpecialFunc(specialKeyboard);
	glutTimerFunc(25,animate,0);
	glutMainLoop();
	return 0;
}


Edit: commented out the InputImage() function so its possible to compile and run it without the image..
Advertisement
Bump :) Anyone?
It doesn't look like your animation is wrong, just choppy because of very quick acceleration. Decrease the force by a factor fo 2 or 4 and you'll see that the animation is a lot smoother. Usually to fix that you need to increase your framerate, but your physics code doesn't appear to be dependent on the timestep. Change your code so that it takes into account the time between physics updates, and then increase the framerate a little, see if that helps. If it still doesn't look good, you could try using the accumulation buffer to generate a motion blur effect.
Quote:Original post by synthetic
It doesn't look like your animation is wrong, just choppy because of very quick acceleration. Decrease the force by a factor fo 2 or 4 and you'll see that the animation is a lot smoother. Usually to fix that you need to increase your framerate, but your physics code doesn't appear to be dependent on the timestep. Change your code so that it takes into account the time between physics updates, and then increase the framerate a little, see if that helps. If it still doesn't look good, you could try using the accumulation buffer to generate a motion blur effect.


So you mean having the physics update and drawing of frames on two different timers right? I tried setting it to draw the frame every 5 ms and then do the physics update every 25 ms as it does in the code I posted, but its still not looking good..

I'll have a look at the accumulation buffer..
No, the problems is that your physics code is independent of time. You need to update your physics faster, but with a smaller timestep, but you aren't using a timestep at all, so you can't get finer ball positioning.

Your code appears to work like this:

calculate force.
add force to velocity.
add velocity to position.

but, if you remember your kinematics.

a=dv/dt
v=dx/dt,

so your new velocity v+dv = v + a*dt, not just v + a. likewise, your new position is x+vdt, not x+v. You have to multiply your acceleration and velocity by the length of your timestep, and then, when you decrease the size of your timestep, the position will update more frequently, and you will get smoother animation. This is the reason your gravity constant has to be so light, 0.2 instead of 9.8, because you needed to multiply your forces by a small number to keep it from freaking out and flying all over the place incredibly quickly. Remember, you're updating the position 40 times a second, so each change should be small.

If you're really interested in physics simulations, you should look into physics for game developers by bourg, its pretty thorough.

aha. I havent thought of it like that before.. I just worked out a way of doing it my self.. I found an article on it.. I'll read through that.. After my exams... :p

http://gafferongames.com/game-physics/
That looks like a good article, although don't believe his rather biased nonsense about euler's method being stupid. runge-kutta IS euler's method, they both approximate a continuous integral as a sum of discrete samples across the region of integration. The only difference is that euler approximates the curve as a series of line segments, whereas runge-kutta approximates the curve as a series of higher order polynomials. You get less integration error per step with runge-kutta, but at the cost of extra calculation time. If I were you, I would go with a modified euler's method, as his RK4 algorithm seems like a bit of overkill for your purposes. An actual game probably doesn't need very low-error physics as much as it needs fast physics.

This topic is closed to new replies.

Advertisement