Android OpenGLES2.0(十八)——輕鬆搞定Blend顏色混合

Blend是OpenGL中的一個非常重要的部分,它可以讓每個輸出的源和目的顏色以多種方式組合在一起,以呈現出不同的效果,滿足不同的需求。

Blend相關函數及意義

在OpenGLES1.0中,Blend在OpenGLES固定的管線中,OpenGLES2.0相對1.0來說,更爲靈活。在OpenGLES2.0中,與Blend相關的函數及功能主要有:

//調用此方法,傳入GL_BLEND開啓BLEND功能
void glEnable(GLenum cap);
//調用此方法,出入GL_BLEND關閉BLEND功能
void glDisable(GLenum cap);
//設置BLEND顏色,結合glBlendFuncSeparate或glBlendFunc使用
void glBlendColor(GLclampf red,GLclampf green,GLclampf blue,GLclampf alpha);
//設置BLEND方程式
void glBlendEquation(GLenum mode);
//對RGB和Alpha分別設置BLEND方程式
void glBlendEquationSeparate(GLenum modeRGB,GLenum modeAlpha);
//設置BLEND函數
void glBlendFunc(GLenum sfactor,GLenum dfactor);
//對RGB和Alpha分別設置BLEND函數
void glBlendFuncSeparate(GLenum srcRGB,GLenum dstRGB,GLenum srcAlpha,GLenum dstAlpha);

Blend的使用比較簡單,但是如果不理解Blend的這些函數及參數的意義,使用了錯誤的參數,就難以獲得我們所期望的混合結果了。
想要使用Blend,glEnable(GL_BLEND)當然是必須的。與之對應的,不需要Blend的時候,我們需要調用glDisable(GL_BLEND)來關閉混合。
另外的四個方法,看名字差不多就能知道他們的意義了。
glBlendFuncglBlendFuncSeparate都是設置混合因子,反正就是這麼個意思了。區別在於glBlendFunc是設置RGBA的混合因子,而glBlendFuncSeparate是分別設置RGB和Alpha的混合因子。設置混合因子是做什麼的呢?繼續看。
glBlendEquationglBlendEquationSeparate都是設置Blend的方程式,也就是設置混合的計算方式了,具體參數後面說。他們的區別在同glBlendFuncglBlendFuncSeparate的區別一樣。
顏色、因子、方程式,組合起來就是:最終顏色=(目標顏色*目標因子)@(源顏色*源因子),其中@表示一種運算符。
至於glBlendColor則是在glBlendFunc和glBlendFuncSeparate的設置中,因子可以設置和常量相關的,這個常量就是由glBlendColor設置進去的。

glBlendFunc及glBlendFuncSeparate詳細說明

glBlendFuncSeparate設置混合因子,參數及它們表示的主要如下,而glBlendFunc的參數也是這些,表示的意義就是RGB和A合併爲RGBA就是了。在下表中,s0表示源,d表示目的,c表示有glBlendColor設置進來的常量。

Parameter RGB Factor Alpha Factor
GL_ZERO (0, 0, 0) 0
GL_ONE (1, 1, 1) 1
GL_SRC_COLOR (Rs0, Gs0, Bs0) As0
GL_ONE_MINUS_SRC_COLOR (1, 1, 1) - (Rs0, Gs0, Bs0) 1 - As0
GL_DST_COLOR (Rd, Gd, Bd) Ad
GL_ONE_MINUS_DST_COLOR (1, 1, 1) - (Rd, Gd, Bd) 1 - Ad
GL_SRC_ALPHA (As0, As0, As0) As0
GL_ONE_MINUS_SRC_ALPHA (1, 1, 1) - (As0, As0, As0) 1 - As0
GL_DST_ALPHA (Ad, Ad, Ad) Ad
GL_ONE_MINUS_DST_ALPHA (1, 1, 1) - (Ad, Ad, Ad) Ad
GL_CONSTANT_COLOR (Rc, Gc, Bc) Ac
GL_ONE_MINUS_CONSTANT_COLOR (1, 1, 1) - (Rc, Gc, Bc) 1 - Ac
GL_CONSTANT_ALPHA (Ac, Ac, Ac) Ac
GL_ONE_MINUS_CONSTANT_ALPHA (1, 1, 1) - (Ac, Ac, Ac) 1 - Ac
GL_SRC_ALPHA_SATURATE (i, i, i) 1

glBlendEquation及glBlendEquationSeparate詳細說明

