1.1 语言和库
现代图形编程使用图形库完成,也就是说,程序员编写代码时,调用一个预先定义的库(或者一系列库)中的函数,由这个库来提供对底层图形操作的支持。现在有很多图形库,但常见的平台无关图形库叫作OpenGL(代表open graphics library,即开放图形库)。本书将会介绍如何在C++中使用OpenGL进行3D图形编程。
在C++中使用OpenGL需要配置多个库。这里按照个人需求,可以有一系列令人眼花缭乱的选择。在本节中,我们会介绍哪几种库是必要的,各种库的一些常见选择,以及我们在本书中选择的库。
总的来说,你需要用到:
- C++开发环境;
- OpenGL / GLSL;
- 窗口管理库;
- 扩展库;
- 数学库;
- 纹理图像加载库。
读者可能需要进行几项准备,以保证这几种库已安装在系统中,并可以正常使用。下面几个小节将简单介绍它们。它们的安装和配置的更多细节请参阅附录。
1.1.1 C++
C++是一种通用编程语言,最早出现在20世纪80年代中期。它的设计,以及它通常被编译成本机的机器码这一事实,使得它成了需要高性能的系统(比如3D图形计算)的优秀选择。C++的另一个优点是OpenGL调用库是基于C语言开发的。
有许多可用的C++开发环境。在阅读本书时,如果读者使用PC(Windows操作系统),我们推荐使用Microsoft Visual Studio [VS20];如果在Mac上,我们推荐使用Xcode [XC18]。附录中也介绍了各个平台下C++开发环境的安装和配置。
1.1.2 OpenGL / GLSL
OpenGL的1.0版本出现在1992年,是一种对各家供应商各不相同的计算机图形应用程序接口(Application Programming Interface,API)的“开放性”替代品。
它的规范和开发工作由当时新成立的OpenGL架构评审委员会管理和控制。ARB是由一群行业参与者组成的小组。2006年,ARB将OpenGL规范的控制权交给了Khronos Group。Khronos Group是一个非营利性联盟,不仅管理着OpenGL标准,还管理着很多其他的开放性行业标准。
从一开始,OpenGL就定期修订和扩展。2004年,2.0版本中引入了OpenGL着色语言GLSL,使得“着色器程序”可以被直接安装到图形管线的各个阶段并执行。
2009年,3.1版本中移除了大量被弃用的功能,以强制使用着色器编程,而不是之前的老方法(称为“立即模式”)[1]。4.0版本(2010年)在可编程管线中增加了一个曲面细分阶段。
本书假定读者的计算机有一个支持至少 4.3 版本 OpenGL 的显卡。如果你不确定你的GPU 支持哪个版本的 OpenGL,网上有免费的应用程序可以用来找出答案。其中一个是GLView,由realtech VR公司提供[GV20]。
1.1.3 窗口管理库
OpenGL实际上并不是把图像直接绘制到计算机屏幕上,而是将之渲染到一个帧缓冲区,然后由计算机来负责把帧缓冲区中的内容绘制到屏幕上的一个窗口中。有不少库都可以支持这一部分工作。一个选择是使用操作系统提供的窗口管理功能,比如Microsoft Windows API。但这通常不实用,因为需要很多底层的编码工作。GLUT库曾经是一个很流行的选择,但现在已经被弃用了。它的一个现代化的变体是freeglut库。其他相关的选项还有CPW库、GLOW库、GLUI库等。
GLFW是最流行的选择之一,也是本书中选择使用的。它内置了对Windows、macOS、Linux和其他操作系统[GF20]的支持。它可以在其官网下载,并且需要在要使用它的计算机上编译。(我们在附录中介绍了相关步骤。)
1.1.4 扩展库
OpenGL围绕一组基本功能和扩展机制进行组织。随着技术的发展,扩展机制可以用来支持新的功能。现代版本的OpenGL,比如我们在本书中使用的4.3以上版本,需要识别GPU上可用的扩展。OpenGL的核心中有一些内置的命令用来支持这一点,但是为了使用现代命令,需要执行很多相当复杂的代码。在本书中,我们会经常使用这些命令。所以使用一个扩展库来处理这些细节已经成了标准做法,这样能让程序员可以直接使用现代OpenGL命令。扩展库有Glee、GLLoader和GLEW,以及新版的GL3W和GLAD。
上面列出的这些库中,常用的是GLEW。这个名称代表OpenGL extension wrangler,即OpenGL扩展牛仔。GLEW支持各种操作系统,包括Windows、macOS和Linux [GE20],但它并不是完美的选择。例如,它需要一个额外的动态链接库。最近,很多开发者选择GL3W或者GLAD。它们的优势是可以自动更新,但是需要Python环境。本书使用GLEW。它可以在其官网下载。附录中给出了安装和配置GLEW的完整说明。
1.1.5 数学库
3D图形编程会大量使用向量和矩阵代数。因此,配合一个支持常见数学计算任务的函数库或者类包,能极大地方便OpenGL的使用。常常和OpenGL一起使用的两个这样的库是Eigen和vmath。后者在流行的《OpenGL超级宝典(第7版)》[SW15]中使用。
本书使用OpenGL Mathematics数学库,一般称作GLM。它是一个只有头文件的C++库,兼容Windows、macOS和Linux [GM20]。GLM命令能很方便地遵循和GLSL相同的命名惯例,使得来回阅读特定应用程序的C++和GLSL代码时更容易。GLM可以在其官网下载。
GLM可提供与图形概念相关的类和基本数学函数,例如矢量、矩阵和四元数。它还包含各种工具类,用于创建和使用常见的3D图形结构,例如透视和视角矩阵。它最早在2005年发布,由Christophe Riccio [GM20]维护。有关安装GLM的说明,请参阅附录。
1.1.6 纹理图像加载库
从第5章开始,我们将使用图像文件来向图形场景中的对象添加“纹理”。这意味着我们会频繁加载这些图像文件到我们的C++/OpenGL代码中。从零开始编写一个纹理图像加载器是可以做到的。但是,考虑到各种各样的图像文件格式,使用一个纹理图像加载库通常是更好的。比如FreeImage、DevIL、GLI和Glraw。SOIL可能是最常用的OpenGL图像加载库,尽管它有点儿过时了。
本书中使用的纹理图像加载库是SOIL2——SOIL的一个更新的分支版本。像我们之前选择的库一样,SOIL2兼容各种平台[SO20]。附录中给出了其详细的安装和配置说明。
1.1.7 可选库
读者可能希望利用很多其他有用的库。例如,在本书中,我们将展示如何从零开始实现一个简单的OBJ模型加载器。然而,正如你将看到的,它没有处理OBJ标准中很多可用的选项。有一些更复杂的、现成的OBJ模型加载器可供选择,比如Assimp和tinyobjloader。本书的例子只会使用书中介绍和实现的简单模型加载器。