OpenGL是一种状态机模式,比如你用glEnable打开一个状态,在以后的绘图中将一直保留并应用这个状态,除非你调用glDisable及同类函数来改变该状态或程序退出。例如当前颜色是一个状态变量,可以把当前颜色设置为白色、红色或其他任何颜色,在此之后绘制的所有物体都将使用这种颜色,直到把当前颜色设置为其他颜色。

除当前颜色之外,OpenGL绝大多数函数都是一种状态机,如控制当前视图和投影变换、直线和多边形点画模式、多边形绘图模式、像素包装约定、光照的位置和特征以及被绘制物体的材料属性等。

前一段时间里,论坛有位朋友问什么是状态机。按我的理解,状态机就是一种存在于理论中的机器,它具有以下的特点:
1. 它有记忆的能力,能够记住自己当前的状态。
2. 它可以接收输入,根据输入的内容和自己的状态,修改自己的状态,并且可以得到输出。
3. 当它进入某个特殊的状态(停机状态)的时候,它不再接收输入,停止工作。

理论说起来很抽象,但实际上是很好理解的。
首先,从本质上讲,我们现在的电脑就是典型的状态机。可以对照理解:
1. 电脑的存储器(内存、硬盘等等),可以记住电脑自己当前的状态(当前安装在电脑中的软件、保存在电脑中的数据,其实都是二进制的值,都属于当前的状态)。
2. 电脑的输入设备接收输入(键盘输入、鼠标输入、文件输入),根据输入的内容和自己的状态(主要指可以运行的程序代码),修改自己的状态(修改内存中的值),并且可以得到输出(将结果显示到屏幕)。
3. 当它进入某个特殊的状态(关机状态)的时候,它不再接收输入,停止工作。 

OpenGL也可以看成这样的一种机器。让我们先对照理解一下:
1. OpenGL可以记录自己的状态(比如:当前所使用的颜色、是否开启了混合功能,等等,这些都是要记录的)
2. OpenGL可以接收输入(当我们调用OpenGL函数的时候,实际上可以看成OpenGL在接收我们的输入),根据输入的内容和自己的状态,修改自己的状态,并且可以得到输出(比如我们调用glColor3f,则OpenGL接收到这个输入后会修改自己的“当前颜色”这个状态;我们调用glRectf,则OpenGL会输出一个矩形)
3. OpenGL可以进入停止状态,不再接收输入。这个可能在我们的程序中表现得不太明显,不过在程序退出前,OpenGL总会先停止工作的。 

还是没理解?呵呵,看来这真不是个好的开始呀,难得等了这么久,好不容易教程有更新了,怎么如此的难懂啊??没关系,实在没理解,咱就不理解它了。接着往下看。
为什么我要提到“状态机”这个枯燥的、晦涩的概念呢?其实它可以帮助我们理解一些东西。
比如我在前面的教程里面,经常说:
可以使用glColor*函数来选择一种颜色,以后绘制的所有物体都是这种颜色,除非再次使用glColor*函数重新设定。
可以使用glTexCoord*函数来设置一个纹理坐标,以后绘制的所有物体都是采用这种纹理坐标,除非再次使用glTexCoord*函数重新设置。
可以使用glBlendFunc函数来指定混合功能的源因子和目标因子,以后绘制的所有物体都是采用这个源因子和目标因子,除非再次使用glBlendFunc函数重新指定。
可以使用glLight*函数来指定光源的位置、颜色,以后绘制的所有物体都是采用这个光源的位置、颜色,除非再次使用glBlendFunc函数重新指定。
……
呵呵,很繁,是吧?“状态机”可以简化这个描述。
OpenGL是一个状态机,它保持自身的状态,除非用户输入一条命令让它改变状态。
颜色、纹理坐标、源因子和目标因子、光源的各种参数,等等,这些都是状态,所以这一句话就包含了上面叙述的所有内容。
此外,“是否启用了光照”、“是否启用了纹理”、“是否启用了混合”、“是否启用了深度测试”等等,这些也都是状态,也符合上面的描述:OpenGL会保持状态,除非我们调用OpenGL函数来改变它。

