OpenGL - FPS样式相机移动,物体固定在相机上

时间:2013-11-16 13:33:38

标签: opengl camera rotation glulookat

我正在尝试在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();
}

1 个答案:

答案 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();
}