cesium中如何高性能渲染3D模型(附水淹分析模拟)

2024-06-20 17:36

本文主要是介绍cesium中如何高性能渲染3D模型(附水淹分析模拟),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

大家好,我是日拱一卒的攻城师不浪,专注可视化、数字孪生、前端、nodejs、AI学习、GIS等学习沉淀,这是2024年输出的第18/100篇文章;

前言

之前在参加城市应急数字孪生项目开发过程中,遇到一个场景,就是模拟水淹分析

也就是说,甲方需要根据你这个平台,在下暴雨的时候,精准监测到城市具体方位的水淹情况,根据大数据推算并精准预警,能够提前监测到风险,防患于未然。

当时的三维渲染引擎用的是Unreal,今天,我将用cesium实现这样的场景模拟,主要需要两大步:

  1. 加载3D模型,也就是建筑物;
  2. 渲染水面并根据时间推移模拟淹没动画

cesium水淹模拟

加载3D瓦片

首先我们需要加载实体建筑物,这回我们用3D瓦片去渲染模型。

什么是3D瓦片数据?

在Cesium中,3D瓦片数据(3D Tiles)是一种用于高效存储和传输大规模3D场景数据的格式。这种格式允许开发者将复杂的3D模型、建筑物、地形以及其他场景元素以瓦片的形式进行组织和渲染。

主要优点

  • 层次化结构:3D瓦片数据以层次化的方式组织,类似于地图瓦片,这样可以在不同的缩放级别上提供不同的细节级别,从而优化渲染性能

  • 异步加载:3D瓦片数据支持异步加载,这意味着可以在用户浏览场景时逐步加载所需的数据,减少初始加载时间。

  • 多级细节(LOD):每个瓦片可以包含多个细节级别,根据摄像机与瓦片的距离动态调整显示的细节,提高渲染效率。

  • 多种数据格式支持:3D瓦片可以包含多种类型的数据,如点云数据多边形网格实例化模型等。

  • 优化的存储:3D瓦片数据格式针对网络传输进行了优化,能够高效地压缩和传输数据。

  • 交互性:用户可以与3D瓦片数据进行交互,例如点击选择查询场景中的元素。

  • 扩展性:3D瓦片数据支持扩展,允许开发者添加自定义属性和功能。

瓦片数据格式示例

