Cesium渲染一帧中用到的图形技术

译者注:本文翻译自Cesium官方博文《Graphics Tech in Cesium - Rendering a Frame》,May 14, 2015 by Patrick Cozzi。html

本文经过追溯Cesium的Scene.render,解释了Cesium 1.9如何使用其WebGL渲染器渲染每一帧。在Scene.render中放置一个断点,运行一个Cesium应用,而后继续。git

因为Cesium专一于可视化地理空间内容,所以使用许多不一样光源的场景并不常见,所以Cesium使用传统的前向阴影管线(Forward Rendering)。 Cesium的管道之因此独特,是由于它使用了多个视锥体来支持巨大的视距,避免形成Z-fighting现象[Cozzi13]。github

译者注:正向渲染/前向渲染(Forward Rendering)与延迟渲染(Deferred Rendering)相对,延迟渲染多用于多光照的场合。参看《正向渲染和延迟渲染彼此之间有什么不一样》web

设置

Cesium将具备帧生存期的常量存储在FrameState对象中。在每一帧的开始阶段,将使用诸如相机参数和仿真时间之类的值对其进行初始化。 这个FrameState对可用于其余对象,例如在整个帧周期中生成命令(绘图调用)的图元(primitives)。数组

UniformState是FrameState的一部分,具备通用的预先计算的着色器uniform变量。 在每一帧的开始阶段,诸如视图矩阵和太阳光线矢量等uniform变量将会被计算缓存

更新

Cesium具备经典的动画/更新/渲染管线,动画步骤能够在不与WebGL交互的状况下移动图元(primitives,Cesium表示可渲染对象的术语),更改材质属性,添加/删除图元等。 这不是Scene.render的一部分,它可能会在应用程序代码中,经过在渲染帧以前显式设置属性时发生;或者可能会在Cesium中隐式地,经过使用Entity API分配时间变值触发。app

imglink1
经典的动画/更新/渲染管线

Scene.render的第一步是更新场景中的全部图元。
在此步骤中,每一个图元会框架

  • 建立/更新其WebGL资源。例如,编译/连接着色器,加载纹理,更新顶点缓冲区等。Cesium永远不会在Scene.render以外调用WebGL,由于这样作会增长requestAnimationFrame的耗时,并使其难以与其余WebGL引擎整合。函数

  • 返回一组DrawCommand对象的列表,这些对象能够表示成绘图调用命令,并引用了由图元建立的WebGL资源。 有些图元(例如折线或布告板(billboard)集合)可能会返回单个命令;而其余的图元(例如Globe或3D模型),可能会返回数百个命令。 大多数帧将是几百到几千个命令的。性能

Globe对象是Cesium的地形和图像引擎,能够看做是一个图元(primitive)。它的更新函数可处理多层级结构的细节和拣选,以及用于加载地形和图像图块的核心外内存管理。

潜在可见集合

拣选是图形引擎常见的优化方法,可以快速的消除视野外的对象;以便管道的其他部分没必要处理这些对象。经过可见性测试的对象就是“潜在可见性集”,并继续沿管道传输。它们多是可见的,由于使用了不精确的保守可见性测试来提升速度。

Cesium经过使用commands的世界空间的boundingVolume(包围盒)对象,来对单个命令(图元,例如执行本身拣选操做的Globe,能够禁用此功能),自动执行视锥和水平剔除[Ring13a,Ring13b]。

传统的图形引擎能够经过检查每一个命令(command)的可见性测试来找到潜在的可见集。 Cesium的createPotentiallyVisibleSet函数更进一步,将命令动态地分为多个视锥(一般是三个),它们将全部命令限制在必定的范围以内,并保持恒定的远近比以免深度冲突( z-fighting)。每一个视锥体具备相同的视场和宽高比,只有近平面和远平面的距离不一样。做为一种优化,此函数利用时间相干性,而且若是对于该帧的命令仍然合理,则将重用最后计算的视锥。

imglink2
左:多视锥体;右: 在视锥体中的命令

渲染

每一个视锥体都有各自的命令列表,组成视锥体列表后,咱们如今能够执行命令了——也就是执行WebGL的drawElements/drawArrays的调用。如下会顺着追踪Cesium的executeCommands相关的内容,由于这是Cesium渲染管线的核心。

首先,清除颜色缓冲区。若是使用了与顺序无关的透明度(OIT)[McGuire13,Bagnell13]或快速近似抗锯齿(FXAA),则它们的缓冲区也将被清除(有关更多信息,请参见下文)。

而后,使用整个视锥体(不是单个计算的视锥之一)来渲染一些特殊状况的图元:

  • 包含星星的天空盒。 老式的优化方法是先渲染天空盒,而后跳过清除颜色缓冲区的操做。 现在,这实际上会影响性能,由于清除颜色缓冲区有助于最大程度地压缩GPU(与清除深度相同)。最佳作法是使天空盒最后渲染以利用Early-Z。Cesium首先渲染天空盒,由于它必须这样作,须要在每一个视锥体以后清除深度(正以下面所描述的那样)。

  • 天空大气。来自[ONeil05]的基本大气。

  • 太阳。若是太阳是可见的,则渲染太阳的布告板(billboard)。若是还启用了泛光过滤器,则会剪掉太阳,而后几个通道将会被渲染:对颜色缓冲区进行降采样,变亮,模糊(分别在水平和垂直通道中进行),而后进行升采样并与原始混合。

