困扰许久的 alpha 问题终于解决了。这个问题在上个 Bulletproof 的进度报告中也提到,不知道是哪里的问题:图层alpha、上下文设置、shader 计算、给的原始点颜色数据。这次将 Flash 的部分抽出来,在未计算图层 alpha 的时候就测试,间接排除了第一种情况;直觉上第四个概率很小。接下来的就是二选一,今天突然想到 Pixi 的颜色结果是正常的,clone 了下来直奔主题。
详述在下文。
我以前的初始化代码是这样的:
var glc = this._context;
glc.disable(gl.DEPTH_TEST);
glc.disable(gl.CULL_FACE);
glc.enable(gl.BLEND);
glc.blendEquation(gl.FUNC_ADD);
glc.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
Pixi 里的是这样的(src/core/renderers/webgl/WebGLRenderer.js
):
var gl = this.gl;
// set up the default pixi settings..
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.CULL_FACE);
gl.enable(gl.BLEND);
很可能是 glBlendFunc()
的设置问题?由于 WebGL 书上的例子采用的都是 alpha/1-alpha 的设置,我用惯了 GDI+ 而 GDI+ 中核心的 AlphaBlend()
在混合时采用的也是 alpha/1-alpha 方式,我就很自然地将这一行放了上去。然后就出现了如二次函数般的颜色衰减。我想是不是混合模式的问题,将最后一行注释掉,结果就正常了。
var glc = this._context;
glc.disable(gl.DEPTH_TEST);
glc.disable(gl.CULL_FACE);
glc.enable(gl.BLEND);
glc.blendEquation(gl.FUNC_ADD);
//glc.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
照这么看,默认采用的混合模式应该是 alpha/1(正确结果是线性衰减而不是二次衰减)。(测试,结果为 1/0。)杨彦君说的是按照自发光且带alpha来理解,但是……由于在 GDI+ 经历的都只是实色混合模型而不是颜色光照模型,不太能理解这种想法……
再次订正于12月3日:
12月1日,上面这个 1/0 的配置,上了图层测试之后就原形毕露了:先画的图层全部消失,因为未使用目标像素(DST = 0
)。又蛋疼了两天。
继续读 Pixi 的源代码,在 GraphicsRenderer.render()
方法中发现了一个对 setBlendMode()
的调用,而且是每次元素绘制之前都会调用。混合模式在 GDI+ 和 Photoshop 里都见过,控制通道的混合输出。顺藤摸瓜在 WebGLRenderer
中找到了 BLEND_MODE
和 blendFunc()
参数的映射。搜索 BLEND_MODE
发现默认的混合模式(最常见的是在滤镜应用前重设)是 BLEND_MODE.NORMAL
,对应的参数配置是 1/1-alpha。考虑到 GLantern 采用的是与 Pixi 类似的缓冲格式(Pixi 是 XYRGBA,放在一个缓冲区,GLantern 是 XYZ + RGBA,放在两个缓冲区;颜色都预乘,GL 环境预乘开),其中颜色是相同的,那么应用同样的配置就应该能得到相同的结果。
于是加入混合模式机制,采用相同的映射,尝试绘制。此时才真正成功了。
细想一下,1/1-alpha 的配置也应该是很好理解的……