首页 > 其他分享 >GIS融合之路(二)CesiumJS和ThreeJS深度缓冲区整合

GIS融合之路(二)CesiumJS和ThreeJS深度缓冲区整合

时间:2024-01-13 11:46:41浏览次数:23  
标签:ThreeJS GIS 山海 CesiumJS depth 深度 缓冲区

在这篇文章开始前再次重申一下,山海鲸并没有使用ThreeJS引擎。但由于ThreeJS引擎使用广泛,下文中直接用ThreeJS同CesiumJS的整合方案代替山海鲸中3D引擎和CesiumJS整合。

系列传送门:

山海鲸可视化:GIS融合之路(一)技术选型CesiumJS/loaders.gl/iTowns?

文章开始之前大家可以看下这个视频当中山海鲸中CesiumJS与山海鲸深度整个的结果,图片中展示了Cesium的地形和山海鲸中的水面的整合,这个过程中就有一个完整的深度缓冲区的整合:

具体内容可以移步完整的视频教程查看:

【山海鲸可视化GIS系统】第三课 GIS地形编辑_哔哩哔哩

感兴趣朋友也欢迎下载软件试一试:山海鲸可视化-一站式数字孪生开发平台-海量数据可视化大屏模板

上一篇文章里简单介绍了山海鲸中城市大师为了整合GIS系统所做的技术选型的探索,最终我们决定采用先后绘制的形式在单个Canvas上整合山海鲸的3D引擎和CesiumJS。那有同学要问了,如果一个先画,一个后画,后画的不就把先画的覆盖了吗?这里我们就要学到深度缓冲区的概念了。

深度缓冲区也称之为DepthBuffer,是GPU为了对光栅化渲染时物体的遮挡关系进行排序用到的概念。概念本身很简单,就是每绘制一个物体的同时,把这个物体在每一个像素点上的深度信息与这个像素点之前的深度信息进行对比,如果这个像素点的深度较小(注意这要看具体深度缓冲的DepthFunction,一般在WebGL上默认是最大的是Depth是1,因此越小越近)则继续渲染像素颜色,否则直接丢弃。

有了深度缓冲区,问题就变得简单了,让CesiumJS先画,山海鲸引擎后画。只要保证深度写入和深度测试都是默认打开的,那不就万事大吉了。Done,下班!

等等,好像有问题;等等,好像有不少问题!等等,好像完全不行....

问题可是真不少,咱还得一关一关的过啊:

1.CesiumJS默认用的LogarithmicDepth,而普通的3D引擎默认用的是LinearDepth

按说这也不是什么大问题,CesiumJS支持修改Scene上的logarithmicDepthBuffer改成linearDepth,Threejs这类也基本都实现了LogarithmicDepth,因此不是大问题。不过由于CesiumJS一般都是大场景和超大场景,改成Linear的话一定会有严重的Z-Fighting,而ThreeJS这类主要是小场景,改成LogarithmicDepth,又会导致在近景部分depth精度不足。当然希望近景和远景同时完美,本身在技术上也是鱼和熊掌的问题,我们暂时不去深入解决这个问题。

2.CesiumJS默认的渲染方式是距离切段后逐段渲染

这条就非常坑了,CesiumJS默认会将整个相机裁切空间(近平面到远平面之间的空间)分成多段,然后逐段渲染。这样做的好处显而易见,可以进一步拓展Depth的利用率,非常适合CesiumJS这种知道所有模型的位置且不会有体积超出范围的大模型的情况。然后每次分段绘制结束之后,depth的信息就会被清除。这就导致我们最开始规划的深度缓冲区整合的方案完全无法使用(除非关闭这个分段绘制机制),只能采用新的方案。

3.CesiumJS绘制过程无法嵌入

CesiumJS绘制过程机制相当复杂,想要找到一个合适的时机将ThreeJS这类引擎的绘制过程嵌入进去非常困难,而且也没有对应的接口,写起来对CesiumJS代码侵入性极强,后续CesiumJS升级时很难跟随升级,为将来的可维护性留下很深的隐患。