取得OpenGL的当前状态
OpenGL保存了自己的状态,我们可以通过一些函数来取得这些状态。
首先来说一些启用/禁用的状态。
我们通过glEnable来启用状态,通过glDisable来禁用它们。例如:
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
可以用glIsEnabled函数来检测这些状态是否被开启。例如:
glIsEnabled(GL_DEPTH_TEST);
glIsEnabled(GL_BLEND);
glIsEnabled(GL_CULL_FACE);
glIsEnabled(GL_LIGHTING);
glIsEnabled(GL_TEXTURE_2D);
如果状态是开启的,则glIsEnabled函数返回GL_TRUE(这是一个不为零的常量,一般被定义为1);否则返回GL_FALSE(这是一个常量,其值为零)
我们可以在程序里面写:

if( glIsEnabled(GL_BLEND) ) {
     // 当前开启了混合功能
} else {
     // 当前没有开启混合功能
}

再看其它类型的状态。
比如当前颜色,其值是四个浮点数,当前设置的直线宽度,其值是一个浮点数,当前的视口(Viewport,参见第五课),其值是四个整数。
为了取得整数类型、浮点数类型的状态,OpenGL提供了glGetBooleanv, glGetIntegerv, glGetFloatv, glGetDoublev这四个函数。调用函数时,指定需要得到的状态的名称,以及需要将状态值存放到的位置(一个指针),则这四个函数可以把状态值存放到指针所值位置。例如:

// 取得当前的直线宽度
GLfloat lw;
glGetFloatv(GL_LINE_WIDTH, &lw);
// 取得当前的颜色
GLfloat cc[4];
glGetFloatv(GL_CURRENT_COLOR, cc);
// 取得当前的视口
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);

说明:
1. 注意元素的个数。比如GL_LINE_WIDTH状态只有一个值,而GL_CURRENT_COLOR有四个值。应该小心的定义变量或者数组,避免下标越界。
2. 使用四个不同的函数,同一种状态也可以返回为不同类型的值。比如要得到当前的颜色,一般可以返回GLfloat类型或者GLdouble类型。代码如下:

GLfloat cc[4];
GLdouble dcc[4];
glGetFloatv(GL_CURRENT_COLOR, cc);
glGetDoublev(GL_CURRENT_COLOR, dcc);

glGetBooleanv, glGetIntegerv, glGetFloatv, glGetDoublev这四个函数可以得到OpenGL中多数的状态,但是还有一些状态不便用这四个函数来取得。比如光源的状态,因为可能有多个光源,所以不可能使用类似glGetFloatv(GL_LIGHT_POSITION, pos);这样的方法来得到光源位置。为了解决这个问题,OpenGL专门提供了glGetLight*系列函数,来取得光源的状态。
类似的,还有glGetMaterial*, glGetTexParameter*等,每个函数都有自己的适用范围。

设置OpenGL状态
呵呵,读者可能会有疑问。既然有getXXX这样的函数来取得OpenGL的状态,那么为什么没有setXXX这样的函数来设置OpenGL状态呢?
答案很简单,因为OpenGL已经提供了大量的函数来设置状态了:glColor*, glMaterial*, glEnable, glDisable, 等等,大多数OpenGL函数都是用来设置OpenGL状态的,因此不需要再设计一个setXXX函数来设置OpenGL状态。

