阅读:1424回复:0
OpenGL系列讲座(22)
第五章 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 反走样多边形 |
|
|