glm::lookAt returns 具有 nan 元素的矩阵

glm::lookAt returns matrix with nan elements

我想为垂直观察地面的相机创建一个视图矩阵:

glm::mat4 matrix = glm::lookAt(glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));

最后一个参数是全局向上向量,所以一切似乎都是正确的,但我得到了以下 matirx:

-nan    -nan    -0  0   
-nan    -nan     1  0   
-nan    -nan    -0  0   
 nan     nan    -1  1

我想我得到 nan 是因为观察向量与向上向量平行,但是如何使用 glm::lookAt 函数构建正确的视图矩阵。

lookAt中不可能让观察方向和向上矢量看向同一方向。如果您想要一个沿负 y 轴观察的相机,则必须调整向上矢量,例如 [0,0,1]。在向上向量中指定的方向控制相机如何围绕视图轴旋转。

问题出在相机的位置或向上矢量上。

您的相机向上 1 个单位 (0,1,0),向下看原点 (0,0,0)。向上向量表示相机的向上方向,而不是世界space。例如,如果您向前看,向上矢量将为 +Y。如果您向下看,头顶朝向 +X,那么向上矢量对您来说就是 +X。它必须与相机的位置矢量完全不平行。

解决方案:

  • 将向上矢量更改为沿 XZ 平面的任何方向
  • 或者当投影到 XZ 平面上时不是 (0,0,0) 的东西
  • 移动您的相机,使其位于 Y 轴以外的任何位置

我 运行 昨天在 return 由 glm::lookAt() 编辑的矩阵中遇到了同样的 NaN 问题,并提出了我认为是解决方法的方法。对于 UP 向量是 vec3(0.0f, 1.0f, 0.0f) 的特殊问题,这似乎对我有用,这似乎是一个常见的用例。

我的 Vulkan 代码如下所示:

struct UniformBufferObject {
    alignas(16) glm::mat4 model;
    alignas(16) glm::mat4 view;
    alignas(16) glm::mat4 proj;
};
...
        UniformBufferObject ubo{};
...
        glm::vec3 cameraPos = glm::vec3(0.0f, 2.0f, 0.0f);
        ubo.view = glm::lookAt(cameraPos, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));

        // if the direction vector from the camera to the point being observed ends up being parallel to the UP vector
        // glm::lookAt() returns a mat4 with NaNs in it. to workaround this, look for NaNs in ubo.view
        int view_contains_nan = 0;

        for (int col = 0; (col < 4) && !view_contains_nan; ++col) {
            for (int row = 0; (row < 4) && !view_contains_nan; ++row) {
                if (std::fpclassify(ubo.view[col][row]) == FP_NAN) {
                    view_contains_nan = 1;
                }
            }
        }

        // if we ended up with NaNs, the workaround ubo.view that seems to work depends on the sign of the camera position Y
        if (view_contains_nan) {
            std::cout << "view contains NaN"  << std::endl;
            if (cameraPos.y >= 0.0f) {
                ubo.view = glm::mat4(   -0.0f, -1.0f,  0.0f,        0.0f,
                             0.0f,  0.0f,  1.0f,        0.0f,
                            -1.0f,  0.0f, -0.0f,        0.0f,
                            -0.0f, -0.0f, -cameraPos.y, 1.0f);
            } else {
                ubo.view = glm::mat4(    0.0f,  1.0f,  0.0f,        0.0f,
                             0.0f,  0.0f, -1.0f,        0.0f,
                            -1.0f,  0.0f, -0.0f,        0.0f,
                            -0.0f,  -0.0f, cameraPos.y, 1.0f);
            }
        }

希望它也对你有用,不过我想如果 glm::lookAt() 可以固定为不包含 NaN 的 return 矩阵会更好。