使用 OpenGL 和 GLUT 创建 FPS 风格的运动系统

Posted

技术标签:

【中文标题】使用 OpenGL 和 GLUT 创建 FPS 风格的运动系统【英文标题】:Creating an FPS style movement system with OpenGL and GLUT 【发布时间】:2014-10-01 03:41:30 【问题描述】:

我正在尝试使用 GLUT 和 OpenGL 实现第一人称移动系统。到目前为止,我的扫射从左到右,向前/向后运动正常工作。但是,我的问题来自环顾四周。我希望能够像大多数/所有 FPS 游戏一样使用鼠标的移动环顾四周。我正在使用 gluLookAt 进行所有运动/环顾四周。目前,对于环视部分,我有这个(取自教程)

    gluLookAt(position.x, position.y, position.z,
        position.x + direction.x, position.y + direction.y, position.z + direction.z,
        up_vector.x, up_vector.y, up_vector.z);

然后,当有被动鼠标移动时,我会检查它并执行以下操作:

horizontal_angle += 0.005* float(x - origin_x);
vertical_angle += 0.005* float(y - origin_y);

direction_vector.x = cos(vertical_angle) * sin(horizontal_angle);
direction_vector.y = sin(vertical_angle);
direction_vector.z = cos(vertical_angle) * cos(horizontal_angle);

position.x = sin(horizontal_angle - 3.14f/2.0f);
position.y = 0.0f;
position.z = cos(horizontal_angle - 3.14f/2.0f);

up_vector = crossProduct(right_vector, direction_vector);

但是,这给了我一些非常奇怪、摇摆不定的效果,与我想要的效果并不特别接近。

【问题讨论】:

【参考方案1】:

首先,据我所知 gluLookAt 已被弃用,如果您不想深入研究该级别,您应该考虑查看 GLM,它是一个可以为您处理几乎所有数学内容的数学库。

其次,您可以考虑使用 quaternions 来旋转您的相机,它们比仅使用普通三角函数来旋转相机要平滑得多,而且它们也不会受到 gimbal lock 的影响。据我所知,GLM 确实有一个四元数的实现,但你也可以自己实现它,我已经做了很长时间了,而且我做对了,所以我不会很难。 :P

如果您现在确实想坚持使用三角函数,这是我更改为四元数之前的旧旋转函数:

void Camera::rotateCamera(int xDelta, int yDelta, int xMid, int yMid)

    const GLfloat X_SCALED = (GLfloat)xDelta / (GLfloat)xMid;
    const GLfloat Y_SCALED = (GLfloat)yDelta / (GLfloat)yMid;
    const GLfloat ANGLE_DELTA = 2 * 360.0f / 360.0f * 3.14f;
    const GLfloat LEFT_RIGHT_ROT = X_SCALED * ANGLE_DELTA;
    const GLfloat UP_DOWN_ROT = Y_SCALED * ANGLE_DELTA;


        direction = d - r;
        vec3 right = cross(direction, u);
        vec4 temp(direction.x, direction.y, direction.z, 0.0f);

        mat4 identity;
        identity = rotate(identity, UP_DOWN_ROT, right);
        identity = rotate(identity, LEFT_RIGHT_ROT, u) ;

        temp = identity * temp;

    d = r;
    d[0] += temp[0];
    d[1] += temp[1];
    d[2] += temp[2];

    view = lookAt(r,d,u);

xDelta 是鼠标从屏幕中心移动的量,xMid 是屏幕中心。 r 是相机的眼睛,d 是它的朝向,u 是它的向上向量。

如果你有任何问题,尽管问我 :)

更新:

这是我用于实现quaternion based camera 的初始文章。

我最好的建议是尽量远离欧拉角,它们会失去精度,并可能导致奇怪的运动和旋转伪影。

【讨论】:

感谢您的回复,我想我会选择四元数,似乎是一个更好的选择! 万向节锁定是我们头部旋转方式的结果,即当您直视或直视时,您会看到一个奇点。您的“基于四元数的解决方案”不是通过四元数来避免万向节锁定,而是通过将间距从两极夹住,这样您就不能直视或直视。您也可以夹紧 Eular 角,从而避免该问题。如果你不夹紧,那么四元数不会救你,因为当View - PositionUp 平行时,它们的叉积会降为零,你就会得到可怕的万向节锁。【参考方案2】:

除了职位部分,你的做法对我来说似乎是正确的:

position.x = sin(horizontal_angle - 3.14f/2.0f);
position.y = 0.0f;
position.z = cos(horizontal_angle - 3.14f/2.0f);

应该是这样的:

vector right_vector = crossProduct(direction_vector, vector(0, 1, 0)); // maybe crossProduct(vector(0, 1, 0), direction_vector)

float speed = 3; // you decide the value.

if ( GetKey(Key_Forward) == Key_Pressed ) 
 position.x += (direction_vector.x * speed);
 position.y += (direction_vector.y * speed);
 position.z += (direction_vector.z * speed);
 else if ( GetKey(Key_Back) == Key_Pressed ) 
 position.x -= (direction_vector.x * speed);
 position.y -= (direction_vector.y * speed);
 position.z -= (direction_vector.z * speed);

if ( GetKey(Key_Right) == Key_Pressed ) 
 position.x += (right_vector.x * speed);
 position.y += (right_vector.y * speed);
 position.z += (right_vector.z * speed);
 else if ( GetKey(Key_Back) == Key_Pressed ) 
 position.x -= (right_vector.x * speed);
 position.y -= (right_vector.y * speed);
 position.z -= (right_vector.z * speed);

GetKey() 和 Key_Pressed 取决于您使用的 API 希望它对你有用,:)。

【讨论】:

以上是关于使用 OpenGL 和 GLUT 创建 FPS 风格的运动系统的主要内容,如果未能解决你的问题,请参考以下文章

在终端应用程序中使用 opengl(没有 glut/glew)[关闭]

win8.1中vs2015配置opengl环境,那个glut.lib和glut32.lib放哪里啊

在 GLUT 中与可变 FPS 无关的恒定游戏速度?

通过 Glut 为 OpenGL 自定义纹理映射

Mac 上的 OpenGL/GLUT 应用程序无法获得焦点 [关闭]

Setup VS2017 for GLUT,使用VS2017 和GLUT 运行opengl程序