zoukankan      html  css  js  c++  java
  • 【Cesium 历史博客】多视锥体优化:使用对数深度缓存

    导语

    Cesium 的渲染引擎是基于高精度渲染设计的。不过,就算是以米作为单位的常规游戏引擎,也会遇到精度问题,例如 z值冲突 和 抖动。

    z值冲突是指两个三角形接近时,有重叠的像素,但是深度缓存的精度不足以确定哪一个三角形更接近相机,当视图发生变化时,这些重叠像素会闪烁。

    之所以会发生 z值冲突,是因为深度缓存的精度 与 深度的倒数成正比,意味着越靠近截平面的三角形绘制精度越高,越远则越低。

    这里有一个动图,显示了相机在 WGS84 椭球上方约 8000 米观察的地形发生的 z值冲突:

    z值冲突的两种解决方法:使用多视锥体、使用对数深度缓存。

    在 Cesium 1.45 版本中,Cesium 混合了这两种技术以替代原来单一的多视锥体技术。

    这么做的好处显而易见:

    • 更好的性能:减少了 drawcall
    • 更好的视觉效果:可以在不影响性能的情况下将近平面尽可能移动得近一些

    1. 多视锥渲染技术

    Cesium 原来的多视锥体实现是使用 3 个视锥体,其分割距离分别是 [1, 1000],[1000, 100w], [100w, 10e] 米。

    这些视锥体从后到前(相对于相机)的顺序进行渲染,并且在每个视锥体中深度缓存被清除。

    渲染开始时,根据绘制命令(DrawCommands)的包裹范围(boundingVolume),将绘制命令放置在一个或多个圆锥体中。

    在两个视锥边界的绘制命令则两边都会绘制一次,为了优化这个重复绘制,Cesium 从视点触发,根据最近和最远的包裹范围计算合适的近平面和远平面距离,以最大程度减少视锥。(这句话翻译得不太好,专业名称比较多)。

    下图是珠穆朗玛峰的近地视图:

    将每个视锥分别着色后的样子(第一个视锥是红色,第二个视锥是绿色,黄色介于第一个和第二个视锥中,这里看不到第三个视锥):

    下图是一样的地形场景,只不过把视锥体显示了出来,第一个视锥(1~1000米)太小了这里看不到。

    在这个场景下,有 137 个 drawcall,第一个视锥有 28 个,第二个视锥有 102 个,第三个视锥有 7 个。重复调用数有 26 个,第一个和第二个视锥之间的重复调用占 12 个;在所有视锥体中都重复的调用有 7 个。

    2. 对数深度缓存

    z值冲突的另一种解决方法是使用对数深度缓存技术。

    将对数值输出到深度缓存,可以很好分配这些数值。Cesium 更新了顶点和片元着色器以支持对数深度缓存。

    关于对数缓存技术,可以参考三篇博客(在国外国内访问不了)

    对上述的场景使用对数深度缓存,近平面为 0.1,远平面为 1e8,只需一个视锥体,一共 111 个 drawcall。

    这么做不仅可以减少 drawcall,而且默认情况下,近平面更接近相机,从而可以近距离查看。

    对于多个视锥体,这并非不可实现,但是可能会有性能问题。只用一个视锥体,使用对数深度缓存,可以减少将绘制命令分配给每个视锥体的 CPU 计算量。

    视锥上清除命令和全屏扫描命令可能比较少。对数深度缓存消除了视锥边界处的奇怪问题,对后续开发的新功能(后处理、贴地线)会有帮助。

    这是一张拖拉机的轮子,近平面为 1 米。

    当近平面距离为 0.1 米时,轮胎看起来就比较完整了。

    简而言之,对于只有地形瓦片的视图,删除重复的 drawcall 为 10~30个。对于 3dTiles 或 BIM 模型来说,能减少 20~40 个 drawcall。

    在片元着色器中,覆盖平面很大一部分的三角形的深度信息将被写入深度缓存,在顶点着色器中计算、插值得来的对数数值可能并不是对的。对数深度缓存的典型优化方法是仅修改顶点着色器、仅修改接近相机的三角形的片元着色器两种。

    在片元着色器中写入片元深度值会导致 GPU 的深度检测被禁用。而在 Cesium 中是不可能的,因为存在一种情况:可能存在覆盖屏幕但是不靠近相机的三角形,例如覆盖整个陆地的超大多边形。所以,浏览器得支持 EXT_frag_depth 这个 WebGL 扩展,才能在片元着色器中写入片元深度,才能利用这个功能,否则 Cesium 仍会使用旧的多视锥体技术。

    虽然 Cesium 中的大多数视图仅需要一个单个对数深度的视锥,但是也有例外。一个极端的例子是,在非常遥远的距离观察一个很大的三角面。

    下例是一个极端情况,即这里有两个超级大平面,和地球切面差不多,它们尺寸是一样的,但是空间距离上只差 300 米,但是相机到观察目标的距离有 6400w 米。

    对于上面的视图,可以预见,几何图形在三角面距离比较远时仍然可见(例如行星)。三角面比较靠近的,则看不到,例如卫星。为了解决这个问题,Cesium使用了一种混合技术,在多个视锥体中,每个视锥都使用对数深度缓存。减小 Scene.logarithmicDepthFarToNearRatio 的值,就会增加视锥体的个数,然后减少z值冲突。

    *译者注

    简而言之,配合对数深度缓存技术和原来的多视锥体技术的灵活搭配使用,减少 drawcall,提升性能,提升显示效果。

  • 相关阅读:
    Oracle 安装报错 [INS-06101] IP address of localhost could not be determined 解决方法输入日志标题
    Linux下安装oracle数据库提示DISPLAY not set. Please set the DISPLAY and try again。
    redhat 关机注销命令详解
    VirtualBox的四种网络连接方式
    修改RedHat的系统显示时间
    insufficient memory to configure kdump(没有足够的内存)解决方法(待验证、待解决)
    xen坑随笔 heartbeat dpkg垃圾数据库清除
    tomcat 监控脚本
    负载均衡随笔
    GIT命令介绍
  • 原文地址:https://www.cnblogs.com/onsummer/p/14059210.html
Copyright © 2011-2022 走看看