【问题标题】:Emulating gluLookAt with glm::Quat(ernions)用 glm::Quat(ernions) 模拟 gluLookAt
【发布时间】:2014-01-17 03:54:12
【问题描述】:

我一直在尝试模拟 gluLookAt 功能,但使用四元数。我的每个游戏对象都有一个 TranslationComponent。该组件存储对象的位置 (glm::vec3)、旋转 (glm::quat)和缩放 (glm::vec3)。相机在每个滴答声中计算其位置:

// UP = glm::vec3(0,1,0); 
//FORWARD = glm::vec3(0,0,1);
cameraPosition = playerPosition - (UP * distanceUP) - (FORWARD * distanceAway);

这个位置代码的作用是expexted,摄像机位于玩家身后3米处,向上1米处。现在,相机的四元数设置如下:

//Looking at the player's feet  
cameraRotation = quatFromToRotation(FORWARD, playerPosition); 

渲染引擎现在获取这些值并生成 ViewMatrix(相机)和 ModelMatrix(播放器),然后渲染场景。代码如下所示:

 glm::mat4 viewTranslationMatrix = 
         glm::translate(glm::mat4(1.0f), cameraTransform->getPosition());
 glm::mat4 viewScaleMatrix = 
         glm::scale(glm::mat4(1.0f), cameraTransform->getScale());
 glm::mat4 viewRotationMatrix = 
         glm::mat4_cast(cameraTransform->getRotation());

 viewMatrix = viewTranslationMatrix * viewRotationMatrix * viewScaleMatrix;

quatFromToRotation(glm::vec3 from, glm::vec3 to)定义如下:

glm::quat quatFromToRotation(glm::vec3 from, glm::vec3 to)
{
    from = glm::normalize(from); to = glm::normalize(to);

    float cosTheta = glm::dot(from, to);
    glm::vec3 rotationAxis;

    if (cosTheta < -1 + 0.001f)
    {
        rotationAxis = glm::cross(glm::vec3(0.0f, 0.0f, 1.0f), from);
        if (glm::length2(rotationAxis) < 0.01f)
            rotationAxis = glm::cross(glm::vec3(1.0f, 0.0f, 0.0f), from);

        rotationAxis = glm::normalize(rotationAxis);
        return glm::angleAxis(180.0f, rotationAxis);
    }

    rotationAxis = glm::cross(from, to);

    float s = sqrt((1.0f + cosTheta) * 2.0f);
    float invis = 1.0f / s;

    return glm::quat(
            s * 0.5f,
            rotationAxis.x * invis,
            rotationAxis.y * invis,
            rotationAxis.z * invis
        );
}

我遇到的问题是 cameraRotation 设置不正确。无论玩家在哪里,相机的前方总是(0,0,-1)

【问题讨论】:

  • 你在哪里/如何计算相机的forward
  • 假设FORWARD 是一个方向而不是一个位置,我认为这不是你想要的......那么quatToFromRotation (playerPosition + FORWARD, playerPosition); 呢?
  • 另外,您在代码中列出的函数是quatFromToRotation (...),这与您在正文中讨论的不同。
  • 啊,是的,那是一个错字。我编辑了它。
  • 请注意,glm 有一个功能上等同于gluLookAt() 的函数,命名为glm::lookAt() 并在&lt;glm/gtc/matrix_transform.hpp&gt; 中定义。如需更多信息,请查看glm manual 并搜索“lookAt”。你会在那里找到函数文档。

标签: c++ opengl quaternions glm-math glulookat


【解决方案1】:

你的问题出在这条线上

//Looking at the player's feet  
cameraRotation = quatToFromRotation(FORWARD, playerPosition);

您需要从相机位置看玩家的脚——而不是从“玩家上方一米”(假设您最初执行此操作时玩家位于 (0,0,0) )。将FORWARD 替换为cameraPosition

cameraRotation = quatToFromRotation(cameraPosition, playerPosition);

编辑我相信您的quatToFromRotation 函数也有错误。有关四元数旋转的非常好的解释(和一些伪代码),请参阅 https://stackoverflow.com/a/11741520/1967396

【讨论】:

  • 这样做会使相机朝向某个我什至无法分辨方向的方向。玩家位于 (0,0,0) 且相机位于 (0,2,-3) 时,四元数为 (0.00513127, 0, -0, 0.999987)。我对四元数的经验并不丰富,所以我不知道这个数字到底意味着什么。我尝试在将位置设置为相机位置并将目标设置为玩家时使用 glm::lookAt,一切正常。这让我相信 quatFromToRotation 给了我一个不正确的轮换。
  • 四元数是有趣的动物。如果您查看最后三个元素并将它们归一化,它们就是您正在旋转的轴(几乎完全是 [0 0 1] 但不完全是);旋转角度是通过求解 cos(theta/2) = q(0) - 所以 theta = 2 * acos(q(0)) 得出的。我本来希望您的几何图形围绕 X 轴旋转,而不是 Z 轴。 quatFromRotation 哪里来的?
  • 旋转有点奇怪,我认为你是对的,它是针对 X 轴的。最初,我自己编写了算法,但我遇到了与此相关的问题。所以,我决定在这里使用算法:opengl-tutorial.org/intermediate-tutorials/…
猜你喜欢
  • 1970-01-01
  • 2013-05-21
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多