OpenGL特性
扩展(Extension)
OpenGL的一大特性就是对扩展的支持,当一个显卡公司提出一个新特性或者渲染上的大优化,通常会以扩展的方式在驱动中实现。如果一个程序在支持这个扩展的显卡上与运行,开发者可以使用这个扩展提供的一些更先进更有效的图形功能。通过这种方式,开发者不必等待一个新的OpenGL规范面世,就可以方便的检查显卡是否支持此扩展。
if(GL_ARB_extension_name)
{
//使用一些新的特性
}
else
{
//不支持此扩展:用旧的方式去做
}
状态机(State Machine)
OpenGL自身是一个巨大的状态机:一个描述OpenGL该如何操作的所有变量的大集合。
OpenGL的状态通常被称为OpenGL上下文(Context)。我们通常使用如下途径去更改OpenGL状态:设置一些选项,操作一些缓存。最后,我们使用当前OpenGL上下文来渲染。
假设当我们想告诉OpenGL去画线而不是三角形的时候,我们通过改变一些上下文来改变OpenGL状态。从而告诉OpenGL如何去绘图。一旦我们改变OpenGL的状态为绘制线段,下一个绘制命令就会画出线段而不是三角形。
用OpenGL工作时,我们会遇到一些状态设置函数(State-changing Function),以及一些在这些状态的基础上状态应用的函数(State-using Function)。只要你记住OpenGL本质上是个大状态机,就能更容易理解它的大部分特性。
对象(Object)
OpenGL库是用C语言写的, 同时也支持多种语言的派生, 但是核心是一个C库。 一些C语言
的结构不易被翻译到其他高层语言, 因此OpenGL设计的时候引入了一些抽象概念。 “对象”就
是其中一个。
在OpenGL中一个对象是指一些选项的集合, 代表OpenGL状态的一个子集。 比如, 我们可以
用一个对象来代表绘图窗口的设置, 可以设置它的大小、 支持的颜色位数等等。 可以把对象
看做一个C风格的结构体:
struct object_name {
GLfloat option1;
GLuint option2;
GLchar[] name;
};
注:
原始类型(Primitive Type)
使用OpenGL时, 建议使用OpenGL定义的原始类型。 比如使用`float`时我们加上前缀GL(因此写作`GLfloat`)。
当我们使用一个对象时, 通常看起来像如下一样(把OpenGL上下文比作一个大的结构体):
// OpenGL的状态
struct OpenGL_Context
{
...
object* object_Window_Target;
...
};
// 创建对象
GLuint objectId = 0;
glGenObject(1, &objectId);
// 绑定对象至上下文
glBindObject(GL_WINDOW_TARGET, objectId);
// 设置GL_WINDOW_TARGET对象的一些选项
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800);
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600);
// 将上下文的GL_WINDOW_TARGET对象设回默认
glBindObject(GL_WINDOW_TARGET, 0);
这一小片代码将会是以后使用OpenGL时常见的工作流。 我们首先创建一个对象, 然后用一个id保存它的引用(实际数据被储存在后台)。 然后我们将对象绑定至上下文的目标位置(例子里窗口对象的目标位置被定义成 GL_WINDOW_TARGET )。 接下来我们设置窗口的选项。 最后我们通过将目标位置的对象id设回0的方式解绑这个对象。 设置的选项被保存在 objectId 代表的对象中, 一旦我们重新绑定这个对象到 GL_WINDOW_TARGET 位置, 这些选项就会重新生效。
使用对象的一个好处是我们在程序中不止可以定义一个对象并且设置他们的状态, 在我们需要进行一个操作的时候, 只需要绑定预设了需要设置的对象即可。 比如, 有一个作为3D模型的数据(一栋房子或一个人物, 由多个子模型构成)容器对象, 在我们想绘制其中任何一个3D模型的时候, 只需绑定相应的子模型数据的对象(我们预先创建并设置好了它们的选项)就可以
了。 拥有数个这样的对象允许我们指定多个模型, 在想画其中任何一个的时候, 简单的将相应的对象绑定上去, 便不需要再进行重复的设置选项的操作了。