文章目录

  • 一、什么是OpenGL
  • 二、OpenGL的由来
  • 三、工具库
  • 3.1、窗口管理
  • 3.2、glut
  • 3.3、freeglut
  • 3.4、glfw
  • 3.5、函数加载
  • 3.6、glew
  • 3.7、glad
  • 3.8、GLTools
  • 四、OpenGL数据类型
  • 五、OpenGL错误
  • 六、OpenGL状态机


一、什么是OpenGL

OpenGL被定义为 “图形硬件的一种软件接口” ;

从本质上讲,它是一个3D图形和模型库,具有高度的可移植性,并且具有非常快的速度;

使用OpenGL,可以创建爱你优雅而漂亮的3D图像,并且具有非常出色的视觉质量;

使用OpenGL的最大有点是它的速度远远快于光线追踪器或软件渲染引擎;


二、OpenGL的由来

OpenGL的前身是SGI公司的 IRIS GL,它最初是一个2D图形函数库,后面逐渐演化为这家公司的高端 IRIS图形工作站所使用的3D编程 API;

OpenGL就是SGI对 IRIS GL的一致性进行改进和提高的结果。这个新的图形API不仅具有GL的功能,而且是一个 “开放” 的标准。它的输入来自其它图形硬件厂商,并且更容易应用到其它硬件平台和操作系统。OpenGL是为了3D几何图形而完全重新设计的。


三、工具库

OpenGL 函数库相关的 API 有核心库(gl),实用库(glu),辅助库(aux)、实用工具库(glut),窗口库(glx、agl、wgl)和扩展函数库等。gl 是核心,glu 是对 gl 的部分封装。glx、agl、wgl 是针对不同窗口系统的函数。glut 是为跨平台的 OpenGL 程序的工具包,比aux 功能强大(aux 很大程度上已经被 glut 库取代)。扩展函数库是硬件厂商为实现硬件更新利用 OpenGL 的扩展机制开发的函数。

3.1、窗口管理

窗口操作在每个系统上都是不一样的,OpenGL 有目的地将这些操作抽象(Abstract)出去。这意味着我们不得不自己处理创建窗口,定义 OpenGL 上下文以及处理用户输入。幸运的是,有一些库已经提供了我们所需的功能。这些库节省了我们书写操作系统相关代码的时间,提供给我们一个窗口和上下文用来渲染。

3.2、glut

OpenGL 工具库(OpenGL Utility Toolkit),所有 glut 的库函数均以 glut 开头,但是版本太老了,理应被时代淘汰,不推荐使用。gult 最后版本 v3.7beta 的历史可追溯至 1998 年 8月,且该项目已经被废弃。它的许可证禁止任何人发布修改后的库代码。

AUX:OpenGL辅助函数库;AUX函数库的目标是帮助人们学习和编写OpenGL程序,而不必为任何平台特定环境的细枝末节而分神,不必顾虑所使用的是UNIX、Windows还是其它平台。如果使用AUX,我们不是编写 “最终” 代码,它更像是一个预备阶段,对自己的想法进行测试。由于缺乏基本的GUI特性,这就限制了这个函数库在创建实用的应用程序方面的应用,在跨平台的实例程序和演示程序中,AUX渐渐被GLUT函数库所取代。

GLUT:OpenGL实用工具箱,它作为AUX函数库的一个功能更强的替代品,添加了一些GUI功能,至少使示例程序在X Window下显得更为实用;在Windows中,GLUT的开发已经中断了,由于GLUT最初并不是作为一种开放源代码的软件,因此一种新的GLUT实现freeglut已经崛起并取代了它的位置。

不要与 GLU:OpenGL实用库 混淆

3.3、freeglut

gult 对应的开源实现,完全兼容 glut,是 glut 的代替品,开源,功能齐全。目前来看,freeglut3.0(2015年3月7日)版本比其它版本稳定,可以使用。该项目几乎可以 100% 的替代原来的 glut,只有少数差别(如,the abandonment of SGI-specific features,按钮盒子和动态视频分辨率)和其他一小部分程序 bug。

3.4、glfw