OpenGL的状态机理解的更多相关文章

  1. 小强学渲染之OpenGL状态机理解

    状态机是理论上的一种机器,呃这个说法非常非常的抽象.通俗一点理解,状态机描述了一个对象在其生命周期内所经历的各种状态,状态间的转变,发生转变的动因,条件及转变中所执行的活动.或者说,状态机是一种行为, ...

  2. OpenGL坐标系的理解

    搬运自: https://learnopengl-cn.github.io/01%20Getting%20started/08%20Coordinate%20Systems/#3d 为了将坐标从一个坐 ...

  3. opengl的矩阵理解

    原文链接:http://blog.csdn.net/byhuang/article/details/1476199 矩阵真的是一个很神奇的数学工具, 虽然单纯从数学上看, 它并没有什么特别的意义, 但 ...

  4. Android OpenGL ES(七)----理解纹理与纹理过滤

    1.理解纹理 OpenGL中的纹理能够用来表示图像.照片,甚至由一个数学算法生成的分形数据.每一个二维的纹理都由很多小的纹理元素组成.它们是小块的数据,类似于我们前面讨论过的片段和像素.要使用纹理,最 ...

  5. opengl微发展理解

    1.什么是OpenGL? 一种程序,可以与界面和图形硬件交互作用.一个开放的标准 2.软件管道 请看上图 - Apllication层     表示你的程序(调用渲染命令.如opengl API) - ...

  6. OpenGL理解

    说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640*480分辨率.16色 ...

  7. opengl入门学习

    OpenGL入门学习 说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640 ...

  8. OpenGL入门学习(转)

    OpenGL入门学习 http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html 说起编程作图,大概还有很多人想起TC的#includ ...

  9. 小强学渲染之OpenGL的CPU管线

    读到这里,应该对OpenGL渲染管线有了初步简单了解.下面着重分析CPU管线,即逻辑控制中心做了什么,这部分还是容易理解的.如下图: 一,将数据加载到显存中. 这是由GPU是访问显存中的数据决定的.因 ...

随机推荐

  1. 如何通过js给QQ好友发送信息

    一般我们在做页面活动的时候可能会碰到点击一个按钮把一些相关的信息通过QQ发送给你的好友,这种信息推送的功能该如何实现呢!下面我来介绍下使用方法! 代码如下: <!DOCTYPE HTML> ...

  2. CF:Problem 427C - Checkposts良好的沟通 Tarjan算法

    tarjan算法的第一个问题 喷我的脸....手写叠式开成BOOL,我一直在找错了... #include<cstdio> #include<cstring> #include ...

  3. UVA11125 - Arrange Some Marbles(dp)

    UVA11125 - Arrange Some Marbles(dp) option=com_onlinejudge&Itemid=8&category=24&page=sho ...

  4. Android项目---ActivityGroup的使用

    ActivityGroup在一年前已经被说明不用了,但是腾讯QQ,新浪微博上也不乏ActivityGroup的身影.所以,即使是过时的东西,也有学习的必要,当然项目中也是可以添加的.在网上找了一个博客 ...

  5. C++关于数字逆序输出的两种思路,及字符串逆序输出

    C++关于数字逆序输出的两种思路,及字符串逆序输出 作者:GREATCOFFEE 发布时间:NOVEMBER 15, 2012 分类:编程的艺术 最近在跟女神一起学C++(其实我是不怀好意),然后女神 ...

  6. 利用cxfreeze将Python 3.3打包成exe程序

    参考自别人的博文:http://blog.csdn.net/yatere/article/details/6667230 步骤如下: (1) 下载cxfreeze后安装(先得安装python 3.3) ...

  7. 【值得收藏】Mathematica数值计算工具的学习资料汇编【可免费下载】

    Mathematica学习教程 Mathematica是一款科学计算软件,很好地结合了数值和符号计算引擎.图形系统.编程语言.文本系统.和与其他应用程序的高级连接.Mathematica与Matlab ...

  8. Amazon前技术副总裁解剖完美技术面试

    Amazon前技术副总裁解剖完美技术面试 投递人 itwriter 发布于 2014-03-03 14:30 评论(0) 有1729人阅读  原文链接  [收藏]  « » 英文原文:The Anat ...

  9. iOS基础 - 文本属性Attributes

    NSKernAttributeName: 调整字句 kerning 字句调整 NSFontAttributeName : [UIFont systemFontOfSize:_fontSize] 设置字 ...

  10. [转]编译 JavaScriptCore For iOS

    from: http://phoboslab.org/log/2011/06/javascriptcore-project-files-for-ios github: https://github.c ...