天天看点

15. Html5的局:WebGL的纹理格式的转换紧接上文纹理格式转换计算量大下一篇

webkit为了统一webgl的书写规范,对opengl的标准进行四书五入,推出了平台无关的api标准,同时为了简化底层硬件的差异,又新增了一些纹理格式的支持,由内核提供高性能的图像转换,扩展了opengl得标准。

那么,webgl在底层做了些什么呢?复杂吗?可以自己实现吗?

这是webgl为前端同学提供的福利,上层开发可以更加专注业务书写,充分挖掘c/c++语言的能力。

重新生成一张内存图片,将纹理像素上下颠倒的复制到新图片。

15. Html5的局:WebGL的纹理格式的转换紧接上文纹理格式转换计算量大下一篇

图片在内存的大小,与图片格式没有直接关系,主要取决于尺寸。以1024x1024的png为例,有r、g、b、a四个通道,每个像素占4字节,总内存:1024 x 1024 x 4 = 4m空间。

新图片上传到gpu后自动释放,不会影响到老图片的生命周期。

unpack_flip_y_webgl的取值:true/false

对图片纹理的每个像素的r、g、b通道,乘以a的值后,并替换原先的值。

我们以一张白色图片,0.5的透明度为例。

每个像素的存储格式为:

15. Html5的局:WebGL的纹理格式的转换紧接上文纹理格式转换计算量大下一篇

r、g、b、a分别为unsigned char类型,俗称uint8_t,预算过程中自动进行浮点数转换,舍去末尾的精度:

r = r * a / 255.0f;

g = g * a / 255.0f;

b = b * a / 255.0f;

a = a;

每个像素都要算一次,1024 x 1024 大小的图片,计算量为1024 x 1024 x 10 约10m次。对于c/c++来说也比较耗时,如果放到js中处理,后果不堪设想。

这也许是webgl设计的初衷。

上面我们提到的图片格式为rgba,转换起来虽然计算量打,但算法比较直观。换成其他格式就不是这么直观了,比如:rgb、rgb565等等,不仅需要按byte进行转换,每个uint8_t都需要掰开使用。

以rgb为例,每个像素占用3个字节,考虑到gpu只能接受2的整数倍的尺寸。所以cpu需要为前端同学做格式转换。

这里我们定义stride,并计算相应的像素对齐后的尺寸。

如果unpackalignment = 1,那么新的图片尺寸是不变的,否则,新的图片尺寸就需要cpu处理做像素对齐,我们这里讨论特殊情况,就是 stride != width的时候。

将每个像素从gl_rgb转换成gl_rgba,保存中间pixel变量,再赋值到新的图片中:

问题来了,既然gl.teximage2d函数的internalformat与format的格式必须是保持一致的,为什么不把函数直接写为:

理由就是为了做兼容,对比webkit代码,我们可以找到firefox这样做的原因。

申请新的图片内存空间:

我们会发现,webkit并不会按照stride来申请空间,也不会参考unpackalignment,它使用了internalformat和type来确定opengl中的纹理格式和空间结构。

到了转换这一步,webkit采用函数模板为路由的方式转发到对应的转换api:

这里webkit做了大量的路由功能,提高了转换效率,但是代码复杂度很高。比如:

我们已知的常用纹理的format为:

webkit还支持了很多其他的format:

这篇内容太多了,我们放到下一篇继续讲,纹理格式转换。

继续阅读