简单的透明:Jeff Molofee(NeHe) 的 OPENGL 教程-第八课

简单的透明

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

混色的公式

若您对数学不感冒,而只想看看如何实现透明,请跳过这一节。若您想深入理解(色彩)混合的工作原理,这一节应该适合您吧。译者注:其实并不难^-^。原文中的公式如下,CKER再唠叨一下吧。其实混合的基本原理是就将要分色的图像各象素的颜色以及背景颜色均按照RGB规则各自分离之后,根据-图像的RGB颜色分量*alpha值+背景的RGB颜色分量*(1-alpha值)-这样一个简单公式来混合之后,最后将混合得到的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()函数存在寻址问题。这条命令在某些卡上启用或关闭深度缓冲测试时似乎不是很有效,所以我已经将启用或关闭深度缓冲测试的代码转成老式的glEnableglDisable

纹理贴图的Alpha混合

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

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

Tom Stanis

* DOWNLOAD
Visual C++ Code For This Lesson.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NeHe OpenGL教程中文版PDF [教程说明] 整个教程nehe制作 课程内容由dancingwind(周炜)以及gamedev和csdn的志愿者翻译 最早的翻译应该是由CKER完成的(1~12章) 注:本教程经dancingwind授权发布于http://www.yakergong.com dancingwind获得Nehe授权 [dancingwind的版权声明] 版权与使用声明: 我是个对学习和生活充满激情的普通男孩,在网络上我以DancingWind为昵 称,我的联系方式是[email protected],如果你有任何问 题,都可以联系我。 引子 网络是一个共享的资源,但我在自己的学习生涯中浪费大量的时间去搜索 可用的资料,在现实生活中花费了大量的金钱和时间在书店中寻找资料, 于是我给自己起了个昵称DancingWind,其意义是想风一样从各个知识的站 点中吸取成长的养料。在飘荡了多年之后,我决定把自己收集的资料整理 为一个统一的资源库。 版权声明 所有DancingWind发表的内容,大多都来自共享的资源,所以我没有资格把 它们据为己有,或声称自己为这些资源作出了一点贡献。故任何人都可以 复制,修改,重新发表,甚至以自己的名义发表,我都不会追究,但你在 做以上事情的时候必须保证内容的完整性,给后来的人一个完整的教程。 最后,任何人不能以这些资料的任何部分,谋取任何形式的报酬。 发展计划 在国外,很多资料都是很多人花费几年的时间慢慢积累起来的。如果任何 人有兴趣与别人共享你的知识,我很欢迎你与我联系,但你必须同意我上 面的声明。 感谢 感谢我的母亲一直以来对我的支持和在生活上的照顾。 感谢我深爱的女友田芹,一直以来默默的在精神上和生活中对我的支持, 她甚至把买衣服的钱都用来给我买书了,她真的是我见过的最好的女孩, 希望我能带给她幸福。
创建一个OpenGL窗口: 在这个教程里,我将教你在Windows环境中创建OpenGL程序.它将显示一个空的OpenGL窗口,可以在窗口和全屏模式下切换,按ESC退出.它是我们以后应用程序的框架. 理解OpenGL如何工作非常重要,你可以在教程的末尾下载源程序,但我强烈建议你至少读一遍教程,然后再开始编程. 2.你的第一个多边形: 在第一个教程的基础上,我们添加了一个三角形和一个四边形。也许你认为这很简单,但你已经迈出了一大步,要知道任何在OpenGL中绘制的模型都会被分解为这两种简单图形。 读完了这一课,你会学到如何在空间放置模型,并且会知道深度缓存的概念。 3.添加颜色: 作为第二课的扩展,我将叫你如何使用颜色。你将理解两种着色模式,在左图中,三角形用的是光滑着色,四边形用的是平面着色。 注意三角形上的颜色是如何混合的。 颜色为OpenGlL 工程增加很多。通过理解平面着色(flat coloring)和平滑着色(smooth coloring),你能显著的改善你的OpenGL Demo的样子。 4.旋转: 在这一课里,我将教会你如何旋转三角形和四边形。左图中的三角形沿Y轴旋转,四边形沿着X 轴旋转。 这一章将引入两个变量, rtri 被用来存储三角形的角度, rquad存储四边形的角度。 和容易创建一个多边形组成的场景。让这些物体动起来是整个场景变得生动起来。在后面的课程钟我将教给你如何绕屏幕上的一个点旋转物体,使得物体绕屏幕而不是它的轴转动。 5.3D形体: 既然我们已经领会到多边形,方形,色彩和旋转。现在该建立3D物体了。我将使用多边形和矩形c创建3D物体。这次我们将扩展上一章的教程,并且将三角形转换成一个彩色的棱锥,把正方形变为一个实心正方体。棱锥使用混合色,正方体每个面使用一种颜色。在3D空间创建物体可能很费时间,但是所获得的结果(收获)值得这样做。充分发挥你的想象力吧。 6.纹理映射: 你想要它,它现在就在这里了,那就是 ... 纹理映射!!!在这一章我将教会你如何将一幅位图(bitmap)映射到正方体的六个面上去。我们将使用第一章的OpenGL代码来创建工程。创建一个空的窗口比修改上一课的代码更容易。 你将会发现第一章的代码在对于快速创建工程来说是及其有价值的。第一章的代码为你设置好了一切,你所需要做的只是集中精力为效果编程。 7.纹理滤波, 光照和键盘控制: 好的,我希望到现在你已经理解了所有的东西,因为这是一个巨大的教程。我想教给你两个新的方法来过滤(filter)你的纹理,简单的光照,键盘控制并且还可能更多 :) .如果你对到这一课为止你所学的东西并不充满信心,那就回头复习一下。玩一下其它课程的代码,不要操之过急。最好专心把每一课学好,而不是蜻蜓点水,只知道如何把东西做出来。 8.混合 有理由等一下,一个来自很酷的Hypercosm的程序员伙伴问(我)他是否可以写一章关于混合的教程第八课通常正是讲混合的,所以太巧了。这一章教程扩展了第七章。混合是一项很酷的技术 .. 我希望你们能好好享受这一章教程。这一章的作者是Tom Stanis他在这制作一章上花费了很多精力,所以让他知道你觉得怎么样。混合可不是一个好讲的话题。 9.在3D空间中移动位图: 这一章覆盖了一些你们要求的主题,你想知道如何移动你在3D屏幕空间上创造的物体。你想要知道如何在屏幕上绘制一幅位图,并且位图的黑色部分不会覆盖它后面的东西。你想要简单的动画,想要更多的混合的应用,这一章将教会你所有这些。You'll notice there's no spinning boxes(yaker:很惭愧这一句我不是很明白)。前面的课程覆盖了OpenGL的基础,每一章都基于前面的内容。前面的课程涵盖了基础的OpenGL,每一课都是在前一课的基础上创建的。这一课是前面几课知识的综合,当你学习这课时,请确保你已经掌握了前面几课的知识。 10.加载3D世界,并在其中漫游: 你一直期待的教程来了!这一章友一个叫Lionel Brites的伙伴制作。这一课里你讲学到如何导入一个3D世界。代码仍然使用第一章的,但是,课程页面只是解释了新的部分,包括导入3D场景,在3D世界中移动。下载VC++代码并且在你阅读教程的同时阅读代码。按[B]键控制混合,[F]键控制滤波,[L]键控制光照(但光并不随场景移动),还有[Page UP]和[Page Down]键。我希望你能喜欢Lionel对网站的贡献。我有空的时候我会让这个教程更容易学习。 11.旗帜效果

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值