hyde
路人甲
路人甲
  • 注册日期2003-09-24
  • 发帖数555
  • QQ
  • 铜币1457枚
  • 威望0点
  • 贡献值0点
  • 银元0个
阅读:1321回复:0

OpenGL系列讲座(22)

楼主#
更多 发布于:2004-03-21 11:08
第五章   OpenGL效果处理
 

 

这一章主要讲述OpenGL的三个特殊效果处理:融合、反走样和雾。如果能很好地运用这

些特殊效果,那么你会发现其中有无数的奥秘,你将用它们构造出千变万化的图形世界来,

例如,透明的玻璃窗,半透明的紫色水晶,光滑的地板,五彩的肥皂泡,雾化的场景等等。

同时,本章还简单介绍一下有关的图形学概念。

 

5.1  融合
5.1.1 Alpha值与融合(Blending)

 

Alpha值在前面几章中已经提到过,但是几乎所有例程都将它设置为1.0,没有详细讨论

它为其它值时的情况。融合,是本章的重点,它是透明技术、数字合成和计算机绘画技术的

核心。固名思义,融合就是指两种颜色各分量依据一定的比例混在一起合二为一。而这种比

例就来源于Alpha值,即RGBA中的A或(r,g,b,a)中的a值,通常称a为不透明性,称(1-a)

为透明性。因为在颜色表方式下不能说明a值,因此融合操作不能在颜色表方式下进行。

为了更好地理解这些概念,我们可以举出一个例子来简要说明。例如,坐在汽车内透过

车窗的茶色玻璃看车外的绿树,这些树木的颜色并不是它们本来的绿色,而是透明的茶色与

不透明的绿色的混合颜色。也就是说,最终的颜色来源于两部分,一部分来自于玻璃的茶色,

另一部分来自于树木的绿色。两部分所占的百分比依据玻璃的透射变化,若玻璃透射率为80%

(即一束光照在其上有80%的透射过去),其不透明度为20%,即这里的a值就等于0.2,这

样进入眼中的树木颜色是20%的玻璃颜色与80%的树木本身颜色的合成。

 

5.1.2 融合因子(Blending Factor)

 

在OpenGL的融合操作中,实际上包含了两个因子的操作,这两个因子就是源因子(Source

Factor)和目的因子(Destination Factor)。从数学的角度来看,设源因子和目的因子分别为

(Sr,Sg,Sb,Sa)和(Dr,Dg,Db,Da),则融合的最终结果是:

 

       (Rs*Sr+Rd*Dr,Gs*Sg+Gd*Dg,Bs*Sb+Bd*Db,As*Sa+Ad*Da)

 

    并且其中每个元素值都约简到[0,1]之间。

 

    在OpenGL中,由函数gjBlendFunc()来产生这两个融合因子的值。其函数形式为:

 

void glBlendFunc(GLenum sfactor,GLenum dfactor)

 

控制源因子和目的因子的结合。参数sfactor指明怎样计算源因子,dfactor指明怎样

计算目的因子。这些参数的可能值见表3-5-1所示。注意,融合因子的值在[0,1]范围内,且

两因子结合后也要约简到[0,1]内,源与目的的RGBA值分别带有s和d下标。

 

_________________________________________________________________________

 

  常  数                    相关因子            计算后得到的融合因子

_________________________________________________________________________

 

GL_ZERO                   源因子或目的因子      (0,0,0,0)

GL_ONE                    源因子或目的因子      (1,1,1,1)

GL_DST_COLOR              源因子                (Rd,Gd,Bd,Ad)

GL_SRC_COLOR              目的因子              (Rs,Gs,Bs,As)

GL_ONE_MINUS_DST_COLOR    源因子                (1,1,1,1)-(Rd,Gd,Bd,Ad)

GL_ONE_MINUS_SRC_COLOR    目的因子              (1,1,1,1)-(Rs,Gs,Bs,As)

GL_SRC_ALPHA              源因子或目的因子      (As,As,As,As)

GL_ONE_MINUS_SRC_ALPHA    源因子或目的因子      (1,1,1,1)-(As,As,As,As)

GL_DST_ALPHA              源因子或目的因子      (Ad,Ad,Ad,Ad)

GL_ONE_MINUS_DST_ALPHA    源因子或目的因子      (1,1,1,1)-(Ad,Ad,Ad,Ad)

GL_SRC_ALPHA_SATURATE     源因子                (f,f,f,1); f=min(As,1-Ad)

_________________________________________________________________________

 

                   表3-5-1 源因子和目的因子

 

 

当用函数glBlendFunc()说明了融合因子的产生后,需调用函数glEnable(GL_BLEND)来

