Win32 OpenGL编程(12) 混合及半透明效果

系统 1433 0

write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie

讨论新闻组及文件

人类所有的力量 ,只是耐心加上时间的混合。 —— 巴尔扎克

混合的力量是很强大的,就如巴尔扎克所言,而图形处理中很多有趣且实用的效果在OpenGL中其实都可以用混合来实现,比如最最常用的半透明效果,这种效果在compiz的3D桌面效果中得到了极致的发挥,让人印象深刻,即使你从来不使用Linux,你也可以去看看很多人秀自己Linux桌面效果的视频,要知道,这效果出来的时候,连Vista都还不知道在哪。呵呵,可惜的是,一个桌面系统好不好,不仅仅是靠谁更炫来比较的。。。。。

概念

在OpenGL中混合是指啥?就如混合的一般意义一样,混合在OpenGL中指的是两个图形的组合,只不过这个组合的方式可以以很多种方式定义罢了。混合是属于那种概念较为简单,相关的接口不算太多,但是因为可定制内容较多,所以参数复杂,而且,利用各个参数的含义简单,但是要知道在什么时候使用什么样的参数却不简单的那类概念,与光照同类。

现实生活中最常见的例子就是透过玻璃看一个东西了,你看到的图像实际是玻璃反射的光和玻璃后物体反射的光穿过玻璃后在眼睛中一起形成的图像,在OpenGL中被描述成玻璃后物体反射的光与玻璃反射的光混合后产生的图像。

alpha这个以前我们一直没有使用的值在混合中发挥着关键的作用,一般我们将其称作透明度,但是事实上,在混合时,此值可以作为更多的用途,当然,仅仅作为透明度使用也完全没有问题。

出于对思维导图的兴趣,还是来个图:

使用

在OpenGL中,将新片段成为源,将已经存在的图形成为目标,使用时先通过glBlendFunc{Separate}指定如何计算源和目标的混合因子,然后通过glBlendEquation{Separate}指定如何混合(即指定混合模式),使用的步骤相当简单,除了按照惯例需要用glEnable(GL_BLEND)启用外,也就这两步,第二步还是在OpenGL 1.2中才加入的,原来只能为加模式,现在在我们忽略第二步时,默认使用加模式。其中附加Separate的函数表示分别指定RGB与alpha值。

OpenGL Programming Guide 》:

glBlendFunc — specify pixel arithmetic
C Specification
void glBlendFunc( GLenum sfactor,
GLenum dfactor);
Parameters

sfactor

Specifies how the red, green, blue,
and alpha source blending factors are computed.
The following symbolic constants are accepted:
GL_ZERO,
GL_ONE,
GL_SRC_COLOR,
GL_ONE_MINUS_SRC_COLOR,
GL_DST_COLOR,
GL_ONE_MINUS_DST_COLOR,
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA,
GL_CONSTANT_COLOR,
GL_ONE_MINUS_CONSTANT_COLOR,
GL_CONSTANT_ALPHA,
GL_ONE_MINUS_CONSTANT_ALPHA, and
GL_SRC_ALPHA_SATURATE.
The initial value is GL_ONE.
dfactor

Specifies how the red, green, blue,
and alpha destination blending factors are computed.
The following symbolic constants are accepted:
GL_ZERO,
GL_ONE,
GL_SRC_COLOR,
GL_ONE_MINUS_SRC_COLOR,
GL_DST_COLOR,
GL_ONE_MINUS_DST_COLOR,
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA.
GL_CONSTANT_COLOR,
GL_ONE_MINUS_CONSTANT_COLOR,
GL_CONSTANT_ALPHA, and
GL_ONE_MINUS_CONSTANT_ALPHA.
The initial value is GL_ZERO.

glBlendEquation — specify the equation used for both the RGB blend equation and the Alpha blend equation
C Specification
void glBlendEquation( GLenum mode);
Parameters

mode

specifies how source and destination colors are combined.
It must be GL_FUNC_ADD, GL_FUNC_SUBTRACT,
GL_FUNC_REVERSE_SUBTRACT, GL_MIN, GL_MAX.

的确,简单的使用真的是非常简单,(虽然参数的组合可以很多)事实上,见下例,仅仅那么几行代码,就实现了一个半透明效果。

      
        //OpenGL初始化开始
      
      
void SceneInit( int w, int h)
{
GLenum err = glewInit();
if (err != GLEW_OK)
{
MessageBox(NULL, _T( "Error" ), _T( "Glew init failed." ), MB_OK);
exit(-1);
}

glClearColor(0.0, 0.0, 0.0, 0.0);

glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_DST_COLOR);
}

