cesium系列篇:Entity vs Primitive 源码解析(从Entity到Primitive)02

上篇文章中,我们介绍了使用viewer.entities.add添加entity之后的信号传递以及最后entity对象被传递到GeometryVisualizer

这篇文章,我们则介绍如何在逐帧渲染的过程中根据GeometryVisualizer中的entity对象创建相应的primitive

这是下文中涉及到的类的类图,从中可以清晰的了解各个对象之间的关系,下面我们结合代码来仔细讲解。

在这里插入图片描述

循环的一帧

我们先看下viewer初始化的时候做了什么,在何处定义了每一帧的循环,并持续的进行渲染,结合时序图(见第三节)和源码,可以将其分为两个部分

Viewer初始化

  1. viewer初始化并创建clock
function Viewer(container, options){let clock;let clockViewModel;let destroyClockViewModel = false;if (defined(options.clockViewModel)) {clockViewModel = options.clockViewModel;clock = clockViewModel.clock;} else {clock = new Clock();clockViewModel = new ClockViewModel(clock);destroyClockViewModel = true;}
}
  1. clock作为参数之一创建cesiumWidget
// 省略其他参数
const cesiumWidget = new CesiumWidget(cesiumWidgetContainer, {clock: clock});
  1. 添加监听事件,建立事件响应,其效果我们在后面再具体描述
eventHelper.add(clock.onTick, Viewer.prototype._onTick, this);

cesiumWidget初始化

  1. 在构造函数中设置渲染循环策略this.useDefaultRenderLoop
this._useDefaultRenderLoop = undefined;
this.useDefaultRenderLoop = defaultValue(options.useDefaultRenderLoop,true
);

结合useDefaultRenderLoopset函数可知其实是调用了startRenderLoop函数

useDefaultRenderLoop: {get: function () {return this._useDefaultRenderLoop;},set: function (value) {if (this._useDefaultRenderLoop !== value) {this._useDefaultRenderLoop = value;if (value && !this._renderLoopRunning) {startRenderLoop(this);}}},
}
  1. startRenderLoop中定义了render函数并每一帧进行调用