启动融合操作,不用时可调用glDisable(GL_BLEND)来关闭它。若源因子的参数为常数GL_ONE,

目的因子的参数为常数GL_ZERO,则相当于关闭融合操作,这些值为缺省值。

 

 

5.1.3 融合实例

 

   首先来看一个融合运用的简单例子 blend2d.c :

 

例 3-15  Alpha二维融合例程 blend2d.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);

 

/* 初始化 alpha 融合的参数 */

 

void myinit(void)

{

    glEnable (GL_BLEND);

    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glShadeModel (GL_FLAT);

    glClearColor (0.0, 0.0, 0.0, 0.0);

}

 

void CALLBACK display(void)

{

    glClear(GL_COLOR_BUFFER_BIT);

 

    glColor4f (1.0, 0.0, 0.0, 0.7);

    glRectf (0.25, 0.4, 0.75, 0.9);

 

    glColor4f (0.0, 1.0, 0.0, 0.5);

    glRectf (0.1, 0.1, 0.6, 0.6);

 

    glColor4f (0.0, 0.0, 1.0, 0.3);

    glRectf (0.4, 0.1, 0.9, 0.6);

 

 

    glFlush();

}

 

void CALLBACK myReshape(GLsizei w, GLsizei h)

{

    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    if (w <= h)

    gluOrtho2D (0.0, 1.0, 0.0, 1.0*(GLfloat)h/(GLfloat)w);

    else

    gluOrtho2D (0.0, 1.0*(GLfloat)w/(GLfloat)h, 0.0, 1.0);

    glMatrixMode(GL_MODELVIEW);

}

 

void main(void)

{

    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);

    auxInitPosition (0, 0, 500, 500);

    auxInitWindow ("Alpha 2D Blending");

    myinit();

    auxReshapeFunc (myReshape);

    auxMainLoop(display);

}

 

    以上程序运行结果是显示三个不同颜色(红、绿、蓝)的方块部分融合的效果。

 

  

 

图3-5-1 红绿蓝方块融合效果

 

 

 
5.2  反走样
 

反走样(Antialiasing),又叫反混淆,是计算机图形学中的一个重要概念。由于计算机

生成的图形是由离散点组成的数字化图像,因而生成的图形必然与真实景物之间存在一定误

差。这种误差表现为图形上的直线或光滑的曲线呈现锯齿状、彩色花纹失去原有的形态和色

彩、细小物体在画面上得不到反映等等。这种锯齿就叫做走样。见图3-5-2所示,左边为走

样线,右边为反走样线。

 

  

图3-5-2 走样线与反走样线

 

5.2.1 行为控制函数

 

在OpenGL中,许多细节的实现算法有所不同。这样,可以调用函数glHint()对图像质

量和绘制速度之间的权衡作一些控制,但并非所有的实现都采用它。其函数形式为:

 

void glHint(GLenum target,GLenum hint);

 

    控制OpenGL行为的某些方面。参数target说明控制什么行为,其可能值见表3-5-2所

示。参数hint可以是:GL_FASTEST(即给出最有效的选择)、 GL_NICEST(即给出最高质量

的选择)、GL_DONT_CARE(即没有选择)。

 

__________________________________________________________________________

 

   参   数                           意      义

__________________________________________________________________________

 

GL_POINT_SMOOTH_HINT

GL_LINE_SMOOTH_HINT               指定点、线、多边形的采样质量

GL_POLYGON_SMOOTH_HINT

 

GL_FOG_HINT                       指出雾的计算是按每个象素进行(GL_NICEST)

                                  还是按每个顶点进行(GL_FASTEST)

 

GL_PERSPECTIVE_CORRECTION_HINT    指定颜色和纹理插值的质量

 

__________________________________________________________________________

 

 

                   表3-5-2 函数glHint()参数及其意义

 

 

 

实际上,对于提示的解释依赖于OpenGL的具体实现,有时可以忽略。参数

GL_PERSPECTIVE_CORRECTION_HINT用于指定一个图元中的颜色值和纹理值怎样进行插值,要

么在屏幕空间进行插值,要么按照透视投影纠正方式进行插值(这种方式需更多计算)。通常,

系统对颜色进行线性插值,虽然从原理和技术的角度来讲未必正确,但是人眼可以接受,且

实现速度很快。然而纹理在大多数情况下,为了看起来可以接受,需要对其进行透视纠正插

值。因此,可以用这个参数控制插值方法。同样,在进行反走样计算时,也要用到这个函数

来控制图形实现的行为。

 

5.2.2 点和线的反走样

 

