日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入了解OpenGL——颜色混合

發布時間:2023/12/8 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入了解OpenGL——颜色混合 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

大家好。這一講,我們講介紹OpenGL的顏色混合模式。

其實顏色混合用到的場合很多,比如多張圖片的合成,動畫游戲中的一些畫面特效等都可以通過顏色混合進行實現。最常用的混合方式就是實現物體與背景的半透明效果。另外,在制作2D游戲時顏色混合可以用來通過制作目標物體的蒙板實現移動。通過蒙板來消除舊位置的物體對象可以不必重繪當前整幀內容,而僅僅是發生變化的那些物體。

為了各位從事iPhone開發的考慮。后面的代碼例子對OpenGL API的使用都會用OpenGL2.1與OpenGL ES1.1相互兼容的接口。

首先介紹一下OpenGL對源對象和目標對象進行顏色混合的實現。
這里,源對象是指你將要繪制的對象;目標對象是指已在幀緩存中的顏色。比如調用glClear(GL_COLOR_BUFFER_BIT);后留在幀緩存中的顏色。
在進行計算時,源和目標的混合都是在繪制源對象時進行計算的,在繪制對象以外的幀緩存像素不會受任何影響。

為了方便顏色混合,我們往往采用RGBA這種顏色模式。其中RGB表示色彩分量,而A就是混合因子(blend factor)。A,我們在圖形、圖像處理中常常表示為:alpha,它在圖像處理中常用作為透明系數。
我們指定了源和目標的混合因子后,OpenGL會對繪制對象的最終顏色做如下計算:
設:源對象的某個頂點的顏色為(Rs, Gs, Bs, As)
?????? 目的對象對應此源對象頂點的顏色為(Rd, Gd, Bd, Ad)
?????? 源混合因子為:(Sr, Sg, Sb, Sa)
??????目的混合因子為:(Dr, Dg, Db, Da)
那么,該頂點最終目標顏色為:
(Rs * Sr??<op>??Rd * Dr,??Gs * Sg??<op>??Gd * Dg,??Bs * Sb??<op>??Bd * Db,??As * Sa??<op>??Ad * Da)
其中,<op>可以是加法(+),減法(-), 逆向減法,最小值,最大值或按位邏輯操作,并且其優先級小于乘法(*)。

下面,我們介紹相關的OpenGL接口。
首先是開啟混合,使用glEnable(GL_BLEND);即可。

然后我們使用glBlendEquation()來指定混合操作,參數可以是:GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, GL_MIN, GL_MAX。
但這里要注意的是,OpenGL ES1.1沒有glBlendEquation接口,因此只能做加法操作。

glBlendFunc()接口用于指定源混合因子與目標混合因子。
參數請參考紅寶石書中文版的第140頁,表6-1。

下面給出示例代碼:

// // MyView.m // OpenGLTest // // Created by Zenny Chen on 4/25/10. // Copyright 2010 GreenGames Studio. All rights reserved. // P44 #import "MyView.h" #include <OpenGL/OpenGL.h> #include <math.h> @implementation MyView - (id)initWithFrame:(NSRect)frame {self = [super initWithFrame:frame];if (self) {// Initialization code here.}return self; } // Destination: a rectangle static c*****t struct VertexInfo {GLfloat vertices[3]; }vertexList[] = {{-0.5f, 0.5f, -1.0f},{-0.5f, -0.5f, -1.0f},{0.5f, 0.5f, -1.0f},{0.5f, -0.5f, -1.0f} }; - (void)prepareOpenGL {glEnable(GL_CULL_FACE);glEnable(GL_BLEND);glEnableClientState(GL_VERTEX_ARRAY);glVertexPointer(3, GL_FLOAT, 0, vertexList);glFrontFace(GL_CCW);glCullFace(GL_BACK);glShadeModel(GL_SMOOTH);// Set Background color(frame buffer color)glClearColor(1.0, 0.0, 0.0, 1.0);glViewport(0, 0, 320, 320);glMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho(-1.0, 1.0, -1.0, 1.0, 1.0, 5.0);glMatrixMode(GL_MODELVIEW);glLoadIdentity();// destination colorglColor4f(1.0f, 1.0f, 1.0f, 0.3f);glBlendEquation(GL_FUNC_ADD);glBlendFunc(GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA); } - (void)drawRect:(NSRect)dirtyRect {// Drawing code here.glClear(GL_COLOR_BUFFER_BIT);glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);glFlush(); } @end


上述代碼第67行的glBlendFunc(GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA);用于指定:
源混合因子:(As, As, As, As),這里是(0.3, 0.3, 0.3, 0.3)
目標混合因子則是:(1, 1, 1, 1) - (As, As, As, As),結果是(0.7, 0.7, 0.7, 0.7)。
這里我們能夠看到,為目標和源指定混合因子可以是源、目標的任一顏色分量或alpha因子,或是[0, 1]范圍內的補。

對于上述代碼,我們可以用等價的方式實現。
已知,目的像素顏色值為:(1.0, 0.0, 0.0, 1.0);源像素顏色值為:(1.0f, 1.0f, 1.0f, 0.3f)。
目的混合因子為:(0.7, 0.7, 0.7, 0.7);源混合因子為:(0.3, 0.3, 0.3, 0.3)

OK。我們可以直接把最終目標像素顏色值給算出來——(1.0 * 0.3 + 1.0 * 0.7,??1.0 * 0.3 + 0.0 * 0.7,??1.0 * 0.3 + 0.0 * 0.7,??0.3 * 0.3 + 1.0 * 0.7) =?
(1.0,??0.3,??0.3,??0.79)。

