gpt4 book ai didi

c - Opengl 相机在某些方向上不起作用

转载 作者:太空宇宙 更新时间:2023-11-03 23:25:09 25 4
gpt4 key购买 nike

我的目标是用 C 语言用 OpenGL 和 SDL 1.2 制作一个相机。我希望能够在所有方向上移动(向前、向后、向左、向右、上下)。我希望能够在所有方向上自由旋转相机:从左到右(就像在太空中的航天器一样)。在第一个版本中,我只是使用键盘,但在未来,我希望能够用鼠标移动相机的方向,用键盘移动航天器的方向。

这是我编写/恢复的完整代码。

#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 个方向上移动,以及向上/向下和向左/向右旋转相机。我什至可以向左/向右滚动相机。

完整代码如下:

主.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;
}

相机.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

相机.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 相机在某些方向上不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29169852/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com