如何在 OpenGL 中更新 "forward" 运动

How to update the "forward" movement in OpenGL

我的 OpenGL 应用程序有问题,您可以在 this gif 中清楚地看到。基本上我想朝光标指向的方向移动,但这并没有发生,而是 "forward" 方向保持不变。

比如我转身180°按"w"向前走,我就向后走。我说的是步行,因为我正在尝试复制第一人称视角,就像在 FPS 游戏中一样。

在这里您可以看到我到目前为止编写的代码:

#include <GL\glew.h>
#include <GL\freeglut.h>
#include <iostream>
#include <cstdlib>
#include "imageLoader.h"

using namespace std;

float _angleY = 0.0f;
float _angleX = 0.0f;
bool about_y = true;

float oldMouseX;
float oldMouseY;

int valid = 0;

float posX = 0.0;
float posZ = 0.0;

// actual vector representing the camera's direction
float lx = 0.0f, lz = -1.0f;

// XZ position of the camera
float x = 0.0f, z = 5.0f;

// the key states. These variables will be zero
// when no key is being presses
float deltaAngle = 0.0f;
float deltaMove = 0;

int xOrigin = -1;

// angle of rotation for the camera direction
float angle = 0.0f;

void mouseMove(int x, int y) {
    // this will only be true when the left button is down
    if (xOrigin >= 0) {

        // update deltaAngle
        deltaAngle = (x - xOrigin) * 0.001f;

        // update camera's direction
        lx = sin(angle + deltaAngle)*2;
        lz = -cos(angle + deltaAngle)*2;
    }
}

void mouseButton(int button, int state, int x, int y) {
    // only start motion if the left button is pressed
    if (button == GLUT_LEFT_BUTTON) {
        // when the button is released
        if (state == GLUT_UP) {
            angle += deltaAngle;
            xOrigin = -1;
        }
        else  {// state = GLUT_DOWN
            xOrigin = x;
        }
    }
}

void handleKeys(unsigned char key, int x, int y){
    switch (key)
    {
        case 'w':
            posZ+=4;
            cout << "FORWARD\n";
            break;
        case 's':
            posZ-=4;
            cout << "BACK\n";
            break;
        case 'd':
            posX-=4;
            cout << "RIGHT\n";
            break;
        case 'a':
            posX+=4;
            cout << "LEFT\n";
            break;
        case 27:
            exit(0);
            break;
    }
}

//initializes 3d rendering 
void initRendering(){
    glEnable(GL_DEPTH_TEST); //permits one object to show up behind another one
    glEnable(GL_COLOR_MATERIAL); 
    glEnable(GL_LIGHTING); //enables the lighting function
    glEnable(GL_LIGHT0);   //enables light num. 1
    glEnable(GL_LIGHT1);   //enables light num. 2
    glEnable(GL_NORMALIZE); 
    Image* image = loadBMP("bricks.bmp");
    _textureId = loadTexture(image);
    delete image;
}

//handles the resize of the window
void handleResize(int w, int h){
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, double(w) / double(h), 1.0, 800.0);
}

void computePos(float deltaMove) {
    x += deltaMove * lx * 0.1f;
    z += deltaMove * lz * 0.1f;
}

//draws the 3D sccene
void drawScene(){
    cout << "ANGLE: "<<angle<<"\n";
    if (deltaMove){
        computePos(deltaMove);
    }

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    // Set the camera
    gluLookAt(x, 1.0f, z,
        x + lx, 1.0f, z + lz,
        0.0f, 1.0f, 0.0f);

    glTranslatef(posX, 0.0f, posZ);

    //HERE WE ADD THE AMBIENT LIGHT
    GLfloat ambientColor[] = { 0.3f, 0.3f, 0.3f, 1.0f }; //the first 3 floats represent the                                                      //RGB intensity of the light 
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);

    //HERE WE ADD THE POSITIONED LIGHT (WHITE INTENSE)
    GLfloat lightColor0[] = { 0.5f, 0.5f, 0.5f, 1.0f }; //LIGHT0 color
    GLfloat lightPos0[] = { 4.0f, 0.0f, 8.0f, 1.0f };   //LIGHT0 position is (4,0,8)
    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0); //sets color/intensity of the light
    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightPos0);   //sets position of the light

    //HERE WE ADD THE DIRECTIONAL LIGHT (RED)
    GLfloat lightColor1[] = { 0.5f, 0.2f, 0.2f, 1.0f }; //LIGHT1 color
    GLfloat lightPos1[] = { -1.0f, 0.5f, 0.5f, 0.0f };  //LIGHT1 is coming from (-1,0.5,0.5)
                                                        //NOTE: we just have to put the 4th 
                                                        //parameter to 0.0f to make it directional

    glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor1); //sets color/intensity of the light
    glLightfv(GL_LIGHT1, GL_DIFFUSE, lightPos1);   //sets position of the light

    glColor3f(1.0f, 1.0f, 0.0f); //we set the cube color

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, _textureId);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    //HERE WE DEFINE COORDINATES FOR THE CUBE
    glBegin(GL_QUADS);

    //Front
    glNormal3f(0.0f, 0.0f, 1.0f);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3f(-40.5f, -40.0f, 40.5f);
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f(40.5f, -40.0f, 40.5f);
    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(40.5f, 40.0f, 40.5f);
    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(-40.5f, 40.0f, 40.5f);

    //Right
    glNormal3f(1.0f, 0.0f, 0.0f);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3f(40.5f, -40.0f, -80.5f);
    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(40.5f, 40.0f, -80.5f);
    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(40.5f, 40.0f, 40.5f);
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f(40.5f, -40.0f, 40.5f);

    //Back
    glNormal3f(0.0f, 0.0f, -1.0f);
    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(-40.5f, -40.0f, -80.5f);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3f(-40.5f, 40.0f, -80.5f);
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f(40.5f, 40.0f, -80.5f);
    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(40.5f, -40.0f, -80.5f);

    //Left
    glNormal3f(-1.0f, 0.0f, 0.0f);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3f(-40.5f, -40.0f, -80.5f);
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f(-40.5f, -40.0f, 40.5f);
    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(-40.5f, 40.0f, 40.5f);
    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(-40.5f, 40.0f, -80.5f);

    glEnd();

    glutSwapBuffers();
}

//main loop of the program
void update(int value){
    glutPostRedisplay();
    glutTimerFunc(25, update, 0);
}

您应该创建 direction 的向量。每次移动鼠标时,都应根据角度重新评估。方向矢量应为 unit circle.

上的矢量

假设你有方向向量 direction = (0.4X, 0.6Z)(数字可以是虚幻的,但让它成为例子),然后为了向前移动你应该将它乘以 velocity = 4 的标量,所以向量 velocity = (1.6X, 2.4Z).这意味着 posX += 1.6, posZ += 2.4;

如果你需要向右转,旋转 90 度并乘以速度标量。

要旋转方向矢量,您可以使用 sincos 函数,因为它位于单位圆上。

要向后和向左移动,您可以使用负速度。