前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[译]OpenGL投影矩阵

[译]OpenGL投影矩阵

作者头像
用户2615200
发布2019-07-11 13:34:58
1.6K0
发布2019-07-11 13:34:58
举报

这是关于OpenGL投影矩阵的一篇译文,原文在这里.

概览(Overview)

电脑显示屏是一个2D平面,为了能够在这个2D平面上显示OpenGL渲染的3D场景,我们必须将3D场景当作2D图像投影到这个2D平面(计算机屏幕)上.GL_PROJECTION 矩阵就是用来做这种投影变换的.首先,该矩阵将所有观察空间的顶点坐标变换到裁剪空间,接着,将变换后的顶点坐标(即裁剪坐标)的每个分量(x,y,z,w)(x,y,z,w)(x,y,z,w)除以坐标的 www 分量,使其变换为标准化设备坐标(NDC).

在这里插入图片描述
在这里插入图片描述

这里我们需要注意的一点就是 : GL_PROJECTION 矩阵同时整合了裁剪(视锥体剔除)和标准化设备坐标(NDC)变换的功能(译注:这里不是指 GL_PROJECTION 矩阵本身整合了这些功能,而是指 OpenGL 的 GL_PROJECTION 矩阵模式整合了这些功能).接下来的内容就是描述如何从6个边界参数(left, right, bottom, top, near 和 far) 构造出这个投影矩阵.

值得一提的是,视锥体剔除是在裁剪空间进行的(NDC变换之前) : 裁剪坐标中的 xcx_cxc​, ycy_cyc​ 和 zcz_czc​ 分量会分别与 wcw_cwc​ 分量进行比较,如果其中任一分量小于 −wc-w_c−wc​,或者大于 wcw_cwc​,则该坐标对应的顶点就会被丢弃(即发生了裁剪).

接着, 如果发生了裁剪, OpenGL 会重新构建发生裁剪的多边形边缘.

透视投影

在透视投影中,视锥体(观察空间)中的一个3D坐标点会被映射到一个立方体中(NDC);其中 xxx 坐标范围会从 [l,r][l, r][l,r] 映射到 [−1,1][-1, 1][−1,1], yyy 坐标范围会从 [b,t][b, t][b,t] 映射到 [−1,1][-1, 1][−1,1], zzz 坐标范围会从 [−n,−f][-n, -f][−n,−f] 映射到 [−1,1][-1, 1][−1,1].

在这里插入图片描述
在这里插入图片描述

这里需要注意的是,观察空间是在右手坐标系下(OpenGL 使用右手坐标系)定义的,但是 NDC 却是在左手坐标系下定义的.换句话说就是,观察空间中的摄像机是指向 -Z 轴的,但是在 NDC 中,摄像机指向的却是 +Z 轴(译注:NDC变换会改变左右手坐标系).由于 glFrustum() 函数只接受正的近/远裁剪面距离,所以我们需要在构造 GL_PROJECTION 矩阵的过程中将近/远裁剪面距离变成负数(译注:因为在观察空间中,摄像机是指向 -Z 轴的).

在 OpenGL 中,观察空间中3D坐标点是投影到近裁剪面(即投影面)上的.下面的示意图展示了一个在观察空间中的坐标点 (xe,ye,ze)(x_e, y_e, z_e)(xe​,ye​,ze​),是如何投影到近裁剪面坐标点 (xp,yp,zp)(x_p, y_p, z_p)(xp​,yp​,zp​) 上的.

视锥体顶部视图
视锥体顶部视图
视锥体侧面视图
视锥体侧面视图

从视锥体的顶部视图可以看到, xex_exe​(观察空间中的 xxx 坐标)的投影坐标 xpx_pxp​ 可以使用相似三角形对应边长成比例来求解:

在这里插入图片描述
在这里插入图片描述

从视锥体的侧面视图来看,ypy_pyp​ 也可以使用类似的方式求解:

在这里插入图片描述
在这里插入图片描述

注意到 xpx_pxp​ 和 ypy_pyp​ 的数值都是依赖于 zez_eze​ 的,并且两者的数值大小都反比与 −ze-z_e−ze​(这两个数值的求解都除以了 −ze-z_e−ze​).这是我们构建 GL_PROJECTION 矩阵的第一条线索.在观察空间中的坐标经过 GL_PROJECTION 矩阵变换之后,得到的裁剪坐标还是一个齐次坐标,需要将坐标的各个分量除以坐标的 www 分量才能将其变换为标准化设备坐标(NDC).(更多细节可以看这里)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

所以,我们可以将裁减坐标的 www 分量设置为 −ze-z_e−ze​,基于此,GL_PROJECTION 矩阵的第四行便可以确定了,应为 (0,0,−1,0)(0, 0, -1, 0)(0,0,−1,0).

在这里插入图片描述
在这里插入图片描述

接下来,我们要将 xpx_pxp​ 和 ypy_pyp​ 线性映射到 NDC 下的 xnx_nxn​ 和 yny_nyn​, 即 [l,r][l, r][l,r] ⇒ [−1,1][-1, 1][−1,1] , [b,t][b, t][b,t] ⇒ [−1,1][-1, 1][−1,1].

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

