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
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