glfw 无愧于其号称的 lightweight 的 OpenGL 框架,的确是除了跨平台必要做的事情都没有做,所以一个头文件,很少量的 API,就完成了任务。glfw 的开发目的是用于替代 glut 的,从代码和功能上来看,我想它已经完全的完成了任务。它是一个轻量级的,开源的,跨平台的library。支持 OpenGL 及 OpenGL ES,用来管理窗口,读取输入,处理事件等。

3.5、函数加载

OpenGL 只是一个标准/规范,具体的实现是驱动开发商针对特定显卡实现的。由于 OpenGL 驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询。所以任务就落在了开发者身上,开发者需要在运行时获取函数地址并将其保存在一个函数指针中供以后使用。这个过程非常复杂,而且很繁琐,需要对每个可能使用的函数都要重复这个过程。幸运的是,有些库能简化此过程。

3.6、glew

glut 或者 freegult 主要是 OpenGL 1.0 的基本函数功能,glew 是使用 OpenGL 2.0 之后的一个工具函数。

不同的显卡公司会发布一些只有自家显卡才支持的扩展函数,要想用这数涵数,不得不去寻找最新的 glext.h,有了 glew 扩展库,就再也不用为找不到函数的接口而烦恼,因为 glew 能自动识别你的平台所支持的全部 OpenGL 高级扩展函数。也就是说,只要包含一个 glew.h 头文件,你就能使用 gl,glu,glext,wgl,glx 的全部函数。

glew 支持目前流行的各种操作系统,但有一个缺陷是它并没有提供一种方式可以屏蔽 OpenGL 旧函数的调用,尽管可以使用 Core profile 的方式,但是代码中仍然存在 glVetex、glBegin 这样固定管线 OpenGL 的函数调用(虽然它们在 Core Profile 模式下没有任何作用),看起来不那么统一。要做到这一点可以使用下面的 glad。

OpenGL API主要通过拓展机制来发展,这种机制能够用来获得指向任何加入OpenGL 1.0之后任何版本核心的OpenGL函数的函数指针。不止一种这样的扩展加载库可供选择,其中一种维护的最好的开源库是GLEW;GLEW被预先封装在GLTools库中,实际上,GLTools库就是基于GLEW的。

3.7、glad

glad 是继 gl3w,glew 之后,当前最新的用来访问 OpenGL 规范接口的第三方库。简单说glad 是 glew 的升级版。

glad 是一个开源的库,它的配置与大多数的开源库有些许的不同,glad 使用了一个在线服务。在这里能够指定 glad 需要定义的 OpenGL 版本,并且根据这个版本加载所有相关的OpenGL 函数。这样做让 glad.h 中仅仅只包含我们想要的头文件,例如在设置 3.3 + Core Profile 版本之后,可以严格控制头文件中只有这些内容,所以凡是代码中有 OpenGL 旧函数的调用都会在编译的时候给出错误提示。


3.8、GLTools

每一个工匠都有一个工具箱,里面装满了自己喜爱的工具,程序员也是如此。有一些有用并且可重用的函数,所有程序员在编写几乎所有OpenGL时都要用到它们。GLTools这个库随着时间的流逝,已经慢慢发展起来了,并提供许多快捷方式和便捷的工具,就像过去的OpenGL应用库(GLU)那样;GLTools包含一个用于操作矩阵和向量的3D数学库,并依靠GLEW获得OpenGL3.3 中用来产生和渲染一些简单3D对象的函数,以及视觉平截头体、相机类和变换矩阵进行管理的函数的充分支持。


四、OpenGL数据类型

为了使OpenGL代码更易于从一个平台移植到另一个平台,OpenGL定义的数据类型。这些数据类型可以映射到所有平台上的特定最小格式。

OpenGL数据类型

最小位宽

描述

GLboolean

1

布尔值

GLbyte

8

有符号字节型

GLubyte

8

无符号字节型

GLchar

8

字符串

GLshort

16

有符号短整型

GLushort

16

无符号短整型

GLhalf

16

半精度浮点值

GLint

32

有符号整型

GLuint

32

无符号整型

GLsizei

32

表示正数形式的size参数

GLenum

32

枚举类型

GLfloat

32

浮点型

GLclampf

32

单精度浮点型的一种提示,表示这个值的范围将 “截取” 在0.0~1.0范围内

