【发布时间】:2014-08-08 05:06:47
【问题描述】:
OpenGL 中的坐标是什么(我在 Android 上使用的是 OpenGL ES 2.0,但我现在主要只是想了解一下理论……)3d 世界的真正含义是什么?
假设我将模型矩阵转换为 x,y,z 模型去哪里了?多远,什么是单位?
此外,如果我显示来自顶点缓冲区对象的点,将每个点定义为具有任意 x、y 和 z,范围为 (-∞,∞)。 MVP乘以这个位置是什么意思?
【问题讨论】:
OpenGL 中的坐标是什么(我在 Android 上使用的是 OpenGL ES 2.0,但我现在主要只是想了解一下理论……)3d 世界的真正含义是什么?
假设我将模型矩阵转换为 x,y,z 模型去哪里了?多远,什么是单位?
此外,如果我显示来自顶点缓冲区对象的点,将每个点定义为具有任意 x、y 和 z,范围为 (-∞,∞)。 MVP乘以这个位置是什么意思?
【问题讨论】:
一个 3D 点 (x,y,z) 实际上在 4D 中表示为一个齐次点 (x,y,z,1) 所以我们 可以用 4x4 矩阵表示所有所需的变换——特别是这允许平移和透视投影。
然后用 4x4 Model-View-Projection (MVP) 矩阵对该点进行转换,从而产生 一个点 (x',y',z',w')。
MVP矩阵就是这三个矩阵相乘形成复合变换。
剪辑坐标中的一个点要可见,它必须(在投影后)位于 剪辑体积,这是一个轴对齐的立方体,角在 (-1 ,-1,-1) 和 (+1,+1,+1)。 通过除以 w' 来投影一个点 - 即 (x',y',z',w') 被映射 to (x'/w', y'/w', z'/w') -- 如果这三个值都在区间 [-1,+1] 中,那么它是可见的,我们说点在 标准化设备坐标。这种划分允许透视投影发生透视缩短。
这里是有趣的部分,剪辑实际上发生在 4D 中(在此透视分割发生之前)。因此,要使一个点可见,x'、y'、z' 的大小必须小于 w' 的大小。如果该点在剪辑中幸存下来,则发生透视分割。
最后,通过视口变换将一个幸存点从标准化的设备坐标映射到实际的设备坐标。这里我们有一个实际的设备坐标 (x,y),它是 帧缓冲区 中的 2D 地址,z 是 深度缓冲区范围内的深度值。 点然后被运送到光栅化器。
总的来说,OpenGL 管道的第一部分是这样的:
建模变换是仿射变换,可以用以下形式的矩阵表示
_ _
| a b c d |
M = | e f g h |
| i j k l |
| 0 0 0 1 |
- -
点 P = (x,y,z,1) 实际上被认为是一个列向量 [x y z 1]^T 并且 通过在右侧乘以 P' = M P 将其转换为 P'(至少在概念上 - 硬件可能会转置 evethying,但它仍然是同一件事)。通过仿射变换,我可以缩放、旋转、剪切、平移……任何保留平行线的东西。请注意,M 的最后一行是恒等式——这很重要,因为我们不希望 M 与 w 坐标混淆——我们稍后将使用投影矩阵来做到这一点。
请注意,我们可以使用 w = 0 来表示方向向量(例如,表面法线),其中 有效地忽略了翻译组件。实际上,为了正确转换表面法线,我们使用关联的 法线矩阵,它是 M 的上 3x3 矩阵的逆转置:
_ _ ^ -T
| a b c |
N = | e f g |
| i j k |
- -
这保留了法线与其各自平面的正交性。
例如,下面是一个矩阵,它以 s 均匀缩放对象,绕 z 轴逆时针旋转 theta,并将结果平移 (4,5,6):
_ _
| s * cos(theta) -s * sin(theta) 0 4 |
| s * sin(theta) s * cos(theta) 0 5 |
| 0 0 1 6 |
| 0 0 0 1 |
- -
视图变换 V 是一种刚性变换,它只是一种旋转和平移,它会改变坐标,使相机位于原点并“向外看”-z 轴。
投影矩阵 P 是让事情变得奇怪的地方——至少对于透视投影来说是这样。在这里,我们必须将 view frustum 扭曲到规范剪裁立方体中。这不是仿射变换。这就是最终乘以 1/w 会派上用场的地方。这里使用形式的矩阵
P = | a 0 0 0 |
| 0 b 0 0 |
| 0 0 c d |
| 0 0 -1 0 |
注意最后一行是不是的身份。点 (x,y,z,1) 映射到 (a*x, b*y, c*z + d, -z)。后来,经过透视分割,你得到 p>
(-a*x/z, -b*y/z, -(c*z + d)/z)
查看除以 -z ——这就是透视缩短的来源。 由于剪裁顶点的 z
无论如何,我会把故事留在那里......
【讨论】:
当您创建图形世界时,3D、2D - 没关系,您需要定义一个与该世界一致的坐标系。你定义它的方式并不重要,只要它是一致的。
这如何应用于 OpenGL?
每个 3D 元素的位置将由其顶点以及您对其进行的任何变换(例如缩放、平移等)定义。例如,如果您正在渲染一个中心在 {2,3,4} 且半径为 1 的球体,此信息可让您知道球体在世界的哪个位置,以及是否应该渲染它.
在 OpenGL 中,您定义了一个相机 - 它本质上是用户的视口。这台摄像机位于某个位置,指向某个方向,并以某个角度旋转。此外,摄像头还有一个投射角度,它通过一定的角度接收它看到的视觉信息(从某种意义上说,这可以被认为是摄像头的“镜头”)。
一旦所有世界都存在于同一个一致的坐标系中,您就可以让相机准确捕捉漂浮在您世界中的 3D 元素,因为元素的位置和大小与相机的位置和属性相关。
【讨论】: