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. 【SSRS】入门篇(六) -- 分组和总计

    原文:[SSRS]入门篇(六) -- 分组和总计 通过[SSRS]入门篇(五) -- 设置报表格式的设计,一份简单格式的报表已产生,如下图: 这节来说说分组和总计: 根据日期.订单对数据进行分组 添加 ...

  2. 在SSIS中使用自定义的DLL文件

    原文:在SSIS中使用自定义的DLL文件 步骤1.开发dll(需要签名) using System;using System.Collections.Generic;using System.Text ...

  3. 1001. 杀死吸引力(3n+1)猜想 (15)(ZJUPAT 数学)

    主题链接:http://pat.zju.edu.cn/contests/pat-b-practise/1001 卡拉兹(Callatz)猜想: 对不论什么一个自然数n,假设它是偶数,那么把它砍掉一半. ...

  4. Android项目---webView

    之前用webView的时候,只知道它可以加载出html页面,竟然不知道,它也可以与js进行交互. WebView是一个网络视图,能加载显示网页,可以将它看作一个浏览器.它使用WebKit渲染引擎加载显 ...

  5. delphi字符串函数大全

    转帖:delphi字符串函数大全 2009-11-17 16:43:55 分类: delphi字符串函数大全 ━━━━━━━━━━━━━━━━━━━━━首部 function StringToGUID ...

  6. Web面试之JQuery

    程序员Web面试之JQuery   又到了一年一度的毕业季了,青春散场,却等待下一场开幕. 在求职大军中,IT行业的程序员.码农是工科类大学生的热门选择之一, 尤其是近几年Web的如火如荼,更是吸引了 ...

  7. Using Ninject in a Web Application

    http://aidenweb.co.uk/?p=15 Using Ninject in a Web Application I have been meaning to look at Ninjec ...

  8. iOS基础 - UIButton - UIImageView

    封装思想:将相同的重复东西保存到方法里,不同的东西用参数代替.不相同的东西交给方法调用者,相同东西自己搞定. 一.UIButton和UIImageView的区别 1.显示图片 1> UIImag ...

  9. 朴素贝页斯分类法 c++实现

    朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法.对于搞机器学习的同学们来说,这是相对简单但效果较好的模型. 朴素贝叶斯方法的理论 设输入为n维特征向量X={x1,x2,...,xn},输出为 ...

  10. 在一个view类里面获取viewcontroller

    - (UIViewController *)viewController {     for (UIView* next = [selfsuperview]; next; next = next.su ...