Cesium原理篇:1最长的一帧之渲染调度
原计划开始着手地形系列,但发现如果想要从逻辑上彻底了解地形相关的细节,那还是需要了解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最长的一帧之渲染调度的更多相关文章
- Cesium原理篇:5最长的一帧之影像
如果把地球比做一个人,地形就相当于这个人的骨骼,而影像就相当于这个人的外表了.之前的几个系列,我们全面的介绍了Cesium的地形内容,详见: Cesium原理篇:1最长的一帧之渲染调度 Cesium原 ...
- Cesium原理篇:3最长的一帧之地形(2:高度图)
这一篇,接着上一篇,内容集中在高度图方式构建地球网格的细节方面. 此时,Globe对每一个切片(GlobeSurfaceTile)创建对应的TileTerrain类,用来维 ...
- Cesium原理篇:7最长的一帧之Entity(下)
上一篇,我们介绍了当我们添加一个Entity时,通过Graphics封装其对应参数,通过EntityCollection.Add方法,将EntityCollection的Entity传递到DataSo ...
- Cesium原理篇:7最长的一帧之Entity(上)
之前的最长的一帧系列,我们主要集中在地形和影像服务方面.简单说,之前我们都集中在地球是怎么造出来的,从这一系列开始,我们的目光从GLOBE上解放出来,看看球面上的地物是如何渲染的.本篇也是先开一个头, ...
- Cesium原理篇:3最长的一帧之地形(1)
前面我们从宏观上分析了Cesium的整体调度以及网格方面的内容,通过前两篇,读者应该可以比较清楚的明白一个Tile是怎么来的吧(如果还不明白全是我的错).接下来,在前两篇的基础上,我们着重讨论一下地形 ...
- Cesium原理篇:3D Tiles(2)数据结构
上一节介绍3D Tiles渲染调度的时候,我们提到目前Cesium支持的Cesium3DTileContent目前支持如下类型: Batched3DModel3DTileContent Instanc ...
- Cesium原理篇:6 Renderer模块(1: Buffer)
刚刚结束完地球切片的渲染调度后,打算介绍一下目前大家都很关注的3D Tiles方面的内容,但发现要讲3D Tiles,或者充分理解它,需要对DataSource,Primitive要有基础,而这要求对 ...
- Cesium原理篇:6 Render模块(4: FBO)
Cesium不仅仅提供了FBO,也就是Framebuffer类,而且整个渲染过程都是在FBO中进行的.FBO,中文就是帧缓冲区,通常都属于高级用法,但其实,如果你了解了它的基本原理后,用起来还是很简单 ...
- Cesium原理篇:3D Tiles(1)渲染调度
Cesium在2016年3月份左右推出3D Tiles数据规范,在glTF基础上提供了LOD能力,定位就是Web环境下海量三维模型数据.虽然目前3D Tiles还是Beta阶段,有不少硬伤,但3D T ...
随机推荐
- python 中使用 global 引发了莫名其妙的问题
哪里出问题了 python 中,使用 global 会将全局变量设为本函数可用.同时,在函数内部访问变量会先本地再全局. 在嵌套函数中,使用 global 会产生不合常理的行为. 上代码: In [9 ...
- Vuforia点击屏幕自动对焦,过滤UGUI的按钮
//点击屏幕自对对焦 #if UNITY_EDITOR )) #elif UNITY_ANDROID || UNITY_IPHONE && Input.GetTouch().phase ...
- MaxTemperature程序Mapper ClassNotFoundException
错误: 执行hadoop权威指南上MaxTemperature程序出现Mapper类ClassNotFoundException异常: 解决: 将书上的 JobConf job = new JobCo ...
- adb 无法启动问题
一.情况描述: 我们在使用eclipse开发有时候会出现adb连接异常中,有时候控制台会打印出来 adb connect异常 比如会出现下面这样 : [2014-12-18 16:18:26 - ] ...
- window下搭建c开发环境(GNU环境的安装)
一.在windows平台上安装GNU环境 windows操作系统不自带GNU环境,如果需要开发跨平台的C语言程序,那么需要给windows安装GNU环境 windows下的两款GNU环境:MinGW和 ...
- Visual Studio 2015 CTP6 发布
微软发布ASP.NET 5 支持在Windows.Mac和Linux上构建程序,Visual Studio 2015 CTP6(社区预览版)现已发布了.感兴趣的朋友们可以登录官网下载[http://w ...
- ASP.NET MVC 5 - 控制器
MVC代表: 模型-视图-控制器 .MVC是一个架构良好并且易于测试和易于维护的开发模式.基于MVC模式的应用程序包含: · Models: 表示该应用程序的数据并使用验证逻辑来强制实施业务规则的数据 ...
- 微冷的雨Java基础学习手记(一)
使用Java理解程序逻辑 之凌波微步 船舶停靠在港湾是很安全的,但这不是造船的目的 北大青鸟五道口原玉明老师出品 1.学习方法: 01.找一本好书 初始阶段不适合,可以放到第二个阶段,看到知识点时,要 ...
- Hibernate框架搭建实例
一,Hibernate是一个持久层,是一个专门负责管理数据库连接的框架: 二,Hibernate的搭建实例: 1.在Hibernate的官方网站(http://www.hibernate.org)可以 ...
- Intellij IDEA 13.1.3 打开多个窗口项目
作者QQ:1095737364 Intellij 是Java开发人员最喜欢的编程工具.默认情况只能打开一个窗口一个项目,本文就是教大家打开多个窗口,实现同时打开多个项目 第一步:打开Intellij, ...