function startRenderLoop(widget) {widget._renderLoopRunning = true;let lastFrameTime = 0;function render(frameTime) {// 此处省略细节widget.render();requestAnimationFrame(render);}requestAnimationFrame(render);
}
  1. render函数中起实际作用的是函数widget.render,其内部通过调用this._clock.tick()发出信号,结合上一节viewer初始化中提到的事件监听的建立可以知道,进行响应的是Viewer.prototype._onTick函数
CesiumWidget.prototype.render = function () {if (this._canRender) {this._scene.initializeFrame();const currentTime = this._clock.tick();this._scene.render(currentTime);} else {this._clock.tick();}
};Clock.prototype.tick = function () {this.onTick.raiseEvent(this);return currentTime;
};
  1. Viewer.prototype._onTick函数中,会通过调用函数this._dataSourceDisplay.update(time)进行实际的primitive对象的创建
Viewer.prototype._onTick = function (clock) {const isUpdated = this._dataSourceDisplay.update(time);
};

时序图

  • 这里我们附上整个过程的时序图,帮助大家更好的了解整个过程
    [图片]

生成Primitive

通过上面的描述,我们知道了cesium的每一帧是如何更新的,以及其通过调用this._dataSourceDisplay.update(time)进行primitive的创建,下面我们就探究下具体的创建过程

  1. update中,获取了this._defaultDataSource_visualizers属性,通过上一篇文章我们知道,其是一个包含了GeometryVisualizer等多个Visualizer的列表,其中GeometryVisualizer是后续创建polygon对应primitive的类

    DataSourceDisplay.prototype.update = function (time) {visualizers = this._defaultDataSource._visualizers;vLength = visualizers.length;for (x = 0; x < vLength; x++) {result = visualizers[x].update(time) && result;}return result;
    };
    

    [图片]

  2. GeometryVisualizerupdate函数中主要做了如下几件事:

    • 获取被添加对象,在上一篇文章中我们知道,通过_onCollectionChanged函数,将添加的entity添加到了this._addedObjects属性中

      const addedObjects = this._addedObjects;
      addedObjects.set(id, entity);
      
    • 遍历每一个被添加的对象

      • 创建UpdaterSet,其内部的updaters包含了PolygonGeometryUpdater在内的10个Updater
        [图片]

      • 通过updater尝试创建instance(后面详细介绍)

    • 移除已经被添加的对象

    • batch中创建primitive(后面详细介绍)

代码节选如下:

GeometryVisualizer.prototype.update = function (time) {// 获取被添加对象const addedObjects = this._addedObjects;const added = addedObjects.values;// 遍历每一个被添加的对象for (i = added.length - 1; i > -1; i--) {entity = added[i];id = entity.id;// 创建UpdaterSetupdaterSet = new GeometryUpdaterSet(entity, this._scene);this._updaterSets.set(id, updaterSet);// 通过每一个updater尝试创建instance 并添加到batch中updaterSet.forEach(function (updater) {that._insertUpdaterIntoBatch(time, updater);});}// 移除已经被添加的对象addedObjects.removeAll();// 在batch中创建primitivelet isUpdated = true;const batches = this._batches;const length = batches.length;for (i = 0; i < length; i++) {isUpdated = batches[i].update(time) && isUpdated;}return isUpdated;
};

生成instance

  1. 获取polygonOutline对应的instance

    • 在函数GeometryVisualizer.prototype._insertUpdaterIntoBatch中将updater传递到StaticOutlineGeometryBatch.prototype.add函数中
    this._outlineBatches[shadows].add(time, updater);
    

    在这里插入图片描述

    • StaticOutlineGeometryBatch.prototype.add先创建polygonOutline对应的instance
    const instance = updater.createOutlineGeometryInstance(time);
    
    • StaticOutlineGeometryBatch.prototype.add中,调用batch.add函数,传入instance,并写入字典this.geometry
    this.geometry.set(id, instance);
    

    在这里插入图片描述

  2. 获取polygon对应的instance

    • 同样在函数GeometryVisualizer.prototype._insertUpdaterIntoBatch中,将updater传递到StaticGeometryColorBatch.prototype.add函数中

      this._closedColorBatches[shadows].add(time, updater);
      

      [图片]

    • StaticGeometryColorBatch.prototype.add先创建polygon对应的instance

    const instance = updater.createFillGeometryInstance(time);
    
    • StaticGeometryColorBatch.prototype.add中,调用batch.add函数,传入instance,并写入字典this.geometry
    this.geometry.set(id, instance);
    

生成primitive

在循环中遍历所有的GeometryBatch对象,并update
[图片]

  1. 生成polygonOutline对应的primitive

    • 通过StaticOutlineGeometryBatch.prototype.update遍历solidBatchesLength属性,并update
      在这里插入图片描述
    • batch.update中生成primitive
      在这里插入图片描述
  2. 生成polygon对应的primitive

    • 通过StaticGeometryColorBatch.prototype.update调用updateItems函数,在其内部,遍历batchupdate
      [图片]

    • batch.update中生成primitive
      [图片]

时序图

  • 在这里我们附上整个过程的时序图,可以帮助大家更好的了解整个过程
    在这里插入图片描述

后续

  • 后面我们会进一步探索创建得到的primitive如何被渲染,并对比其和我们直接添加的primitive在组织结构上有什么区别

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/458815.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言中的内存函数你知道多少呢?

目录 ​编辑 1. memcpy的使用和模拟实现 1.1函数介绍 ​编辑 1.2函数的使用 1.3模拟实现 2. memmove的使用和模拟实现 2.1函数介绍 2.2函数的使用 2.3模拟实现 3. memset函数的使用 3.1函数介绍 3.2函数的使用 ​编辑 4. memcmp函数的使用 4.1函数介绍 4.2函数…

漏电流的检测要求和理解

漏电流的检测要求和理解 简介漏电流的产生和效应标准要求漏电流的试验漏电流与电磁兼容的关系小结 简介 漏电流是指非功能性电流&#xff0c;是非期望的会引起安全方面危险的电流。漏电流表明了设备中电气绝缘起到防电击作用具有的性能&#xff0c;以使穿过电气绝缘的电流控制…

基于spring cloud alibaba的微服务平台架构规划

平台基础能力规划&#xff08;继续完善更新…&#xff09; 一、统一网关服务&#xff08;独立服务&#xff09; 二、统一登录鉴权系统管理&#xff08;独立服务&#xff09; 1.统一登录 2.统一鉴权 3.身份管理 用户管理 角色管理 业务系统和菜单管理 部门管理 岗位管理 字典管…

3D Slicer-最强大的开源医学图像分割工具简要概述

3D Slicer-最强大的开源医学图像分割工具简要概述 本系列涵盖从 3D Slicer 医学图像查看器的基础使用到高级自动分割扩展程序的内容&#xff08;从入门到高阶&#xff01;&#xff09;&#xff0c;具体包括软件安装、基础使用教程&#xff0c;自动分割扩展&#xff08;totalse…

CTFshow web(php命令执行 37-40)

?ceval($_GET[shy]);&shypassthru(cat flag.php); #逃逸过滤 ?cinclude%09$_GET[shy]?>&shyphp://filter/readconvert.base64-encode/resourceflag.php #文件包含 ?cinclude%0a$_GET[cmd]?>&cmdphp://filter/readconvert.base64-encode/…

NLP_Seq2Seq编码器-解码器架构

文章目录 Seq2Seq架构构建简单Seq2Seq架构1.构建实验语料库和词汇表2.生成Seq2Seq训练数据3. 定义编码器和解码器类4.定义Seq2Seq架构5. 训练Seq2Seq架构6.测试Seq2Seq架构 归纳Seq2Seq编码器-解码器架构小结 Seq2Seq架构 起初&#xff0c;人们尝试使用一个独立的RNN来解决这种…

Page246~250 11.1GUI下的I/O基础

11.1.1 从“控制台”说起 “命令行交互界面”&#xff08;简称CUI,也有人称为CLI)。 CUI需要我们记忆并在控制台输入命令文本内容&#xff0c;而GUI则以图形的方式呈现、组织各类命令&#xff0c;比如Windows的“开始”菜单&#xff0c;用户只需通过简单的键盘或鼠标操作&am…

登录+JS逆向进阶【过咪咕登录】(附带源码)

JS渗透之咪咕登录 每篇前言&#xff1a;咪咕登录参数对比 captcha参数enpassword参数搜索enpassword参数搜索J_RsaPsd参数setPublic函数encrypt加密函数运行时可能会遇到的问题此部分改写的最终形态JS代码&#xff1a;运行结果python编写脚本运行此JS代码&#xff1a;运行结果&…

hummingbird,一个非常好用的 Python 库!

前言 随着人工智能和机器学习的快速发展&#xff0c;将训练好的模型部署到生产环境中成为了一个重要的任务。而边缘计算设备&#xff0c;如智能手机、嵌入式系统和物联网设备&#xff0c;也需要能够运行机器学习模型以进行实时推理。Python Hummingbird 是一个强大的工具&…

【图形学】投影和消隐简介

投影 正交投影 对于物体上任意一点的三维坐标P(x,y,z),投影后的三维坐标为 P ′ ( x ′ , y ′ , z ′ ) P^\prime(x^\prime,y^\prime,z^\prime) P′(x′,y′,z′),那么正交投影的方程为 { x ′ x y ′ y z ′ 0 \begin{cases} x^\primex\\y^\primey\\z^\prime0 \end{case…

做跨境电商需要使用住宅代理IP吗?

住宅代理IP是近年来跨境电商领域日益受到重视的技术工具&#xff0c;不仅可以保护隐私、优化网络速度&#xff0c;还能助推跨境电商的精细化管理。接下来&#xff0c;我们将深入探讨利用住宅代理IP如何为跨境电商业务带来竞争优势。 一、住宅代理IP与跨境电商 住宅代理IP&…

flex:1最后一行或者只有一行时不想占满整行

flex:1最后一行或者只有一行时不想占满整行 问题解决方法注意 问题 在设置flex1的时候&#xff0c;如果内容只有一行或者多行的最后一行的时候&#xff0c;往往最后一行会占满整行&#xff0c;导致项目比其他行宽&#xff0c;比如&#xff1a; 解决方法 这时候我们可以使用…