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