我正在尝试在3d空间中移动相机。到目前为止,我已成功使用此代码移动和旋转相机:
void specialKeyHandler(int key, int x, int y) {
float fraction = 0.05f;
switch (key) {
case GLUT_KEY_LEFT :
camAngle -= 0.01f;
lX = sin(camAngle);
lZ = -cos(camAngle);
break;
case GLUT_KEY_RIGHT :
camAngle += 0.01f;
lX = sin(camAngle);
lZ = -cos(camAngle);
break;
case GLUT_KEY_UP :
iX += lX * fraction;
iZ += lZ * fraction;
break;
case GLUT_KEY_DOWN :
iX -= lX * fraction;
iZ -= lZ * fraction;
break;
default:
break;
}
}
我当然定义了这些变量。 lX,lY,lZ用于LookAt变量,iX,iY和iZ用于相机的眼睛。
相机根据需要移动,但现在我想在“相机的眼睛”上附加一个物体,该物体随相机一起移动。就像FPS游戏中的武器一样
这就是我的意思:
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawEarth();
drawWalls();
glColor3f(255,0,0);
glPushMatrix();
glTranslatef(iX+0.05,iY, iZ-0.05);
glRotatef(camAngle, 0,1,0);
glutWireCone(0.005,0.1,20,20); // object to go with camera
glPopMatrix();
glutSwapBuffers();
}
此代码当前在向上和向下移动时将对象与相机绑定在一起。但是当我按左右键旋转相机时,物体会停留在那里,相机会自行移动。
有解决方案吗
这是完整的opengl代码,如果有人想要运行:
#include <GL/glut.h>
#include<iostream>
#include<math.h>
using namespace std;
void display(void);
void reshape(int, int);
void mouseHandler(int button, int state, int x, int y);
void keyBoardHandler(unsigned char c, int x, int y);
void specialKeyHandler(int key, int x, int y);
float angle = 0;
bool camDefault = true, perspectiveOrtho = true;
float iX =0 , iY = -0.8, iZ = 0, lX = 0, lY = -0.8, lZ = -1, uX = 0, uY = 1, uZ = 0;
float camAngle = 0;
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitWindowSize(512, 512);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutCreateWindow("FPS Camera");
glutDisplayFunc(display);
glutIdleFunc(display);
//look from negative x axis towards origin. with y on top
glutReshapeFunc(reshape);
glEnable(GL_DEPTH_TEST);
glClearColor(0,0,0,1);
glutMouseFunc(mouseHandler);
glutKeyboardFunc(keyBoardHandler);
glutSpecialFunc(specialKeyHandler);
glutMainLoop();
return 0;
}
void drawEarth() {
glColor3f(0,255,0);
glBegin(GL_QUADS);
glVertex3f(-1,-1,-1);
glVertex3f(-1,-1,1);
glVertex3f(1,-1,1);
glVertex3f(1,-1,-1);
glEnd();
}
void drawWalls() {
glColor3f(0,0,255);
glBegin(GL_QUADS);
glVertex3f(-1,-1,-1);
glVertex3f(-1,-1,1);
glVertex3f(-1,1,1);
glVertex3f(-1,1,-1);
glEnd();
glColor3f(0,234,255);
glBegin(GL_QUADS);
glVertex3f(-1,-1,1);
glVertex3f(-1,1,1);
glVertex3f(1,1,1);
glVertex3f(1,-1,1);
glEnd();
}
float unitVector(float dir, float x, float y, float z) {
float sumSqr = pow(x,2) + pow(y,2) + pow(z,2);
return dir / (sqrt(sumSqr));
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawEarth();
drawWalls();
glColor3f(255,0,0);
glPushMatrix();
glTranslatef(iX+0.05,iY, iZ-0.05);
glRotatef(camAngle, 0,1,0);
glutWireCone(0.005,0.1,20,20);
glPopMatrix();
glutSwapBuffers();
}
void reshape(int width, int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90,1, 0.001, 1000);
gluLookAt(iX,iY,iZ,iX+lX,lY,iZ+lZ,uX,uY,uZ);
glMatrixMode(GL_MODELVIEW);
}
void updateLookAt() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective (90, 1 ,0.001, 1000);
gluLookAt(iX,iY,iZ,iX+lX,lY,iZ+lZ,uX,uY,uZ);
glMatrixMode(GL_MODELVIEW);
}
void keyBoardHandler(unsigned char c, int x, int y) {
switch(c) {
case 'f': // go left
iX-=0.01;
lX -= 0.01;
cout<<endl<<"S pressed";
break;
case 's': // go right
iX += 0.01;
lX += 0.01;
break;
case 'e': // go up
iZ += 0.01;
lZ += 0.01;
break;
case 'd': // go down
iZ -= 0.01;
lZ -= 0.01;
break;
default:
break;
}
updateLookAt();
}
void mouseHandler(int button, int state, int x, int y) {
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
if(camDefault) {
glLoadIdentity();
gluLookAt(-1,0,0,0.0,0.0,0.0,0.0,1,0);
camDefault = false;
}
else {
glLoadIdentity();
gluLookAt(0,0,0,0.0,0.0,0.0,0.0,1,0);
camDefault = true;
}
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(perspectiveOrtho) {
gluPerspective (90, 1 ,0.00001, 1000);
perspectiveOrtho = false;
}
else {
glOrtho(-1,1,-1,1, -1,100);
perspectiveOrtho = true;
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if(camDefault)
gluLookAt(0,0,1,0.0,0.0,0.0,0.0,1,0);
else
gluLookAt(-1,0,0,0.0,0.0,0.0,0.0,1,0);
}
}
void specialKeyHandler(int key, int x, int y) {
float fraction = 0.05f;
switch (key) {
case GLUT_KEY_LEFT :
camAngle -= 0.01f;
lX = sin(camAngle);
lZ = -cos(camAngle);
break;
case GLUT_KEY_RIGHT :
camAngle += 0.01f;
lX = sin(camAngle);
lZ = -cos(camAngle);
break;
case GLUT_KEY_UP :
iX += lX * fraction;
iZ += lZ * fraction;
break;
case GLUT_KEY_DOWN :
iX -= lX * fraction;
iZ -= lZ * fraction;
break;
default:
break;
}
updateLookAt();
}
答案 0 :(得分:2)
你有两个问题。
第一个问题出在你的坐标系上。
申请时:
glTranslatef(iX+0.05,iY, iZ-0.05);
您将对象放在相机位置,并添加偏移量以查看他。但这是世界坐标系。因此,当您旋转相机时,对象不会移动,因为它不会跟随相机的坐标系。
您需要转换到相机中心,旋转相机,然后添加偏移。
第二个问题是轮换问题。你的“camAngle”变量是弧度的,因为你使用cos()和sin()。但在OpenGL中,glRotate将角度视为度数值。您需要以角度转换此角度:angle * = 180 / PI。 (180 / PI~ = 57.2957795)
这里是更正后的显示功能:
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(255,0,0);
glPushMatrix();
glTranslatef(iX,iY,iZ); // Translation to the camera center
glRotatef(-camAngle * 57.2957795, 0,1,0); // Rotate to correspond to the camera
glTranslatef(0.05,0,-0.05); // Offset to draw the object
glutWireCone(0.005,0.1,20,20);
glPopMatrix();
drawEarth();
drawWalls();
glutSwapBuffers();
}