{"asset": {"version": "1.0", // 3D Tiles 版本"tilesetVersion": "1.0" // 瓦片集版本},"geometricError": 10, // 瓦片的几何误差,用于确定瓦片的渲染精度"root": { // 根节点定义"boundingVolume": { // 根节点的边界体积"region": [ // 地区定义,包含经纬度和高度范围-122.4, // 西经37.7,   // 北纬-122.1, // 东经37.8,   // 南纬0,      // 最小高度100     // 最大高度]},"geometricError": 5, // 子瓦片的几何误差"refine": "ADD", // 细化策略,"ADD"表示子瓦片是可选的"children": [ // 子瓦片列表{"boundingVolume": {"box": [ // 子瓦片的边界盒[-122.4, 37.7, 0],[-122.1, 37.8, 100]]},"geometricError": 2, // 子瓦片的几何误差"content": { // 瓦片内容定义"url": "0/0/0.b3dm" // 子瓦片的URL,指向.b3dm文件}}// 其他子瓦片...]}
}

在这个示例中,我们定义了一个3D Tiles瓦片集的根节点,包括:

  • asset: 包含瓦片集的版本信息。
  • geometricError: 瓦片的几何误差,用于确定瓦片的渲染精度。
  • root: 定义了瓦片集的根节点,包括:
  • boundingVolume: 根节点的边界体积,这里使用了一个地区定义。
  • geometricError: 子瓦片的几何误差。
  • refine: 细化策略,可以是"ADD"或"REPLACE"。
  • children: 子瓦片列表,每个子瓦片都有自己的边界体积和内容定义。

每个子瓦片可以是一个更小的瓦片集,具有自己的边界体积几何误差和内容定义。

content字段的url指向实际的3D内容文件,通常是.b3dm格式,这是3D Tiles中用于存储3D模型数据的二进制文件格式。

好了,了解完瓦片是什么,接下来让我们用瓦片数据去绘制一个建筑物。

要用到Cesium.Cesium3DTileset大类去加载瓦片数据

Cesium3DTileset

Cesium3DTileset:一个3D Tiles 瓦片集,用于流式传输海量异构3D地理空间数据集。

API一览直达:http://cesium.xin/cesium/cn/Documentation1.95/Cesium3DTileset.html?classFilter=Cesium3DTileset

const set3Dtitle3 = () => {let translation = Cesium.Cartesian3.fromArray([0, 0, 0]);let m = Cesium.Matrix4.fromTranslation(translation);const url = "http://data.mars3d.cn/3dtiles/max-fsdzm/tileset.json";let tilesetJson = {url,modelMatrix: m,show: true, // 是否显示图块集(默认true)skipLevelOfDetail: true, // --- 优化选项。确定是否应在遍历期间应用详细级别跳过(默认false)baseScreenSpaceError: 1024, // --- When skipLevelOfDetailis true,在跳过详细级别之前必须达到的屏幕空间错误(默认1024)maximumScreenSpaceError: 32, // 数值加大,能让最终成像变模糊---用于驱动细节细化级别的最大屏幕空间误差(默认16)原128skipScreenSpaceErrorFactor: 16, // --- 何时skipLevelOfDetail是true,定义要跳过的最小屏幕空间错误的乘数。与 一起使用skipLevels来确定要加载哪些图块(默认16)skipLevels: 1, // --- WhenskipLevelOfDetail是true一个常量,定义了加载图块时要跳过的最小级别数。为 0 时,不跳过任何级别。与 一起使用skipScreenSpaceErrorFactor来确定要加载哪些图块。(默认1)immediatelyLoadDesiredLevelOfDetail: false, // --- 当skipLevelOfDetail是时true,只会下载满足最大屏幕空间错误的图块。忽略跳过因素,只加载所需的图块(默认false)loadSiblings: false, // 如果为true则不会在已加载完概况房屋后,自动从中心开始超清化房屋 --- 何时确定在遍历期间skipLevelOfDetail是否true始终下载可见瓦片的兄弟姐妹(默认false)cullWithChildrenBounds: false, // ---优化选项。是否使用子边界体积的并集来剔除瓦片(默认true)cullRequestsWhileMoving: false, // ---优化选项。不要请求由于相机移动而在返回时可能未使用的图块。这种优化只适用于静止的瓦片集(默认true)cullRequestsWhileMovingMultiplier: 10, // 值越小能够更快的剔除 ---优化选项。移动时用于剔除请求的乘数。较大的是更积极的剔除,较小的较不积极的剔除(默认60)原10preloadWhenHidden: true, // ---tileset.show时 预加载瓷砖false。加载图块,就好像图块集可见但不渲染它们(默认false)preloadFlightDestinations: true, // ---优化选项。在相机飞行时在相机的飞行目的地预加载图块(默认true)preferLeaves: true, // ---优化选项。最好先装载叶子(默认false)maximumMemoryUsage: 2048, // 内存分配变小有利于倾斜摄影数据回收,提升性能体验---瓦片集可以使用的最大内存量(以 MB 为单位)(默认512)原512 4096progressiveResolutionHeightFraction: 0.5, // 数值偏于0能够让初始加载变得模糊 --- 这有助于在继续加载全分辨率图块的同时快速放下图块层(默认0.3)dynamicScreenSpaceErrorDensity: 10, // 数值加大,能让周边加载变快 --- 用于调整动态屏幕空间误差的密度,类似于雾密度(默认0.00278)dynamicScreenSpaceErrorFactor: 1, // 不知道起了什么作用没,反正放着吧先 --- 用于增加计算的动态屏幕空间误差的因素(默认4.0)dynamicScreenSpaceErrorHeightFalloff: 0.25, // --- 密度开始下降的瓦片集高度的比率(默认0.25)foveatedScreenSpaceError: true, // --- 优化选项。通过暂时提高屏幕边缘周围图块的屏幕空间错误,优先加载屏幕中心的图块。一旦Cesium3DTileset#foveatedConeSize加载确定的屏幕中心的所有图块,屏幕空间错误就会恢复正常。(默认true)foveatedConeSize: 0.1, // --- 优化选项。当Cesium3DTileset#foveatedScreenSpaceError为 true 时使用来控制决定延迟哪些图块的锥体大小。立即加载此圆锥内的瓷砖。圆锥外的瓷砖可能会根据它们在圆锥外的距离及其屏幕空间误差而延迟。这是由Cesium3DTileset#foveatedInterpolationCallback和控制的Cesium3DTileset#foveatedMinimumScreenSpaceErrorRelaxation。将此设置为 0.0 意味着圆锥将是由相机位置及其视图方向形成的线。将此设置为 1.0 意味着锥体包含相机的整个视野,禁用效果(默认0.1)foveatedMinimumScreenSpaceErrorRelaxation: 0.0, // --- 优化选项。当Cesium3DTileset#foveatedScreenSpaceError为 true 时使用以控制中央凹锥之外的图块的起始屏幕空间误差松弛。屏幕空间错误将从 tileset 值开始Cesium3DTileset#maximumScreenSpaceError根据提供的Cesium3DTileset#foveatedInterpolationCallback.(默认0.0)// foveatedTimeDelay: 0.2, // ---优化选项。使用 whenCesium3DTileset#foveatedScreenSpaceError为 true 来控制在相机停止移动后延迟瓷砖开始加载之前等待的时间(以秒为单位)。此时间延迟可防止在相机移动时请求屏幕边缘周围的瓷砖。将此设置为 0.0 将立即请求任何给定视图中的所有图块。(默认0.2)luminanceAtZenith: 0.2, // --- 用于此模型的程序环境贴图的天顶处的太阳亮度(以千坎德拉每平方米为单位)(默认0.2)backFaceCulling: true, // --- 是否剔除背面几何体。当为 true 时,背面剔除由 glTF 材质的 doubleSided 属性确定;如果为 false,则禁用背面剔除(默认true)debugFreezeFrame: false, // --- 仅用于调试。确定是否应仅使用最后一帧的图块进行渲染(默认false)debugColorizeTiles: false, // --- 仅用于调试。如果为 true,则为每个图块分配随机颜色(默认false)debugWireframe: false, // --- 仅用于调试。如果为 true,则将每个图块的内容渲染为线框(默认false)debugShowBoundingVolume: false, // --- 仅用于调试。如果为 true,则为每个图块渲染边界体积(默认false)debugShowContentBoundingVolume: false, // --- 仅用于调试。如果为 true,则为每个图块的内容渲染边界体积(默认false)debugShowViewerRequestVolume: false, // --- 仅用于调试。如果为 true,则呈现每个图块的查看器请求量(默认false)debugShowGeometricError: false, // --- 仅用于调试。如果为 true,则绘制标签以指示每个图块的几何误差(默认false)debugShowRenderingStatistics: false, // --- 仅用于调试。如果为 true,则绘制标签以指示每个图块的命令、点、三角形和特征的数量(默认false)debugShowMemoryUsage: false, // --- 仅用于调试。如果为 true,则绘制标签以指示每个图块使用的纹理和几何内存(以兆字节为单位)(默认false)debugShowUrl: false, // --- 仅用于调试。如果为 true,则绘制标签以指示每个图块的 url(默认false)dynamicScreenSpaceError: true, // 根据测试,有了这个后,会在真正的全屏加载完之后才清晰化房屋 --- 优化选项。减少距离相机较远的图块的屏幕空间错误(默认false)};const tileset = new Cesium.Cesium3DTileset(tilesetJson);// 非异步加载viewer.scene.primitives.add(tileset);// 定位到瓦片渲染的模型位置viewer.flyTo(tileset);tileset.allTilesLoaded.addEventListener(function () {console.log("模型已经全部加载完成");});
};
set3Dtitle3();

瓦片数据中已经包含了位置信息,因此我们不用关心这个模型要放在哪里,只需要相机定位到模型即可。

模拟水面

这里我们直接使用entities去构建一个几何多边形,然后赋予水的颜色,或者说直接用动态水的材质都可以(后者效果要逼真一些)。

这期我们先用第一种方法,画出水之后,我们要做水位不断上升的动画。

let waterEntity = null;
let waterTimer = null;
const onStart = () => {// 几何体的顶点坐标const waterCoord = [121.48033090358801, 29.790483294870796, 0, 121.4778771950879,29.79083578574342, 0, 121.47877939338282, 29.79193540741442, 0,121.4804061804202, 29.791480141327728, 0,];let startHeight = 10; // 几何体初始高度const targetHeight = 20; // 几何体最终的高度waterEntity = viewer.entities.add({polygon: {hierarchy: Cesium.Cartesian3.fromDegreesArrayHeights(waterCoord),material: Cesium.Color.fromBytes(64, 157, 253, 200),perPositionHeight: true,// 不断监听startHeight的值的变化而更新集合体的高度extrudedHeight: new Cesium.CallbackProperty(() => {return startHeight;}, false),},});// 模拟水位上升的动画,改变startHeight的值waterTimer = setInterval(() => {if (startHeight < targetHeight) {startHeight += 0.1;if (startHeight >= targetHeight) {startHeight = targetHeight;clearInterval(waterTimer);}// 使用该方式会闪烁,改用 Cesium.CallbackProperty 平滑// this.waterEntity.polygon.extrudedHeight.setValue(startHeight)}}, 50);
};

OK,这时只要执行onStart方法,就可看到水位不断上升的效果了,并且水面会自动根据高程淹没不同高度的建筑物体。

总结

实际上,模拟水淹或者洪水演进,如果再逼真和有效一点的话,需要根据IOT的数据回传加上算法推算,例如三角顶点每个顶点的高程的动态变化,每个顶点的颜色变化,动态绘制三角面组成更真实的场景。

【开源地址】:https://github.com/tingyuxuan2302/cesium-vue3-vite/blob/github/src/views/scene/waterFlood.vue

有需要进技术产品开发交流群(可视化&GIS)可以加我:brown_7778,也欢迎数字孪生可视化领域的交流合作。

最后,如果觉得文章对你有帮助,也希望可以一键三连👏👏👏,给开源点点star,你的鼓励是支持我持续开源和分享下去的动力~

这篇关于cesium中如何高性能渲染3D模型(附水淹分析模拟)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1078799

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

usaco 1.2 Transformations(模拟)

我的做法就是一个一个情况枚举出来 注意计算公式: ( 变换后的矩阵记为C) 顺时针旋转90°:C[i] [j]=A[n-j-1] [i] (旋转180°和270° 可以多转几个九十度来推) 对称:C[i] [n-j-1]=A[i] [j] 代码有点长 。。。 /*ID: who jayLANG: C++TASK: transform*/#include<

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

MySQL高性能优化规范

前言:      笔者最近上班途中突然想丰富下自己的数据库优化技能。于是在查阅了多篇文章后,总结出了这篇! 数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符 临时库表必须以tmp_为前缀并以日期为后缀,备份

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}