在OpenGL中虽然颜色表方式可以实现反走样,但建议最好用RGBA方式进行。不管何种

方式,对图元进行反走样,首先要用glEnable()启动反走样(参数为GL_POINT、GL_LINE_SMOOTH

或GL_POLYGON_SMOOTH),同时,也可以调用glHint()提供一个图像质量提示。但需注意的

是,在RGBA方式下,必须启动混合,最可能用的混合因子是GL_SRC_ALPHA(源)和

GL_ONE_MINUS_SRC_ALPHA(目的)。另外,可以使目的因子为GL_ONE,则线的交点处要亮一

些。下面举出一个例子 antiline.c:

 

例 3-16  反走样线例程 antiline.c

 

#include "glos.h"

 

#include <GL/gl.h>

#include <GL/glu.h>

#include <GL/glaux.h>

#include <stdio.h>

 

void myinit(void);

void CALLBACK myReshape(GLsizei w, GLsizei h);

void CALLBACK display(void);

 

/*  初始化反走样为 RGBA 模式,同时包括 alpha 混合、提示、线宽等的设置。 */

void myinit(void)

{

    glEnable (GL_LINE_SMOOTH);

    glEnable (GL_BLEND);

    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);

    glLineWidth (5.0);

 

    glShadeModel(GL_FLAT);

    glClearColor(0.0, 0.0, 0.0, 0.0);

    glDepthFunc(GL_LESS);

    glEnable(GL_DEPTH_TEST);

}

 

void CALLBACK display(void)

{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glColor4f (0.0, 0.6, 1.0, 1.0);

     auxWireOctahedron(1.0);

    glFlush();

}

 

void CALLBACK myReshape(GLsizei w, GLsizei h)

{

    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    gluPerspective (45.0, (GLfloat) w/(GLfloat) h, 3.0, 5.0);

 

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity ();

    glTranslatef (0.0, 0.0, -4.0);  /*  将物体移至视见区内  */

    glRotatef(15.0,1.0,1.0,0.0);

   }

 

void main(void)

{

    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);

    auxInitPosition (0, 0, 400, 400);

    auxInitWindow ("Antialiased Lines Using RGBA");

    myinit();

    auxReshapeFunc (myReshape);

    auxMainLoop(display);

}

 

以上程序运行结果是显示一个反走样的网状八面体。

 

  

 

图 3-5-3 反走样线

 

5.2.3 多边形的反走样

 

填充多边形的反走样类似于点线的反走样,不同的只是将所有POINT或LINE的地方改为

POLYGON而已。如下面的一个在RGBA 模式下的多边形反走样例子antipoly.c:

 

例 3-17  多边形反走样例程 antipoly.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);

 

void myinit(void)

{

    GLfloat mat_ambient[] = { 0.5, 0.5, 0.0, 1.00 };

    GLfloat mat_diffuse[] = { 1.0, 0.8, 0.1, 1.0 };

    GLfloat position[] = { 1.0, 0.0, 1.0, 0.0 };

 

    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);

    glMaterialfv(GL_FRONT, GL_DIFFUSE,mat_diffuse);

    glLightfv (GL_LIGHT0, GL_POSITION, position);

 

    glEnable (GL_LIGHTING);

    glEnable (GL_LIGHT0);

    glEnable (GL_BLEND);

    glCullFace (GL_BACK);

    glEnable (GL_CULL_FACE);

    glEnable (GL_POLYGON_SMOOTH);

    glDisable (GL_DEPTH_TEST);

    glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE);

 

    glClearColor (0.0, 0.0, 0.0, 0.0);

}

 

void CALLBACK display(void)

{

 

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 

    glTranslatef (0.0, 0.0, -8.0);

    glRotatef (-45.0, 1.0, 0.0, 0.0);

    glRotatef (45.0, 0.0, 1.0, 0.0);

    auxSolidIcosahedron (1.0);

 

    glFlush ();

}

 

void CALLBACK myReshape(GLsizei w, GLsizei h)

{

    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    gluPerspective(30.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);

    glMatrixMode(GL_MODELVIEW);

}

 

void main(void)

{

    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_ALPHA );

    auxInitPosition (0, 0, 400, 400);

    auxInitWindow ("Antialiased Polygons");

    myinit();

    auxReshapeFunc (myReshape);

    auxMainLoop(display);

}

 

    以上程序运行结果是显示一个黄色的填充反走样二十面体。

 

  

 

图 3-5-4 反走样多边形

 

 

 

 

 
喜欢0 评分0
夜落了,风静了,我喜欢一本书,一杯茶,一粒摇曳的烛光...
游客

返回顶部