WebGL精灵渲染Alpha混合出现白边的原因及解决方法咨询
我有一个带Alpha通道的精灵(下图为原精灵,为防止纹理渗色做了纹理填充,因此看起来更“厚重”),另一张是它的渲染效果。目前Alpha混合功能已生效:圆形内部的浅蓝色是带Alpha的蓝色,边缘橙色部分也因抗锯齿带有Alpha色,但蓝色圆形周围却出现了白边。既然Alpha混合对蓝色像素有效,为什么作为Alpha橙色像素的白边会出现?如何避免这个白边?
当前使用的WebGL混合设置如下:
gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
将该精灵渲染到HTML Canvas时表现正常,具备Alpha混合效果且无白边。
注:下图无Alpha通道,但我的应用中实际存在该通道。


问题原因分析
你当前使用的gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)是预乘Alpha的混合模式,但你的精灵纹理大概率没有做预乘Alpha处理。
预乘Alpha要求纹理的RGB通道值已经乘以了Alpha通道的值,比如原本的颜色是(R, G, B, A),预乘后应该是(R*A, G*A, B*A, A)。如果你的精灵没有做预乘,直接用这个混合模式渲染,边缘那些Alpha值较低的像素(比如抗锯齿的橙色边缘),其RGB值没有乘以Alpha,就会导致混合后残留白色底色——因为未预乘的低Alpha像素,RGB部分还是原本的亮色,混合时无法被正确抵消。
而Canvas 2D默认会自动处理预乘Alpha的适配,所以渲染正常。
解决方法
有两种可行方案:
- 对精灵纹理做预乘Alpha处理
- 处理纹理像素数据,将每个像素的R、G、B值分别乘以对应的Alpha值,再重新生成纹理。
- 这种方式适合需要保留当前混合模式的场景,是WebGL中推荐的做法。
- 修改混合模式为非预乘模式
- 将混合函数改为:
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); - 这种方式不需要修改纹理数据,但要注意部分渲染场景下可能出现的颜色精度问题,不过对于你的精灵场景来说,应该可以解决白边问题。
- 将混合函数改为:
另外,还要检查纹理的采样设置,确保gl.TEXTURE_WRAP_S和gl.TEXTURE_WRAP_T设置为gl.CLAMP_TO_EDGE,避免纹理边缘的重复采样导致渗色,虽然你已经做了纹理填充,但这个设置可以进一步加固。
内容的提问来源于stack exchange,提问作者Jung Ervin

