Graphics 版 (精华区)

发信人: JJason (UFO), 信区: Graphics
标  题: Jeff Molofee(NeHe) 的 OPENGL 教程-第08课
发信站: 哈工大紫丁香 (2002年10月31日08:41:43 星期四), 站内信件

标题     简单的透明:Jeff Molofee(NeHe) 的 OPENGL 教程-第八课    cker(翻译)  
  
关键字     OpenGL CKER 
  
出处     http://nehe.gamedev.net/tutorials/ 
  


 

 

Jeff Molofee(NeHe) 的 OPENGL 教程 
 
第八课 
 Translated by 
CKER  
  


简单的透明
OpenGL中的绝大多数特效都与某些类型的(色彩)混合有关。混色的定义为,将某个象素的
颜色和已绘制在屏幕上与其对应的象素颜色相互结合。至于如何结合这两个颜色则依赖于
颜色的alpha通道的分量值,以及/或者所使用的混色函数。Alpha通常是位于颜色值末尾的
第4个颜色组成分量。前面这些课我们都是用GL_RGB来指定颜色的三个分量。相应的GL_RGB
A可以指定alpha分量的值。更进一步,我们可以使用glColor4f()来代替glColor3f()。
绝大多数人都认为Alpha分量代表材料的透明度。这就是说,alpha值为0.0时所代表的材料
是完全透明的。alpha值为1.0时所代表的材料则是完全不透明的。

混色的公式
若您对数学不感冒,而只想看看如何实现透明,请跳过这一节。若您想深入理解(色彩)混
合的工作原理,这一节应该适合您吧。『译者注:其实并不难^-^。原文中的公式如下,CKE
R再唠叨一下吧。其实混合的基本原理是就将要分色的图像各象素的颜色以及背景颜色均按
照RGB规则各自分离之后,根据-图像的RGB颜色分量*alpha值+背景的RGB颜色分量*(1-alp
ha值)-这样一个简单公式来混合之后,最后将混合得到的RGB分量重新合并。』
 公式如下:
(Rs Sr + Rd Dr, Gs Sg + Gd Dg, Bs Sb + Bd Db, As Sa + Ad Da) 
OpenGL按照上面的公式计算这两个象素的混色结果。小写的s和r分别代表源象素和目标象
素。大写的S和D则是相应的混色因子。这些决定了您如何对这些象素混色。绝大多数情况
下,各颜色通道的alpha混色值大小相同,这样对源象素就有 (As, As, As, As),目标象
素则有1, 1, 1, 1) - (As, As, As, As)。上面的公式就成了下面的模样:
(Rs As + Rd (1 - As), Gs As + Gd (1 - As), Bs As + Bs (1 - As), As As + Ad (1 
- As)) 
这个公式会生成透明/半透明的效果。

OpenGL中的混色
在OpenGL中实现混色的步骤类似于我们以前提到的OpenGL过程。接着设置公式,并在绘制
透明对象时关闭写深度缓存。因为我们想在半透明的图形背后绘制 对象。这不是正确的混
色方法,但绝大多数时候这种做法在简单的项目中都工作的很好。
Rui Martins 的补充: 正确的混色过程应该是先绘制全部的场景之后再绘制透明的图形。
并且要按照与深度缓存相反的次序来绘制(先画最远的物体)。
考虑对两个多边形(1和2)进行alpha混合,不同的绘制次序会得到不同的结果。(这里假定
多边形1离观察者最近,那么正确的过程应该先画多边形2,再画多边形1。正如您再现实中
所见到的那样,从这两个<透明的>多边形背后照射来的光线总是先穿过多边形2,再穿过多
边形1,最后才到达观察者的眼睛。)
在深度缓存启用时,您应该将透明图形按照深度进行排序,并在全部场景绘制完毕之后再
绘制这些透明物体。否则您将得到不正确的结果。我知道某些时候这样做是很令人痛苦的
,但这是正确的方法。
我们将使用第七课的代码。一开始先在代码开始处增加两个新的变量。出于清晰起见,我
重写了整段代码。
 

