OpenGL摄像机 - 来自四元数的视图矩阵行为不正确,音高过于限制 [英] OpenGL camera - View matrix from quaternion behaves incorrectly and pitch is too restricted

查看:1276
本文介绍了OpenGL摄像机 - 来自四元数的视图矩阵行为不正确,音高过于限制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用当前方向(四元数)及其当前位置为相机创建视图矩阵。

I'm creating the view matrix for my camera using its current orientation (quaternion) and its current position.

void Camera::updateViewMatrix()
{
    view = glm::gtx::quaternion::toMat4(orientation);

    // Include rotation (Free Look Camera)
    view[3][0] = -glm::dot(glm::vec3(view[0][0], view[0][1], view[0][2]), position);
    view[3][1] = -glm::dot(glm::vec3(view[1][0], view[1][1], view[1][2]), position);
    view[3][2] = -glm::dot(glm::vec3(view[2][0], view[2][1], view[2][2]), position);

    // Ignore rotation (FPS Camera)
    //view[3][0] = -position.x;
    //view[3][1] = -position.y;
    //view[3][2] = -position.z;

    view[3][3] = 1.0f;
}

有一个问题,我不相信四元数矩阵计算是给出正确的答案。

There is a problem with this in that I do not believe the quaternion to matrix calculation is giving the correct answer. Translating the camera works as expected but rotating it causes incorrect behavior.

我使用当前鼠标位置和屏幕中心之间的差异旋转相机(重置每个框架的鼠标位置)

I am rotating the camera using the difference between the current mouse position and the the centre of the screen (resetting the mouse position each frame)

int xPos;
int yPos;
glfwGetMousePos(&xPos, &yPos);

int centreX = 800 / 2;
int centreY = 600 / 2;

rotate(xPos - centreX, yPos - centreY);

// Reset mouse position for next frame
glfwSetMousePos(800 / 2, 600 / 2);

在此方法中执行轮播

void Camera::rotate(float yawDegrees, float pitchDegrees)
{
    // Apply rotation speed to the rotation
    yawDegrees *= lookSensitivity;
    pitchDegrees *= lookSensitivity;

    if (isLookInverted)
    {
        pitchDegrees = -pitchDegrees;
    }

    pitchAccum += pitchDegrees;

    // Stop the camera from looking any higher than 90 degrees
    if (pitchAccum > 90.0f)
    {
        //pitchDegrees = 90.0f - (pitchAccum - pitchDegrees);
        pitchAccum = 90.0f;
    }

    // Stop the camera from looking any lower than 90 degrees
    if (pitchAccum < -90.0f)
    {
        //pitchDegrees = -90.0f - (pitchAccum - pitchDegrees);
        pitchAccum = -90.0f;
    }

    yawAccum += yawDegrees;

    if (yawAccum > 360.0f)
    {
        yawAccum -= 360.0f;
    }

    if (yawAccum < -360.0f)
    {
        yawAccum += 360.0f;
    }

    float yaw = yawDegrees * DEG2RAD;
    float pitch = pitchDegrees * DEG2RAD;

    glm::quat rotation;

    // Rotate the camera about the world Y axis (if mouse has moved in any x direction)
    rotation = glm::gtx::quaternion::angleAxis(yaw, 0.0f, 1.0f, 0.0f);

    // Concatenate quaterions
    orientation = orientation * rotation;

    // Rotate the camera about the world X axis (if mouse has moved in any y direction)
    rotation = glm::gtx::quaternion::angleAxis(pitch, 1.0f, 0.0f, 0.0f);

    // Concatenate quaternions
    orientation = orientation * rotation;
}

我正确地连接四元数用于正确的方向?

Am I concatenating the quaternions correctly for the correct orientation?

音高累积也有一个问题,它将我的视图限制在〜±5度,而不是±90度。这可能是什么原因?

There is also a problem with the pitch accumulation in that it restricts my view to ~±5 degrees rather than ±90. What could be the cause of that?

编辑:

我已经解决了音高积累的问题其范围是[-90,90]。事实证明glm使用度数而不是向量作为轴角度,并且四元数连接的乘法顺序不正确。

I have solved the problem for the pitch accumulation so that its range is [-90, 90]. It turns out that glm uses degrees and not vectors for axis angle and the order of multiplication for the quaternion concatenation was incorrect.