然后,我们将 xpx_pxp​ 和 ypy_pyp​ 的表达式代入上面的等式.

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

由于要进行透视除法的关系(xc/wc,yc/wc)(x_c/w_c, y_c/w_c)(xc​/wc​,yc​/wc​),我们将等式都调整成了除以 −ze-z_e−ze​ 的形式.我们先前已经设置了 wc 为 −ze-z_e−ze​,所以等式括号里项即是裁剪坐标 xcx_cxc​ 和 ycy_cyc​.

通过这些等式,我们就可以确定 GL_PROJECTION 矩阵的第一行和第二行了:

在这里插入图片描述
在这里插入图片描述

现在,我们只需要求解出 GL_PROJECTION 矩阵的第三行便可以了,不过计算 znz_nzn​ 和之前计算的 xnx_nxn​ 和 yny_nyn​ 有些不同,因为观察空间中的 zez_eze​ 总是会被投影到近裁剪面上(数值为−n-n−n),而我们需要的是唯一的 zzz 值以进行裁剪和深度检测,另外的,我们也应该能够"反投影"(unproject,投影的逆变换)znz_nzn​.由于我们知道 zzz 坐标并不依赖与 xxx 坐标和 yyy 坐标,所以我们可以借助 www 分量来求解 znz_nzn​ 和 zez_eze​ 的关系,计算方法如下:

在这里插入图片描述
在这里插入图片描述

观察空间中, wew_ewe​ 等于 111,所以上面的等式可以化简为:

在这里插入图片描述
在这里插入图片描述

为了计算 AAA 和 BBB 这两个参数,我们可以利用 (ze,zn)(z_e, z_n)(ze​,zn​) 的两个条件关系:(−n,−1)(-n, -1)(−n,−1) 和 (−f,1)(-f, 1)(−f,1)(译注:即 ze=−nz_e = -nze​=−n 时, zn=−1z_n = -1zn​=−1; ze=−fz_e = -fze​=−f 时, zn=1z_n = 1zn​=1),代入上面的等式,我们有:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

通过上面的计算,我们得到了系数 AAA 和 BBB 的表达式,于是 zez_eze​ 与 znz_nzn​ 的关系式变为:

在这里插入图片描述
在这里插入图片描述

最终,我们得到了完整的 GL_PROJECTION 矩阵:

在这里插入图片描述
在这里插入图片描述

上面的投影矩阵对应于一般的视锥体投影,如果视锥体是上下左右对称的话(即 r=−l,t=−br = -l, t = -br=−l,t=−b),则上面的投影矩阵可以做如下简化:

在这里插入图片描述
在这里插入图片描述

在我们继续讲解之前,我们再来观察一下 zez_eze​ 和 znz_nzn​ 的关系,也就是上面的等式(3)(3)(3).注意到该等式是个非线性的有理函数,当 zez_eze​ 靠近近裁剪面的时候,对应 znz_nzn​ 的精度会比较高,当 zez_eze​ 靠近远裁剪面的时候,对应 znz_nzn​ 的精度则比较低.于是,当[−n,−f][-n, -f][−n,−f]的范围变大的时候,就会发生深度缓冲的精度问题(z-fighting),因为此时靠近远裁剪面的 zez_eze​ 的微小变化并不会影响 znz_nzn​ 的数值(译注:数学角度讲,zez_eze​ 的任何变化其实都会影响到 znz_nzn​ 的数值,这里说不会影响 znz_nzn​ 的数值是从计算机中数值精度表示有限的角度来讲的),所以我们应该尽量缩短 nnn 和 fff 之间的距离,以最小化上述的深度缓冲精度问题.

在这里插入图片描述
在这里插入图片描述
正交投影

为正交投影构建一个 GL_PROJECTION 矩阵比上面说的透视投影要简单多了.

在这里插入图片描述
在这里插入图片描述

所有观察空间的 xex_exe​, yey_eye​ 和 zez_eze​ 分量都被线性的映射到 NDC 中,我们要做的就是将长方体(观察空间)缩放成一个立方体(NDC),然后将其移动到原点位置.我们马上来算一下 GL_PROJECTION 矩阵的各个元素:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

由于在正交投影中,我们不需要 www 分量的参与,所以 GL_PROJECTION 矩阵的第四行设置为了 (0,0,0,1)(0, 0, 0, 1)(0,0,0,1).最终的 GL_PROJECTION 矩阵表示如下:

在这里插入图片描述
在这里插入图片描述

同透视投影一样,如果视锥体是上下左右对称的话(即 r=−l,t=−br = -l, t = -br=−l,t=−b),上面的 GL_PROJECTION 矩阵可以简化为:

在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年04月09日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概览(Overview)
  • 透视投影
  • 正交投影
相关产品与服务
图像处理
图像处理基于腾讯云深度学习等人工智能技术,提供综合性的图像优化处理服务,包括图像质量评估、图像清晰度增强、图像智能裁剪等。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档