1.宽高比问题
我们现在相当熟悉这样一个事实,在OpenGL里,我们要渲染的一切物体都要映射到X轴和Y轴上[-1,1]的范围内,对于Z轴也一样。这个范围内的坐标被称为归一化设备坐标,其独立于屏幕实际尺寸或形状。
不幸的是,因为它们独立于实际的屏幕尺寸,如果直接使用它们,我们就会遇到问题,例如在横屏模式下被压扁的桌子。
假设实际的设备分辨率以像素为单位是1280*720,这在新的Android设备上是一个常用的分辨率。为了使讨论更加容易,让我们也暂时假定OpenGL占用整个显示屏。
如果设备是在竖屏模式下,那么[-1,1]的范围对应1280像素高,却只有720像素宽。图像会在X轴显得扁平,如果在横屏模式,同样的问题也会发生在Y轴上。
归一化设备坐标假定坐标空间是一个正方形,如下图所示:
然而,因为实际的视口可能不是一个正方形,图像就会在一个方向上被拉伸,在另一个方向上被压扁。在一个竖屏设备上,归一化设备坐标上定义的图像看上去就是在水平方向上被压扁了:
在横屏模式下,同样的图像就在另一个方向上看起来被压扁的。
2.适应宽高比
我们需要调整坐标空间,以使它把屏幕的形状考虑在内,可行的一个方法是把较小的范围固定在[-1,1]内,而按屏幕尺寸的比例调整较大的范围。
举例来说,在竖屏情况下,其宽度是720,而高度是1280,因此我们可以把宽度范围限定在[-1,1],并把高度范围调整为[-1280/720,1280/720]或[-1.78,1.78]。同理在横屏模式情况下,把高度范围设为[-1.78,1.78],而把高度范围设为[-1,1]。
通过调整已有的坐标空间,最终会改变我们可用的空间。
通过这个方法,不论是竖屏模式还是横屏模式,物体看起来就都一样了。
3.使用虚拟坐标空间
调整坐标空间,以便我们把屏幕方向考虑进来,我们需要停止直接在归一化设备坐标上工作,遥开始在虚拟坐标空间里工作。接下来,我们需要找到某种可以把虚拟空间坐标转化回归依化设备坐标的方法,让OpenGL可以正确的渲染它们。这种转换应该把屏幕方向计算在内,以使图像在竖屏模式和横屏模式看上去都一样。
我们想要进行的操作叫作正交投影。使用正交投影,不管多远或者多近,所有物体看上去大小总是相同的。为了更高的理解这种投影是做什么的,想象一下,在我们的场景中有一个火车轨道,直接从空中俯瞰,这些轨道看起来是这样的:
还有一种特殊类型的正交投影,被称为等轴测投影,它是从侧角观察一种正交投影。正如在一些城市模拟和策略游戏中看到的,这种类型的投影能用来重新创建一个经典的三维角。
当我们使用正交投影把虚拟坐标变换回归化设备坐标时,实际上定义了三维世界内部的一个区域。在这个区域内的所有东西都会显示在屏幕上,而区域外的所有东西都会被剪裁掉。
利用正交投影矩阵改变立方体的大小,以使我们可以在屏幕上看到或多或少的场景。我们也能改变立方体的形状弥补屏幕的宽高比的影响。
4.线性代数基础
OpenGL大量使用了向量和矩阵,矩阵的最重要的用途之一就是建立正交和透视投影。其原因之一是,从本质上来说,使用矩阵做投影只涉及对一组数据按顺序执行大量的加法和乘法,这些运算在现代GPU上执行的非常快。
4.1向量
一个向量是一个有多个元素的一维数组。在OpenGL里,一个位置通常是一个四元素向量,颜色也一样。我们使用的大多数向量一般都有四个元素。在下面的例子中, 我们可看到一个位置向量,它有一个X,一个Y,一个Z,一个W分量。
4.2矩阵
一个矩阵是一个有多个元素的二维数组。在OpenGL里,我们一般使用矩阵作向量投影,如正交或者透视投影,并且也用它们旋转物体,平移物体以及缩放物体。我们把矩阵与每个要变换的向量相乘可实现这些变换。下面就是一个矩阵:
4.3矩阵与向量的乘法
要让矩阵乘以一个向量,我们把矩阵放在左边,向量放在右边。如下:
规则就是矩阵第一行乘以向量第一列,以第一行为例:矩阵第一行第一个元素乘以向量第一列第一个元素,加上矩阵第一行第二个元素乘以向量第一列第二个元素,加上矩阵第一行第三个元素乘以向量第一列第三个元素,加上矩阵第一行第四个元素乘以向量第一列第四个元素。矩阵二,三,四行同理。
4.4单位矩阵
单位矩阵如下:
之所以被称为单位矩阵,是因为这个矩阵乘以任何向量总是得到与原来相同的向量。就像把任何数字乘以1会得到原来的数字一样。
4.5平移矩阵
既然理解了单位矩阵,让我们看一个非常简单的矩阵类型---平移矩阵。它在OpenGL里十分常用。使用这种类型的矩阵,我们可以把一个物体沿着指定的距离移动。这个矩阵和单位矩阵差不多,但在右侧指定了三个额外的元素:
让我们盾一个位置(2,2)的例子,这个位置Z默认是0,W默认是1.我们把这个向量沿X轴平移3,沿Y轴也平移3,因此,把Xtranslation赋值为3,Ytranslation赋值为3。结果如下:
这个位置正是我们所期望和(5,5)。