// Rotate the camera about the world Y axis
// N.B. 'angleAxis' method takes angle in degrees (not in radians)
rotation = glm::gtx::quaternion::angleAxis(yawDegrees, 0.0f, 1.0f, 0.0f);

// Concatenate quaterions ('*' operator concatenates)
// C#: Quaternion.Concatenate(ref rotation, ref orientation)
orientation = orientation * rotation;

// Rotate the camera about the world X axis
rotation = glm::gtx::quaternion::angleAxis(pitchDegrees, 1.0f, 0.0f, 0.0f);

// Concatenate quaterions ('*' operator concatenates)
// C#: Quaternion.Concatenate(ref orientation, ref rotation)
orientation = rotation * orientation;

剩下的问题是视图矩阵旋转看起来旋转绘制对象,一个正常的FPS相机。

The problem that remains is that the view matrix rotation appears to rotate the drawn object and not look around like a normal FPS camera.

我已经上传了一个视频到YouTube来演示这个问题。

I have uploaded a video to YouTube to demonstrate the problem. I move the mouse around to change the camera's orientation but the triangle appears to rotate instead.

YouTube视频演示相机定位问题

编辑2:

void Camera::rotate(float yawDegrees, float pitchDegrees)
{
    // Apply rotation speed to the rotation
    yawDegrees *= lookSensitivity;
    pitchDegrees *= lookSensitivity;

    if (isLookInverted)
    {
        pitchDegrees = -pitchDegrees;
    }

    pitchAccum += pitchDegrees;

    // Stop the camera from looking any higher than 90 degrees
    if (pitchAccum > 90.0f)
    {
        pitchDegrees = 90.0f - (pitchAccum - pitchDegrees);
        pitchAccum = 90.0f;
    }
    // Stop the camera from looking any lower than 90 degrees
    else if (pitchAccum < -90.0f)
    {
        pitchDegrees = -90.0f - (pitchAccum - pitchDegrees);
        pitchAccum = -90.0f;
    }

    // 'pitchAccum' range is [-90, 90]
    //printf("pitchAccum %f \n", pitchAccum);

    yawAccum += yawDegrees;

    if (yawAccum > 360.0f)
    {
        yawAccum -= 360.0f;
    }
    else if (yawAccum < -360.0f)
    {
        yawAccum += 360.0f;
    }

    orientation = 
        glm::gtx::quaternion::angleAxis(pitchAccum, 1.0f, 0.0f, 0.0f) * 
        glm::gtx::quaternion::angleAxis(yawAccum, 0.0f, 1.0f, 0.0f);
}

EDIT3:

以下乘法顺序允许摄像机围绕其自身轴旋转,但面向错误的方向:

The following multiplication order allows the camera to rotate around its own axis but face the wrong direction:

    glm::mat4 translation;
translation = glm::translate(translation, position);

view = glm::gtx::quaternion::toMat4(orientation) * translation;

EDIT4:

(基于旋转后的位置应用转换矩阵)

The following will work (applying the translation matrix based on the position after then rotation)

// Rotation
view = glm::gtx::quaternion::toMat4(orientation); 

// Translation
glm::mat4 translation;
translation = glm::translate(translation, -position);

view *= translation;

我无法获得每个定向轴的点积,但

I can't get the dot product with each orientation axis to work though

// Rotation
view = glm::gtx::quaternion::toMat4(orientation); 

glm::vec3 p(
    glm::dot(glm::vec3(view[0][0], view[0][1], view[0][2]), position),
    glm::dot(glm::vec3(view[1][0], view[1][1], view[1][2]), position),
    glm::dot(glm::vec3(view[2][0], view[2][1], view[2][2]), position)
    );

// Translation
glm::mat4 translation;
translation = glm::translate(translation, -p);

view *= translation;


推荐答案

为了给你一个明确的答案,我们需要显示如何实际提供视图矩阵和顶点到OpenGL的代码。但是,症状听起来很不正确的矩阵顺序。

In order to give you a definite answer, I think that we would need the code that shows how you're actually supplying the view matrix and vertices to OpenGL. However, the symptom sounds pretty typical of incorrect matrix order.

考虑一些变量:

