为什么从上方直接向下看时不渲染形状?

Why does a shape not render when looking directly down on it from above?

我从 http://www.opengl-tutorial.org/beginners-tutorials/tutorial-4-a-colored-cube/

中稍微调整了 tutorial04.cpp

我制作了一个金字塔形状,我想将相机放在金字塔上方并向下看,但我发现当相机位于金字塔正上方时它根本不会渲染。如果我将我的 X 值更改为 0 以外的任何值,它会呈现良好。

如果我将 X 设置为 -0.0000001f 或 0.0000001f,它也可以正常渲染。

下面的代码不起作用。

glm::mat4 View = glm::lookAt(
    glm::vec3(0,10,0), // Camera
    glm::vec3(0,0,0), // and looks at the origin
    glm::vec3(0,1,0)  // Head is up (set to 0,-1,0 to look upside-down)
);

这段代码工作正常

glm::mat4 View = glm::lookAt(
    glm::vec3(1,10,0), // Camera
    glm::vec3(0,0,0), // and looks at the origin
    glm::vec3(0,1,0)  // Head is up (set to 0,-1,0 to look upside-down)
);

我有 5 个点用于绘制 6 个三角形。

一个:0,1,0

b: 1,0,-1

c: 1,0,1

d: -1,0,1

e: -1,0,-1

三角形 1:a、b、c

三角形 2:a、c、d

三角形 3:a、e、b

三角形 4:a、e、b

三角形 5:b、d、c

三角形 6:d、b、e

static const GLfloat g_vertex_buffer_data[] = {
0,1,0,
1,0,-1,
1,0,1,//a,b,c
0,1,0,
1,0,1,
-1,0,1,//a,c,d
0,1,0,
-1,0,1,
-1,0,-1,//a,d,e
0,1,0,
-1,0,-1,
1,0,-1,//a,e,b
1,0,-1,
-1,0,1,
1,0,1,//b,d,c
-1,0,1,
1,0,-1,
-1,0,-1//4,2,5
};

虽然你不是第一个被这种效果影响的人:link

有两种解决方案:

  • 要么根本不使用 lookAt 函数,而是用四元数表示相机的旋转;
  • 或跟踪并且永远不要为您的相机应用 "straight up" (0,X,0) 或 "straight down" (0,-X,0) 寻找方向。

到底是什么问题? 我试图深入研究 glm 代码,lookAt 看起来像

    template<typename T, qualifier Q>
    GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtLH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up)
    {
        vec<3, T, Q> const f(normalize(center - eye));
        vec<3, T, Q> const s(normalize(cross(up, f)));
        vec<3, T, Q> const u(cross(f, s));

        mat<4, 4, T, Q> Result(1);
        Result[0][0] = s.x;
        Result[1][0] = s.y;
        Result[2][0] = s.z;
        Result[0][1] = u.x;
        Result[1][1] = u.y;
        Result[2][1] = u.z;
        Result[0][2] = f.x;
        Result[1][2] = f.y;
        Result[2][2] = f.z;
        Result[3][0] = -dot(s, eye);
        Result[3][1] = -dot(u, eye);
        Result[3][2] = -dot(f, eye);
        return Result;
    }

如果您的相机直视向上或向下,那么 f 将是 (0,1,0),s 将始终是 (0,0,0),因为 upf 共线,因此它们的叉积为零,并且 u 也是 (0,0,0),因为 s 是。所以你得到的结果矩阵是:

[0 0 0 0]
[0 0 1 0]
[0 0 0 0]
[0 0 0 1]

如果你了解一些线性代数,你就会知道这个矩阵的秩为 2,当它应用于图形旋转和平移时,它会将你看到的所有内容折叠成低维线性 space(我'我对数学没有信心,但这就是想法)。您基本上丢失了 3D space 的一个或多个维度,然后当它投影到您的 2D 屏幕上时,您可能会看到一个 1D 图像,它是一条细线,根本看不到。

这也可能是 Gimbal Lock 的一个隐含的特殊情况 - 当直观 "X-Y-Z" 旋转可能最终失去 1 个或更多自由度时的效果,使得 "unrotate" space回来了。这就是四元数出现的地方,它们不受 Gimbal Lock 的影响,与 mat4 相比,它们需要更少的内存来存储,它们计算速度更快,更难解释和理解(但 glm 有一个实施它,所以使用它)。请记住,您不应该自己修改四元数的组件,否则它会变得无效,因此只能使用知道如何修改它们的函数。

作为旁注,它完美地解释了为什么在视频游戏中你不能将你的相机直接向上转动以从弓向上射击然后用你的头接住你的箭。箭头总是飞得有点偏离垂直方向,因为你的相机永远不会竖直