#include <windows.h>   // // Windows的头文件 
#include <stdio.h>    // 标准输入输出库头文件
#include <gl\gl.h>    // OpenGL32库的头文件
#include <gl\glu.h>   // GLu32库的头文件
#include <gl\glaux.h>   // GLaux库的头文件
HDC  hDC=NULL;  // 私有GDI设备描述表
HGLRC  hRC=NULL;  // 永久着色描述表
HWND  hWnd=NULL;  // 保存我们的窗口句柄
HINSTANCE hInstance;  // 保存程序的实例
bool keys[256];   // 用于键盘例程的数组
bool active=TRUE;   // 窗口的活动标志,缺省为TRUE
bool fullscreen=TRUE;   // 全屏标志缺省设定成全屏模式
bool light;    // 光源的开/关 // Lighting ON/OFF
bool    blend;    // Blending OFF/ON? ( 新增 ) 
bool lp;    // L键按下了么? 
bool fp;    // F 键按下了么?
bool bp;    // B 键按下了么? ( 新增 ) 
GLfloat xrot;    // X 旋转 
GLfloat yrot;    // Y 旋转
GLfloat xspeed;    // X 旋转速度
GLfloat yspeed;    // Y 旋转速度
GLfloat z=-5.0f;    // 深入屏幕的距离 
GLfloat LightAmbient[]=  { 0.5f };  // 环境光参数
GLfloat LightDiffuse[]= { 1.0f };  // 漫射光参数
GLfloat LightPosition[]= { 0.0f };  // 光源位置
GLuint filter;    // 滤波类型
GLuint texture[3];   // 3种纹理的储存空间
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // WndProc定义

然后往下移动到 LoadGLTextures() 这里。找到" if 
(TextureImage[0]=LoadBMP("Data/Crate.bmp")) "这一行。我们现在使用有色玻璃纹理来
代替上一课中的木箱纹理。 

 if (TextureImage[0]=LoadBMP("Data/glass.bmp")); // 载入玻璃位图 ( 已修改 )

在InitGL()代码段加入以下两行。第一行以全亮度绘制此物体,并对其进行50%的alpha混
合(半透明)。当混合选项打开时,此物体将会产生50%的透明效果。第二行设置所采用的混
合类型。
Rui Martins 的补充: alpha通道的值为 0.0意味着物体材质是完全透明的。1.0 则意味着
完全不透明。 

 glColor4f(1.0f,1.0f,1.0f,0.5f);   // 全亮度, 50% Alpha 混合( 新增 ) 
 glBlendFunc(GL_SRC_ALPHA,GL_ONE);  // 基于源象素alpha通道值的半透明混合函数 
( 新增 )
在接近第七课结尾处的地方找到下面的代码段。  

 if (keys[VK_LEFT])    //Left方向键按下了么? 
 {
  yspeed-=0.01f;    //若是, 减少yspeed 
 }
接着上面的代码,我们增加如下的代码。这几行监视B键是否按下。如果是的话,计算机检
查混合选项是否已经打开。然后将其置为相反的状态。 

 if (keys['B'] && !bp)    // B 健按下且bp为 FALSE么?
 {
  bp=TRUE;    // 若是, bp 设为 TRUE
  blend = !blend;    // 切换混合选项的 TRUE / FALSE 
  if(blend)    // 混合打开了么?
  {
   glEnable(GL_BLEND);  // 打开混合
   glDisable(GL_DEPTH_TEST); // 关闭深度测试
  }
  else     // 否则
  {
   glDisable(GL_BLEND);  // 关闭混合
   glEnable(GL_DEPTH_TEST); // 打开深度测试
  }
 }
 if (!keys['B'])     //  B 键松开了么?
 {
  bp=FALSE;    // 若是, bp设为 FALSE
 }

