Woo*_*ath 2 opengl glut opengl-es glu glm-math
我试图了解glFrustum()在OpenGL中创建的投影矩阵,以及将其转换为x = [-1,1],y = [-1,1]和z = [-1的规范化设备坐标的转换,1]和发生的一系列4x4矩阵乘法,得出的投影矩阵为
我知道最终结果(在NDC中)是通过应用连续变换后除以w分量获得的,但是那些连续变换又是什么呢?
那就是表达式中的矩阵T(就近,远,左,右,上,下变量而言)
这样每个T仅代表scale,平移,旋转或剪切运算/变换?
我读了一些有关OpenGL LH或RH的文章,以及Projection Matrix教程,但是我对正在进行的基本操作(例如,缩放,平移,旋转或剪切操作)仍然不了解。
透视变换矩阵不能仅分解为缩放,平移旋转和剪切操作。这些操作都是仿射的,而透视变换是投影的(不是仿射的;特别是,透视将不会保留线的平行性)。
“目标体积”是归一化设备空间中与轴对齐的立方体。在标准OpenGL中,在所有尺寸上这都从-1变为1(Direct3D以及Vulkan,使用略有不同的约定:[-1,1]表示x和y,但[0,1]表示z。这意味着矩阵的第三行看起来会有所不同,但是概念是相同的)。
构造投影矩阵,以使锥体视锥转化为该标准化体积。OpenGL还使用了约定:在眼睛空间中,相机朝向-z。要创建透视效果,只需将通过投影中心和相关点组成的光线与实际观察平面相交,即可将每个点投影到平面上。
上面的透视矩阵假定图像平面平行于xy平面(如果需要其他平面,则可以应用仿射旋转)。在OpenGL眼空间中,投影中心始终位于原点。在进行数学运算时,您会看到透视图可以归结为截距定理的简单实例。如果你想项目的所有点,这是1个单位在中心(“照相机”)的前一个平面上,你最终将x和y通过-z。
这可以用矩阵形式写成
( 1 0 0 0 )
( 0 1 0 0 )
( 0 0 1 0 )
( 0 0 -1 0 )
Run Code Online (Sandbox Code Playgroud)
它通过设置起作用w_clip = -z_eye,因此当按剪辑空间w进行分割时,我们得到:
x_ndc = x_clip / w_clip = - x_eye / z_eye
y_ndc = y_clip / w_clip = - y_eye / z_eye
Run Code Online (Sandbox Code Playgroud)
请注意,这也适用于z:
z_ndc = z_clip / w_clip = - z_eye / z_eye = 1
Run Code Online (Sandbox Code Playgroud)
这样的矩阵通常不用于渲染,因为深度信息会丢失-所有点实际上都注入到单个平面上。通常,我们要保留深度(也许以某种非线性偏离的方式)。
为此,我们可以调整z的公式(第三行)。由于我们不希望z依赖于x和y,因此只有最后一个元素可以调整。通过使用表格的一行
(0 0 A B),我们得到以下方程式:
z_ndc = - A * z_eye / z_eye - B / z_eye = -A - B / z_eye
Run Code Online (Sandbox Code Playgroud)
这只是眼睛空间z值的双曲线变换变体-深度仍然保留-矩阵变为可逆。我们只需要计算A和B。
让我们调用函数z_ndc(z_eye) = -A - B / z_eye只Z(z_eye)。由于观看量由z_ndc = -1(前平面)和界定z_ndc = 1,并且眼空间中近平面和远平面的距离作为参数给出,因此我们必须将近平面映射z_eye=-n为-1,将远平面映射z_eye=-f为1。 A和B,我们必须解决2个(非线性)方程组:
Z(-n) = -1
Z(-f) = 1
Run Code Online (Sandbox Code Playgroud)
这将精确地得出您在矩阵第三行中找到的两个系数。
对于x和y,我们要控制两件事:视场角和平截头体的不对称性(与投影仪中已知的“镜头移位”类似)。视场由在NDC中映射到[-1,1]的图像平面上的x和y范围定义。因此,您可以想象在与图像平面平行的任意平面上仅出现一个与轴对齐的矩形。此矩形描述了场景的一部分,该部分已映射到可见视口,并且距摄像机的选定距离为该部分。更改视野仅意味着在x和y上缩放该矩形。
从概念上讲,镜头移位只是翻译,因此您可能认为它应该放在最后一栏中。但是,由于除法w=-z将在矩阵乘法之后进行,因此我们必须先将该转换乘以-z。这意味着翻译部分现在位于第三列中,并且我们具有以下形式的矩阵
( C 0 D 0 )
( 0 E F 0 )
( 0 0 A B )
( 0 0 -1 0 )
Run Code Online (Sandbox Code Playgroud)
对于x,这给出:
x_clip = (x_eye * C + D * z_eye ) / (-z_eye) = -x_eye / z_eye - D
Run Code Online (Sandbox Code Playgroud)
现在,我们只需要找到正确的系数C,d将其映射x_eye=l到x_ndc=-1和x_eye=r到x_ndc=1。需要注意的是经典的GL视锥功能解释的值l,并r在这里为近平面的距离,所以我们要计算这一切的z_eye=-n。解决这个由2个方程组成的新系统,将得出在平截头体矩阵中看到的那些系数。