翻译有误请指出,规范性转载。@秋意正寒。api
原文出处Graphics Tech in Cesium - Renderer Architecture | cesium.com数组
Cesium 是一个 WebGL 引擎,自 WebGL 1.0 在 2011 年 3 月发布后,官方就开始开发了。缓存
官方将 Cesium 的 Renderer 视为他们本身的第四代渲染器,由于它基于他们的 OpenGlobe 的经验改进而来。除此以外,还有其余技术人员在 AGI 的 Insight 3D 和 STK 的经验。因此说,Cesium 的渲染器并非凭空设计而来。框架
固然,能够把 WebGL 的调度分散在各处,可是集中在一个渲染器对象中有不少好处:函数
推出 Cesium 的渲染器的主要缘由是官方有丰富的经验,而且能够根据实际状况调整 Cesium 引擎以得到最佳性能。性能
Cesium 的着色器流水线远远超出了普通图形程序的概念范围。学习
还有一个缘由是由于,官方推出这个实际上是想经过此学习 JavaScript,并且 WebGL 在 2011 年的时候并不成熟(发文时是 2015年)。ui
在 Cesium 1.9 中,渲染器的主要组件(js对象)是:编码
VertexArray、RenderState、ShaderProgram、FrameBufferprototype
Renderer 类在 Source/Renderer
目录下。Renderer 的代码并非公开的 api,因此谨慎使用。
左边一列的对象构成 Cesium 的绘制命令的基础,它们封装了 WebGL 的 drawcall 指令。为了渲染一帧,Cesium 在随处都会执行这些命令。
Buffer
对象中(参考 Buffer.js)。若是可行,顶点数组使用 OES_vertex_array_object
的扩展名以减小 WebGL 的调用次数(这句不太懂)。着色器保存在 Source/Shader
目录下的 .glsl
后缀名的文件中。
Cesium 会删除文件内的注释、无效空格,并转换为 js 代码(字符串)以便其余 Cesium 对象能调用,而无需从新请求文件。
Cesium 提供了一个庞大的 GLSL 函数库,包括函数、结构体、常量。若是你的代码须要用到自定义 glsl 代码,你彻底能够不声明、不加入 #include
预编译指令,能够直接使用它们。
它们以 czm_
开头标识。例如,这是一个天空大气的片元着色器:
czm_ellipsoid ellipsoid = czm_getWgs84EllipsoidEC(); vec3 direction = normalize(v_positionEC); czm_ray ray = czm_ray(vec3(0.0), direction); czm_raySegment intersection = czm_rayEllipsoidIntersectionInterval(ray, ellipsoid); if (!czm_isEmpty(intersection)) { discard; }
这些内置对象造成了有向无环图(DAG)。
在运行时,glsl 源代码将传递给 ShaderSource
对象,这个对象查找 czm_
字符串并遍历 DAG
以生成最终的着色器。
若是在拾取操做时用到了着色器,它还会输出 pick id,而不是真正的颜色(这句话没看太懂)。
以上均在 Cesium 程序运行的时候完成的,而不是写死在引擎内部。由于有的绘制直到它要进行绘制时才知道着色器的编码顺序等。
内置的 GLSL uniform 被称为 自动 uniform。它也不须要声明或引入 #include,遍历 DAG 会同样遍历到。
自动 uniform 一般表明与帧相关(或视锥体相关、命令相关)的值,例如变换矩阵。见 AutomaticUniforms.js
。
例如,天空盒的顶点着色器使用到了自动 uniform 来转换一个 2x2x2 的立方体的坐标,这个立方体的中心在 True Equator Mean Equinox 框架,转换到裁剪坐标的中心:
attribute vec3 position; varying vec3 v_texCoord; void main() { vec3 p = czm_viewRotation * (czm_temeToPseudoFixed * (czm_entireFrustum.y * position)); gl_Position = czm_projection * vec4(p, 1.0); v_texCoord = position.xyz; }
使用原始的 GLSL 源代码做为 key 来缓存着色器程序,以减小初始化和使用着色器时的 WebGL 调用数。参考 ShaderCache.js
。
熟悉 WebGL 的读者,应该知道绘制命令的执行是由 WebGLContext
对象的 drawXXX
函数执行的。它被封装在 Cesium 的 Context.prototype.draw
方法中,它作了这些事:
当一帧结束后,Context.prototype.endFrame
方法会解除着色器的 WebGLProgram 的绑定、解除对帧缓存、绘制缓存、纹理的绑定以清理状态。这样能减小每一个绘制命令执行时渲染器的状态管理量。
渲染器将被 Scene 对象给 Primitive 对象来建立 WebGL 资源。例如,Globe 自己和三维模型。而且,渲染器还将执行绘制命令,将这些资源绘制到一帧上。
WebGL 2.0 的出现,须要对渲染器进行不少改进。
与时下不少引擎同样,设置 uniform 变量是 Cesium 的瓶颈。Uniform buffers 在 WebGL 2 获得了性能上的提升。
支持实例的绘制使得 Cesium 能渲染大量对象,例如树,固然每棵树能够有不一样的属性,例如位置、高度等。
感谢 Greg Beatty 和 Scott Hunter,他们编写了 glsl 着色器。
[Cozzi11] Patrick Cozzi and Kevin Ring. 3D Engine Design for Virtual Globes. CRC Press. 2011.