但是怎样才能在使用纹理贴图的时候指定混合时的颜色呢?很简单,在调整贴图模式时,文
理贴图的每个象素点的颜色都是由alpha通道参数与当前地象素颜色相乘所得到的。比如,
绘制的颜色是 (0.5, 0.6, 0.4),我们会把颜色相乘得到(0.5, 0.6, 0.4, 0.2) (alpha参
数在没有指定时,缺省为零)。
就是如此!OpenGL实现Alpha混合的确很简单!

原文注 (11/13/99)
我(NeHe)混色代码进行了修改,以使显示的物体看起来更逼真。同时对源象素和目的象素
使用alpha参数来混合,会导致物体的人造痕迹看起来很明显。 会使得物体的背面沿着侧
面的地方显得更暗。基本上物体会看起来很怪异。我所用的混色方法也许不是最好的,但
的确能够工作。启用光源之后,物体看起来很逼真。感谢Tom提供的原始代码,他采用的混
色方法是正确的,但物体看起来并不象所期望的那样吸引人:)
代码所作的再次修改是因为在某些显卡上glDepthMask()函数存在寻址问题。这条命令在某
些卡上启用或关闭深度缓冲测试时似乎不是很有效,所以我已经将启用或关闭深度缓冲测
试的代码转成老式的glEnable和glDisable。

纹理贴图的Alpha混合
用于纹理贴图的alpha参数可以象颜色一样从问题贴图中读取。方法如下,您需要在载入所
需的材质同时取得其的alpha参数。然后在调用glTexImage2D()时使用GL_RGBA的颜色格式

 
『译者:NeHe的文档似乎很简单,似乎很罗嗦。但仔细想来这样的高手您又见过几个?还
是那句话,我不是高手,希望您是,真诚的。』 
下面是源代码下载链接。祝您好运!  

Tom Stanis 

* DOWNLOAD Visual C++ Code For This Lesson.
* DOWNLOAD Visual C++ / OpenIL Code For This Lesson. ( Conversion by Denton 
Woods )
* DOWNLOAD Visual Basic Code For This Lesson. ( Conversion by Peter De Tagyos 
)
* DOWNLOAD Visual Fortran Code For This Lesson. ( Conversion by Jean-Philippe 
Perois )
* DOWNLOAD GLUT Code For This Lesson. ( Conversion by Andy Restad )
* DOWNLOAD Game GLUT Code For This Lesson. ( Conversion by Milikas Anastasios 
)
* DOWNLOAD Cygwin (FREE Language) Code For This Lesson. ( Conversion by 
Stephan Ferraro )
* DOWNLOAD Delphi Code For This Lesson. ( Conversion by Marc Aarts )
* DOWNLOAD MASM Code For This Lesson. ( Conversion by Nico (Scalp) )
* DOWNLOAD Linux/GLX Code For This Lesson. ( Conversion by Mihael Vrbanec )
* DOWNLOAD MacOS X/GLUT Code For This Lesson. ( Conversion by Raal Goff )
* DOWNLOAD Linux Code For This Lesson. ( Conversion by Richard Campbell )
* DOWNLOAD Linux/SDL Code For This Lesson. ( Conversion by Ti Leggett )
* DOWNLOAD Irix Code For This Lesson. ( Conversion by Lakmal Gunasekara )
* DOWNLOAD Solaris Code For This Lesson. ( Conversion by Lakmal Gunasekara )
* DOWNLOAD Mac OS Code For This Lesson. ( Conversion by Anthony Parker )
* DOWNLOAD Power Basic Code For This Lesson. ( Conversion by Angus Law )
* DOWNLOAD BeOS Code For This Lesson. ( Conversion by Chris Herborth )
* DOWNLOAD Java Code For This Lesson. ( Conversion by Darren Hodges )
* DOWNLOAD MingW32 & Allegro Code For This Lesson. ( Conversion by Peter Puck 
)
* DOWNLOAD Borland C++ Builder 4.0 Code For This Lesson. ( Conversion by 
Patrick Salmons )
 
 
 
--

     人生,就是一团欲望:
     欲望没有满足的时候就是痛苦,
     欲望被满足的时候就是无聊;
     人生就是在痛苦与无聊之间徘徊。

※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 202.118.229.69]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:3.385毫秒