OpenGL颜色

几乎所有OpenGL应用目的都是在屏幕窗口内绘制彩色图形,所以颜色在OpenGL编程中占有很重要的地位。这里的颜色与绘画中的颜色概念不一样,它属于RGB颜色空间,只在监视器屏幕上显示。另外,屏幕窗口坐标是以象素为单位,因此组成图形的每个象素都有自己 的颜色,而这种颜色值是通过对一系列OpenGL函数命令的处理最终计算出来的。本章将讲述计算机颜色的概念以及OpenGL的颜色模式、颜色定义和两种模式应用场合等内容,若掌握好颜色的应用,你就能走进缤纷绚丽的色彩世界,从中享受无穷的乐趣。

9.1、计算机颜色

  9.1.1 颜色生成原理
  计算机颜色不同于绘画或印刷中的颜色,显示于计算机屏幕上每一个点的颜色都是由监视器内部的电子枪激发的三束不同颜色的光(红、绿、蓝)混合而成,因此,计算机颜色通 常用R(Red)、G(Green)、B(Blue)三个值来表示,这三个值又称为颜色分量。颜色生成原理 示意图见图9-1所示。

 
图9-1 计算机颜色生成原理

  9.1.2 RGB色立体(RGB Color Cube)
  所有监视器屏幕的颜色都属于RGB颜色空间,如果用一个立方体形象地表示RGB颜色组成关系,那么就称这个立方体为RGB色立体,如图9-2所示。

 
图9-2 RGB色立体

  在图中,R、G、B三值的范围都是从0.0到1.0。如果某颜色分量越大,则表示对应的颜色分量越亮,也就是它在此点所贡献的颜色成分越多;反之,则越暗或越少。当R、G、B三个值都为0.0时,此点颜色为黑色(Black);当三者都为1.0时,此点颜色为白色(White);当三个颜色分量值相等时,表示三者贡献一样,因此呈现灰色(Grey),在图中表现为从黑色顶点到白色顶点的那条对角线;当R=1.0、G=1.0、B=0.0时,此点颜色为黄色(Yellow);同理,R=1.0、G=0.0、B=1.0时为洋红色,也叫品色(Magenta);R=0.0、G=1.0、B=1.0时为青色(Cyan)。

9.2、颜色模式
  OpenGL颜色模式一共有两个:RGB(RGBA)模式和颜色表模式。在RGB模式下,所有的颜色定义全用R、G、B三个值来表示,有时也加上Alpha值(与透明度有关),即RGBA模式。在颜色表模式下,每一个象素的颜色是用颜色表中的某个颜色索引值表示,而这个索引值指向了相应的R、G、B值。这样的一个表成为颜色映射(Color Map)。

  9.2.1 RGBA模式(RGBA Mode)
  在RGBA模式下,可以用glColor*()来定义当前颜色。其函数形式为:

  void glColor3{b s i f d ub us ui}(TYPE r,TYPE g,TYPE b);
  void glColor4{b s i f d ub us ui}(TYPE r,TYPE g,TYPE b,TYPE a);
  void glColor3{b s i f d ub us ui}v(TYPE *v);
  void glColor4{b s i f d ub us ui}v(TYPE *v);

  设置当前R、G、B和A值。这个函数有3和4两种方式,在前一种方式下,a值缺省为1.0,后一种Alpha值由用户自己设定,范围从0.0到1.0。同样,它也可用指针传递参数。另外,函数的第二个后缀的不同使用,其相应的参数值及范围不同,见下表9-1所示。虽然这些参数值不同,但实际上OpenGL已自动将它们映射在0.0到1.0或-1.0或范围之内。因此,灵活使用这些后缀,会给你编程带来很大的方便。

后缀 数据类型 最小值 最小值映射 最大值 最大值映射 
b 1字节整型数 -128 -1.0 127 1.0 
s 2字节整型数 -32,768 -1.0 32,767 1.0 
i 4字节整型数 -2,147,483,648 -1.0 2,147,483,647 1.0 
ub 1字节无符号整型数 0 0.0 255 1.0 
us 2字节无符号整型数 0 0.0 65,535 1.0 
ui 4字节无符号整型数 0 0.0 4,294,967,295 1.0 
表9-1 整型颜色值到浮点数的转换

  9.2.2 颜色表模式(Color_Index Mode)
  在颜色表方式下,可以调用glIndex*()函数从颜色表中选取当前颜色。其函数形式为:

  void glIndex{sifd}(TYPE c);
  void glIndex{sifd}v(TYPE *c);

  设置当前颜色索引值,即调色板号。若值大于颜色位面数时则取模。

  9.2.3 两种模式应用场合
  在大多情况下,采用RGBA模式比颜色表模式的要多,尤其许多效果处理,如阴影、光照、雾、反走样、混合等,采用RGBA模式效果会更好些;另外,纹理映射只能在RGBA模式下进行。下面提供几种运用颜色表模式的情况(仅供参考):
  1)若原来应用程序采用的是颜色表模式则转到OpenGL上来时最好仍保持这种模式,便于移植。
  2)若所用颜色不在缺省提供的颜色许可范围之内,则采用颜色表模式。
  3)在其它许多特殊处理,如颜色动画,采用这种模式会出现奇异的效果。