综合这三个问题,最终决定不再让CesiumJS直接绘制到Canvas上,而是采用CesiumJS提供的PostProcessStage接口将整个绘制的ColorBuffer和DepthBuffer都存入FrameBuffer当中,在ThreeJS中再将这两个FrameBuffer转换为WebGLRenderTarget。通过这两种方式就可以拿到CesiumJS的绘制结果。

将CesiumJS的绘制结果转换为两个Texture之后,就要在ThreeJS端绘制进去。这个过程类似PostProcess的过程,但是要先做。这里参考CesiumJS中的ViewportQuad接口,在ThreeJS中创建一个PlaneGeometry,设置一个ShaderMaterial,在VetexShader中,将四个点对齐到整个视口的四个角上,实现代码非常简单。

void main() {
  gl_Position = vec4( position.x, position.y, 1., 1. );
}

在FragmentShader当中读入ColorBuffer和DepthBuffer

uniform sampler2d czmColorSampler;
uniform sampler2d czmDepthSampler;

ColorBuffer直接写入,非常简单,depth如何写入呢。

首先我们要明确我们从CesiumJS拿到的是什么depth,查看Cesium源码可以发现,我们拿到的depth是LogarithmicDepth被映射到0~1之间之后被pack在rgba四个通道上之后的结果。因此我们首先要对CesiumJS的depth进行unpack,并且根据相机的near和far将depth恢复到相机空间的z距离。拿到这个距离之后为了方便存储,山海鲸目前的做法是将这个z距离再在自己引擎的相机中的near和far做一次映射,算出线性的0~1的depth,这样就可以和自己引擎中拿到的depth一致了,当然为了提高精度,也pack到rgba中去。最终得到的结果存入czmDepthSampler,具体结果如下图所示:

czmColorSampler czmDepthSampler 最终合成图

这个结果理论上就可以直接和ThreeJS里的相机空间的depth进行对比了,但是注意我们这里并不打算在代码中对比,而是希望用GPU自己的深度缓冲区测试,这个怎么做呢?这里就要用到Shader的深度写入功能。一般来说GPU在拿到vetexShader中的gl_Position之后会自己把得到的坐标转换到NDC空间中,并进一步将depth映射到0~1之间,再存入depth buffer。

WebGL中转换前和转换后坐标

我们需要再FragmentShader中接管这个功能,WebGL也提供的接口:gl_FragDepth。(但是要特别注意的是,一旦开启Shader的深度缓冲区写入,GPU的early-Z优化就会自动关闭,所有的像素点着色都会进行,因此不是我们这种迫不得已的情况,还是尽量不要用的。)有了这些知识,我们只需要最后将线性空间的depth模拟GPU的计算过程,转换为ndc空间的depth写入就可以了。

我们通过以上方式正式将Cesium的渲染过程并入了山海鲸引擎的渲染过程当中,当然这中间还要处理很多gl state状态的问题,不过不管怎样,最难的一步已经越过去了,剩下的就是对目前的机制进行完善,防止状态冲突问题即可。但是深度整合成功是不是Cesium就整合完成了呢,正式成为了山海鲸可视化的一部分?答案显然是否定的,现在的Cesium除了遮挡正常了以外,相机还没有同步,一旦移动,就会发现完全对不上位置。另外除了相机起码还有3个比较大问题:1.阴影的整合 2.光照的整合 3.G-buffer管线数据的同步。别急,我们一步一步来,后面的文章逐个给大家展开这些问题的处理。

标签:ThreeJS,GIS,山海,CesiumJS,depth,深度,缓冲区
From: https://www.cnblogs.com/shanhaibi/p/17962162

