HTML5中国

 找回密码
 立即注册

QQ登录

只需一步,快速开始

HTML5中国 首页 应用推荐 查看内容

WebGL中的Alpha与混色

2016-10-9 09:45| 发布者: Hyukoh| 查看: 513| 评论: 0|原作者: HalfLab|来自: 半实验室

摘要: 要想实现直觉上的透明颜色,混色的数学原理如下

  要想实现直觉上的透明颜色,混色的数学原理如下:

// 源颜色指的是我们要绘制的颜色
// 目标颜色指的是当前位置颜色缓冲区中的颜色
// 结果颜色 = 源颜色 * 源alpha + 目标颜色 * (1 - 目标alpha)
color = sColor.rgb * sColor.a + dColor.rbg * (1 - sColor.a);

  实际上,我们的计算机就是通过这种方式来绘制透明图形的。

这里有个小误区,很多人认为gl标准混色为

gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

其实是不对的,正确的应该是:

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

因为在经验公式中,a通道并不需要取均值!

  在很多3D引擎中,往往会在材质导入的时候就进行预乘处理。


  预乘


  如果我们图片中有一个像素rgba表示为[255, 255, 255, 127]。

  那么预乘之后它就变成了[127, 127, 127, 127]。

  第一个好处是,混色公式可以简化为:

// 因为sColor已经预乘
// 结果颜色 = 源颜色 + 目标颜色 * (1 - 目标alpha)
color = sColor.rgb + dColor.rbg * (1 - sColor.a);

  以WebGL为例,这就是为什么很多渲染引擎默认的混色模式为:

  gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);


  其实性能优化还不是预乘最大的作用。(实际WebGL性能测试,预乘并不会对性能有很大提升。)预乘另外一个重要的作用,是实现更好的线性差值计算。

  假设,图形中有A与B两个顶点。A点的颜色[255, 0, 0, 255],B点颜色为[0, 255, 0, 1],那么AB中点的颜色为多少呢?

  如果没有进行预乘处理,通过线性差值计算,结果为[127, 127, 0, 127]。其实这是不符合直觉的,rgb通道的均值计算并没有考虑到alpha通道的权重。

  如果进行预乘处理,A点颜色为[255, 0, 0, 255],B点颜色为[0, 1, 0, 1],线性差值后中点颜色为[127, 0.5, 0, 127]。整体颜色终于偏向了直觉中的红色。

  WebGL中,提供一个“傻瓜”式的预乘处理开关:

  gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);

  一旦开启,在调用gl.texImage2D上传图片信息的时候,WebGL内部会自动对图片信息进行预乘处理。(但我在使用gl.compressedTexImage2D上传图片信息时发现,预乘命令会失效!此处有待进一步验证)

  实际工程中采用哪种方式,因情况而异。本文的结论是,最好对材质进行预乘处理!


  小坑


  混色模式在使用的时候,如果有两种被混的颜色都被擦除的情况,会导致第三种颜色的混入。如果是WebGL,它可能是Canvas元素的背景色或者其它Dom元素的颜色;如果是OpenGL,可能就是[0, 0, 0, 0]。

  此处,为了保证WebGL与OpenGL原生平台的统一,可以采取两种方式:

  •   强制设置canvas的背景色为black
  •   将webGL的上下文属性alpha设置为false

  以上两种方式效果一致,但是,alpha属性在某些手机浏览器上经测试设置无效。



原文作者:HalfLab

鲜花

握手

雷人

路过

鸡蛋
更多

相关阅读

最新评论

HTML5中国微信

小黑屋|关于我们|HTML5论坛|友情链接|手机版|HTML5中国 ( 京ICP备11006447号 京公网安备:11010802018489号  

GMT+8, 2017-1-18 03:18

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

返回顶部