WebGL 及其实现
前面章节介绍了Canvas2D,同时也介绍了在canvas中同样也可以绘制3D图形,也就是Canvas3D或者称为WebGL。同Canvas2D不一样的是,WebGL标准草案不是由W3C来起草的,而是Khronos组织来负责的,目前很多浏览器支持WebGL,例如Firefox, Chrome, Safari(仅限Mac平台)和Opera 。但是,微软以安全性为由拒绝在IE中支持WebGL,虽然它支持Canvas2D。
WebGL很热,自从诞生以来就备受关注,想知道WebGL有多酷,你可以查看参考文献1看看Google为大家制作的一些很棒的示例,看看网页中如何显示3D图形,相信你可以借此进一步了解它的魅力。
那么WebGL到底是何方神圣呢?根据官方标准中的说法,”WebGL是一套为Web设计的基于立即模型绘制3D的API。” 它来源于OpenGL ES2.0,提供了相似的3D绘图功能,只不过它运行在HTML网页中,简单上来理解, 你可以把它看成OpenGLES 2.0的JavaScript绑定,网页的开发者可以利用它来在网页中显示3D图形。WebGL定义的是一个被HTML Canvas元素创建(同样通过getContext)的用来3D渲染的上下文接口。
前面一章在介绍Canvas 2D的时候,曾经介绍过一个简单的例子,该例子是把canvas区域填充满红色。下面看一个WebGL的简单例子,功能一样, 把canvas区域填充满红色。
上图示例代码包含一个Canvas元素和一段JavaScript代码。根据以前的介绍,你应该已经知道,第5行是获得canvas元素的DOM节点对象,第6行代码通过传入“experimental-webgl”参数让该节点对象创建一个3D的上下文对象,之后就可以利用该上下文对象绘制3D图形。第7行设置用于下一行的颜色,格式为RGBA,。最后一行将之前设置的颜色填充到颜色缓冲区中(对应于canvas的后端缓冲区之一),从而将canvas区域设置为红色。
同Canvas2D类似地,Canvas元素提供了绘制的场所,WebGL则提供了绘制3D内容的上下文类- WebGLRenderingContext,下面将对其详细介绍。与Canvas 2D不同的是,WebGL没有软件渲染和硬件加速两种模式,它仅在硬件加速开启的情况下才能运行,因为它依赖于3D的图形库。
根据WebGL规范中的描述,下面来介绍一下它的几个主要部分:
- 上下文及内容展示:在使用WebGL的API之前,需要获取WebGLRenderingContext和DrawingBuffer(Chromium需要它)。对JavaScript来说,GL的操作都是由WebGLRenderingContext来负责完成。但是, DrawingBuffer对用户来说是透明的,它是用来存储渲染的内容并被合成器所合成,它包括帧缓冲器对象(绘制的结果存储)和纹理对象(纹理被合成器所使用)。
- WebGL的资源及其生命周期:textures,buffers (i.e., VBOs), framebuffers, renderbuffers, shaders and programs。它们有对应的JavaScript对象WebGLObject对应,它们的生命周期是一致的。
- 安全:为保证安全性,它要求:1,所有的WebGL资源必须包含初始化的数据;2,来源安全性,为防止信息泄露,当canvas的属性’origin-clean’为false时, readPixels将会抛出安全方面的异常。3,要求所有的着色语言必须符合OpenGL ES shading language 1.0; 4, 为防止DoS攻击,建议采取适当的措施对花费时间过长的渲染操作过程进行监控和限制。
- WebGL接口:主要包括各种资源类的接口和上下文类的接口,用于绘制3D的操作,这些API基本上来源于OpenGL ES 2.0.
- WebGL与OpenGLES 2.0的区别:这里不再一一介绍,读者可以自行翻阅和了解相关细节。 想要了解你的浏览器对WebGL支持的详细情况,请访问http://webglreport.sourceforge.net/获取详细参数。
WebGL的渲染过程
在这一部分将介绍WebGL如何被渲染以及如何被合成器合成的,大致的过程如下图所示。先解释以下图中的5个模块。WebGL 模块是指WebKit和Chromium中为支持WebGL而引入的基础设施。“GL 3D context used by WebGL”是GPU进程中为支持WebGL创建的GLES的实际的3D上下文对象。 CC模块是chromiumcompositor,就是合成器。“GL 3D context used by compositor”是GPU进程中为网页合成而创建的3D上下文对象。
第一步,当JavaScript的代码通过HTML Canvas对象创建3D上下文时,WebGL模块便为其创建一个绘制3D图形用的上下文对象,该对象在GPU进程中会有一个实际的OpenGL ES的上下文对象对应。同时,DrawingBuffer对象也会被创建。
第二步,DrawingBuffer会同时创建了一个帧缓冲区对象,用于存储该WebGL绘制的内容,同时获取用于合成的纹理对象,WebGL模块会获取这些对象的ID信息。
第三步,JavaScript的调用上下文对象的绘制图形代码被V8解析后,利用V8的绑定机制,会调用相应的WebGLRenderingContext对象的Callback函数,这些函数把它们转换成内部的Commands, 通过IPC机制传给GPU进程,GPU进程在之前创建好的上下文对象,完成实际的绘制工作。在这过程中,有两点值得关注,第一,很多命令需要同步,这会有很大的开销,第二,很多情况下,JavaScript需要操作各种图片资源,所以需要将它们共享给GPU进程,同时将它们上载到GPU的内存,因而开销比较大。
第四步,GPU进程执行renderer进程发送过来的命令,调用GL库函数把计算结果内容更新存储到帧缓冲区中,前面这四步在解析JavaScript时,同时执行。之后,它会调度一个任务,请求更新一个矩形区域(同viewport大小)。
第五步,从这步开始,合成器发起合成,当由任何变化或者更新网页的请求时都会触发它。合成器要求每层去更新自己的发生变化的部分,这需要尽可能的快,以避免大幅地影响一次网页的绘制工作。WebGL此时会准备绘制内容或者更新内容到帧缓冲区中,同时把内容拷贝到纹理对象中去,以备合成器所使用。
第六步和第七步,因为WebGL的纹理对象是在这些GL的上下文对象中共享的,WebGL模块切换到合成器的上下文对象环境中,将它的纹理对象根据变换绘制到该环境中的帧缓冲区中去,完成对该层的合成。
第八步,当所有层次的绘制完成后,最后一步就是交换前后端的缓冲区,来显示合成完的内容。
## WebKit和Chromium基础设施
前面介绍了WebGL如何渲染的过程,那么WebGL模块在WebKit和Chromium中包含哪些相关的重要类来支持的呢?如下图所示,里面包括了一些主要的WebGL模块类。
- HTMLCanvasElement:它是起点,是DOM中表示Canvas元素的类。如Canvas2D类似,当传入‘webgl’到它的方法getContext时,WebGLRenderingContext对象就会被创建。 WebGLRenderingContext:JavaScript中的3D操作基本上都是由该类来处理,也就是说该类其实是JavaScript和GL实现的桥梁。在WebGLRenderingContext创建的同时,DrawingBuffer也同时被创建,但是目前只有chromium中会创建它。
- DrawingBuffer: 表示规范中的DrawingBuffer,在WebKit的chromium移植中,DrawingBuffer会创建绘制用的Chromium的3D上下文对象和所需要的buffer, 这些buffer最后会被CC的CCCanvasLayerImpl使用。
- GraphicsContext3D: WebKit中用于绘制3D图形的上下文基础类,其对图形的绘制接口都是对该类的调用,具体需要各个移植的实现。
- GraphicsContext3DPrivate,WebGraphicsContext3D: Chromium中的具体3D图形上下文的具体实现的两个辅助类。WebGraphicsContext3D是一个chromium平台的基类,其子类可以是In-Process的3D绘图上下文实现类,也可以是out-of-process的3D绘图上下文实现类。
- PlatformLayer,WebGLLayerChromium:平台相关的用于表示各个移植中的,其可以将绘制好的buffer,发布到平台相关的层次上。
CCCanvasLayerImpl:CC中的用于表示canvaslayer的类,其来具体完成平台层的绘制请求,并将它们的结果内容会知道合成器的结果中。
源文件目录
WebKit/Source/WebCore/html/canvas/ WebKit支持Canvas相关的类,包括支持2D和3D上下文及其所涉及的其他类 WebKit/Source/WebCore/platform/graphics/chromium Chromium的DrawingBuffer支持,3D上下文,及其为合成WebGL所涉及的类
参考文献
- WebGL demos: http://www.chromeexperiments.com/webgl
- WebGL Spec https://www.khronos.org/registry/webgl/specs/1.0/
- WebGL Report for browser: http://webglreport.sourceforge.net/
- OpenGL ES2.0 http://www.khronos.org/opengles/sdk/docs/man/