WebGL blendMode 详解

来源:互联网 发布:网络作家作品集 编辑:程序博客网 时间:2024/05/16 15:01

一、简单介绍

          blendMode 翻译过来也就是大家常说的颜色混合模式,或者大家在 PS 里见过得图层之间的混合模式。具体概念就不在这里详谈了,不太明白的可以先搜索一下,只要有普通的概念就好了,接下来看看 WebGL 是如何处理一个个的图像,并正确显示它们混合之后的颜色的。


二、webgl 中的 blendMode 函数

     (这一章看完可能会不懂,结合第三章再反过来查阅这一章,就会明白。所以这一章只是API参考,跟很多讲 webgl 、 opengl 的书籍一样,需要结合栗子甚至实际操作结合才能理解、明白这些概念)

       在 webgl 里有如下几个函数控制 blendMode :

       1. gl.blendEquation(enum mode)

       2. gl.blendEquationSeprate(enum modeRGB,enum modeAlpha)

       3. gl.blendFunc(enum src, enum dst)

       4. gl.blendFuncSeprate(enum srcRGB, enum dstRGB, enum srcAlpha, enum dstAlpha)

       5. gl.blendColor(r,g,b,a)


2.1 blendEquation

       其中 函数 1 和 2 是做同一件事情。

       gl.blendEquation(gl.FUNC_ADD) 等同于 gl.blendEquation(gl.FUNC_ADD,gl.FUNC_ADD)。

       gl.blendEquation 的可选参数如图



2.2 blendFunc

       函数3 和 4 是做同一件事。

       gl.blendFunc(gl.ONE,gl.ZERO) 就相当于 gl.blendFuncSeprate(gl.ONE,gl.ZERO,gl.ONE,gl.ZERO)。

       gl.blendFunc 的可选参数如图


R、G、B、A 分别都有下标,这些下标是指:

       首先明确一个概念,假设 webgl 里面有一块颜色画板 (dst),这个时候我们要画一个对象 M (src) 上去,这样可以得到更新的画板,下次再画对象 N (src)时,取最新的画板颜色 (dst) 进行混合就可以得到下一次的混合底色 (dst) 或者 最终颜色 。

s 即 src,也就是要要叠加的对象的颜色。

d 即 dst,也就是画板上得颜色。

c 即 const,也就是 gl.blendColor 指定的颜色,默认情况下 gl.blendColor 的颜色为 (1,1,1,1)

画板初始的颜色全部为 (0,0,0,0),如果调用过 gl.clearColor(r,g,b,a) 就是 gl.clear 刷新过的 (r,g,b,a)。


三、栗子

       接下来看个实际的栗子,看看这些函数到底是怎么控制颜色混合的。

       例如文字 FPS,放大后我们可以看到它的边缘有一些半透明的颜色(抗锯齿效果,不至于全是实线,实线转弯的地方锯齿很严重): 

       接下来看看几种情况下绘制的结果和我们的推算。

 

情况一:

              gl.clearColor(0,0,0,0);

              绘制文字("FPS");

        这里并没有调用任何 blendMode 相关的函数,也就是各个情况都是默认的。也就是相当于:

        gl.blendColor(1,1,1,1)

        gl.blendEquationSeprate(gl.FUNC_ADD, gl.FUNC_ADD)

        gl.blendFuncSeprate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA)

