【问题标题】:Creating an FPS style movement system with OpenGL and GLUT使用 OpenGL 和 GLUT 创建 FPS 风格的运动系统
【发布时间】: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);

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

【问题讨论】:

    标签: c++ opengl mouse glut frame-rate


    【解决方案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 希望它对你有用,:)。

    【讨论】:

      猜你喜欢
      • 2023-03-13
      • 1970-01-01
      • 2014-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-25
      相关资源
      最近更新 更多