首页 > 解决方案 > OpenGL:我自己实现的截锥体函数导致黑屏

问题描述

我目前正在开发一个涉及大量相机移动的应用程序。我已经编写了我自己的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;
}

我传入近、右和上为 2。远、左和下传为 -2。当我用这些参数调用我的函数时,它返回以下矩阵:

┏ -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

我不确定这是否正确,我的问题出在其他地方,或者函数中的某些内容是否关闭。

标签: copenglglm-math

解决方案


我传入近、右和上为 2。远、左和下传为 -2。

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

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

0 < near < far

透视投影矩阵可以由平截头体定义。
距离leftright和是近平面bottomtop从视图中心到截锥体侧面的距离。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

投影矩阵是从视图空间到剪辑空间的变换,分别是归一化的设备空间。在 OpenGL 中,视图空间通常是右手坐标系,而标准化的设备空间是左手坐标系。投影矩阵镜像z轴以实现变换。因此,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;
}

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


推荐阅读