旋转opengl相机的问题

Problems rotating opengl camera

我无法理解这个问题背后的数学原理,我正在尝试创建一个 FPS 相机,我可以通过鼠标输入自由查看。

我正在尝试以 180 度的自由度旋转和定位我的观察点。我知道更简单的解决方案是 glRotate 世界以适应我的视角,但我不想要这种方法。我对这里涉及的三角学相当陌生,无法弄清楚如何按照我想要的方式解决这个问题...

这是我到目前为止的尝试...

获取鼠标相对于window中心的坐标的代码,然后在我的相机对象中处理它

#define DEG2RAD(a) (a * (M_PI / 180.0f))//convert to radians
static void glutPassiveMotionHandler(int x, int y) {
    glf centerX = WinWidth / 2; glf centerY = WinHeight / 2;//get windows origin point
    f speed = 0.2f;
    f oldX = mouseX;  f oldY = mouseY;

    mouseX = DEG2RAD(-((x - centerX)));//get distance from 0 and convert to radians
    mouseY = DEG2RAD(-((y - centerY)));//get distance from 0 and convert to radians

    f diffX = mouseX - oldX; f diffY = mouseY - oldY;//get difference from last frame to this frame

    if (mouseX != 0 || mouseY != 0) {
        mainCamera->Rotate(diffX, diffY);
    }

旋转相机的代码

void Camera::Rotate(f angleX, f angleY) {
    Camera::refrence = Vector3D::NormalizeVector(Camera::refrence * cos(angleX)) + (Camera::upVector * sin(angleY));//rot up
    Camera::refrence = Vector3D::NormalizeVector((Camera::refrence * cos(angleY)) - (Camera::rightVector * sin(angleX)));//rot side to side
};

Camera::refrence是我们的lookat point,处理lookat point的处理如下

void Camera::LookAt(void) {
    gluLookAt(
        Camera::position.x, Camera::position.y, Camera::position.z,
        Camera::refrence.x, Camera::refrence.y, Camera::refrence.z,
        Camera::upVector.x, Camera::upVector.y, Camera::upVector.z
    );
};

U_Cam_X_angle是左右旋转..U_Cam_Y_angle是上下旋转.

view_radiusU_look_point_xU_look_point_yU_look_point_z 的视距(缩放)。 这始终是一个负数!这是因为你总是朝积极的方向看。在屏幕的更深处是更积极的。 这都是以弧度为单位的。

最后三个.. eyeXeyeYeyeZ 是相机在 3D 中的位置 space。

此代码在 VB.net 中。在线查找 VB 到 C++ 的转换器或手动进行。

Public Sub set_eyes()

    Dim sin_x, sin_y, cos_x, cos_y As Single
    sin_x = Sin(U_Cam_X_angle + angle_offset)
    cos_x = Cos(U_Cam_X_angle + angle_offset)
    cos_y = Cos(U_Cam_Y_angle)
    sin_y = Sin(U_Cam_Y_angle)
    cam_y = Sin(U_Cam_Y_angle) * view_radius
    cam_x = (sin_x - (1 - cos_y) * sin_x) * view_radius
    cam_z = (cos_x - (1 - cos_y) * cos_x) * view_radius

    Glu.gluLookAt(cam_x + U_look_point_x, cam_y + U_look_point_y, cam_z + U_look_point_z, _
                        U_look_point_x, U_look_point_y, U_look_point_z, 0.0F, 1.0F, 0.0F)

    eyeX = cam_x + U_look_point_x
    eyeY = cam_y + U_look_point_y
    eyeZ = cam_z + U_look_point_z

End Sub

相机由位置点 (position) 目标点 (refrence) 和向上矢量 upVector 定义。如果你想改变相机的方向,那么你必须将方向矢量从位置(position)旋转到目标(refrence)而不是目标点Rotation matrix.

注意,由于这 2 个角度是应该改变已经旋转的视图的角度,因此您必须使用旋转矩阵来旋转指向任意方向的向量。

写一个函数,设置绕任意轴的 3x3 旋转矩阵:

void RotateMat(float m[], float angle_radians, float x, float y, float z)
{
    float c = cos(angle_radians);
    float s = sin(angle_radians);

    m[0] = x*x*(1.0f-c)+c;   m[1] = x*y*(1.0f-c)-z*s; m[2] = x*z*(1.0f-c)+y*s;
    m[3] = y*x*(1.0f-c)+z*s; m[4] = y*y*(1.0f-c)+c;   m[5] = y*z*(1.0f-c)-x*s;
    m[6] = z*x*(1.0f-c)-y*s; m[7] = z*y*(1.0f-c)+x*s; m[8] = z*z*(1.0f-c)+c };
}

编写一个函数,通过矩阵旋转 3 维向量:

Vector3D Rotate(float m[], const Vector3D &v)
{
  Vector3D rv;
  rv.x = m[0] * v.x + m[3] * v.y + m[6] * v.z;
  rv.y = m[1] * v.x + m[4] * v.y + m[7] * v.z;
  rv.z = m[2] * v.x + m[5] * v.y + m[8] * v.z;
  return rv;
}

从目标位置计算向量:

Vector3D los = Vector3D(refrence.x - position.x, refrence.y - position.y, refrence.z - position.z);

将所有向量围绕世界的 z 轴旋转 angleX:

float rotX[9];
RotateMat(rotX, angleX, Vector3D(0, 0, 1));

los = Rotate(rotX, los);
upVector = Rotate(rotX, upVector);

将所有向量围绕视图的当前 y 轴旋转 angleY:

float rotY[9];
RotateMat(rotY, angleY, Vector3D(los.x, los.y, 0.0));

los = Rotate(rotY, los);
upVector = Rotate(rotY, upVector);

计算新的目标点:

refrence = Vector3D(position.x + los.x, position.y + los.y, position.z + los.z);