因此,我們可以將67行的glBlendFunc(GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA);給注釋掉,然后將63行的glColor4f(1.0f, 1.0f, 1.0f, 0.3f);改為:
glColor4f(1.0f,??0.3f,??0.3f,??0.79f);能夠獲得相同的效果。

我們上面講述了如何用glBlendFunc函數來做顏色混合。但是這會帶來一個問題,當我們進行了顏色混合后,最終目標顏色分量A同時也被改變了——原來A是0.3,混合后變成了0.79。
下面我們將引入另一個混合接口——glBlendFuncSeparate用于分別指定源和目標的顏色(RGB)分量和A(alpha)分量。下面給出該函數原型:

voidglBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);


如果我們要將1樓代碼中最終目標顏色的alpha分量值與混合前保持一致,可以將第67行(glBlendFunc那行)替換為:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);


上面將源alpha混合因子設置為1,而將目的alpha因子設為0,這樣做混合計算——As * 1.0 + Ad * 0.0后,結果為As,與原來的源alpha值保持一致。

另外,這里要注意的是OpenGL ES1.1沒有glBlendFuncSeparate這個接口,而OpenGL ES2.0才開始支持這個接口。


我們在制作游戲過程中會碰到這么種情況。比如有一層玻璃,然后后面有一些物體。
我們以前討論過深度緩存問題,在光照這一講中。深度緩存能夠幫助我們把擋在前面物體之后的物體都裁剪調。那么對于同時存在不透明物體和透明物體的遮擋該如何處理呢?
我們首先要記住以下兩種情況:
1、如果不透明物體在前,透明物體在后,那么不透明物體會把透明物體完全遮擋掉;
2、如果透明物體在前,不透明物體在后,那么透明物體與不透明物體做顏色混合。

此時,我們將通過開關混合、以及深度測試功能來完成這個任務。
下面先介紹下保持深度緩存的函數——

?

voidglDepthMask( GLboolean flag )

flag的值為GL_TRUE和GL_FALSE。
如果用GL_TRUE來調用這個函數,那么深度緩存將會把后面繪制的頂點記錄到深度緩存內;如果用GL_FALSE來調用此函數,那么深度緩存將不會記錄后面繪制的頂點,而保持原來的記錄。

由此,我們的繪制順序為:
1、首先,關閉GL_BLEND功能以及打開glDepthMask,繪制所有不透明的物體;
2、打開GL_BLEND功能以及關閉glDepthMask,繪制所有透明物體。
這樣,前面的透明物體將不會完全遮擋后面的不透明物體。
下面是示例代碼。這個代碼首先繪制白色矩形,作為背景。然后繪制前景紅色矩形。該矩形是不透明的,因此會把后面白色背景完全遮蓋掉。
最后繪制一個前景藍色矩形。該矩形是透明的,因此將與白色背景做顏色混合。

// // MyView.m // OpenGLTest // // Created by Zenny Chen on 4/25/10. // Copyright 2010 GreenGames Studio. All rights reserved. // P44#import "MyView.h"#include <OpenGL/OpenGL.h> #include <math.h>@implementation MyView - (id)initWithFrame:(NSRect)frame {self= [superinitWithFrame:frame];if(self) {// Initialization code here.}returnself; } staticc*****t structVertexInfo {GLfloat vertices[3]; }vertexList[] = {// background rectangle{-0.8f, 0.8f, -2.0f},{-0.8f, -0.8f, -2.0f},{0.8f, 0.8f, -2.0f},{0.8f, -0.8f, -2.0f},// rectangle hidden{-0.5f, 0.5f, -1.0f},{-0.5f, -0.5f, -1.0f},{0.0f, 0.5f, -1.0f},{0.0f, -0.5f, -1.0f},// rectangle blended{0.0f, 0.5f, -1.0f},{0.0f, -0.5f, -1.0f},{0.5f, 0.5f, -1.0f},{0.5f, -0.5f, -1.0f} };- (void)prepareOpenGL {glEnable(GL_CULL_FACE);glEnable(GL_DEPTH_TEST);glEnableClientState(GL_VERTEX_ARRAY);glVertexPointer(3, GL_FLOAT, 0, vertexList);glFrontFace(GL_CCW);glCullFace(GL_BACK);glShadeModel(GL_SMOOTH);glClearColor(0.4, 0.4, 0.4, 1.0);glViewport(0, 0, 320, 320);glMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho(-1.0, 1.0, -1.0, 1.0, 1.0, 5.0);glMatrixMode(GL_MODELVIEW);glLoadIdentity();glBlendEquation(GL_FUNC_ADD);glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); } - (void)drawRect:(NSRect)dirtyRect {// Drawing code here.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glDisable(GL_BLEND);glDepthMask(GL_TRUE);// Draw bakcgound rectangleglColor4f(1.0f, 1.0f, 1.0f, 1.0f); // whiteglDrawArrays(GL_TRIANGLE_STRIP, 0, 4);// Draw hidden rectangleglColor4f(1.0f, 0.0f, 0.0f, 0.3f); // redglDrawArrays(GL_TRIANGLE_STRIP, 4, 4);glEnable(GL_BLEND);glDepthMask(GL_FALSE);// Draw blended rectangleglColor4f(0.0f, 0.0f, 1.0f, 0.3f); // blueglDrawArrays(GL_TRIANGLE_STRIP, 8, 4); glFlush(); } @end 取自: http://www.cocoachina.com/bbs/read.php?tid=26284&page=1


總結

以上是生活随笔為你收集整理的深入了解OpenGL——颜色混合的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。