原计划开始着手地形系列,但发现如果想要从逻辑上彻底了解地形相关的细节,那还是需要了解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. bootstarp3 支持ie8

    http://blog.csdn.net/hyb3280660/article/details/51850832 想要bootstarp3 支持ie8? 引入 <!-- 存放全局css/js - ...

  2. svn相关知识点

    1.查找linux操作系统:uname -a 2.svn 安装:yum install -y subversion 3.svn操作命令 a.将文件checkout到本地目录: svn co svn:/ ...

  3. Ruby 里的 %Q, %q, %W, %w, %x, %r, %s, %i (译)转

    原文地址  转自 %Q 用于替代双引号的字符串. 当你需要在字符串里放入很多引号时候, 可以直接用下面方法而不需要在引号前逐个添加反斜杠 (\") >> %Q(Joe said: ...

  4. 使用EntityFramework6连接MySql数据库(db first方式)

    准备工具: VS2013.MySQL For VisualStudio 1.1.4.Connector/Net 6.8.3(百度网盘里) 程序包管理器执行命令: Install-Package Ent ...

  5. MVC学习一:EF

    目录 一.EF修改和删除的多种方法 二.标准查询where 三.include 四.skip take 五.反射获取实例属性 六.EF DLL数据访问帮助类 一.EF修改和删除的多种方法 方法1:官方 ...

  6. [翻译]理解Swift中的Optional

    原文出处:Understanding Optionals in Swift 苹果新的Swift编程语言带来了一些新的技巧,能使软件开发比以往更方便.更安全.然而,一个很有力的特性Optional,在你 ...

  7. Javascript分号,加还是不加?

    关于这个问题,网上已经有很多人讨论过了,我先说说自己对这个问题的回答:加!(但非必须) 有些人写代码,懒得加分号,除非是迫不得已才勉强放一个分号上去.如果你可以保证你写的代码不出现任何 bug,那当然 ...

  8. Google分布式构建软件之四:分发构建结果

    注:本文英文原文在google开发者工具组的博客上[需要FQ],以下是我的翻译,欢迎转载,但请尊重作者版权,注名原文地址. 之前的文章,介绍了Google在分布式构建软件过程中,如何把构建过程分发到许 ...

  9. Three.js + HTML5 Audio API 打造3D音乐频谱,Let’s ROCK!

    继续玩味之前写的音乐频谱作品,将原来在Canvas标签上的 作图利用Three.js让它通过WebGL呈现,这样就打造出了一个全立体感的频谱效果了. 项目详情及源码 项目GitHub地址:https: ...

  10. Swift 和 C# 的语法比较

    昨天看到Jacob Leverich 写了一篇文章 Swift is a lot like Scala 介绍Swift 和 Scala 的语法对比,从这篇文章的确可以看到Swift 的语法和 Scal ...