C++ OpenGL相机四元数导致翻转问题

4

当我将目标移动到右侧时,它会看向目标并一直保持注视,直到它转过-z轴的180度并决定改变方向。

Matrix4x4 camera::GetViewMat()
{
    Matrix4x4 oRotate, oView;
    oView.SetIdentity();

    Vector3 lookAtDir = m_targetPosition - m_camPosition;
    Vector3 lookAtHorizontal = Vector3(lookAtDir.GetX(), 0.0f, lookAtDir.GetZ());
    lookAtHorizontal.Normalize();

    float angle = acosf(Vector3(0.0f, 0.0f, -1.0f).Dot(lookAtHorizontal));
    Quaternions horizontalOrient(angle, Vector3(0.0f, 1.0f, 0.0f));

    ori = horizontalOrient;
    ori.Conjugate();
    oRotate = ori.ToMatrix();

    Vector3 inverseTranslate = Vector3(-m_camPosition.GetX(), -m_camPosition.GetY(), -m_camPosition.GetZ());
    oRotate.Transform(inverseTranslate);

    oRotate.Set(0, 3, inverseTranslate.GetX());
    oRotate.Set(1, 3, inverseTranslate.GetY());
    oRotate.Set(2, 3, inverseTranslate.GetZ());
    oView = oRotate;

    return oView;
}

我不是在提取它们,而是在创建它们。无论如何,我正在尝试找出如何创建四元数,使相机朝向目标,并找出如何避免万向锁问题。我尝试了许多不同的方法,但现在我迷失了方向,不知道自己做错了什么。 - Jose
在创建这些向量时,您正在使用(0,1,0)进行叉积运算,这意味着您无法直视向上,这可能与万向锁一样糟糕。如果您从默认方向检索旋转摄像机的四元数到目标对象,并将其用作旋转矩阵,如我之前所说,摄像机可以自由地查看任何位置。如果您愿意,我可以挖掘我的项目并设置一个示例代码作为答案。编辑:很难在您的代码中找到任何错误,因此我无法直接回答哪里出了问题。 - Invalid
我明白了,谢谢回复。您会如何创建一个摄像机,使其始终旋转以朝向目标?我之前尝试过但失败了,如果可以的话,您能给我一个示例吗?顺便说一下,谢谢。 - Jose
嗯,我明白了,好的。那么这意味着它正在工作,我只需要弄清楚如何反过来操作。我会继续尝试并在网上搜索相关信息,然后再看下一步该怎么做。非常感谢您一直陪伴着我回复消息。我很感激 :)。 - Jose
我想说的是,相机的上向量希望保持在正向上方,不喜欢转向负向上方。 - Jose
显示剩余18条评论
1个回答

2
按照承诺,这里有一些代码展示了我如何让相机始终注视着空间中的特定点。
首先,我们需要一种方法来根据角度和轴构造四元数,我恰好在pastebin上有这个方法,角度输入以弧度为单位。

http://pastebin.com/vLcx4Qqh

请确保您不要输入轴(0,0,0),这根本没有任何意义。

现在是实际的更新方法,我们需要获取四元数,将相机从默认方向旋转到指向目标点。请注意,我只是凭空写了这个,它可能需要一些调试和优化,但至少可以让您朝着正确的方向前进。

void camera::update()
{
    // First get the direction from the camera's position to the target point
    vec3 lookAtDir = m_targetPoint - m_position;

    // I'm going to divide the vector into two 'components', the Y axis rotation
    // and the Up/Down rotation, like a regular camera would work.

    // First to calculate the rotation around the Y axis, so we zero out the y
    // component:
    vec3 lookAtHorizontal = vec3(lookAtDir.x, 0.0f, lookAtDir.z).normalize();

    // Get the quaternion from 'default' direction to the horizontal direction
    // In this case, 'default' direction is along the -z axis, like most OpenGL
    // programs. Make sure the projection matrix works according to this.
    float angle = acos(vec3(0.0f, 0.0f, -1.0f).dot(lookAtHorizontal));
    quaternion horizontalOrient(angle, vec3(0.0f, 1.0f, 0.0f));

    // Since we already stripped the Y component, we can simply get the up/down
    // rotation from it as well.
    angle = acos(lookAtDir.normalize().dot(lookAtHorizontal));
    if(angle) horizontalOrient *= quaternion(angle, lookAtDir.cross(lookAtHorizontal));

    // ...
    m_orientation = horizontalOrient;
}

现在我们要将 m_orientationm_position 结合起来,得到世界坐标系到相机坐标系的矩阵

// First inverse each element (-position and inverse the quaternion),
// the position is rotated since the position within a matrix is 'added' last
// to the output vector, so it needs to account for rotation of the space.
mat3 rotationMatrix = m_orientation.inverse().toMatrix();
vec3 inverseTranslate = rotationMatrix * -m_position; // Note the minus

mat4 matrix = mat3; // just means the matrix is expanded, the last entry (bottom right of the matrix) is a 1.0f like an identity matrix would be.

// This bit is row-major in my case, you just need to set the translation of the matrix.
matrix[3] = inverseTranslate.x;
matrix[7] = inverseTranslate.y;
matrix[11] = inverseTranslate.z;

编辑 我认为这很明显,但为了完整起见,.dot()取向量的点积,.cross()取叉积,执行该方法的对象是向量A,方法的参数是向量B。


好的,谢谢。一旦我回家,我会试试看,然后告诉你它的效果如何。反转是不是和共轭是一样的呢? - Jose
是的,在这种情况下,逆和共轭是相同的。 - Invalid
调试后,我发现一个问题,难道这个点积不会始终给你相同的结果吗?float angle = acos(vec3(0.0f, -1.0f, 0.0f).dot(lookAtHorizontal));它们的点积每次都会得到相同的数字,即90度,以弧度表示为1.57,这就是我得到的结果。 - Jose
哦!愚蠢的错误,应该是vec3(0.0f,0.0f,-1.0f),我说沿着-z轴,但出于某种原因我决定键入-y轴,已修复该帖子。顺便说一句,你注意到了这一点,干得好 :P - Invalid
没关系,每个人都会犯错误。虽然很难发现,但调试有助于解决问题,现在它正在偏航旋转。它的表现不太好,因为相机会超过目标旋转,或者有时它会选择错误的方向旋转。可能是旋转速度太快了? - Jose
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接