HTML5的Canvas提供了两种绘图上下文(Graphic Context):一种是”2d”用于绘制二维矢量图,一种是”webgl”用于绘制三维图形。二维矢量图API提供的函数非常人性化,10分钟时间就能入门,所以cantk当初选择了使用二维矢量图API。”webgl”的接口和OpenGL ES 2.0差不多,用起来相当繁琐(我折腾了以整天才搞清除怎么画一张图)。
大家都知道”webgl”是硬件加速的,我和很多人一样认为”webgl”会比”2d”快。http://jsperf.com/也有证据证明这种想法: ”webgl”的drawArrays比”2d”的drawImage快一个数量级。前段时间我决定用webgl实现一套”2d”接口,让cantk不做修改的情况下也能利用webgl的性能优势。
在github也找到了webgl实现”2d”API的库,不过在chrome上用不了,它也几年没有更新了,所以我决定趁此机会学习一下WebGL,自己动手写这样一个库。在软件性能方面我做过不少工作,通常失望的时候比较多,所以在实现drawImage后,先做了一下性能测试,免得做完后才发现性能没有预期的好。
测试结果让人惊讶,仔细一想又在预料之中:
- 1.对于Android 4.4之前的手机,我没有支持WebGL的手机,欢迎提供测试数据(测试程序见后面)。
- 2.对于Android 4.4的低端手机(如红米),WebGL的实现反而更慢,不论图片多少,WebGL的实现总是要慢一拍。
- 3.对于Android 4.4的中高端手机(如Nexus 5),WebGL的实现在图片超过100个(256x256)后才有微弱优势。
为什么jsperf里的案例与实际情况差别这么大呢?我分析了一下,有几个原因:
- 1.WebGL的矩阵运算是JS实现的,在对象较多时,计算量不容忽视。而jsperf里的案例根本没有矩阵运算,与实际情况完全不符。
- 2.WebGL的矩阵等状态保存和恢复是JS实现的,在对象较多时,计算量不容忽视。而jsperf里的案例也没有考虑,与实际情况完全不符。
- 3.drawImage和drawArrays直接对比没有意义,即使不考虑纹理创建和Shader的创建,甚至不考虑多个纹理的切换,不考虑GL Program的切换,要绘制一张图片,在drawArrays之前要调用一大堆函数,才能完成一次贴图。
总的说来,在Android 4.4之后的手机上,”2d”API已经开启了硬件加速,此时WebGL在开发2D游戏上并无明显优势。在iPhone上,”2d”API非常高效,用WebGL开发2D游戏也无必要。WebGL的性能与原生GL ES没法比,所以我觉得WebGL在短时间内不会有太大用途。
附测试程序,欢迎测试和改进:https://github.com/drawapp8/webgl-2d-perfomance