OpenGL:我自己实现的 frustum 函数导致黑屏

OpenGL: my own implementation of the frustum function causes a blank screen

我目前正在开发一个涉及大量相机移动的应用程序。我已经编写了自己的 lookAt 函数,它似乎工作正常。我现在想实现自己的 frustum 功能。目前我有一个以原点为中心的 1x1x1 立方体。我正在尝试更改我的视图,以便我可以在所有轴上看到从 -2 到 2 的范围,以检查我的功能是否正常工作。 这是我的函数的代码:

mat4 frustum(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far)
{
  mat4 f;
  f.x.x = 2*near/(right-left);
  f.y.x = 0;
  f.z.x = (right + left)/(right - left);
  f.w.x = 0;

  f.x.y = 0;
  f.y.y = 2*near/(top-bottom);
  f.z.y = (top + bottom)/(top - bottom);
  f.w.y = 0;

  f.x.z = 0;
  f.y.z = 0;
  f.z.z = (far+near)/(far-near);
  f.w.z = 2*(far*near)/(far-near);

  f.x.w = 0;
  f.y.w = 0;
  f.z.w = -1.0;
  f.w.w = 0;
  
    return f;
}

我将 near、right 和 top 传递为 2。far、left 和 bottom 将传递为 -2。 当我用这些参数调用我的函数时,它 returns 以下矩阵:

┏ -1.000000 0.000000 0.000000 0.000000
┃ 0.000000 -1.000000 0.000000 0.000000
┃ 0.000000 0.000000 0.000000 -2.000000
┗ 0.000000 0.000000 -1.000000 0.000000

我不确定这是否正确,我的问题出在其他地方,或者函数中是否有问题。

I am passing in near, right and top as 2. far, left and bottom are being passed in as -2.

近平面的负值无效。在透视投影中,投影矩阵描述了从针孔相机看到的世界中的 3D 点到视口中 2D 点的映射。透视投影矩阵定义了一个Viewing Frustum:

因此近平面和远平面必须为正值:

0 < near < far

透视投影矩阵可以定义为frustum
距离 leftrightbottomtop 是近平面上从视图中心到平截头体侧面的距离。 nearfar 指定到平截头体近平面和远平面的距离。

r = right, l = left, b = bottom, t = top, n = near, f = far

x:    2*n/(r-l)      0              0                0
y:    0              2*n/(t-b)      0                0
z:    (r+l)/(r-l)    (t+b)/(t-b)    -(f+n)/(f-n)    -1
t:    0              0              -2*f*n/(f-n)     0

投影矩阵从视图 space 变换到剪辑 space 分别归一化设备 space。在 OpenGL 中,视图 space 通常是一个 right-handed 坐标系,而归一化设备 space 是一个 left-handed 系统。投影矩阵镜像z-axis实现变换。因此,z分量必须反转:

mat4 frustum(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far)
{
   mat4 f;
    f.x.x = 2*near/(right-left);
    f.y.x = 0;
    f.z.x = (right + left)/(right - left);
    f.w.x = 0;

    f.x.y = 0;
    f.y.y = 2*near/(top-bottom);
    f.z.y = (top + bottom)/(top - bottom);
    f.w.y = 0;

    f.x.z = 0;
    f.y.z = 0;
    f.z.z = - (far+near)/(far-near);
    f.w.z = - 2*(far*near)/(far-near);

    f.x.w = 0;
    f.y.w = 0;
    f.z.w = -1.0;
    f.w.w = 0;
  
    return f;
}

您需要确保几何体位于视锥体的近平面和远平面之间。截锥之外的所有几何体都被剪裁。
请注意,视图 space Z 坐标为 0 的几何体将被剪裁,因为 0 < near < far.