void DrawSmoothColorPyramid(GLfloat adSize)
{
static GLfloat fPyramidDatas[] = { 0.0, 1.0, 0.0, // 三角锥上顶点
-1.0, 0.0, 1.0, // 底面左前顶点
1.0, 0.0, 1.0, // 底面右前下顶点
0.0, 0.0, -1.0}; // 底面后下顶点

GLfloat fPyramidSizeDatas[ sizeof (fPyramidDatas)/ sizeof (GLfloat)] = {0};

// 计算大小
for ( int i = 0; i < 12; ++i)
{
fPyramidSizeDatas[i] = fPyramidDatas[i] * adSize;
}

static GLfloat fPyramidColors[] = { 0.0, 0.0, 0.0, 0.7,
1.0, 0.0, 0.0, 0.7,
0.0, 1.0, 0.0, 0.7,
0.0, 0.0, 1.0, 0.7};

static GLubyte ubyIndices[] = { 0, 1, 2, // 正面
0, 3, 1, // 左侧面
0, 2, 3, // 右侧面
1, 3, 2}; // 底面

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

glVertexPointer(3, GL_FLOAT, 0, fPyramidSizeDatas);
glColorPointer(4, GL_FLOAT, 0, fPyramidColors);

for ( int i = 0; i < 4; ++i)
{
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, ubyIndices+i*3);
}
}

//这里进行所有的绘图工作
void SceneShow(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 0.0, 0.0);


glPushMatrix();
DrawSmoothColorPyramid(0.5);
DrawSmoothColorPyramid(1);
glPopMatrix();

glLoadIdentity();
gluLookAt(gViewPosX, gViewPosY, gViewPosZ, gViewDirX, gViewDirY, gViewDirZ, gViewUpDirX, gViewUpDirY, gViewUpDirZ);

glFlush();
}

此例是从原来的2009-10-25/glCullFace改过来的,基本思路是在一个小的三角锥外再画一个大的三角锥,即如下几句:
    
      glPushMatrix
    
    
();

    
      DrawSmoothColorPyramid
    
    
(0.5);

    
      DrawSmoothColorPyramid
    
    
(1);

    
      glPopMatrix
    
    
();
  
除此外,新添的关键代码就是
    
      glEnable
    
    
(
    
      GL_BLEND
    
    
);

    
      glBlendFunc
    
    
(
    
      GL_SRC_ALPHA
    
    
, 
    
      GL_DST_COLOR
    
    
);
  

两句了,分别是开启混合,并将混合的因子设为源混合因子使用RGB+alpha值,目标混合因子颜色即原颜色,并且,我们使用了默认的混合加模式。很简单吧?就两句代码而已。
另外,特别注意的是,此时我在颜色数组中添加进了alpha参数(原来没有)

static GLfloat fPyramidColors[] = { 0.0, 0.0, 0.0, 0.7,
1.0, 0.0, 0.0, 0.7,
0.0, 1.0, 0.0, 0.7,
0.0, 0.0, 1.0, 0.7};

此时表示三角锥的颜色alpha值为0.7.
我们看看实现的半透明效果是怎么样的。

先看左边的截图,根本看不到小的三角锥,原因很明显,因为外面的三角锥后绘制,将其内部先绘制的小三角锥完全的覆盖掉了,但是右边的截图我们清晰的看到了内部的小三角锥,呵呵,因为我们启用了半透明效果(用混合实现)嘛。

为节省篇幅仅贴出关键片段,完整源代码见我博客源代码的2009-11-11/glHalfTrans/ 目录,获取方式见文章最后关于获取博客完整源代码的说明。

自从决定以概念的讲解和演示为主后,本系列文章就像原来那样常常力图展示所有参数的概念和效果了,此处对混合的使用可以说是最最简单的了,我甚至都没有去调用glBlendEquation{Separate}函数,但是实际的使用可以相当复杂,各个参数的作用大家就去参考《 OpenGL Programming Guide 》罗:)

本系列其他文章见OpenGL专题 《 Win32 OpenGL系列专题

参考资料

1. 《 OpenGL Reference Manual 》,OpenGL参考手册

2. 《OpenGL 编程指南》(《 OpenGL Programming Guide 》),Dave Shreiner,Mason Woo,Jackie Neider,Tom Davis 著,徐波译,机械工业出版社

3. 《Nehe OpenGL Tutorials》,Nehe著,在 http://nehe.gamedev.net/ 上可以找到教程及相关的代码下载,(有PDF版本教程下载)Nehe自己还做了一个面向对象的框架,作为演示程序来说,这样的框架非常合适。也有 中文版 ,各取所需吧。

4. 《OpenGL入门学习》 ,eastcowboy著,这是我在网上找到的一个比较好的教程,较为完善,而且非常通俗。这是第一篇的地址: http://bbs.pfan.cn/post-184355.html

完整源代码获取说明

由于篇幅限制,本文一般仅贴出代码的主要关心的部分,代码带工程(或者makefile)完整版(如果有的话)都能用Mercurial在Google Code中下载。文章以博文发表的日期分目录存放,请直接使用Mercurial克隆下库:

https://blog-sample-code.jtianling.googlecode.com/hg/

Mercurial使用方法见《 分布式的,新一代版本控制系统Mercurial的介绍及简要入门

要是仅仅想浏览全部代码也可以直接到google code上去看,在下面的地址:

http://code.google.com/p/jtianling/source/browse?repo=blog-sample-code

原创文章作者保留版权 转载请注明原作者 并给出链接

write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie

Win32 OpenGL编程(12) 混合及半透明效果


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论