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