9.3、颜色应用举例
  颜色是一个极具吸引力的应用,在前面几章中已经逐步介绍了RGBA模式的应用方式,这里就不再多述。下面着重说一下颜色表模式的应用方法,请看例程:

  例9-1 颜色表应用例程(cindex.c)

  #include "glos.h"
  #include <GL/gl.h>
  #include <GL/glaux.h>

  void myinit(void);
  void InitPalette(void);
  void DrawColorFans(void);
  void CALLBACK myReshape(GLsizei w,GLsizei h);
  void CALLBACK display(void);

  void myinit(void)
  {
    glClearColor(0.0,0.0,0.0,0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glShadeModel(GL_FLAT);
  }

  void InitPalette(void)
  {
    GLint j;
    static GLfloat rgb[][3]={
      {1.0,0.0,0.0},{1.0,0.0,0.5},{1.0,0.0,1.0},{0.0,0.0,1.0},
      {0.0,1.0,1.0},{0.0,1.0,0.0},{1.0,1.0,0.0},{1.0,0.5,0.0}};

    for(j=0;j<8;j++)
      auxSetOneColor(j+1,rgb[j][0],rgb[j][1],rgb[j][2]);
  }

  void CALLBACK myReshape(GLsizei w,GLsizei h)
  {
    glViewport(0,0,w,h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if(w<=h)
      glOrtho(-12.0,12.0,-12.0*(GLfloat)h/(GLfloat)w, 12.0*(GLfloat)h/(GLfloat)w,-30.0,30.0);
    else
      glOrtho(-12.0*(GLfloat)h/(GLfloat)w, 12.0*(GLfloat)h/(GLfloat)w,-12.0,12.0,-30.0,30.0); 
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
  }

  void CALLBACK display(void)
  {
    InitPalette();
    DrawColorFans();
    glFlush();
  }

  void DrawColorFans(void)
  {
    GLint n;
    GLfloat pp[8][2]={
      {7.0,-7.0},{0.0,-10.0},{-7.0,-7.0},{-10.0,0.0},
      {-7.0,7.0}, {0.0,10.0},{7.0,7.0},{10.0,0.0}};

    /* draw some filled_fan_triangles */
    glBegin(GL_TRIANGLE_FAN);
      glVertex2f(0.0,0.0);
      glVertex2f(10.0,0.0);
      for(n=0;n<8;n++)
      {
        glIndexi(n+1);
        glVertex2fv(pp[n]);
      }
    glEnd();
  }

  void main(void)
  {
    auxInitDisplayMode(AUX_SINGLE|AUX_INDEX);
    auxInitPosition(0,0,500,500);
    auxInitWindow("Color Index");
    myinit();
    auxReshapeFunc(myReshape);
    auxMainLoop(display);
  }

  这个程序运行结果是在屏幕上显示八个连成扇形的不同颜色的三角形,每个三角形的颜色定义采用颜色表模式。其中,调用了辅助库函数auxSetOneColor()来装载颜色映射表,即调色板。因为将某个颜色装载到颜色查找表(color lookup table)中的过程必须依赖窗口系统,而OpenGL函数与窗口系统无关,所以这里就调用辅助库的函数来完成这个过程,然后才调用OpenGL自己的函数glIndex()设置当前的颜色号。

 


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/StFairy/archive/2007/07/15/1691800.aspx

posted @ 2010-11-19 16:03 白了少年头 Views(363) Comments(0)  Edit

在OpenGL窗口中, 左下角的像素为(0, 0). 一般而言, 像素(x, y)占据的矩形区域左下角为(x, y), 右上角为(x+1, y+1).

10.1 缓存及其用途


1) 颜色缓存,  左前,右前,左后,右后和任意数量的辅助颜色缓存;
2) 深度缓存
3) 模板缓存
4) 累积缓存

注意:X窗口系统,RGBA模式至少保证1个颜色缓冲区,模板缓冲区,深度缓冲区,累计缓冲区
颜色索引模式至少保证1个眼色缓冲区,深度缓冲区,模板缓冲区.
可以使用glXGetConfig{}函数查询.

