Opengl混合算法探究

在我们的实际应用中使用OpenGL进行混合常见的问题有以下三种:

  • 使用Opengl自带的混合算法
  • 自定义混合算法
  • 半透明混合
    针对以上三种情况我们具体分析有何不同及如何解决问题。

一、Opengl自带混合算法

OpenGL渲染管线的最后阶段会将源色和底色进行混合,我们大部分情况下只需考虑实现此次drawcall的渲染实现即可,无心过分操心如何与底色进行混合。那么如何使用自带的混合呢?

首先我们需要开启混合模式,开启混合模式之后即可使用OpenGL自带的混合算法。

glEnable(GL_BLEND);

开启混合之后如何混合源颜色与底色呢?混合需要设置两个函数,一是设置混合因子即源颜色与底色各按何种比例进行混合,另一个就是混合函数,决定源颜色与底色使用哪种运算符得到结果。同时RGB颜色也能与Alpha值分别设置不同得混合因子与混合函数。

//设置源颜色混合因子与底色混合因子
glBlendFunc(GLenum sfactor,GLenum defector);
//示例
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

//分别设置RGB颜色与Alpha值得混合因子
glBlendFuncSeparate(GLenum srcRGB,GLenum dstRGB,GLenum srcAlpha,GLdstAlpha)
//示例
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);

//设置混合函数
glBlendEquation(GLenum mode);
//示例
glBlendEquation(GL_FUNC_ADD);

//分别设置RGB颜色与Alpha值得混合函数
glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
//示例
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);

上面得代码示例表示:源颜色(RGB或RGBA)需要乘源颜色得alpha,底色(RGB或RGBA)需要乘以一减源颜色得alpha,而混合函数为GL_FUNC_ADD,所以最终混合算法为:

//未分别设置
Color = vec4(Srgb * Sa + Drgb * (1 - Sa), Sa * Sa + Da * (1 - Sa));
//分别设置RGB与Alpha得混合
Color = vec4(Srgb * Sa + Drgb * (1 - Sa), Sa + Da * (1 - Sa));

详细得混合因子与混合函数参考OpenGL混合示例,不再赘述。唯一需要注意得颜色是否预乘alpha得问题,由于默认也是最常用得混合模式结果是预乘的,因此如果想要得到未预乘的结果,自带的混合算法并不适用。
总的来说,自带混合算法比较方便速度也比较快可以满足大部分的使用场景,但功能支持有限有些需求无法满足。

二、自定义混合算法

上面讲到如果要得到未预乘的结果Opengl自带混合算法无法为我们得到正确的结果,此时我们就需要关闭OpenGL自带的混合模式在shader中自己实现混合算法。PhotoShop与AE中都有混合模式这个功能,有很多的混合模式可选,但由于OpenGL自带的混合算法支持的功能有限,这些混合算法都无法直接通过OpenGL自带的混合算法实现。手动实现混合算法比较自由,我们可以自定义一些混合方法,实现一些OpenGL自带混合模式无法实现的复杂混合算法,缺点是在大部分GPU上同一个texture无法既作FBO输出,又作纹理采样输入,如果底图作为输入传入Fragment Shader,则当前FBO需要绑定另一个texture作为输出。如果混合区域覆盖全图,可以用FBO绑定一个空的texture作为输出,同时原始底图传入Fragment Shader作为输入;如果混合区域只占全图的一部分,那么就需要首先复制一份底图纹理并绑定到FBO作为输出,同时原始底图纹理传入Fragment Shader做混合,这两种不同的混合场景下,不管混合区域是全图还是部分区域,都需要申请一块额外的底图大小的纹理存储(空白或复制底图),另外部分区域混合时还需要一次额外的渲染(复制底图),混合所需要的空间和时间都有额外开销。虽然实现了我们的需求,但缺点也是显而易见的,时间与空间的开销都比较大。

一些常用的自定义混合算法可以从这里找到

三、半透明混合

在3D渲染中,深度缓冲去非常重要,深度值决定了当前片元是否需要丢弃,如果透明物体与半透明物体放在一起渲染就可能会出现半透明物体没有与背后的物体进行混合。例如


发生这一现象的原因是,深度测试和混合一起使用的话会产生一些麻烦。当写入深度缓冲时,深度缓冲不会检查片段是否是透明的,所以透明的部分会和其它值一样写入到深度缓冲中。结果就是不考虑透明度都会进行深度测试。即使透明的部分应该显示背后的物体,但深度测试仍然丢弃了它们。这也是混合变得有些麻烦的部分。要想保证窗户中能够显示它们背后的窗户,我们需要首先绘制背后的这部分窗户。这也就是说在绘制的时候,我们必须先手动将窗户按照最远到最近来排序,再按照顺序渲染。

但这仍然不能解决所有问题,因为物体在3d空间中可能会交叉导出我们无法确定顺序,甚至我们都无法确定物体是否为半透明的。这样看来这也不是一个好的解决办法。那么如果我们能逐像素对所有的渲染目标进行排序,这样我们就能分清远近关系。这就需要我之前一篇文章提到的OIT渲染

半透明混合是非常棘手的,如果想要得到好的效果必然带来性能或空间的巨大损失,OIT渲染的未来仍需要提出更好的方案及硬件支持。

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

推荐阅读更多精彩内容