-
Help with OpenGL camera
Hello,i have a project for school to make a snake3d game.This is the code i've got so far:
Code:
#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <gl/glut.h>
#define UP 1
#define Down 2
#define LEFT 3
#define RIGHT 4
// Variabile de stare
GLint lvl = 1;
GLint points = 0;
GLint size = 0;
GLbyte gameOver = true;
GLbyte EnableLight = true;
// Variabilele la vierme
GLint bodyPos[2][100] = {{}};
GLint _x = 5;
GLint _z = 10;
GLint _oldX[2] = {};
GLint _oldZ[2] = {};
GLbyte direction = 0;
// Variabile la mancare
GLint _bx = 0;
GLint _bz = 0;
// Variabile de ecran
GLint _w = 800;
GLint _h = 550;
GLint _Giw = 0;
GLint _Gih = 0;
GLint _Gfw = 150;
GLint _Gfh = 150;
//Variabile pentru unghiul camerei
static GLfloat view_rotx=45.0F ;
static GLfloat view_roty=0.0F ;
static GLfloat view_rotz=0.0F ;
static GLfloat headRotation=90.0F ;
static GLfloat zoom=-300.0F ;
// Variabile pentru FPS
DWORD g_dwLastFPS = 0;
int g_nFPS = 0, g_nFrames = 0;
//Configurarea Luminii
void initLight()
{
//Adaugam lumina ambientala
GLfloat ambientColor[] = {0.3f, 0.4f, 0.8f, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);
//Lumina pozitionata
GLfloat lightColor0[] = {0.5f, 0.5f, 0.5f, 1.0f};
GLfloat lightPos0[] = {4.0f, 0.0f, 8.0f, 1.0f};
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);
//Adaugam lumina directa
GLfloat lightColor1[] = {0.5f, 0.2f, 0.2f, 1.0f};
//Vine din directia (-1, 0.5, 0.5)
GLfloat lightPos1[] = {-1.0f, 0.5f, 0.5f, 0.0f};
glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor1);
glLightfv(GL_LIGHT1, GL_POSITION, lightPos1);
}
//Initializarea primelor configuratii
void Initialize(void)
{
glEnable(GL_DEPTH_TEST);
glClearColor(0.7f, 0.9f, 0.3f,0.7f); //Schimbam culoarea "cerului" intr-un...verde sau ce o fi iesit pe aici
if(EnableLight){
glEnable(GL_COLOR_MATERIAL); //Dam enable la culoare
glEnable(GL_LIGHTING); //Dam enable la lumina
glEnable(GL_LIGHT0); //Dam enable la lumina #0
glEnable(GL_LIGHT1); //Dam enable la lumina #1
glEnable(GL_NORMALIZE); //Automatizarea normalizarii normalelor
}
}
//Redimensionarea ferestrei
void resize (int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (double)w / (double)h, 1, 800.0);
}
void Write(char *string){//Scriem un string pe ecran
while(*string)
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, *string++);
}
//Aceasta functie va intoarce obiectele in functie de unghi
void ManipulateViewAngle() {
glRotatef(view_rotx,1.0,0.0,0.0);//Intoarcem in jurul la axa X
glRotatef(view_roty,0.0,1.0,0.0);//Intoarcem in jurul la axa Y
glRotatef(view_rotz,0.0,0.0,1.0);//Intoarcem in jurul la axa Z
}
//Resetam dimensiunea la vierme si locatia lui(sau sa ii zicem mai bine "joc nou" HAHA HIHI HEHE HOHO)
void Reset(){
_x = 5;
_z = 10;
direction = 0;
lvl = 1;
points = 0;
size = 0;
gameOver = false;
view_rotx=45.0F ;
view_roty=0.0F ;
view_rotz=0.0F ;
headRotation=90.0F ;
zoom=-300.0F ;
}
//WELCOOOOOMEEEE SCREEEEEENNNN YUPYYY
void WelcomeScreen(){
char tmp_str[40];
glColor3f(1, 0, 0);
glRasterPos2f(0, 20);
Write("Snake 3D");
glColor3f(0, 0, 1);
glRasterPos2f(0, 10);
Write("Marin Alexandru Radu");
glColor3f(0, 0, 1);
glRasterPos2f(0, 0);
Write("Apasati 'n' pentru joc nou.");
}
void DrawSnake(){
int i;
//Desenam capul si suprafata
glPushMatrix();
ManipulateViewAngle();
//Suprafata de marshaluire a sarpelui
glPushMatrix();
glColor3f(0.5f, 0.0f, 1.0f);
glTranslatef(75.0, -16.0, 75.0);
glScalef(155,5.0,155);
glutSolidCube(1);
glPopMatrix();
//HEAD OF THE WORM
glColor3f(1.0,0.0,0.0);//Culoare..
glTranslatef(_x,-10.0,_z);//Ii dam locatia in functie de _x si _z
glScalef(0.5,0.5,0.5);
glutSolidSphere(10,20,20);//Ii facem capul mai tuguiat(o sfera putin mai mare decat celalte sfere)
glRotatef(headRotation, 0.0, 1.0, 0.0);
glColor3f(1.0,1.0,0.0);
glTranslatef(0,0.0,6.0);
glScalef(0.8,1.0,1.0);
glutSolidCone(10,10,20,20);
glColor3f(0,0,0);
glTranslatef(-4.0,10.0,0.0);
glScalef(0.3,0.3,0.3);
glutSolidSphere(10,20,20);
glTranslatef(26.0,0.0,0.0);
glutSolidSphere(10,20,20);
glPopMatrix();
//Desenarea corpului
for(i=0; i<size; i++){//Loop-ul va da lungimea corpului si va desena sfere
glPushMatrix();
ManipulateViewAngle();
glTranslatef(bodyPos[0][i],-10.0,bodyPos[1][i]);//Localizarea sferelor
glColor3f(0.8,0.4,0.4);
glScalef(0.5,0.5,0.5);
glutSolidSphere(7,20,20);
glPopMatrix();
}
}
void DrawFood()
{
//Desenam sferele AKA mancarea pentru vierme
glPushMatrix();
ManipulateViewAngle();
glTranslatef(_bx,-10.0,_bz);
glColor3f(0.8, 0.4, 0.4);//MEMO "SCHIMBA CULOAREA LA MANCARE CA ESTE FOARTE ENERVANTA ASA!!!!!!!"
glScalef(0.5,0.5,0.5);
glutSolidSphere(7,20,20);
glPopMatrix();
}
void GameStatus(){
char tmp_str[40];
// Vom face un "status" al jocului ce il vom afisa pe ecran
glColor3f(0, 0, 0);
glRasterPos2f(5, 50);
sprintf(tmp_str, "Nivel: %d Puncte: %d", lvl, points);
Write(tmp_str);
}
//Generam numere aleatoare pentru locatia mancarii viermelui
int RandomNumber(int high, int low)
{
return (rand() % (high-low))+low;
}
//Generam noua mancare pentru vierme
void newFood(){
time_t seconds;
time(&seconds);
srand((unsigned int) seconds);
_bx = RandomNumber(_Gfw-_Giw, _Giw+10);
_bz = RandomNumber(_Gfh-_Gih, _Gih+10);
}
//Functie de calcul FPS
void getFPS(){
char tmp_str[40];
if( GetTickCount() - g_dwLastFPS >= 1000 ) // Cand a trecut o secunda...
{
g_dwLastFPS = GetTickCount(); // Updatam variabila de timp
g_nFPS = g_nFrames; // Salvam FPS
g_nFrames = 0; // Resetam FPS
}
g_nFrames++;
glRasterPos2f(75, 50);
sprintf(tmp_str, "FPS: %d", g_nFPS);
Write(tmp_str);
glRasterPos2f(50, 60);
sprintf(tmp_str, "Poz X: %d Poz Z: %d", _x, _z);//Afisam pozitia X si Z
Write(tmp_str);
}
//Functia de "accidentare"
bool collision(){
int i;
for(i=0; i<size; i++){
if((bodyPos[0][i] == _x && bodyPos[1][i] == _z) ||
((bodyPos[0][i] >= _x) && (bodyPos[0][i] <= _x + 5) && (bodyPos[1][i] >= _z) && (bodyPos[1][i] <= _z + 5)) ||
((bodyPos[0][i] <= _x) && (bodyPos[0][i] >= _x - 5) && (bodyPos[1][i] <= _z) && (bodyPos[1][i] >= _z - 5)) ||
((bodyPos[0][i] <= _x) && (bodyPos[0][i] >= _x - 5) && (bodyPos[1][i] >= _z) && (bodyPos[1][i] <= _z + 5)) ||
((bodyPos[0][i] >= _x) && (bodyPos[0][i] <= _x + 5) && (bodyPos[1][i] <= _z) && (bodyPos[1][i] >= _z - 5)))
return true;
}
return false;
}
//Functie pentru miscarea sarpelui in functie de directie
//Putin logic,dar vom folosi tastatura (old school: sus,jos,dreapta,stanga)
void Run(int value){
int i;
_oldX[1] = _x;
_oldZ[1] = _z;
switch(direction){
case RIGHT:
headRotation =90;
_x += 6;
if(_x > _Gfw-2) _x = _Giw-1;//Daca viermele se duce intr-o margine,aici il vom face sa "apara" in partea cealalta (no walls)
break;
case LEFT:
headRotation =-90;
_x -= 6;
if(_x < 0) _x = _Gfw-2;//Acelasi lucru ca mai sus
break;
case UP:
headRotation =0;
_z += 6;
if(_z > _Gfh-2) _z = _Gih-1;//Acelasi lucru ca mai sus
break;
case Down:
headRotation =180;
_z -= 6;
if(_z < 2) _z = _Gfh-2;//Acelasi lucru ca mai sus
break;
}
//Verificat daca s-a papat singur,IF DAAAA,atunci GAME OVER
if(collision()) gameOver = true;
//Vedem daca viermele isi mananca mancarea (verificam X si Y)
// Daca da crestem numarul de puncte,marimea viermelui si creeam o sfera (mancare YUM YUM) noua
if((_x == _bx && _z == _bz) ||
((_x >= _bx) && (_x <= _bx + 4) && (_z >= _bz) && (_z <= _bz + 4)) ||
((_x <= _bx) && (_x >= _bx - 4) && (_z <= _bz) && (_z >= _bz - 4)) ||
((_x <= _bx) && (_x >= _bx - 4) && (_z >= _bz) && (_z <= _bz + 4)) ||
((_x >= _bx) && (_x <= _bx + 4) && (_z <= _bz) && (_z >= _bz - 4))){
points++;
if(points < 100) size++;
if(points%5 == 0 && lvl < 15) lvl++;
newFood();
}
for(i = 0; i<size; i++){// Salvam pozitiile partilor corpului la "el vierme"
_oldX[0] = _oldX[1];
_oldZ[0] = _oldZ[1];
_oldX[1] = bodyPos[0][i];
_oldZ[1] = bodyPos[1][i];
bodyPos[0][i] = _oldX[0];
bodyPos[1][i] = _oldZ[0];
}
//Setam timpul
glutTimerFunc(130-lvl*4, Run, 0);
}
void Display(void){//Draw Function
//Golire ecran
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if(EnableLight) initLight();
glTranslatef (-60.0, 40.0, zoom);
//Daca "Game over" e adavarat,naspa,daca nu continuam jocul.
if(!gameOver){
GameStatus();
DrawFood();
DrawSnake();
}
else
WelcomeScreen();
getFPS();
// Updatam ecranul
glutPostRedisplay();
glutSwapBuffers();
}
void Special(int key, int x, int y){
switch(key){
case GLUT_KEY_RIGHT :
if(direction != LEFT)
direction = RIGHT;
break;
case GLUT_KEY_LEFT :
if(direction != RIGHT)
direction = LEFT;
break;
case GLUT_KEY_UP :
if(direction != UP)
direction = Down;
break;
case GLUT_KEY_DOWN :
if(direction != Down)
direction = UP;
break;
}
}
void keyboard (unsigned char key, int x, int y)//Functii de baza pt miscarea viermelui
{
switch (key) {
//Toate rotatiile viermelui peste unghiurile X, Y, Z
case 'x' : view_rotx +=2 ;
glutPostRedisplay();
break;
case 'X' : view_rotx -=2 ;
glutPostRedisplay();
break;
case 'y' : view_roty +=2 ;
glutPostRedisplay();
break;
case 'Y' : view_roty -=2 ;
glutPostRedisplay();
break;
case 'z' : view_rotz +=2 ;
glutPostRedisplay();
break;
case 'Z' : view_rotz -=2 ;
glutPostRedisplay();
break;
case 'a' : size++ ;//Functie ascunsa pentru utilizator (HAHA HIHI HEHE HOHO) cu care putem sa facem marimea sarpelui mai mare
glutPostRedisplay();
break;
case 'A' : size-- ;//Functie ascunsa pentru utilizator (HAHA HIHI HEHE HOHO) cu care putem sa facem marimea sarpelui mai mica
glutPostRedisplay();
break;
case '+' : zoom++ ;//Functie ascunsa pentru utilizator (HAHA HIHI HEHE HOHO) cu care putem sa facem zoom inspre plansa
glutPostRedisplay();
break;
case '-' : zoom-- ;//Functie ascunsa pentru utilizator (HAHA HIHI HEHE HOHO) cu care putem sa facem zoom mai departe de plansa (O facem miica mica mica)
glutPostRedisplay();
break;
case 'n' : Reset() ;//Functie de reset,care noi il mintim pe utilizator ca este de fapt pentru inceperea jocului (HAHA HIHI HEHE HOHO)
glutPostRedisplay();
break;
//ESC pentru a iesi.
case 27:
exit(0);
break;
default:
break;
}
}
int main(void){
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(_w,_h);
glutInitWindowPosition(80,80);
glutCreateWindow("Snake Game ");
glutSpecialFunc(Special);
glutKeyboardFunc(keyboard);
glutDisplayFunc(Display);
glutReshapeFunc(resize);
newFood();
Run(0);
Initialize();
glutMainLoop();
}
The problem is that i am trying to change the camera mode to follow the head object.The problem is that i've find the function gluLookAt(),but i don't understand what variables to put in there.
Should i put something like:
Code:
(GL_MODELVIEW); glLoadIdentity(); gluLookAt( cameraPosition.x, cameraPosition.y, cameraPosition.z, _x, -10.0, _z,0.0,1.0,0.0);
And now where do i modify this in my code?I would apreciate if somebody can help me,thank you.
-
OpenGl has two matrices, the model view matrix and the projection matrix.
The modelview matrix is used for converting objects into "world space", and is popped and pushed continuously.
The projection matrix converts from world space to 2d screen x, y co-ordinates. So the camera needs to affect the projection matrix. A look at matrix will point the camera in the right direction, but it won't do the perspective calculations.
So you need to multiply the projection matrix by the look at matrix. Then you don't touch it.
3D graphics cameras are different from real cameras in that they need a near and far clipping plane. This is because otherwise the z values go to infinity as you perspective correct. It's a common error not to set the clipping planes to sensible values.
-
Ok,so i need to redo the whole snake by using a pojection matrix i understand?
-
Most of it shouldn't need redoing.
Code:
//Redimensionarea ferestreivoid resize (int w, int h){ glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, (double)w / (double)h, 1, 800.0);}
This is where you set up your perspective transform, which is half of the camera. You need to add a line to multiply by the look at matrix, which means passing in camera x,y,z, target x, y, z (presumably the snake's head or something), and the up direction. You do that every frame, then you don't touch it again, all the other matrix operations are with the modelview matrix, moving the snake and food into world space.
Check at 1 and 800 are Ok for near and far clipping planes. No object can come closer than 1 worldspace unit to the camera, or move further than 800 units away.
I'm deeply suspicious of your manipulateviewangle function. It looks like you are trying to do some of the camera work on the modelview matrix (this will work, because ultimately everything is multiplied together into one transform, but it will quickly get you into a mess). However I would have to actually run the program to be sure what you are doing here.