GLbitfield

32

表示那些包含二进制位段的变量

GLdouble

64

双精度浮点型

GLclampd

64

双精度浮点型一种提示,表示这个值的范围将 “截取” 在0.0~1.0范围内

GLint64

64

有符号64位整型

GLuint64

64

无符号64位整型

GLsizeiptr

本地指针大小

GLintptr

本地指针大小

GLsync

本地指针大小

同步对象句柄

OpenGL并没有对指针和数组作特殊考虑,可以像下面这样声明一个包含10个GLshort变量的数组:

GLshort gl_shorts[10];

可以像下面这样声明一个长度为10的指向GLdouble类型变量的指针数组:

GLdouble *gl_doubles[10];

五、OpenGL错误

在编写程序时,希望程序能够流畅的运行,就需要考虑程序可能出现的错误以及一些出乎意料的情况,就像C++的try–catch语句,OpenGL提供了一种有用的机制,可以在代码中执行一种偶然健全性检查。

OpenGL在内部保留了一组错误标志(共4个),其中每个标志代表一种不同类型的错误。当一个错误发生是,与这个错误相对应的标志就会被设置。为了观察哪些标志被设置,可以调用glGetError函数:

GLenum glGetError(void);

glGetError函数返回下面列表中所列出的其中一个值:

错误代码

描述

GL_INVALID_ENUM

枚举参数超出范围

GL_INVALID_VALUE

数值参数超出范围

GL_INVALID_OPERATION

在当前的状态中操作非法

GL_INVALID_MEMORY

没有足够的内存来执行这条命令

GL_NO_ERROR

没有错误出现

  • 如果被设置的标志不止一个,glGetError仍然只返回一个唯一的值;
  • 当glGetError函数被调用时,这个值随后会被清除;
  • 在没有错误发生时,或者已经调用过个glGetError,将返回一个错误标志或GL_NO_ERROR;
  • 通常情况下,我们需要在一个循环中调用glGetError函数,持续检查错误标志,知道返回值是GL_NO_ERROR为止;

六、OpenGL状态机

绘制3D图形时一项复杂的任务,对于一个特定的集合图形,有许多因素可能会影响它的绘制:

  • 对象是不是与背景混合?
  • 要不要进行证明或背面剔除?
  • 当前限制的是什么纹理?

这样的问题数不胜数,我们把这类变量的集合称为管线的状态。

状态机是一个抽象的模型,表示一组状态变量的集合。每个状态变量可以有各种不同的值,或者只能打开或关闭等;

当我们在OpenGL中进行绘图时,如果每次都要指定所有这些变量显然有点不切实际,OpenGL使用状态机来追踪所有的OpenGL状态变量。

当一个状态值被设置之后,它就一直保持这状态,直到其它函数对它进行修改为止;

打开、关闭状态量

为了打开和关闭这些类型的状态变量,可以如下OpenGL函数:

void glEnable(GLenum capability);
void glDisable(GLenum capability);

例如:以深度测试为例:

glEnable(GL_DEPTH_TEST);
glDisable(GL_DEPTH_TEST);

深度测试:打开深度测试的几何绘图将会被检查以确保在进行渲染之前总会在任何位于她后面的对象前方,关闭深度测试后进行几何绘图则会在不进行深度比较的情况下进行绘制;

查询状态量

如果希望对一个状态量进行测试,以判断它是否已经被打开,OpenGL提供了一种方便的机制:

GLboolean glIsEnable(GLenum capability);

但是,并不是所有的状态变量都只是简单的打开或者关闭。许多OpenGL函数专门用于设置变量的值,此后这些变量一直保持被设置的值,直到再次被修改。OpenGL提供了一组查询函数,可以查询布尔型、整型、单精度浮点型和双精度浮点型变量的值,这4个函数原型如下所示:

void glGetBooleanv(GLenum pname, GLboolean *params);
void glGetDoublev(GLenum pname, GLboolean *params);
void glGetFloatv(GLenum pname, GLboolean *params);
void glGetIntegerv(GLenum pname, GLboolean *params);

每个函数都会返回单个值,或者返回一个数组,把一些值存储到我们指定的地址中。