my goal is to make a camera with OpenGL and SDL 1.2 in the C language. I want to be able to move in all the directions (forward, backward, left, right, up down). I want to be able to rotate freely the camera in all the direction : up down left right (like in space with a spacecraft). In this first version, I just use the keyboard but in the future, I want to be able to move the direction of the camera with the mouse and the spacecraft with the keyboard.
Here is the full code I wrote/recover.
#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#define WINDOWS_WIDTH 1280.0
#define WINDOWS_HEIGHT 720.0
#define SPEED_MOVE 0.1
#define SPEED_CAMERA 0.005
typedef struct strucvect{
double x;
double y;
double z;
}vect;
double phi=0, theta=0;
vect position, orientation, lateral, vertical, target;
int continuing=1;
vect scaleVector(vect v){
v.x *= SPEED_MOVE;
v.y *= SPEED_MOVE;
v.z *= SPEED_MOVE;
return v;
}
vect unitVector(vect v){
double norm = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
v.x = v.x / norm;
v.y = v.y / norm;
v.z = v.z / norm;
return v;
}
vect productVector(vect v1 ,vect v2){
vect new;
new.x = v1.y * v2.z - v1.z * v2.y;
new.y = v1.z * v2.x - v1.x * v2.z;
new.z = v1.x * v2.y - v1.y * v2.x;
return new ;
}
vect addVector(vect v1 ,vect v2){
v1.x += v2.x;
v1.y += v2.y;
v1.z += v2.z;
return v1;
}
vect subVector(vect v1 ,vect v2){
v1.x -= v2.x;
v1.y -= v2.y;
v1.z -= v2.z;
return v1;
}
void computeOrientation(){
orientation.x = cos(phi) * sin(theta);
orientation.y = cos(phi) * cos(theta);
orientation.z = sin(phi);
}
void manageKeys(Uint8 *keys){
if(keys[SDLK_ESCAPE] == SDL_PRESSED){
continuing = 0;
return;
}
if(keys[SDLK_w] == SDL_PRESSED) // move forward
position = addVector(position,scaleVector(orientation));
if(keys[SDLK_s] == SDL_PRESSED) // move backward
position = subVector(position,scaleVector(orientation));
if(keys[SDLK_a] == SDL_PRESSED){ // moveleft
lateral = unitVector(productVector(vertical,orientation));
position = addVector(position,scaleVector(lateral));
}
if(keys[SDLK_d] == SDL_PRESSED){ // move right
lateral = unitVector(productVector(vertical,orientation));
position = subVector(position,scaleVector(lateral));
}
if(keys[SDLK_SPACE] == SDL_PRESSED){ // move up
vertical = unitVector(productVector(orientation,lateral));
position = addVector(position,scaleVector(vertical));
}
if(keys[SDLK_q] == SDL_PRESSED){ // move bottom
vertical = unitVector(productVector(orientation,lateral));
position = subVector(position,scaleVector(vertical));
}
if(keys[SDLK_z] == SDL_PRESSED){ // turn the camera to look at the right
theta += SPEED_CAMERA;
if(theta > 6.28318530)
theta = 0;
computeOrientation();
lateral = unitVector(productVector(vertical,orientation));
}
if(keys[SDLK_x] == SDL_PRESSED){ // turn the camera to look at the left
theta -= SPEED_CAMERA;
if(theta < -6.28318530)
theta = 0;
computeOrientation();
lateral = unitVector(productVector(vertical,orientation));
}
if(keys[SDLK_c] == SDL_PRESSED){ // turn the camera to look up
phi += SPEED_CAMERA;
if(phi > 6.28318530)
phi = 0;
computeOrientation();
vertical = unitVector(productVector(orientation,lateral));
}
if(keys[SDLK_v] == SDL_PRESSED){ // turn the camera to look bottom
phi -= SPEED_CAMERA;
if(phi < -6.28318530)
phi = 0;
computeOrientation();
vertical = unitVector(productVector(orientation,lateral));
}
}
void display(){
double ratio= WINDOWS_WIDTH/WINDOWS_HEIGHT;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70,ratio,1,2000);
target = addVector(position ,orientation); // we look a point in front of us : in the direction of the orientation vector
gluLookAt(position.x, position.y, position.z, target.x,target.y,target.z, vertical.x,vertical.y,vertical.z);
glBegin(GL_QUADS); // we draw the 6 face of a cube
// bottom wall
glColor3f(0.1, 0.1, 0.6);
glVertex3f(-10,-10,-10);
glVertex3f(-10,10,-10);
glVertex3f(10,10,-10);
glVertex3f(10,-10,-10);
// up wall
glColor3f(0.6, 0.1, 0.6);
glVertex3f(-10,-10,10);
glVertex3f(-10,10,10);
glVertex3f(10,10,10);
glVertex3f(10,-10,10);
// right wall
glColor3f(0.6, 0.1, 0.1);
glVertex3f(-10,-10,-10);
glVertex3f(-10,-10,10);
glVertex3f(10,-10,10);
glVertex3f(10,-10,-10);
// left wall
glColor3f(0.6, 0.6, 0.1);
glVertex3f(-10,10,-10);
glVertex3f(-10,10,10);
glVertex3f(10,10,10);
glVertex3f(10,10,-10);
// front wall
glColor3f(0.1, 0.6, 0.1);
glVertex3f(-10,-10,-10);
glVertex3f(-10,-10,10);
glVertex3f(-10,10,10);
glVertex3f(-10,10,-10);
// behind wall
glColor3f(0.1, 0.6, 0.6);
glVertex3f(10,-10,-10);
glVertex3f(10,-10,10);
glVertex3f(10,10,10);
glVertex3f(10,10,-10);
glEnd();
glFlush();
SDL_GL_SwapBuffers();
}
int main(int argc, char* argv[]){
SDL_Event event;
SDL_Init(SDL_INIT_VIDEO);
SDL_WM_SetCaption("Camera",NULL);
SDL_SetVideoMode(WINDOWS_WIDTH, WINDOWS_HEIGHT, 32, SDL_OPENGL);
glEnable(GL_DEPTH_TEST);
position.x = position.y = position.z = 0; // we are in the middle of the cube
orientation.x = cos(phi) * sin(theta);
orientation.y = cos(phi) * cos(theta);
orientation.z = sin(phi);
vertical.x = 0;
vertical.y = 0;
vertical.z = 1;
lateral = unitVector(productVector(vertical,orientation));
while (continuing){
SDL_PollEvent(&event);
switch(event.type){
case SDL_QUIT:
continuing = 0;
break;
}
manageKeys(SDL_GetKeyState(NULL));
display();
}
SDL_Quit();
return EXIT_SUCCESS;
}
And the command I use to compile:
gcc -Wall -lGL -lGLU -lm -lSDL main.c -o main
In the program, I draw a cube with a different color for the 6 face and I place the camera in the middle of the cube.
I made the move of the camera work with these keys w(forward) a(left) s(backward) d(right) space(up) q(down)
I can rotate in one of the two direction with no problem (with z(right) and x(left) or c(up) and v(down)). I can even move the camera horizontally and then vertically with no problem.
The issues are with first a vertical rotation and then a horizontal.
- if I rotate with c or v key at 180°, then the rotation with the horizontal axis are inverted and I don't want it.
- if I rotate with c or v key at 90°, then the rotation with the horizontal axis seems to do nothing and the camera is stuck and I don't want it
I read some things over the internet talking about an issue called gimbal lock with Euler angles, but I don't know if this is my issue. I also read about camera with quaternions and I plan to use this method if I can't manage to made this first one work.
Can you tell me what are my issue about and how to resolve it ?