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值。
glBlendFunc — specify pixel arithmetic
C Specification
void glBlendFunc( GLenum sfactor,
GLenum dfactor);
Parameterssfactor
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.
dfactorSpecifies 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);
Parametersmode
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();
}
glPushMatrix (); DrawSmoothColorPyramid (0.5); DrawSmoothColorPyramid (1); glPopMatrix ();
glEnable ( GL_BLEND ); glBlendFunc ( GL_SRC_ALPHA , GL_DST_COLOR );
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};
先看左边的截图,根本看不到小的三角锥,原因很明显,因为外面的三角锥后绘制,将其内部先绘制的小三角锥完全的覆盖掉了,但是右边的截图我们清晰的看到了内部的小三角锥,呵呵,因为我们启用了半透明效果(用混合实现)嘛。
为节省篇幅仅贴出关键片段,完整源代码见我博客源代码的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