glBlendEquationSeparate的設置混合操作,參數及其意義如下表所示。通過glBlendEquationSeparate或者glBlendEquation設置的方程中,源和目的顏色分別爲(Rs,Gs,Bs,As)(Rd,Gd,Bd,Ad) 。最終混合的顏色結果爲(Rr,Gr,Br,Ar) 。源和目的的混合因子分別爲(sR,sG,sB,sA)(dR,dG,dB,dA) 。其中,所有的顏色分量的取值範圍都爲[ 0, 1 ]。GL_MIN和GL_MAX是在OpenGLES3.0纔有的

Mode RGB Components Alpha Component
GL_FUNC_ADD RrGrBr=sRRs+dRRd=sGGs+dGGd=sBBs+dBBd Ar=sAAs+dAAd
GL_FUNC_SUBTRACT RrGrBr=sRRsdRRd=sGGsdGGd=sBBsdBBd Ar=sAAsdAAd
GL_FUNC_REVERSE_SUBTRACT RrGrBr=dRRdsRRs=dGGdsGGs=dBBdsBBs Ar=dAAdsAAs
GL_MIN RrGrBr=min(Rs,Rd)=min(Gs,Gd)=min(Bs,Bd) Ar=min(As,Ad)
GL_MAX RrGrBr=max(Rs,Rd)=max(Gs,Gd)=max(Bs,Bd) Ar=max(As,Ad)

Blend代碼示例

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    GLES20.glClearColor(0,0,0,0);
    mSrcFilter.create();
    mDstFilter.create();
    int[] textures=new int[2];

    //導入一張圖片設置爲源紋理
    GLES20.glGenTextures(2,textures,0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textures[0]);
    EasyGlUtils.useTexParameter();
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D,0,GLES20.GL_RGBA,srcBitmap,0);
    mSrcFilter.setTextureId(textures[0]);
    //再導入一張圖片設置爲目標紋理
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textures[1]);
    EasyGlUtils.useTexParameter();
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D,0,GLES20.GL_RGBA,dstBitmap,0);
    mDstFilter.setTextureId(textures[1]);

}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
    this.width=width;
    this.height=height;
    mSrcFilter.setSize(width,height);
    mDstFilter.setSize(width,height);
    MatrixUtils.getMatrix(mDstFilter.getMatrix(),MatrixUtils.TYPE_FITSTART,
         dstBitmap.getWidth(),dstBitmap.getHeight(),width,height);
    MatrixUtils.getMatrix(mSrcFilter.getMatrix(),MatrixUtils.TYPE_FITSTART,
         srcBitmap.getWidth(),srcBitmap.getHeight(),width,height);
}

@Override
public void onDrawFrame(GL10 gl) {
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    //開啓Blend
    GLES20.glEnable(GLES20.GL_BLEND);
    //設置BlendFunc,第一個參數爲源混合因子,第二個參數爲目的混合因子
    GLES20.glBlendFunc(nSrcPar,nDstPar);
    //設置BlendEquation,GLES2.0中有三種
    GLES20.glBlendEquation(equaInt[nEquaIndex]);
    GLES20.glViewport(0,0,width,height);
    //先渲染目的紋理出來,再渲染源紋理出來,是源紋理去與目的紋理混合
    mDstFilter.draw();
    mSrcFilter.draw();
}

目的紋理和源紋理使用的圖片分別如下所示(作爲源的圖片爲了表現混合效果,上中下三部分用了不一樣的透明度,最下面部分不透明):
這裏寫圖片描述這裏寫圖片描述

根據公式推敲下渲染的結果:
1. 當目標和源因子都設置爲GL_ZERO,無論混合方程怎樣設置,最終肯定啥也沒有。
2. 當源設置爲GL_ONE,目標設置爲GL_ZERO,方程設置爲加還是減,最終應該渲染的就是目標的顏色,也就是之渲染出金幣。
3. 當源設置爲GL_ONE,目標設置爲GL_SRC_COLOR,方程設置爲加,根據公式最終顏色=(目標顏色*目標因子)+(源顏色*源因子),得到最終有顏色的區域必定是源alpha不爲0的區域,因爲源是作爲目標因子的,源*目標,最終源中alpha爲0的區域,這個結果也爲0,也就是最終的結果區域透明瞭。
其他的都根據公式了。最終不同參數下的混合結果所示,1、2、3分別於圖1、2、3對應。

這裏寫圖片描述這裏寫圖片描述這裏寫圖片描述這裏寫圖片描述這裏寫圖片描述這裏寫圖片描述這裏寫圖片描述

源碼

所有的代碼全部在一個項目中,託管在Github上,歡迎Star和Fork——Android OpenGLES 2.0系列博客的Demo


歡迎轉載,轉載請保留文章出處。湖廣午王的博客[http://blog.csdn.net/junzia/article/details/76580379]


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章