Cesium中的图形渲染技术-一帧的渲染

Cesium中的图形渲染技术-一帧的渲染

2015年5月14日

这篇文章追溯了 Cesium 的 Scene.render来解释Cesium 1.9是如何使用其WebGL渲染器渲染帧的。在 Scene.render 处设置断点,运行Cesium应用程序,并遵循以下步骤。

考虑到Cesium专注于地理空间内容的可视化,具有许多不同光源的场景并不常见,因此Cesium使用传统的前向阴影管道(traditional forward-shading pipeline)。Cesium 的管道是独特的,因为它使用多个视锥来支持大规模的视野距离,而不需要z-fighting伪影[Cozzi13]。

开始(Setup)

Cesium 将包含帧生存期的常量存储在FrameState对象中。在帧的开始时,它被初始化(initialized)并赋予相应值,如相机参数和模拟时间。帧状态可用于其他对象,例如在整个帧中生成命令(draw calls)的 primitives。

UniformState是常见的预先计算着色器uniforms的帧状态的一部分。在帧的开始,计算(computed)视图矩阵和太阳向量等一致性。

更新(Update)

Cesium有一个经典的动画/更新/渲染管道(aniamte/update/render pipeline),其中动画步骤可能会移动 primitives (Cesium对可渲染对象的术语)、更改材质属性、添加/删除primitives等,而不需要与WebGL交互。这不是场景的一部分。它可能发生在应用程序代码中,在渲染帧之前显式设置属性,也可能在Cesium中通过使用Entity API分配时隐式发生值的改变(time-varying values)。

Cesium中的图形渲染技术-一帧的渲染_第1张图片

场景的第一个主要步骤 Scene.render 是更新场景中的所有图元 (primitives)。

在此步骤中,每个图元(primitive)

  • 创建/更新它的WebGL资源,例如编译/链接着色器,上传纹理,更新顶点缓冲区等。Cesium从不在场景之外调用WebGL。因为这样做会影响requestAnimationFrame的时间,并且很难与其他WebGL引擎集成。

  • 返回一个DrawCommand对象的列表,这些对象表示一个draw call,并引用由该基本类型创建的WebGL资源。有些图元,如polyline或billboard collection,可以返回单个命令;而其他图元,如地球仪(globe)或3D模型(3D Model),可能会返回数百个命令。大多数帧都有几百到几千个命令。

Globe是Cesium的地形和图像引擎,也是一个图元(primitive)。它的更新函数(update function)处理细节层次和剔除,以及用于加载地形和图像瓦片的外存管理(out-of-core memory management)。

潜在可见集(The Potentially Visible Set)

剔除(Culling)是一种常见的优化,图形引擎使用它来快速删除视野之外的对象,以便管道的其余部分不必处理它们。通过可见性测试的对象是潜在可见集,并在管道中继续。它们可能是可见的,因为对速度使用了不精确的保守性可见性检验。

Cesium 支持通过使用命令的世界空间(world-space)boundingVolume自动视图截锥和地平线裁剪[Ring13a, Ring13b]为单独的命令(图元primitives,如 Globe 执行自己的裁剪,可以禁用此命令)。

传统的图形引擎可以通过检查每个命令的可见性测试来找到潜在可见的设置。Cesium的createPotentiallyVisibleSet更进一步,动态地将命令划分为多个视锥(通常是三个),这些视锥绑定所有命令,并保持恒定的远近比以避免z-fighting。每个视锥具有相同的视场和宽高比,只是近、远平面距离不同。作为一个优化,该函数利用时间一致性,并将重用上一帧计算的视锥,如果它们仍然适用于此帧的命令。

Cesium中的图形渲染技术-一帧的渲染_第2张图片

渲染(Render)

有了这些锥体列表,每个锥体都有一个命令列表,现在就可以执行命令了,这将导致调用WebGL的drawElements/drawArrays。请跟随Cesium的执行命令(executeCommands),因为这是Cesium渲染管道的核心。

首先,清除颜色缓冲区(the color buffer is cleared)。如果使用了顺序独立的透明度(Order-Independent Transparency,OIT) [McGuire13, Bagnell13]或快速近似反锯齿(FXAA),它们的缓冲区也会被清除(更多关于这些的内容在下面)。

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

  • 星星的天空盒。一种老式的优化是通过先渲染天空盒来跳过清除颜色缓冲区。今天,这实际上会损害性能,因为清除颜色缓冲区有助于最大限度地压缩GPU(清除深度也是如此)。最佳实践是最后渲染天空盒以利用early-z的优势。Cesium首先渲染天空盒,因为它必须这样做,因为深度在每个视锥后被清除,如下所述。

  • 天空的气氛(Sky atmosphere)。基本的大气来自[ONeil05]。

  • 太阳。如果太阳是可见的,太阳广告牌被渲染。如果同时启用bloom filter,太阳会被剪掉,然后会多次/几遍渲染:颜色缓冲会被下采样(downsampled)、调亮、模糊(在水平和垂直方向上分开),然后上采样(upsampled)并与原始图像混合。

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

  • 设置视锥特定的统一状态。这只是视锥体的远近距离。

  • 清除深度缓冲区。

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

  • 接下来,执行半透明的命令。如果由于缺乏浮点纹理而不支持OIT,则命令会从后到前排序,然后执行。否则,使用OIT来提高半透明物体相交的视觉质量,并避免排序的CPU开销。命令的着色器为OIT打了补丁(并缓存),如果支持MRT,则在一个OIT通道中渲染,或者两个通道作为备用。参考OIT.executeCommands。

