OpenGL视口(viewport) OpenGL需要我们定义一个可以被观察者看到的空间。
OpenGL ES中具有的两种不同的视口类型:正交和透视。
OpenGL可以设定的视口中的一种就是使用透视。当你这样设置视口时,物体会随着移远而越来越小,视线会在物体移离观察者时最终交汇。这是对真实视觉的模拟;人们就是以这种方式观察世界的。
另一种看设置的视口称为正交(orthogonal) 视口。这种类型的视口,视线永远不会交汇而且物体不会改变其大小。没有透视效果。对于CAD程序以及其他各种目的是十分方便的,但因为它不像人们眼睛观察的方式所以看上去是不真实的,通常也不是你所希望的。
对于正交视口,你看将摄像机置于铁轨上,但这些铁轨永远不会交汇。它们将随着远离你的视线而继续保持等距。即使你定义了一个无限大的视口(OpenGL ES并不支持),这些线仍保持等距。
正交视口的优点是容易定义。因为线永不交汇,你只需定义一个像箱子一样的3D空间,像这样:
设置正交视口
在使用glViewport()函数定义视口前,你可以通过glOrthof()通知OpenGL ES你希望使用正交视口。下面是一个简单的例子:
CGRect rect = view.bounds;
glOrthof(-1.0, // Left
1.0, // Right
-1.0 / (rect.size.width / rect.size.height), // Bottom
1.0 / (rect.size.width / rect.size.height), // Top
0.01, // Near
10000.0); // Far
glViewport(0, 0, rect.size.width, rect.size.height);
这不难理解。首先我们获取视窗的尺寸。然后设定视口空间的宽度为两个单位,沿x轴从 -1.0 到 +1.0。很容易吧。
接着怎样设定底部和顶部?我们希望我们定义空间的X和Y坐标的宽高比与视窗的宽高比(也就是iPhone全屏时的宽高比)一样。由于iPhone的宽度与高度不同,我们需要确保视口的x和y坐标不同,但遵循一样的比例。
之后,我们定义了 near(远)和 far(近) 范围来描述观察的深度。 near 参数说明了视口开始的位置。如果我们站在原点处,视口就位于我们的面前,所以习惯上使用 .01 或 .001 作为正交视口的起点。这使得视口处于原点“前方”一点点。far 可以根据你程序的需要来设定。如果你程序中的物体永远不会远过20个单位,那么你不需要将 far设置为20,000 个单位。具体的数字随程序的不同而不同。
调用 glOrthof()之后,我们使用视窗矩形来调用 glViewport()。
设置透视视口
另一种情况就不那么简单,这里是原因。如果物体随着远离观察者而变小,那么它和你定义的可见空间的形状有什么关系。随着视线越来越远,你可以看到更广阔的世界,所以如果你使用透视,那么你定义的空间将不是一个立方体。是的,当使用透视时可见空间的形状称为锥台(frustum)。
CGRect rect = view.bounds;
GLfloat size = .01 * tanf(DEGREES_TO_RADIANS(45.0) / 2.0);
glFrustumf(-size, // Left
size, // Right
-size / (rect.size.width / rect.size.height), // Bottom
size / (rect.size.width / rect.size.height), // Top
.01, // Near
1000.0); // Far