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设置进来的常量。


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=sRRs−dRRd=sGGs−dGGd=sBBs−dBBd
Ar=sAAs−dAAd
GL_FUNC_REVERSE_SUBTRACT RrGrBr=dRRd−sRRs=dGGd−sGGs=dBBd−sBBs
Ar=dAAd−sAAs
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,方程设置为加,根据公式最终颜色=(目标颜色x目标因子)+(源颜色x源因子),得到最终有颜色的区域必定是源alpha不为0的区域,因为源是作为目标因子的,源*目标,最终源中alpha为0的区域,这个结果也为0,也就是最终的结果区域透明了。
    其他的都根据公式了。最终不同参数下的混合结果所示,1、2、3分别于图1、2、3对应。





最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容

  • javax.microedition.khronos.opengles 接口GL10 上级接口:GL 下级接口:G...
    福later阅读 2,238评论 0 0
  • 混合是什么呢?混合就是把两种颜色混在一起。具体一点,就是把某一像素位置原来的颜色和将要画上去的颜色,通过某种方式混...
    落寒z阅读 8,569评论 0 7
  • 最近这段时间在搞openGL ES处理视频和图像,要进行纹理混合,重新温习了一下大学时候的课本,找了一些资料,把一...
    北冥有猫其名为喵阅读 31,553评论 5 19
  • 1.OpenGLES提供了一个为几何图形中的每个顶点设置不同颜色的方法。 2.纹理可以控制一个渲染的三角形中的每个...
    碧玉小瑕阅读 357评论 0 0
  • 什么是纹理 纹理是一个用来保存图像的颜色色素值得OpenGL ES缓存, 纹理的作用是为了使我们渲染的几何图像更加...
    冰三尺阅读 658评论 0 1