原计划开始着手地形系列,但发现如果想要从逻辑上彻底了解地形相关的细节,那还是需要了解Cesium的数据调度过程,这样才能更好的理解,因此,打算先整体介绍一下Cesium的渲染过程,然后在过渡到其中的两个主要模块:地形数据和影像数据。

简述

设想一下,印度洋的暖流,穿过喜马拉雅山,形成了滴一滴水,落在了青藏高原的唐古拉山,顺势而下,涌入太平洋,长江之水自此经久不息。而Cesium的一切的一切,也是从一个并不起眼的函数开始的:

通过requestAnimationFrame函数,每一帧的结束,就是下一帧的开始,从Cesium启动之时,直至其消亡,不曾停歇。

现在,我们就开始万里长征第一步,最终,该函数会调用Scene的Render方法:

虽然render(scene, time)的方法很长,但对于地球的主要要素(地形&影像),都是在Globe的beginFrame和endFrame之间完成的:

其中红色高亮的两个函数用来维护两个重要的逻辑,updateAndExecuteCommands负责数据的调度,比如哪些Tile需要创建,这些Tile相关的地形数据,以及涉及到的影像数据之间的调度,都是在该函数中维护。但是updateAndExecuteCommands函数只负责管理,也就是他所创建的Tile类只是一个个的Tasks,自己并不负责Tasks内容的实现(数据的加载和维护)。这样,导致架构会有些复杂,因为不是一个流水线的作业方式,所以就需要有状态的维护。但这也是必然的,不仅保证该函数高效,不拖累每一帧的时间消耗,同时因为实时性满足人的要求(帧数能够达到或接近60),每一帧需要的Tile队列可以实时计算,不用考虑时间和状态之间的关系。

可以这样理解,updateAndExecuteCommands是一个管理者,只说不做,与之相反,scene.globe.endFrame中,会对该帧所涉及的GlobeTile的下载,解析等进行处理。

如上图,简单而言,updateAndExecuteCommands负责上面看得见的事情,根据当前这一帧相机的状态,先打一个黄色的网格,然后检查当前状态下,这些网格里面的地形和影像数据是否都已经准备好了,如果准备好,每一个Tile就创建一个DrawCommand来渲染,把这个球画出来。如果没准备好也不管,反正有endFrame函数负责,各司其职,每个人做好本职工作,不是很好吗。

scene.globe.endFrame就按照吩咐来准备每一个Tile的数据,全是看不见的工作,默默的奉献自己的青春。这里,Promise,Worker等技术都会使用,通过异步和多线程的方式,来缓解每一帧的负担,而在主线程下,主要是数据状态的维护。如果一个Tile的数据解析完成,则该GlobeTile的状态更新为renderable(可渲染),done(已完成)。

类关系

在这个过程中,类的关系大致如下:

网格按照经纬度来划分的,每一个网格对应一个QuadtreeTile四叉树类,其中有一个GlobeSurfaceTile,里面保存地形数据TileTerrain和影像数据TileImagery。当前相机下需要多个网格,就需要多个QuadtreeTile,该队列保存在QuadtreePrimitive,QuadtreePrimitive统一维护所有Tile的管理,具体是通过GlobeSurfaceTileProvider来实现逻辑操作,而QuadtreePrimitive上面包了一个Globe和Scene。

渲染过程

updateAndExecuteCommands的关系过程如下:

在QuadtreePrimitive的update中,调用selectTilesForRendering来或许当前需要创建的网格,其中,在第一帧会把全球分为两块Tile:

而在queueChildrenLoadAndDetermineIfChildrenAreAllRenderable函数中,基于这两个Tile来做四叉树剖分,也就是所有的后来的QuadtreeTile都能够上溯到这两个Tile之一:

创建的GlobeSurfaceTile都会存储到更新队列中,等待数据下载和解析的过程,而如果当前帧中,存在准备好的,已经可以渲染的GlobeSurfaceTile,则调用addDrawCommandsForTile,构造成VBO,最终通过WebGL实现渲染。

更新过程

更新队列的逻辑如上,稍显复杂,还是着重看框选的部分:

最初,在processTileLoadQueue中,遍历更新队列中所有的GlobeSurfaceTile,如果发现里面没有数据,状态是QuadtreeTileLoadState. START,于是乎,大声喊道:“姐妹们,开始接客了”。

青楼就在GlobeSurfaceTile.processStateMachine。GlobeSurfaceTile就是这里的顾客,尽管人潮涌动,但来此处的人,不外乎三种:第一次来的,您就到prepareNewTile函数来吧,先帮你疏通疏通筋骨:new TileTerrain(),新建地形数据类,在帮你润润肌肤:_createTileImagerySkeletons,创建影像数据类;原来是老司机了,那就老规矩,来个三温暖吧:processTerrainStateMachine来负责地形数据加载,createWaterMaskTextureIfNeeded负责水面(如果该Tile是海洋区域的话),还有TileImagery.prototype.processStateMachine负责影像数据的加载;服务满意吗,来结账买单了:renderable = true/state = QuadtreeTileLoadState.DONE。

通过上面的描述,一个地球的渲染过程主要四个环节:

l 网格划分

l Terrain数据

l Imagery数据

l 渲染

而这四个环节互相交错,虽然看上去有些混乱,函数众多,但不知道你是否注意到,无论是渲染过程还是更新过程,都是针对当前状态的响应和状态的更新。