用glGetIntegerv()查询每个像素占据的缓存空间的参数
GL_RED_BITS, GL_GREEN_BITS, GL_BLUE_BITS, GL_ALPHA_BITS --- 颜色缓存中R, G, B, A分量的位数
GL_INDEX_BITS --- 颜色缓存中每个颜色索引的位数
GL_DEPTH_BITS --- 深度缓存中每个像素的位数
GL_STENCIL_BITS --- 模板缓存中每个像素的位数
GL_ACCUM_RED_BITS, GL_ACCUM_GREEN_BITS, GL_ACCUM_BLUE_BITS, GL_ACCUM_ALPHA_BITS --- 累积缓存中R, G, B, A分量的位数.

10.1.1 颜色缓存


1) 颜色缓存存储了颜色索引或RGB颜色数据, 还可能存储了alpha值. 
2) 支持立体观察(stereoscopic viewing)的OpenGL实现有左颜色缓存和右颜色缓存. 它们分别用于左立体图像和右立体图像.
3) 如不支持立体观察, 则只使用左颜色缓存.
4) 双颜色缓存有前缓存和后缓存, 单缓存系统只有前缓存.
5) 支持不可显示的辅助颜色缓存
6) 函数glGetBooleanv()查询是否支持立体观察和双缓存: GL_STEREO和GL_DOUBLE_BUFFER. 
   函数glGetIntegerv()查询多少个辅助缓存可用: GL_AUX_BUFFERES.

10.1.2 深度缓存


深度缓存 --- 存储了每个像素的深度值. 通常是离视点的距离, 因此深度值大的像素会被深度值小的像素覆盖.

10.1.3 模板缓存


用途之一: 绘图范围限制在屏幕的特定区域内.

10.1.4 累积缓存


累积缓存也存储RGBA颜色数据, 将一系列的图像合成一幅图像. 
可以对图像进行超量采样, 然后对样本进行平均, 并将结果写入颜色缓存中, 从而实现场景反走样. 不能将数据直接写入累积缓存.
累加操作总是针对一个矩形块的, 通常是将数据移入或移出颜色缓存.

10.1.5 清空缓存


