Opengl 相机在某些方向上不起作用
Opengl camera doesn't work in some directions
我的目标是用 C 语言用 OpenGL 和 SDL 1.2 制作一个相机。
我希望能够在所有方向上移动(向前、向后、向左、向右、上下)。我希望能够在所有方向上自由旋转相机:从左到右(就像在 space 中使用 spacecraft)。在第一个版本中,我只使用键盘,但在未来,我希望能够使用鼠标移动相机的方向,使用键盘移动 spacecraft。
这是我的完整代码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;
}
以及我用来编译的命令:
gcc -Wall -lGL -lGLU -lm -lSDL main.c -o main
在程序中,我为6面画了一个不同颜色的立方体,并将相机放在立方体的中间。
我使用这些键使相机移动 w(forward) a(left) s(backward) d(right) space(up) q(down)
我可以毫无问题地沿两个方向之一旋转(使用 z(右)和 x(左)或 c(上)和 v(下))。我什至可以水平移动相机,然后垂直移动相机。
首先是垂直旋转,然后是水平旋转。
- 如果我用c键或v键旋转180°,那么横轴旋转就反了,我不要了
- 如果我用c或v键旋转90°,然后水平轴旋转好像什么也没做,相机卡住了,我不想
我在网上读到一些关于欧拉角万向节锁的问题,但我不知道这是否是我的问题。
我还阅读了有关带四元数的相机的信息,如果我无法完成第一个工作,我打算使用此方法。
你能告诉我我的问题是什么以及如何解决吗?
我给相机植入了四元数(我用这个website来做公式)。我拥有我想要的一切:在 6 个方向上移动,并旋转相机 up/down 和 left/right。我什至可以转动 left/right 相机。
完整代码如下:
main.c
#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "camera.h"
#define WINDOWS_WIDTH 1280.0
#define WINDOWS_HEIGHT 720.0
#define SPEED_MOVE 0.1
#define SPEED_CAMERA 0.005
vector position, orientation, lateral, vertical, target;
int continuing=1;
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, SPEED_MOVE));
if(keys[SDLK_s] == SDL_PRESSED) // move backward
position = subVector(position, scaleVector(orientation, SPEED_MOVE));
if(keys[SDLK_a] == SDL_PRESSED) // move left
position = addVector(position, scaleVector(lateral, SPEED_MOVE));
if(keys[SDLK_d] == SDL_PRESSED) // move right
position = subVector(position, scaleVector(lateral, SPEED_MOVE));
if(keys[SDLK_SPACE] == SDL_PRESSED) // move up
position = addVector(position, scaleVector(vertical, SPEED_MOVE));
if(keys[SDLK_q] == SDL_PRESSED) // move bottom
position = subVector(position, scaleVector(vertical, SPEED_MOVE));
if(keys[SDLK_z] == SDL_PRESSED){ // turn the camera to look at the left
orientation = makeRotation(orientation, vertical, SPEED_CAMERA);
lateral = unitVector(productVector(vertical,orientation));
}
if(keys[SDLK_x] == SDL_PRESSED){ // turn the camera to look at the right
orientation = makeRotation(orientation, vertical, -SPEED_CAMERA);
lateral = unitVector(productVector(vertical,orientation));
}
if(keys[SDLK_c] == SDL_PRESSED){ // turn the camera to look up
orientation = makeRotation(orientation, lateral, -SPEED_CAMERA);
vertical = unitVector(productVector(orientation,lateral));
}
if(keys[SDLK_v] == SDL_PRESSED){ // turn the camera to look bottom
orientation = makeRotation(orientation, lateral, SPEED_CAMERA);
vertical = unitVector(productVector(orientation,lateral));
}
if(keys[SDLK_f] == SDL_PRESSED){// turn the camera with a roll to the left
lateral = makeRotation(lateral, orientation, -SPEED_CAMERA);
vertical = unitVector(productVector(orientation,lateral));
}
if(keys[SDLK_g] == SDL_PRESSED){// turn the camera with a roll to the right
lateral = makeRotation(lateral, orientation, SPEED_CAMERA);
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);
gluLookAt(position.x, position.y, position.z, target.x,target.y,target.z, vertical.x,vertical.y,vertical.z);
glBegin(GL_QUADS);
// 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 = 1;
orientation.y = 0;
orientation.z = 0;
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;
}
camera.h
#ifndef CAMERA
#define CAMERA
#include <math.h>
typedef struct structVector{
double x, y, z;
}vector;
vector addVector(vector u, vector v);
vector subVector(vector u, vector v);
vector unitVector(vector v);
vector productVector(vector u ,vector v);
vector scaleVector(vector u, double scale);
typedef struct structQuaternion{
double x, y, z, w;
}quaternion;
quaternion conjugateQuaternion(quaternion a);
quaternion multiplyingQuaternion(quaternion a, quaternion b);
quaternion vector2quaternion(vector v);
quaternion createRotation(vector v, double angle);
vector makeRotation(vector v, vector rotationAxis, double angle);
#endif
camera.c
#include "camera.h"
vector addVector(vector u, vector v){
u.x += v.x;
u.y += v.y;
u.z += v.z;
return u;
}
vector subVector(vector u, vector v){
u.x -= v.x;
u.y -= v.y;
u.z -= v.z;
return u;
}
vector unitVector(vector v){
double norm = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
v.x /= norm;
v.y /= norm;
v.z /= norm;
return v;
}
vector productVector(vector u ,vector v){
vector a;
a.x = u.y * v.z - u.z * v.y;
a.y = u.z * v.x - u.x * v.z;
a.z = u.x * v.y - u.y * v.x;
return a;
}
vector scaleVector(vector u, double scale){
u.x *= scale;
u.y *= scale;
u.z *= scale;
return u;
}
quaternion conjugateQuaternion(quaternion a){
a.x = -a.x;
a.y = -a.y;
a.z = -a.z;
return a;
}
quaternion multiplyingQuaternion(quaternion a, quaternion b){
quaternion c;
c.x = a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y;
c.y = a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x;
c.z = a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w;
c.w = a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z;
return c;
}
quaternion vector2quaternion(vector v){
quaternion a;
a.x = v.x;
a.y = v.y;
a.z = v.z;
a.w = 0;
return a;
}
quaternion createRotation(vector v, double angle){
quaternion a;
a.x = v.x * sin(angle/2);
a.y = v.y * sin(angle/2);
a.z = v.z * sin(angle/2);
a.w = cos(angle/2);
return a;
}
vector makeRotation(vector v, vector rotationAxis, double angle){
quaternion rotation = createRotation(rotationAxis, angle);
quaternion quaternionOfV = vector2quaternion(v);
quaternion a = multiplyingQuaternion(rotation, quaternionOfV );
a = multiplyingQuaternion(a, conjugateQuaternion(rotation));
v.x = a.x;
v.y = a.y;
v.z = a.z;
return v;
}
即使我不看东西,我仍然使用函数 gluLookAt。也许还有其他更好的方法。
我的目标是用 C 语言用 OpenGL 和 SDL 1.2 制作一个相机。 我希望能够在所有方向上移动(向前、向后、向左、向右、上下)。我希望能够在所有方向上自由旋转相机:从左到右(就像在 space 中使用 spacecraft)。在第一个版本中,我只使用键盘,但在未来,我希望能够使用鼠标移动相机的方向,使用键盘移动 spacecraft。
这是我的完整代码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;
}
以及我用来编译的命令:
gcc -Wall -lGL -lGLU -lm -lSDL main.c -o main
在程序中,我为6面画了一个不同颜色的立方体,并将相机放在立方体的中间。
我使用这些键使相机移动 w(forward) a(left) s(backward) d(right) space(up) q(down)
我可以毫无问题地沿两个方向之一旋转(使用 z(右)和 x(左)或 c(上)和 v(下))。我什至可以水平移动相机,然后垂直移动相机。
首先是垂直旋转,然后是水平旋转。
- 如果我用c键或v键旋转180°,那么横轴旋转就反了,我不要了
- 如果我用c或v键旋转90°,然后水平轴旋转好像什么也没做,相机卡住了,我不想
我在网上读到一些关于欧拉角万向节锁的问题,但我不知道这是否是我的问题。 我还阅读了有关带四元数的相机的信息,如果我无法完成第一个工作,我打算使用此方法。
你能告诉我我的问题是什么以及如何解决吗?
我给相机植入了四元数(我用这个website来做公式)。我拥有我想要的一切:在 6 个方向上移动,并旋转相机 up/down 和 left/right。我什至可以转动 left/right 相机。
完整代码如下:
main.c
#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "camera.h"
#define WINDOWS_WIDTH 1280.0
#define WINDOWS_HEIGHT 720.0
#define SPEED_MOVE 0.1
#define SPEED_CAMERA 0.005
vector position, orientation, lateral, vertical, target;
int continuing=1;
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, SPEED_MOVE));
if(keys[SDLK_s] == SDL_PRESSED) // move backward
position = subVector(position, scaleVector(orientation, SPEED_MOVE));
if(keys[SDLK_a] == SDL_PRESSED) // move left
position = addVector(position, scaleVector(lateral, SPEED_MOVE));
if(keys[SDLK_d] == SDL_PRESSED) // move right
position = subVector(position, scaleVector(lateral, SPEED_MOVE));
if(keys[SDLK_SPACE] == SDL_PRESSED) // move up
position = addVector(position, scaleVector(vertical, SPEED_MOVE));
if(keys[SDLK_q] == SDL_PRESSED) // move bottom
position = subVector(position, scaleVector(vertical, SPEED_MOVE));
if(keys[SDLK_z] == SDL_PRESSED){ // turn the camera to look at the left
orientation = makeRotation(orientation, vertical, SPEED_CAMERA);
lateral = unitVector(productVector(vertical,orientation));
}
if(keys[SDLK_x] == SDL_PRESSED){ // turn the camera to look at the right
orientation = makeRotation(orientation, vertical, -SPEED_CAMERA);
lateral = unitVector(productVector(vertical,orientation));
}
if(keys[SDLK_c] == SDL_PRESSED){ // turn the camera to look up
orientation = makeRotation(orientation, lateral, -SPEED_CAMERA);
vertical = unitVector(productVector(orientation,lateral));
}
if(keys[SDLK_v] == SDL_PRESSED){ // turn the camera to look bottom
orientation = makeRotation(orientation, lateral, SPEED_CAMERA);
vertical = unitVector(productVector(orientation,lateral));
}
if(keys[SDLK_f] == SDL_PRESSED){// turn the camera with a roll to the left
lateral = makeRotation(lateral, orientation, -SPEED_CAMERA);
vertical = unitVector(productVector(orientation,lateral));
}
if(keys[SDLK_g] == SDL_PRESSED){// turn the camera with a roll to the right
lateral = makeRotation(lateral, orientation, SPEED_CAMERA);
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);
gluLookAt(position.x, position.y, position.z, target.x,target.y,target.z, vertical.x,vertical.y,vertical.z);
glBegin(GL_QUADS);
// 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 = 1;
orientation.y = 0;
orientation.z = 0;
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;
}
camera.h
#ifndef CAMERA
#define CAMERA
#include <math.h>
typedef struct structVector{
double x, y, z;
}vector;
vector addVector(vector u, vector v);
vector subVector(vector u, vector v);
vector unitVector(vector v);
vector productVector(vector u ,vector v);
vector scaleVector(vector u, double scale);
typedef struct structQuaternion{
double x, y, z, w;
}quaternion;
quaternion conjugateQuaternion(quaternion a);
quaternion multiplyingQuaternion(quaternion a, quaternion b);
quaternion vector2quaternion(vector v);
quaternion createRotation(vector v, double angle);
vector makeRotation(vector v, vector rotationAxis, double angle);
#endif
camera.c
#include "camera.h"
vector addVector(vector u, vector v){
u.x += v.x;
u.y += v.y;
u.z += v.z;
return u;
}
vector subVector(vector u, vector v){
u.x -= v.x;
u.y -= v.y;
u.z -= v.z;
return u;
}
vector unitVector(vector v){
double norm = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
v.x /= norm;
v.y /= norm;
v.z /= norm;
return v;
}
vector productVector(vector u ,vector v){
vector a;
a.x = u.y * v.z - u.z * v.y;
a.y = u.z * v.x - u.x * v.z;
a.z = u.x * v.y - u.y * v.x;
return a;
}
vector scaleVector(vector u, double scale){
u.x *= scale;
u.y *= scale;
u.z *= scale;
return u;
}
quaternion conjugateQuaternion(quaternion a){
a.x = -a.x;
a.y = -a.y;
a.z = -a.z;
return a;
}
quaternion multiplyingQuaternion(quaternion a, quaternion b){
quaternion c;
c.x = a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y;
c.y = a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x;
c.z = a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w;
c.w = a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z;
return c;
}
quaternion vector2quaternion(vector v){
quaternion a;
a.x = v.x;
a.y = v.y;
a.z = v.z;
a.w = 0;
return a;
}
quaternion createRotation(vector v, double angle){
quaternion a;
a.x = v.x * sin(angle/2);
a.y = v.y * sin(angle/2);
a.z = v.z * sin(angle/2);
a.w = cos(angle/2);
return a;
}
vector makeRotation(vector v, vector rotationAxis, double angle){
quaternion rotation = createRotation(rotationAxis, angle);
quaternion quaternionOfV = vector2quaternion(v);
quaternion a = multiplyingQuaternion(rotation, quaternionOfV );
a = multiplyingQuaternion(a, conjugateQuaternion(rotation));
v.x = a.x;
v.y = a.y;
v.z = a.z;
return v;
}
即使我不看东西,我仍然使用函数 gluLookAt。也许还有其他更好的方法。