从流程上讲了一下大致的过程,不知道大家是否还有疑惑,或者文中有不对的地方,也希望多提意见。当然这个颗粒度还有点大,后面,在和大家分享一下每一个环节中具体的技术和优化策略。

Cesium原理篇:1最长的一帧之渲染调度的更多相关文章

  1. Cesium原理篇:5最长的一帧之影像

    如果把地球比做一个人,地形就相当于这个人的骨骼,而影像就相当于这个人的外表了.之前的几个系列,我们全面的介绍了Cesium的地形内容,详见: Cesium原理篇:1最长的一帧之渲染调度 Cesium原 ...

  2. Cesium原理篇:3最长的一帧之地形(2:高度图)

           这一篇,接着上一篇,内容集中在高度图方式构建地球网格的细节方面.        此时,Globe对每一个切片(GlobeSurfaceTile)创建对应的TileTerrain类,用来维 ...

  3. Cesium原理篇:7最长的一帧之Entity(下)

    上一篇,我们介绍了当我们添加一个Entity时,通过Graphics封装其对应参数,通过EntityCollection.Add方法,将EntityCollection的Entity传递到DataSo ...

  4. Cesium原理篇:7最长的一帧之Entity(上)

    之前的最长的一帧系列,我们主要集中在地形和影像服务方面.简单说,之前我们都集中在地球是怎么造出来的,从这一系列开始,我们的目光从GLOBE上解放出来,看看球面上的地物是如何渲染的.本篇也是先开一个头, ...

  5. Cesium原理篇:3最长的一帧之地形(1)

    前面我们从宏观上分析了Cesium的整体调度以及网格方面的内容,通过前两篇,读者应该可以比较清楚的明白一个Tile是怎么来的吧(如果还不明白全是我的错).接下来,在前两篇的基础上,我们着重讨论一下地形 ...

  6. Cesium原理篇:3D Tiles(2)数据结构

    上一节介绍3D Tiles渲染调度的时候,我们提到目前Cesium支持的Cesium3DTileContent目前支持如下类型: Batched3DModel3DTileContent Instanc ...

  7. Cesium原理篇:6 Renderer模块(1: Buffer)

    刚刚结束完地球切片的渲染调度后,打算介绍一下目前大家都很关注的3D Tiles方面的内容,但发现要讲3D Tiles,或者充分理解它,需要对DataSource,Primitive要有基础,而这要求对 ...

  8. Cesium原理篇:6 Render模块(4: FBO)

    Cesium不仅仅提供了FBO,也就是Framebuffer类,而且整个渲染过程都是在FBO中进行的.FBO,中文就是帧缓冲区,通常都属于高级用法,但其实,如果你了解了它的基本原理后,用起来还是很简单 ...

  9. Cesium原理篇:3D Tiles(1)渲染调度

    Cesium在2016年3月份左右推出3D Tiles数据规范,在glTF基础上提供了LOD能力,定位就是Web环境下海量三维模型数据.虽然目前3D Tiles还是Beta阶段,有不少硬伤,但3D T ...

随机推荐

  1. [原创]MySQL innodb_rollback_on_timeout参数对锁的影响

    环境:Server version:         5.6.21-log MySQL Community Server (GPL) 前提提要: innodb_rollback_on_timeout是 ...

  2. 浏览器全屏事件(Html5)

    <button onclick="launchFullscreen(document.documentElement);"></button> functi ...

  3. bat 延时删除指定文件夹中的文件经验分享

    1.bat延时 xp程序中通过ping 127.0.0.1 -n 20 来实现延时操作,ping本地地址20行. win7中通过timeout 20 来实现延时20秒. 2.删除指定文件 del /q ...

  4. JS 怎么控制某个div的滚动条滚动到顶部? (已解决)

    获取这个元素,然后设置它的滚动条的位置为初始位置(0,0). document.getElementById(..).scrollTop = 0;

  5. MVC辅助方法

    我相信很多人虽然经常用mvc去做一些东西,但是可能很少使用mvcHtml辅助方法 首先我们要创建一个mvc项目 二创建一个HtmlHelper文件夹 三编写文件 四调用辅助方法 调用辅助方法 和使用其 ...

  6. myeclipse中导入js报如下错误Syntax error on token "Invalid Regular Expression Options", no accurate correc

    今天在使用bootstrap的时候引入的js文件出现错误Syntax error on token "Invalid Regular Expression Options", no ...

  7. XMPP iOS客户端实现一:服务器

    1.下载ejabberd,下载链接http://www.process-one.net/en/ejabberd/downloads/ 2.安装,使用默认配置即可,next.. 3.启动ejabberd ...

  8. 剑指Offer面试题:10.数值的整数次方

    一.题目:数值的整数次方 题目:实现函数double Power(doublebase, int exponent),求base的exponent次方.不得使用库函数,同时不需要考虑大数问题. 在.N ...

  9. 【效率】专为Win7系统设计的极简番茄计时器 - MiniPomodoro (附源码)

    时光飞逝,一转眼坚持使用番茄工作法已经快3年了!能坚持这么长时间,主要还是得益于它的简单.但是令人纠结的是,这么长时间以来,换了7款不同的番茄计时器,仍然没有找到非常满意的: ■ 机械的噪音太大,会妨 ...

  10. 跟vczh看实例学编译原理——三:Tinymoe与无歧义语法分析

    文章中引用的代码均来自https://github.com/vczh/tinymoe.   看了前面的三篇文章,大家应该基本对Tinymoe的代码有一个初步的感觉了.在正确分析"print ...