void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
void glClearIndex(GLfloat index);
void glClearDepth(GLclampd depth);
void glClearStencil(GLint s);
void glClearAccum(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
功能: 指定用于清除颜色缓存(RGBA模式或颜色索引模式), 深度缓存, 模板缓存和累积缓存的值. 
类型为GLclampf和GLclampd的参数值被截取到[0.0, 1.0]. 深度缓存的默认清除值为1.0, 其他缓存为0.0.

设置清除值后, 便可以调用函数glClear()来清除缓存.
void glClear(GLbitfield mask);
功能: 清除指定的缓存. 
mask:GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT, GL_ACCUM_BUFFER_BIT的逻辑或(OR).
清除颜色缓存时, 如果启用了像素所有权测试, 裁剪测试和抖动操作, 它们都会在清除操作中执行. 
屏蔽操作(glColorMask()和glIndexMask())也会生效.alpha测试, 模版测试, 深度测试并不会影响glClear()函数的操作.

10.1.6 指定要读写的颜色缓存


指定要写入的缓存 glDrawBuffer();
指定要读取的缓存 glReadBuffer();

使用双缓存, 通常只绘制后缓存, 并在绘制完成后交换缓存. 你可能想将双缓存窗口视为单缓存窗口: 通过调用函数glDrawBuffer()使得可以同时绘制前缓存和后缓存.
void glDrawBuffer(GLenum mode); 
功能: 指定要写入或消除的颜色缓存以及禁用之前被启用的颜色缓存. 可以一次性启用多个缓存.
GL_FRONT: 单缓存的默认值    
GL_FRONT_RIGHT:    
GL_NONE:
GL_FRONT_LEFT:
GL_FRONT_AND_BACK:
GL_RIGHT:
GL_AUXi: i表示第几个辅助缓存.
GL_LEFT:
GL_BACK_RIGHT:
GL_BACK: 双缓存的默认值
GL_BACK_LEFT:
注意: 启用多个缓存用于写操作时, 只要其中一个缓存存在, 就不会发生错误. 如果指定的缓存都不存在, 就发生错误.

void glReadBuffer(GLenum mode); 
功能: 选择接下来的函数调用glReadPixels(), glCopyPixels(), glCopyTexImage*(), glCopyTexSubImage*() 和 glCopyConvolutionFilter*()将读取的缓存.
      并启用以前被函数glReadBuffer()启用的缓存.
参数mode取值:
GL_FRONT: 单缓存默认
GL_FRONT_RIGHT:
GL_BACK_RIGHT:
GL_FRONT_LEFT:
GL_LEFT:
GL_AUX:
GL_BACK_LEFT:
GL_BACK: 双缓存默认
GL_RIGHT:
注意: 启用缓存用于读取操作时, 指定的缓存必须存在, 否则将发生错误.

10.1.7 屏蔽缓存


void glIndexMask(GLuint mask);
void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
void glDepthMask(GLboolean flag);
void glStencilMask(GLuint mask);
 
功能: 设置掩码, 用于控制写入到指定缓存中的数据,
glIndexMask: 只用于颜色索引模式中, 掩码中1对应的数据位被写入颜色索引缓存中. 0对应的位不写入.
glColorMask: 只影响RGBA模式下的写入, red, green, blue, alpha决定是否写入相应的分量, GL_TRUE时写入.
glDepthMask(): 如果参数flag的值为GL_TRUE, 则启用深度缓存用于写入, 否则禁用深度缓存.
glStencilMask(): 参数mask的含义与函数glIndexMask()中相同. 
所有GLboolean参数的默认值是GL_TRUE, 两个GLuint参数的默认值都是1.

禁用深度缓存: 如果背景很复杂, 则在背景绘制之后, 禁用深度缓存. 绘制新增的物体, 只要不相互重叠.. 下一帧时, 只需恢复树木图像, 无需恢复深度缓存中的值.
这种方法很有效.

模板缓存的屏蔽操作让你能够使用一个多位模板缓存来存储多个模板(每位一个)
函数glStencilMask()指定的掩码用于控制哪些模板位面可写, 与函数glStencileFunc()的第三个参数指定的掩码无关, 后者指定模板函数将考虑哪些位面.

10.2 片段测试和操作


测试顺序:
1. 裁剪测试 
2. alpha测试 
3. 模版测试
4. 深度测试
5. 混合
6. 抖动
7. 逻辑操作

10.2.1 裁剪测试


void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
设置裁剪矩形的位置和大小. 需要启用GL_SCISSOR_TEST.

10.2.2 alpha测试


需要启用GL_ALPHA_TEST
void glAlphaFunc(GLenum func, GLclampf ref); 
设置用于alpha测试的参考值和比较函数.
alpha测试可用于透明算法和贴花.

10.2.3 模板测试


void glStencilFunc(GLenum func, GLint ref, GLuint mask);
void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
 
设置模板测试所使用的比较函数(func),参考值(ref),掩码(mask)

void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass);
void glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
指定当一个片段通过或未通过模板测试时, 模板缓冲区中的数据如何进行修改.

下图设置模板为中间的方块

11

模板查询glGetInteger()可使用的参数:
GL_STENCIL_FUNC
GL_STENCIL_REF
GL_STENCIL_VALUE_MASK
GL_STENCIL_FAIL
GL_STENCIL_PASS_DEPTH_FAIL
GL_STENCIL_PASS_DEPTH_PASS

 

10.2.4 深度测试


void glDepthFunc(GLenum func); 
为深度测试设置比较函数.

10.2.5 遮挡测试


遮挡测试允许我们判断一组几何图形在进行深度测试之后是否可见.
步骤:
1. 为每个所需的遮挡查询生成一个查询ID
2. 调用glBeginQuery(), 表示开始一个遮挡查询
3. 渲染需要进行遮挡查询的几何图形
4. 调用glEndQuery(), 表示已经完成了遮挡查询
5. 提取通过遮挡查询的样本数量.

生成查询对象
void glGenQueries(GLsizei n, GLuint* ids);

对遮挡查询对象进行初始化
void glBeginQuery(GLenum target, GLuint id);
void glEndQuery(GLenum target);
 
target必须为GL_SAMPLES_PASSED.

判断遮挡查询的结果
void glGetQueryObjectiv(GLenum id, GLenum pname, GLint *params);
void glGetQueryObjectuiv(GLenum id, GLenum pname, GLuint *params);

清除遮挡查询对象
void glDeleteQueries(GLsizei n, const GLuint *ids);

10.2.6 混合,抖动和逻辑操作


void glLogicOp(GLenum opcode); 
选择需要执行的逻辑操作.

10.3 累计缓冲区


void glAccum(GLenum op, GLfloat value); 
控制累积缓冲区
op参数:
GL_ACCUM--用glReadBuffer()所读取的当前缓冲区中读取每个像素.把R,G,B,A值乘以value.而后结果累加到累积缓冲区.
GL_LOAD--同上,只是用结果替换累积缓冲区中的值.
GL_RETURN--累积缓冲区中的值乘以value, 结果放在颜色缓冲区中.
GL_ADD和AL_MULT--累积缓冲区中的值与value相加或者相乘,结果写回累积缓冲区. 另GL_MULT的结果截取[-1.0. 1.0].GL_ADD的结果不截取.