使用多个视锥体会导致一些有趣的情况,例如如果命令重叠多个视锥体,则可以多次执行。详情参见[Cozzi13]。

此时,每个视锥体的命令都已执行。如果使用了OIT,则执行最终的OIT composite pass。如果启用了FXAA,则执行fullscreen pass以抗锯齿。

类似于平视显示器(HUD),overlay pass的命令是最后执行的。

Cesium中的图形渲染技术-一帧的渲染_第3张图片

排序和批处理(Sorting and Batching)

在每个视锥中,命令都保证按照primtives返回的顺序执行。例如,Globe将其命令前后排序,以利用GPU early-z优化。

由于性能通常依赖于命令的数量,因此许多primitives使用批处理将不同对象组合为一个命令来减少命令的数量。例如,BillboardCollection将尽可能多的广告牌存储在一个顶点缓冲区中,并用相同的着色器渲染它们。

拾取(Picking)

Cesium使用颜色缓冲区实现选择/拾取。每个可拾取的对象都有一个唯一的id(颜色)。为了确定在窗口坐标中的给定(x, y)处选择/拾取什么,将一个帧渲染到屏幕外(offscreen)的framebuffer,其中编写的颜色是 pick ids。然后,使用WebGL的readPixels读取颜色,并返回选中的对象。

Scene.pick 的渲染管道和 Scene.render 相似,但简化了,因为,例如,天空盒,大气和太阳是不可选择的。

未来的工作

对于帧的渲染方式,有一些正在进行和计划进行的改进工作。

Ground Pass

在 Scene.render 的 passes 在图形引擎中很常见:不透明(OPAQUE),半透明(TRANSLUCENT),然后叠加(OVERLAY)。不透明实际上可以分为GLOBE和OPAQUE。这可能会被扩展,以便顺序是:基本的球体,固定在地面上的矢量数据,然后是一般的不透明对象。参考# 2172。

Shadows

阴影将通过阴影映射(shadow mapping)来实现。场景从每个阴影投射光的角度进行渲染,每个投射物体构成一个深度缓冲或阴影图,即从阴影投射光的角度到每个物体的距离。然后,在主颜色通道中,每个阴影接收对象检查每个光源的阴影图中的距离,以查看其碎片是否在阴影中。产品实现是相当复杂的,需要解决锯齿瑕疵(aliasing artifacts),软阴影,多视锥和Cesium的核心外地形引擎(out-of-core terrain engine)。参考# 2594。

Depth Textures

添加阴影的一个子集是添加对深度纹理的支持,例如,可以用于针对地形的深度测试广告牌和从深度重建世界空间位置。

WebVR

添加阴影的另一部分是能够从不同的角度渲染场景。WebVR支持可以在此基础上构建。使用标准摄像机和视锥进行裁剪和LOD选择,然后使用两个偏离中心的视锥进行渲染,每个眼睛一个视锥。NICTA的VR插件有类似的方法,但使用了两个画布。

Cubemap Pass

阴影的另一个扩展是渲染立方贴图的能力,即6个2D纹理组成一个盒子,描述盒子中间一点周围的环境。立方体映射(Cubemaps)在反射、折射和基于图像的光照中很有用。Cubemap Pass 可能会变得很耗性能,所以我怀疑它只会在实时生成中少量使用。

Post-Processing Effects 后处理效果

Scene.render 有一些硬编码的后处理效果,如sun bloom, FXAA,甚至为OIT合成。我们计划创建一个通用的后处理框架,将纹理作为输入,通过一个或多个后处理阶段运行它们,这些阶段基本上是运行在视口对齐的四边形上的片段着色器,然后输出一个或多个纹理。例如,这将用驱动后处理框架的数据替换大部分硬编码的Sun bloom,并开发许多新的效果,如景深、SSAO、辉光、运动模糊等。请看这些笔记。

Compute Pass

Cesium使用老式GPGPU进行gpu加速的图像重投影,它渲染一个离屏幕视口对齐的四块,以将重投影推送到着色器。这可以在帧开始计算期间使用后处理框架完成。参考# 751。

Cesium中的图形渲染技术-一帧的渲染_第4张图片

致谢(Acknowledgments)

Dan Bagnell 和 Patrick Cozzi 写了 Cesium 的大部分 renderer. 为了好玩, 90年代,当我还在上高中的时候,我在AGI做了最初的多视锥实现,可以查看我们的笔记: notes of the Cesium wiki. Ed Mackey

参考

[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.

你可能感兴趣的:(Cesium,3d,cesium,图形渲染)