[译][译]OpenGL投影矩阵

栏目: 编程工具 · 发布时间: 5年前

内容简介:这是关于OpenGL投影矩阵的一篇译文,原文在电脑显示屏是一个2D平面,为了能够在这个2D平面上显示OpenGL渲染的3D场景,我们必须将3D场景当作2D图像投影到这个2D平面(计算机屏幕)上.GL_PROJECTION 矩阵就是用来做这种投影变换的.首先,该矩阵将所有观察空间的顶点坐标变换到裁剪空间,接着,将变换后的顶点坐标(即裁剪坐标)的每个分量

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

概览(Overview)

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

[译][译]OpenGL投影矩阵

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

值得一提的是,视锥体剔除是在裁剪空间进行的(NDC变换之前) : 裁剪坐标中的 x c x_c , y c y_c z c z_c 分量会分别与 w c w_c 分量进行比较,如果其中任一分量小于 w c -w_c ,或者大于 w c w_c ,则该坐标对应的顶点就会被丢弃(即发生了裁剪).

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

透视投影

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

[译][译]OpenGL投影矩阵

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

在 OpenGL 中,观察空间中3D坐标点是投影到近裁剪面(即投影面)上的.下面的示意图展示了一个在观察空间中的坐标点 ( x e , y e , z e ) (x_e, y_e, z_e) ,是如何投影到近裁剪面坐标点 ( x p , y p , z p ) (x_p, y_p, z_p) 上的.

[译][译]OpenGL投影矩阵 [译][译]OpenGL投影矩阵 从视锥体的顶部视图可以看到, x e x_e (观察空间中的 x x 坐标)的投影坐标 x p x_p 可以使用相似三角形对应边长成比例来求解:

[译][译]OpenGL投影矩阵

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

[译][译]OpenGL投影矩阵

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

[译][译]OpenGL投影矩阵 [译][译]OpenGL投影矩阵 所以,我们可以将裁减坐标的 w w 分量设置为 z e -z_e ,基于此,GL_PROJECTION 矩阵的第四行便可以确定了,应为 ( 0 , 0 , 1 , 0 ) (0, 0, -1, 0) .

[译][译]OpenGL投影矩阵

接下来,我们要将 x p x_p y p y_p 线性映射到 NDC 下的 x n x_n y n y_n , 即 [ l , r ] [l, r] [ 1 , 1 ] [-1, 1] , [ b , t ] [b, t] [ 1 , 1 ] [-1, 1] .

[译][译]OpenGL投影矩阵

[译][译]OpenGL投影矩阵

然后,我们将 x p x_p y p y_p 的表达式代入上面的等式.

[译][译]OpenGL投影矩阵 [译][译]OpenGL投影矩阵 由于要进行透视除法的关系 ( x c / w c , y c / w c ) (x_c/w_c, y_c/w_c) ,我们将等式都调整成了除以 z e -z_e 的形式.我们先前已经设置了 wc 为 z e -z_e ,所以等式括号里项即是裁剪坐标 x c x_c y c y_c .

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

[译][译]OpenGL投影矩阵

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

[译][译]OpenGL投影矩阵

观察空间中, w e w_e 等于 1 1 ,所以上面的等式可以化简为:

[译][译]OpenGL投影矩阵

为了计算 A A B B 这两个参数,我们可以利用 ( z e , z n ) (z_e, z_n) 的两个条件关系: ( n , 1 ) (-n, -1) ( f , 1 ) (-f, 1) ( 译注:即 z e = n z_e = -n 时, z n = 1 z_n = -1 ; z e = f z_e = -f 时, z n = 1 z_n = 1 ),代入上面的等式,我们有:

[译][译]OpenGL投影矩阵

[译][译]OpenGL投影矩阵

[译][译]OpenGL投影矩阵

[译][译]OpenGL投影矩阵

通过上面的计算,我们得到了系数 A A B B 的表达式,于是 z e z_e z n z_n 的关系式变为:

[译][译]OpenGL投影矩阵

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

[译][译]OpenGL投影矩阵

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

[译][译]OpenGL投影矩阵

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

[译][译]OpenGL投影矩阵

正交投影

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

[译][译]OpenGL投影矩阵

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

[译][译]OpenGL投影矩阵 [译][译]OpenGL投影矩阵 [译][译]OpenGL投影矩阵

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

[译][译]OpenGL投影矩阵

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

[译][译]OpenGL投影矩阵


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法新解

算法新解

刘新宇 / 人民邮电出版社 / 2016-12-1 / CNY 99.00

本书分4 部分,同时用函数式和传统方法介绍主要的基本算法和数据结构。数据结构部分包括二叉树、红黑树、AVL 树、Trie、Patricia、后缀树、B 树、二叉堆、二项式堆、斐波那契堆、配对堆、队列、序列等;基本算法部分包括各种排序算法、序列搜索算法、字符串匹配算法(KMP 等)、深度优先与广度优先搜索算法、贪心算法以及动态规划。 本书适合软件开发人员、编程和算法爱好者,以及高校学生阅读参考......一起来看看 《算法新解》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具