10.3.1 场景抗锯齿


首先清除累积缓冲区, 并启用前缓冲区用于读取和写入.
然后循环执行几次(例如n次)代码, 对图像进行微移和绘制.
对数据进行累积的方法:
glAccum(GL_ACCUM, 1.0/n);    // 绘制到不会显示的颜色缓冲区中, 避免显示中间图像.
并最终调用
glAccum((GL_RETURN, 1.0);    // 绘制到可显示的颜色缓冲区中(或即将交换的后缓冲区).

可提供一用户接口, 来显示每次图像累积之后所获得的改善, 如图像足够满意, 可随时终止累积.

本例主要是逐步在窗口累积各颜色分量.
一共累积八次,且其中每次都用j8数组的数据微移场景, 使用glFrustum函数可以是的我们场景不必对称.

正交投影的偏移只需要用glTranslatef()移动一个像素内的偏移即可.

下图为没有反锯齿没有用累积缓存的图像

 2

下图为使用了累积缓存反锯齿的图像

1

 

累积缓存我分步骤显示,看看效果

 3 4 5 6 7

10.3.2 运动模糊


按照相同的方式设置累积缓冲区, 但不是对图像进行空间上的微移, 而是进行时间上的微移.
glAccum(GL_MULT, decayFactor); 
这样随着场景绘制到累积缓冲区中,整个场景越来越模糊. 其中decayFactor是个0.0到1.0之间的数字, 其值越小, 运动速度越快.
然后使用
glAccum(GL_RETURN, 1.0); 
转移到眼色缓冲区中.

9

10.3.3 景深


距离聚焦平面越远,物体就越模糊.

accPerspective函数
第五个和第六个参数表示在x和y方向上微移, 实现场景抗锯齿
第九个参数设定聚焦平面.
模糊程度有第七个和第八个参数决定, 由这两个参数的乘积决定.

10

10.3.4 柔和阴影


多个光源所产生的柔和阴影-- 可以多次渲染场景,每次只打开一个光源, 然后将渲染结果累积起来.

10.3.5 微移


样本的微移值

posted @ 2010-11-19 14:23 白了少年头 Views(972) Comments(0)  Edit

  在前面的章节中,已经讲述了几何数据(点、线、多边形)绘制的有关方法,但OpenGL还有另外两种重要的数据类:一是位图,二是图像。这两种数据都是以象素矩阵形式存储,即用一个矩形数组来表示某一位图或图像。二者不同之处是位图包含每个象素的一位信息,而图像数据一般包含每个象素的多位信息(如,红、绿、蓝和Alpha值);还有位图类似于掩码,可用于遮掩别的图像,而图像数据则简单地覆盖先前已经存在的数据或者与之混合。下面将详述这些内容。

11.1、位图

  11.1.1 位图Bitmap与字符Font
  位图是以元素值为0或1的矩阵形式存储的,通常用于对窗口中相应区域的绘图屏蔽。比如说,当前颜色设置为红色,则在矩阵元素值为1的地方象素用红色来取代,反之,在为0的地方,对应的象素不受影响。位图普遍用于字符显示,请看下面例子:

  例11-1 位图字符例程font.c

#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h> 
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void)
GLubyte rasters[12] = {
      0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc,    0xfc, 0xc0, 0xc0, 0xc0, 0xff, 0xff}
void myinit(void)  
{
        
  glPixelStorei (GL_UNPACK_ALIGNMENT, 1);    
  glClearColor (0.0, 0.0, 0.0, 0.0);    
  glClear(GL_COLOR_BUFFER_BIT);  
}   
void CALLBACK display(void)  
{
        
  glColor3f (1.0, 0.0, 1.0);    
  glRasterPos2i (100, 200);    
  glBitmap (8, 12, 0.0, 0.0, 20.0, 20.0, rasters);   
  lBitmap (8, 12, 0.0, 0.0, 0.0, 0.0, rasters)
  glColor3f (1.0, 1.0, 0.0);    glRasterPos2i (150, 200);    
  glBitmap (8, 12, 0.0, 0.0, 0.0, 0.0, rasters)
  glFlush();  
}   
void CALLBACK myReshape(GLsizei w, GLsizei h)  
{
        
  glViewport(0, 0, w, h);    
  glMatrixMode(GL_PROJECTION);    
  glLoadIdentity();    
  glOrtho (0, w, 0, h, -1.0, 1.
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值