相关文章

  • GIS融合之路(一)技术选型CesiumJS/loaders.gl/iTowns
    大家好,我是山海鲸的技术负责人。今天来和大家分享一下山海鲸可视化在数字孪生系统当中对GIS系统的整合之路,大家可以移步视频教程中看一下目前的整合效果。【山海鲸可视化GIS系统】第六课GIS与数字孪生_哔哩哔哩熟悉山海鲸的朋友应该知道,山海鲸可视化在3.0之后,在软件内部整合了......
  • 如何在Linux上搭建本地Docker Registry并实现远程连接
    Hello,大家好我是咕噜铁蛋!当今,Docker已成为了广受欢迎的容器化解决方案。我们需要掌握Docker相关的技能,其中之一就是如何在Linux上搭建本地DockerRegistry并实现远程连接。我也通过科技手段整理了些,今天我将详细介绍如何在Linux上搭建本地DockerRegistry,并实现远程连接,......
  • GIS坐标系与投影
    GIS坐标系与投影笛卡尔坐标系空间直角坐标系空间直角坐标系是指坐标原点位于参考椭球的中心,Z轴指向参考椭球的北极,X轴指向起始子午面与赤道的交点,Y轴位于赤道面与X轴成90度夹角,并指向东,形成右手系。空间直角坐标系有右手系和左手系的区分:右手系右手系有两种表示方法,......
  • 删除Azure Container Registry中tag为null的容器镜像
    删除AzureContainerRegistry中tag为null的容器镜像近几年容器技术的蓬勃发展,越来越多的客户开始在Azure中使用AKS,ACR等容器相关的Azure服务,来满足其不断发展的业务使用需求。但随着时间的推移和业务复杂性的增长,很多客户都会发现,ACR中的某些Repo内,显示的清单计数和实际的清单数量......
  • Threejs——十四、关于深度冲突、重叠、以及加载模型进度条效果实现(附完整代码)
    深度冲突两个模型重叠的模型,通过浏览器旋转预览,会发现模型旋转的时候会发生闪烁。这种情况,主要是两个模型重合,电脑分不清谁在前谁在后,这种情况,可以理解为深度冲突Z-fighting。functionaddBox(){constgeometry=newTHREE.BoxGeometry(10,10,10);//材质constmater......
  • 使用 Docker Compose 部署 Docker Registry
    在内网环境中,我们期望能够在本地共享镜像。为了解决这一问题,DockerRegistry成为了我们的救星。DockerRegistry是一个用于存储和管理Docker镜像的开源工具。通过在本地部署DockerRegistry,您可以轻松地构建、存储和分享自己的Docker镜像。本文将详细介绍如何使用DockerCompose快......
  • ArcGIS打不开或者打开后就闪退怎么办?
      本文介绍ArcMap卡在加载界面,无法打开软件的多种解决方法。  最近,突然发现ArcMap软件打不开了,每次双击快捷方式后其会显示如下所示的加载界面,但是等待很久后加载界面消失,软件窗口却一直不弹出来。  此外,在电脑右下角的小图标区域,可以看到ArcGIS的图标原本会出现一段时间,......
  • CF566C Logistical Questions
    更好的阅读体验CF566CLogisticalQuestions好强的题,感觉完全想不到。如果对于每个点都计算答案的话复杂度是\(\mathcalO(n^2)\),但是由于题目中给了一个\(\frac{3}{2}\)次方这么一个非常恶心人的东西,这个算法基本没有优化空间,所以考虑换一种思路,先选择一个点,然后尝试对答案......
  • ArcGIS打开工具箱未响应问题
    有时,打开工具箱的工具时,出现未响应的情况,主要以下规律:(1)所有工具都可能出现这种情况,与工具的功能无关;(2)不是每一次都会出现这样的情况;(3)从目录窗口中打开工具会出现这种情况,从ArcToolbox窗口打开不会出现。不知道是什么原因,遇到这种情况,一般把程序缓冲文件删除后会解决。 ......
  • 初见threejs
    threejs底层封装了强大的webGL技术,让开发者们可以开箱即用(其实也并非开箱即用,还是挺麻烦的......