OpenGL超级宝典学习笔记——Using OpenGL(三)
OpenGL状态机
绘制3D图形是一项复杂的任务。我们需要许多的属性,比如光照属性,材料属性,纹理等。如果我们在每次绘制图形的时候,都去设置这些属性,或者以参数的形式传进去。那工作量非常大,而且还易出错。所以OpenGL使用了状态模式,来管理这些属性,使得图形编程变得更简洁,容易。
光照属性,材料属性等等属性变量的集合就是管线的状态。状态机是一系列状态变量的集合的抽象模型。每个状态变量可以有不同的值,例如打开或关闭等。
打开状态可以使用:
void glEnable(GLenum capability);
关闭状态可以使用
void glDisable(GLenum capability);
例子:
打开光照
glEnable(GL_LIGHTING);
关闭光照
glDisable(GL_LIGHTING);
Opengl还提供了检查这些状态的方法:
GLboolean glIsEnabled(GLenum capability);
不是所有的状态变量只有简单的打开或关闭的状态。许多OpenGL的函数设置这些状态值一直到被改变为止。你可以随时查找这些状态变量的值。OpenGL提供了各种类型的超找函数。
void glGetBooleanv(GLenum pname, GLboolean params);
void glGetDoublev(GLenum panme, GLdouble params);
void glGetFloatv(GLenum pname, GLfloat params);
void glGetIntegerv(GLenum pname, GLint params);
每一个函数返回一个值或者一个值数组,存储在你提供的参数params中。
保存和恢复状态
OpenGL提供了保存和恢复状态的方法。是使用栈(后进先出LIFO)的方式来保存这些变量的。
两个OpenGL的命令如下:
保存状态 void glPushAttrib(GLbitfield mask);
恢复状态 void glPopAttrib(GLbitfield mask);
参数是使用位段的方式来保存状态。这就意味着你可以在单个函数调用中用位OR操作来表示多个状态。
例如:
glPushAttrib(GL_TEXTURE_BIT|GL_LIGHTING_BIT);
获取时:
glPopAttrib(mask);
if (mask & GL_LIGHTING_BIT == GL_LIGHTING_BIT) glEnable(GL_LIGHTING);
OpenGL的错误处理
OpenGL在内部维护了一组错误标志,每个标志代表一种不同类型的错误。当一个错误发生时,与这个错误相对应的标志会被设置。我们可以调用glGetError(void)来检查这些标志。
GLenum glGetError(void);
glGetError会返回一个错误值。如果被设置的错误值不止一个,glGetError仍然只返回一个值。需要遍历不断去取值,持续检查错误值,直到返回GL_NO_ERROR。
错误代码
描述
GL_INVALID_ENUM
枚举值超出函数范围
GL_INVALID_VALUE
数值参数超出范围
GL_INVALID_OPERATION
在当前的状态下操作非法
GL_STACK_OVERFLOW
堆栈上溢
GL_STACK_UNDERFLOW
堆栈下溢
GL_OUT_OF_MEMORY
没有足够的内存来执行这条命令
GL_TABLE_TOO_LARGE
指定的表太大
GL_NO_ERROR
没有出现错误
我们可以使用GLU函数库的另一个函数gluErrorString来获得一个错误标志的字符串描述
const GLubyte gluErrorString(GLenum errorCode);
这个函数将错误标志作为它的唯一参数,并返回一个描述这个错误的静态字符串。
例子: 如果当前的错误标志位GL_INVALID_ENUM,则
gluErrorString(glGetError()); 将返回
invalid enumerant
获取版本
有时候我们希望利用一个特定环境所提供的特定功能。我们需要针对不同的环境进行编程的话,我们需要知道OpenGL驱动程序的生产商和版本号。可以调用glGetString
const GLubyte glGetString(GLenum name);
这个函数返回一个静态的字符串,描述了GL函数库的相关信息。
GLU函数库提供了另一个对应的函数gluGetString.
const GLubyte gluGetString(GLenum name);
这个函数返回一个字符串,描述它所请求的GLU函数的相关信息。
glHint
有时我们需要在性能和渲染效果中进行选择,而glHint能给OpenGL提供一个启示,你更关注渲染效果还是性能。
glHint允许指定偏重与视觉还是性能,函数原型如下:
void glHint(GLenum target, GLenum mode);
target指定行为类型。mode参数则告诉OpenGL我们最为关心的部分。这是唯一一个完全依赖于生产商的实现的函数。
检查扩展
OpenGL允许厂商进行扩展。要检查一个驱动程序包含了哪些扩展。如下:
const char szExtensions = glGetString(GL_EXTENTIONS);
这个字符串包含了驱动程序支持的所有扩展名称(用空格分隔)。查找希望使用的扩展:
if(strstr(extensions, “WGL_EXT_swap_control”) != NULL)
{
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress(“wglSwapIntervalEXT”);
if (wglSwapIntervalEXT != NULL)
wglSwapIntervalEXT(1);
}
使用这种方法,还应该确保扩展后面的那个字符串是空格或NULL,否则如果这个扩展被WGL_EXT_swap_control2所取代。此时C运行时函数strstr仍然找到第一个字符串,但是我们无法确定第二个的行为和第一个是否相同。
OpenGL的扩展前缀
前缀 | 厂商 |
SGI | silicon Graphics |
IBM | IBM |
WGL | MicroSoft |
NV | NVida |
ATI | ATI |
EXT | 跨厂商 |
ARB_ | ARB标准 |
NVida的扩展得到了广泛的使用,ATI也支持了NVida的扩展。
ARB批准的扩展,是通过OpenGL ARB的审查的扩展。