V 代表相机当前方向的倒数(四元数)。< br>
T 表示保存摄像机位置的转换矩阵。这应该是一个单位矩阵,其中相机的位置取决于第四列(假设我们右乘列向量)。

U 表示

p 表示世界空间中的顶点。

注意:所有矩阵都是逆矩阵,因为变换将应用于顶点,而不是相机,但最终结果是相同的。

Consider some variables:
V represents the inverse of the current orientation of the camera (the quaternion).
T represents the translation matrix holding the position of the camera. This should be an identity matrix with negation of the camera's position going down the fourth column (assuming that we're right-multiplying column vectors).
U represents the inverse of the change in orientation.
p represents a vertex in world space.
Note: all of the matrices are inverse matrices because the transformations will be applied to the vertex, not the camera, but the end result is the same.

默认情况下,OpenGL摄像机处于原点, z轴。当视图不改变( U == I )时,顶点从世界坐标到相机坐标的转换应该是: p'= TVp 。您首先定向相机(通过沿相反方向旋转世界),然后将相机平移到位置(通过沿相反方向移动世界)。

By default the OpenGL camera is at the origin looking down the negative-z axis. When the view isn't changing (U==I), then the vertex's transformation from world coordinates to camera coordinates should be: p'=TVp. You first orient the camera (by rotating the world in the opposite direction) and then translate the camera into position (by shifting the world in the opposite direction).

现在有几个地方可以放置 U 。如果我们将 U 放在 V 的右侧,那么我们就会获得第一人称视图的行为。当您向上移动鼠标时,无论当前正在查看的是什么,相机周围向下旋转。

Now there are a few places to put U. If we put U to the right of V, then we get the behavior of a first-person view. When you move the mouse up, whatever is currently in view rotates downward around the camera. When you move the mouse right, whatever is in view rotates to the left around the camera.

如果我们在 T之间放置 U V ,则相机会相对于世界的轴而不是相机的轴。这是奇怪的行为。如果 V 发生在将相机关闭的一侧,则上下移动鼠标会使世界看起来滚动而不是俯仰或偏航。

If we put U between T and V, then the camera turns relative to the world's axes instead of the camera's. This is strange behavior. If V happens to turn the camera off to the side, then moving the mouse up and down will make the world seem to 'roll' instead of 'pitch' or 'yaw'.

如果我们将 U 左侧的 T ,那么摄像机绕着世界的轴绕着世界的原点旋转。这甚至可以陌生,因为它使相机飞越通过世界更快的相机是从原点。然而,因为旋转是在原点周围,如果相机碰巧查看原点,那么对象就会转向。这是你所看到的,因为你使用的旋转相机的位置的点产品。

If we put U left of T, then the camera rotates around the world's axes around the world's origin. This can be even stranger because it makes the camera fly through world faster the farther the camera is from the origin. However, because the rotation is around the origin, if the camera happens to be looking at the origin, objects there will just appear to be turning around. This is sort of what you're seeing because of the dot-products that you're taking to rotate the camera's position.

您检查以确保 pitchAccum 保留在[-90,90],但您已注释掉将利用该事实的部分。这对我来说似乎很奇怪。

You check to make sure that pitchAccum stays within [-90,90], but you've commented out the portion that would make use of that fact. This seems odd to me.

你左旋多次的俯仰,但右偏转使得你的四元数对你没有太大的影响。他们只是抱着你的欧拉角。除非方向变化来自其他地方,你可以简单地说 orientation = glm :: gtx :: quaternion :: angleAxis(pitchAccum * DEG2RAD,1.0f,0.0f,0.0f)* glm: :gtx :: quaternion :: angleAxis(yawAccum * DEG2RAD,0.0f,1.0f,0.0f); 并完全覆盖旧方向。

The way that you left-multiply pitch but right-multiply yaw makes it so that your quaternions aren't doing much for you. They're just holding your Euler angles. Unless orientation changes are coming in from other places, you could simply say that orientation = glm::gtx::quaternion::angleAxis(pitchAccum*DEG2RAD, 1.0f, 0.0f, 0.0f) * glm::gtx::quaternion::angleAxis(yawAccum*DEG2RAD, 0.0f, 1.0f, 0.0f); and overwrite the old orientation completely.

这篇关于OpenGL摄像机 - 来自四元数的视图矩阵行为不正确,音高过于限制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