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的扩展前缀

前缀厂商
SGIsilicon Graphics
IBMIBM
WGLMicroSoft
NVNVida
ATIATI
EXT跨厂商
ARB_ARB标准

NVida的扩展得到了广泛的使用,ATI也支持了NVida的扩展。

ARB批准的扩展,是通过OpenGL ARB的审查的扩展。

相关推荐