写的浅显易懂. 留一下.
感谢作者.
–
Lesson 08 Blending
简单的透明
OpenGL 中的很多特效都是通过混合(Blending) 来完成的, 混合就是把屏幕上已有的颜色与新的颜色进行合成。 至于合成的方法, 取决于颜色的Alpha值, 还有/或所用的混合函数。 Alpha值是颜色的第4个分量, 过去你使用GL_RGB 也就是3个颜色分量来指定一个颜色, 现在你可以使用GL_RGBA 来增加一个Alpha值了。 那么我们可以用glColor4f() 函数代替glColor3f() 函数。
大多数人把Alpha值理解为材质(material) 的不透明程度, 0.0代表材质完全透明, 1.0代表材质完全不透明。
混合式
如果你不喜欢数学, 只是想看看怎样实现透明, 可以跳过这部分。 如果你想知道混合(Blending) 的工作方式, 这部分就是为你准备的。
(Rs Sr + Rd Dr, Gs Sg + Gd Dg, Bs Sb + Bd Db, As Sa + Ad Da)
OpenGL利用上面的式子来计算两个像素的混合结果。 小写字母s和d分别代表 源(source) 和 目标(destination) 像素点 (译注:原文误写为s和r,更正)。 大写字母S和D是(源和目标的) 混合因子, 这些值决定着混合方式。 最常用的情况就是把S设为 (As, As, As, As), D设为 (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))
这个式子将产生透明/半透明的视觉效果。
(译著:混合式其实是非常简单的。 其中有大写字母RGBA, 当然分别代表红绿蓝和Alpha分量。RGBA附带的小写字母只有s和d, 代表源像素和目标像素。 其中还有大写字母S和D, 分别是源和目标的混合因子。 它们附带小写字母rgba, 分别是RGBA分量的混合因子。 那么对于任意一个分量的混合计算方法, 就是源分量和目标分量分别乘以各自的混合因子之后的和, 很简单。)
OpenGL 中的混合
首先我们得打开混合, 然后设置混合式。 在绘制透明物体的时候, 我们关闭深度缓存, 因为我们仍然希望在半透明物体后面的物体能被绘制。 这并不是使用混合的正确方式, 但是在情况简单的时候它会工作得很好。Rui Martins 补充: 正确的方法是在整个场景绘制完之后再绘制所有的透明 (alpha < 1.0) 多边形, 而且要按照由远及近的深度顺序, 这是由于事实上按照不同的顺序混合两个(1和2)多边形会得到不同的结果。 假如多边形1距离我们最近, 那么正确的方法是先绘制多边形2, 然后是多边形1。 如果你看着它, 那么真实情况就是它们后面的光首先经过多边形2, 然后经过多边形1, 最后到达你的眼睛。 所以, 你需要按照深度将透明的多边形进行排序, 开着深度缓存并在整个场景绘制完毕之后再绘制它们, 否则将得到不正确的结果。 我知道这有时候是令人头痛的问题, 但这是正确的方法。
利用上一篇的代码, 首先我们在代码的前段增加两个变量。 为了清晰我列出了整段代码。
#include <windows.h> // Header File For Windows
#include <stdio.h> // Header File For Standard Input/Output
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library
#include <gl\glaux.h> // Header File For The GLaux Library
HDC hDC=NULL; // Private GDI Device Context
HGLRC hRC=NULL; // Permanent Rendering Context
HWND hWnd=NULL; // Holds Our Window Handle
HINSTANCE hInstance; // Holds The Instance Of The Application
bool keys[256]; // Array Used For The Keyboard Routine
bool active=TRUE; // Window Active Flag Set To TRUE By Default
bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default
bool light; // Lighting ON/OFF
bool blend; // Blending OFF/ON? ( NEW )
bool lp; // L Pressed?
bool fp; // F Pressed?
bool bp; // B Pressed? ( NEW )
GLfloat xrot; // X Rotation
GLfloat yrot; // Y Rotation
GLfloat xspeed; // X Rotation Speed
GLfloat yspeed; // Y Rotation Speed
GLfloat z=-5.0f; // Depth Into The Screen
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; // Ambient Light Values
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; // Diffuse Light Values
GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f }; // Light Position
GLuint filter; &
#160; // Which Filter To Use
GLuint texture[3]; // Storage for 3 textures
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc
然后到LoadGLTextures() 中把 if (TextureImage[0]=LoadBMP("Data/Crate.bmp")) 替换为下面的这行代码。 我们用彩色玻璃的纹理代替上一篇的木箱纹理。
if (TextureImage[0]=LoadBMP("Data/glass.bmp")) // Load The Glass Bitmap ( MODIFIED )
在InitGL() 里面增加下面两行代码。 这行代码将绘制物体的颜色设置为全亮度, 和50% 的alpha (不透明度)。 这意味着当混合打开时, 物体会以50% 的透明度绘制。 第二行代码设置我们所用的混合类型。
Rui Martins 补充: Alpha 值0.0代表材质完全透明, Alpha值1.0代表材质完全不透明。
glColor4f(1.0f,1.0f,1.0f,0.5f); // Full Brightness, 50% Alpha ( NEW )
glBlendFunc(GL_SRC_ALPHA,GL_ONE); // Blending Function For Translucency Based On Source Alpha Value ( NEW )
下面的代码将第7篇教程的底部找到。
if (keys[VK_LEFT]) // Is Left Arrow Being Pressed?
{
yspeed-=0.01f; // If So, Decrease yspeed
}
在上面所示的代码后面, 增加随后的这些代码。 这些代码检查键盘上的B键是否被按下。 如果它被按下了, 接着会检查混合是开还是关。 如果混合开着, 就将其关掉, 如果关着, 就将其打开。
if (keys['B'] && !bp) // Is B Key Pressed And bp FALSE?
{
bp=TRUE; // If So, bp Becomes TRUE
blend = !blend; // Toggle blend TRUE / FALSE
if(blend) // Is blend TRUE?
{
glEnable(GL_BLEND); // Turn Blending On
glDisable(GL_DEPTH_TEST); // Turn Depth Testing Off
}
else // Otherwise
{
glDisable(GL_BLEND); // Turn Blending Off
glEnable(GL_DEPTH_TEST); // Turn Depth Testing On
}
}
if (!keys['B']) // Has B Key Been Released?
{
bp=FALSE; // If So, bp Becomes FALSE
}
但当使用纹理影射的时候我们怎样指定颜色呢? 很简单, 在调制的纹理模式中, 纹理的每个像素点都会与当前颜色相乘。 所以, 如果要被绘制的颜色为(0.5, 0.6, 0.4), 通过相乘我们可以得到(0.5, 0.6, 0.4, 0.2)。(alpha默认值为1.0)
就是这样!混合在OpenGL中是容易实现的。
(译著:此篇教程简单了, 混合其实是一个主题, 详见红皮书)
Note (11/13/99)
我 (NeHe) 已经改进了混合代码, 这样物体看起来会更真实一些。 对源和目标使用alpha值来制造混合, 会使物体看起来不很自然, 导致背面连同侧面开起来发暗。 基本上物体看上去会很奇怪。 我的混合方法也许不是最好的, 但它能工作, 而且当打开灯光的时候会表现得更自然一些。 感谢Tom和他的最初代码, 他使用alpha值进行渲染的方法是正确的, 只不过不像所期待的那样具有吸引力:)
代码被再次修改了, 原因是glDepthMask() 在某些显卡上不能有效地打开和关闭深度测试, 所以我又改回了老式的glEnable 和 glDisable 来开关深度测试。
来自纹理图的Alpha
用于透明的alpha值可以像颜色一样从纹理图中被读取, 要做到这一点, 你需要把alpha加入到要载入的图像中, 并在调用glTexImage2D() 时使用GL_RGBA作为颜色格式。
(译著:???)
问题?
如果你有任何问题, 可以为我来信至 stanis@cs.wisc.edu。
Tom Stanis
Jeff Molofee (NeHe)
译 Aman JIANG (江超宇)
2004年5月29日
Comments(0)