接下来,从最远的视锥开始,按照如下步骤执行每一个视锥中的命令:

  • 视锥体特定的uniform状态量将会被设置。这只是视锥体的近距离和远距离。

  • 深度缓冲区将会被清空。

  • 首先执行不透明图元的命令。 执行命令会设置WebGL状态,例如渲染状态(深度,混合等),顶点数组,纹理,着色器程序和统一,而后发出绘图调用。

  • 接下来,执行半透明命令。若是因为缺乏浮点纹理而不支持OIT,则将命令从头至尾排序,而后执行。不然,OIT用于提升相交半透明对象的视觉质量,并避免排序的CPU开销。命令的着色器针对OIT进行了修补(并缓存),若是支持MRT,则经过一次OIT渲染进行渲染,或者做为后备经过两次渲染。能够参阅OIT.executeCommands

使用多个视锥会致使一些有趣的状况,例如若是命令重叠多个视锥,则命令能够执行屡次。详细信息请参见[Cozzi13]。

至此,每一个视锥体的命令已执行。若是使用OIT,则执行最后的OIT复合通道。若是启用了FXAA,则会执行全屏通道以进行抗锯齿。

与平视显示器(HUD)类似,覆盖通道的命令最后执行。

imglink3
Cesium当前的渲染管线。

排序和批处理

在每一个视锥中,保证按图元返回命令的顺序执行命令。例如,Globe从头至尾对其命令进行排序,以利用GPU Early-Z优化。

因为性能一般取决于命令的数量,所以许多图元使用批处理经过将不一样的对象组合为一个命令来减小命令的数量。 例如,BillboardCollection在一个顶点缓冲区中存储尽量多的布告板,并使用相同的着色器对其进行渲染。

拾取

Cesium使用颜色缓冲区实现拾取。每一个可选取的对象都有一个惟一的ID(颜色)。为了肯定在给定的(x,y)窗口坐标中拾取到内容,将帧渲染到屏幕外的帧缓冲区,其中写入的颜色为拾取ID。而后,使用WebGL的readPixels读取颜色,并将其用于返回拾取的对象。

Scene.pick的管道相似于Scene.render,但因为例如天空盒,大气层和太阳没法拾取而得以简化。

将来的工做

关于一帧中进行的渲染工做,有一些正在进行中还处于计划阶段的提高。

地面通道

上面描述的Scene.render中的通道在图形引擎中很常见:OPAQUE,TRANSLUCENT,而后是OVERLAY。 实际上,OPAQUE分为GLOBE和OPAQUE。 可能会对其进行扩展,以便其顺序为:基本globe,固定在地面上的矢量数据,而后是通常的不透明对象。 参见#2172

阴影

阴影将经过shadow mapping实现。从每一个阴影投射光的角度渲染场景,而且每一个显示投射对象都有助于深度缓冲区或阴影贴图,即从灯光角度到每一个对象的距离。而后,在主色通道中,每一个阴影接收对象检查每一个光源阴影图中的距离,以查看其片断是否在阴影内。实际的生产实现很是复杂,须要解决锯齿伪像,柔和阴影,多个视锥体以及Cesium的核心外地形引擎。 参见#2594

深度纹理

添加阴影的一个子集增长了对深度纹理的支持,例如,能够将其用于针对地形进行深度测试的告示板,并根据深度重构世界空间的位置。

WebVR

添加阴影的另外一部分是从不一样角度渲染场景的能力。WebVR支持能够基于此。标准相机和视锥用于拣选和LOD选择,而后使用两个偏爱的视锥(每一个眼睛一个)进行渲染。NICTA的VR插件使用相似的方法,可是使用了两个画布。

立方体贴图通道

阴影的另外一个扩展是渲染立方体贴图的能力,即造成一个盒子的六个2D纹理描述了盒子中间某个点周围的环境。立方体贴图可用于反射,折射和基于图像的照明。立方体贴图通道的使用代价可能会变得昂贵,所以我怀疑这将仅少许用于即时生成。

后处理效果

Scene.render具备一些后期处理效果,这些效果通过硬编码,例如太阳泛光,FXAA甚至是OIT合成。咱们计划建立一个通用的后处理框架,将纹理做为输入,经过一个或多个后处理阶段运行它们,这些通道基本上是在视口对齐的四边形上运行的片断着色器,而后输出一个或多个纹理。例如,这将用驱动后处理框架的数据代替许多硬编码的太阳泛光,并打开许多新效果,例如景深,SSAO,发光,运动模糊等。 请参阅这些说明

计算通道

Cesium会使用老式的GPGPU来进行GPU加速的图像重投影,在该渲染过程当中,它将渲染一个与屏幕视口对齐的四边形,以将重投影推向着色器。这能够经过在帧开始时的计算过程当中使用后处理框架来完成。参见#751

imglink4
潜在的将来Cesium渲染管线(新阶段以粗体显示)。

致谢

我和Dan Bagnell编写了大多数Cesium渲染器。要得到娱乐,请参阅咱们的Cesium Wiki注释。 当我还在读高中时,Ed Mackey在90年代就在AGI进行了最初的多视锥体实现。

参考

[Bagnell13] Dan Bagnell. Weighted Blended Order-Independent Transparency. 2013

[Cozzi13] Patrick Cozzi. Using Multiple Frustums for Massive Worlds. In Rendering Massive Virtual Worlds Course. SIGGRAPH 2013.

[McGuire13] McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013

[ONeil05] Sean O’Neil. Accurate Atmospheric Scattering. In GPU Gems. Edited by Matt Pharr and Randima Fernando. 2005.

[Ring13a] Kevin Ring. Horizon Culling. 2013.

[Ring13b] Kevin Ring. Computing the horizon occlusion point. 2013.

相关文章
相关标签/搜索