取文字FPS边缘的一个半透明像素考虑 (F上面那一横,用QQ截图就能看到颜色,截图会看到那一行的像素颜色为(113,113,113)),像素颜色为 (0,0,0,143/255)。

        1. 在调用 gl.clearColor(0,0,0,0) 后,所有的颜色清除为 (0,0,0,0)

        2. 绘制文字 FPS,那么 src 的颜色为 (0,0,0,0.5),dst 的颜色为 (0,0,0,0)

        3. 采用混合参数可以知道  (参考第二章的混合参数设置,中间的 + 来自 gl.blendEquationSeprate 的第一个参数)

            r = srcR * srcAlpha + dstR * (1 - srcAlpha) = 0 * 143/255 + 0 * (1 -143/255) = 0 

            g = srcG * srcAlpha + dstG * (1 - srcAlpha) = 0 *143/255 + 0 * (1 -143/255) = 0 

            b = srcB * srcAlpha + dstB * (1 - srcAlpha) = 0 *143/255 + 0 * (1 -143/255) = 0 

            a = srcA * 1 + dstA * (1 - srcAlpha) =143/255 * 1 + 0 * (1 -143/255) =143/255

        4. 混合之后的颜色为 (0,0,0,143/255)

        5. 由于网页背景色是 (1,1,1,1),所以网页背景色再跟 (0,0,0,143/255) 做混合就可以得到 

            r = srcR * srcAlpha + dstR * (1 - srcAlpha) = 0 *143/255 + 1 * (1 -143/255) = 113/255

            g = srcG * srcAlpha + dstG * (1 - srcAlpha) = 0 *143/255 + 1 * (1 -143/255) =113/255

            b = srcB * srcAlpha + dstB * (1 - srcAlpha) = 0 *143/255 + 1 * (1 -143/255) =113/255

            a = srcA * 1 + dstA * (1 - 143/255) = 143/255 * 1 + 1 * (1 - 143/255) = 1

        可能有人会说这样推出的结果其实不靠谱,因为我又不知道 F 上面那横如果没有任何颜色叠加真正的颜色是什么,其实可以在 PS 里看到,这个 F 的字体是 Heletica ,24 号字体,放大了4倍。

        当然我们可以继续用别的颜色混合看看结果是否正确(情况二)。

        不过我可以明确的说明,这里我没有在 PS 里取色,而是用了混合公式反推出的原始颜色。


情况二:

             gl.clearColor(1,0,0,0);

             绘制文字("FPS");

          先看看结果:

          结果表明,在文字有颜色的地方会显示黑色和红色(半透明的边缘像素),没有颜色的地方是白色。

          先取文字FPS边缘的一个半透明像素 (0,0,0,143/255) 做混合后显示的颜色为:

          1. 经过 gl.clearColor(1,0,0,0) 之后像素颜色为 (1,0,0,0)

          2. 叠加颜色 (0,0,0,143/255) 之后

            r = srcR * srcAlpha + dstR * (1 - srcAlpha) = 0 *143/255 + 1 * (1 -143/255) =113/255

            g = srcG * srcAlpha + dstG * (1 - srcAlpha) = 0 *143/255 + 0 * (1 -143/255) = 0 

            b = srcB * srcAlpha + dstB * (1 - srcAlpha) = 0 *143/255 + 0 * (1 -143/255) = 0 

            a = srcA * 1 + dstA * (1 - srcAlpha) =143/255 * 1 + 0 * (1 -143/255) =143/255

          3. 混合的颜色为 (113/255,0,0,143/255)

          4. 混合网页底色 (1,1,1,1) 和 (113/256,0,0,143/255) 之后

            r = srcR * srcAlpha + dstR * (1 - srcAlpha) = (113/255) * (143/255) + 1 * (1 - 143/255) = 206/255

            g = srcG * srcAlpha + dstG * (1 - srcAlpha) = 0 *143/255 + 1 * (1 -143/255) = 113/255

            b = srcB * srcAlpha + dstB * (1 - srcAlpha) = 0 *143/255+ 1 * (1 -143/255) = 113/255

            a = srcA * 1 + dstA * (1 - srcAlpha) = 143/255 * 1 + 1 * (1 - 143/255) = 1

          5. 混合之后的颜色为 (206/255,113/255,113/255,1),QQ 截图之后发现颜色为 (233,112,115),之后又测试了纯色块的 (0,0,0,143/255) 发现颜色为 (226,113,113)。

0 0