引言
今天在公司的时候,基本工作做完之后,趁着一点多余的时间,回顾了下以前学习的OpenGL的知识。在看到第一章节的时候,书中使用一个正交窗口,显示一些很简单的图形。本来单单就这么一个实例的话,是很容易实现的。但是我一直以来都没有太搞清楚,OpenGL中各种指令到底做了些什么工作。所以,带着这样的疑问,我主要探究了下OpenGL中三个比较重要的概念,View Volume,Viewport以及Screen的关系。
概念介绍
View Volume
View Volume,有时候叫做View Frustum,也就是视景体。这个东西是定义了我们能够通过虚拟的3D摄像机所能看到的场景。当我们在一个3D场景中站立的时候,除了我们的位置之外,同样需要视野来定义我们所能够看到的东西。而这个视野就是通过视景体来定义的。一般在3D中,我们有两种不同的方式定义视景体。他们的形状分别如下所示:
图1
图2
上面给出了两个不同的视景体,图1表示的是中心透视视景体,而图2表示的是正交投影视景体。这两个几何体都全面的定义了我们所能够看到的视野,在OpenGL中也分别有不同的指令对应与这两个几何体。
我们都知道,在3D图形学中,我们是通过定义投影矩阵的方式来描述视景体的。通过定义中心透视矩阵来描述中心透视视景体,通过定义正交矩阵的方式来定义正交视景体。
Viewport
Viewport,中文翻译为视口。它的定义具有两个意义。一个意义是它定义了上面定义的视景体中的景物将会绘制到一张什么尺寸的画布之上,另外一个意义表示这个绘制好的图像将会被显示在屏幕的什么区域。
很明显,如果我们定义的视景体的投影平面的宽高比和视口所定义的宽高比不相同的话,那么将视景体中的物体绘制到画布上的时候会进行拉伸或者压缩;而当视景体投影平面的宽高比和视口所定义的宽高比一致的时候,图像将会不进行任何缩放绘制到视口所定义的画布之上。
视口定义中还包含了这个视口所表示的图像将会被绘制到屏幕的哪块区域之上的信息。在很多的图形应用中,我们都会发现在一个窗口中绘制多个3D场景的情况。而这个技术就是通过定义多个视口,绘制多个图像,然后“贴在”一个比较大的屏幕的多个不同的区域。
Screen
Screen即屏幕的意思,在真实世界中,我们都是通过屏幕上的东西来观察3D世界的。所有的场景最终都要被光栅化成为我们显示器上的图像。也就是说屏幕是3D场景的最终输出目的地。一个Screen可以容纳显示多个视口中的内容。
三者的关系
通过前面的介绍,我们大致的了解了这三个不同东西的概念。从中我们可以知道,通过定义投影矩阵,我们实际上是在虚拟的3D空间中,创建了一个视野,也就是视景体。在接着,我们通过定义视口,来描述视景体中的内容如何映射到一个虚拟的画布之上,并且这个画布最终将显示在屏幕上的什么位置。当所有的这些都设置完毕,我们绘制完毕场景之后,就能够通过硬件在我们的显示器屏幕上看到最终的画面。更理论的表述就是,通过定义投影矩阵,将3D场景投影到一个投影平面之上。通过定义视口,我们将投影平面上的内容映射到这个视口中去,并且填满它,同时根据定义视口是给定的屏幕坐标的位置,将这个视口中的图像映射到窗口的指定位置之上,最终我们就看到了图像。
代码演示
为了演示前面所讲述的内容,简单的做了一个Demo,它将在一个屏幕上绘制4个不同视口里面的画面,代码如下所示:
- #ifndef GLUT_DISABLE_ATEXIT_HACK
- #define GLUT_DISABLE_ATEXIT_HACK
- #endif
- #include <GL\glut.h>
- #include <GL\GL.h>
- #include <stdio.h>
- void oglDisplay();
- int main()
- {
- glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
- glutInitWindowSize(400,400);
- glutCreateWindow("Viewport");
- glutDisplayFunc(oglDisplay);
- glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
- glutMainLoop();
- return 0;
- }
- void oglDisplay()
- {
- glClear(GL_COLOR_BUFFER_BIT);
- // Left-Bottom
- glViewport(0,0, 200, 200);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(-100.0f, 100.0f, -100.0f, 100.0f, 100.0f, -100.0f);
- glColor3f(1.0f, 0.0f, 0.0f);
- glRectf(-100.0f, 100.0f, 100.0f, -100.0f);
- // Right-Bottom
- glViewport(200, 0, 200, 200);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(-100.0f, 100.0f, -100.0f, 100.0f, 100.0f, -100.0f);
- glColor3f(0.0f, 1.0f, 0.0f);
- glRectf(-100.0f, 100.0f, 100.0f, -100.0f);
- // Left-Top
- glViewport(0, 200, 200, 200);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(-100.0f, 100.0f, -100.0f, 100.0f, 100.0f, -100.0f);
- glColor3f(0.0f, 0.0f, 1.0f);
- glRectf(-100.0f, 100.0f, 100.0f, -100.0f);
- // Right-Top
- glViewport(200, 200, 200, 200);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(-100.0f, 100.0f, -100.0f, 100.0f, 100.0f, -100.0f);
- glColor3f(1.0f, 1.0f, 0.0f);
- glRectf(-100.0f, 100.0f, 100.0f, -100.0f);
- glFlush();
- }
运行结果如下所示: