GIS融合之路(七)-Cesium实现夜空月亮星星渲染

系列传送门:

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

山海鲸可视化:GIS融合之路(二)CesiumJS和ThreeJS深度缓冲区整合

山海鲸可视化:GIS融合之路(三)CesiumJS和ThreeJS相机同步

山海鲸可视化:GIS融合之路(四)如何用CesiumJS做出Cesium For Unreal的效果

山海鲸可视化:GIS融合之路(五)给CesiumJS加上体积云(Volumetric Cloud)和高度雾(Height Fog)

山海鲸可视化:GIS融合之路(五)番外-山海鲸的体积云又又又升级了

山海鲸可视化:GIS融合之路(六)-Cesium的雨雪风雷电效果

本来没打算写到第七篇,但最近山海鲸的GIS夜景被同事们吐槽的厉害,说GIS白天很不错 但是夜景效果很一般。人嘛,一定要知耻而后勇。在严词拒绝了同事们升级夜空的诉求之后,便默默地开始了夜空渲染的研究。

开始之前我们还是有必要先回顾一下山海鲸中Cesium整合天空各个元素的效果:

白天效果

 夕阳效果

要知道,山海鲸是完全基于WebGL的渲染引擎,特效全靠手搓,而目前白天完全可以比肩了游戏引擎的视觉能力了(这里必须吐槽一下那些套壳UE的同行,明明底层就用UE,竟然好意思说自己比UE好)。有兴趣的朋友可以下载一下我们的软件试试我们的天空效果,山海鲸的编辑功能是完全免费的:山海鲸可视化-免费的零代码数字孪生可视化大屏开发平台

好了,咱们正式进入正文,话说在之前的技术调研中,写白天大气散射和体积云渲染的文章可以说是多如牛毛,具体可以参考我前面的系列文章。但写夜空渲染的文章竟然一个没有。同时UE和Unity似乎也对夜空渲染不感兴趣,在官方的天空中都没有整合夜空的逻辑。UE新版大气散射的介绍视频中倒是提了一句:“如果要做夜空只需要整合一张星空贴图即可”。Unity的官方Roadmap中也有提到说很难用基于物理的方式来实现夜空,因此打算提供一些艺术家向的设置来实现夜空的渲染。真正有意义的也只有几篇关于夜空渲染的论文,却也没有见到什么像样的代码实现。

在开始之前,我们值得先讨论一个问题,为什么夜空的渲染文章这么少呢?我想主要有以下几个方面的原因:

1.需求不够大,对于传统游戏来说,日景要比夜景更常用,毕竟晚上都不太看得清,只能作为辅助玩法,不能作为主线。夜晚的天空盒子也就够用了。

2.基于物理渲染的夜景大概率是全黑的,除了星星和月亮,没有太多细节。

3.目前的夜空拿白天的天空改改艺术向的一些设置就能实现了。

总结来说也就是说费劲巴拉的真的按照物理方式去渲染夜空,可能还不如改改艺术向设置让人觉得真实,性能还更好。这里也可见计算机图形学第一定律在发挥作用了:如果它看上去是对的,那么它就是对的。

那山海鲸还做不做夜空渲染呢?那肯定还是要做的。我们的产品理念是要帮用户把复杂的技术细节屏蔽掉,我们的用户和游戏引擎的用户不一样,游戏引擎可以要求用户去改亮度,改大气散射粒子浓度。而山海鲸则希望客户什么都不改就能用。因此我们还是得从目前仅有的论文开始看起:

对于渲染来说,最重要的是光源。那么我们先看下夜晚的光源都有些什么,这里我们贴一下论文中的天空光源强度和光源类型:

 

从左至右分别是黄道光,星光和气辉

可以看到满月相对其他夜空光源来说是具有统治地位的,而黄道光,星光和气辉逐步降低,再往后我都不知道是啥了。这里我们要发挥一下图形学神功的精髓-大胆而无耻的假设,除了月光,其他就先当做不存在。

好了做完的这个假设,问题变的简单的,夜空和日空是很类似的,单光源结合大气散射即可,是不是可以直接复用日空的代码,把亮度调小10的六次方即可了呢,显然这里还有两个细节问题值得探讨:

1.夜空亮度调小10的六次方,那么基本上就是纯黑了,那为什么人类夜晚能看到夜空呢?这里必须引入一个新的概念就是人眼的自动适应,本质是人眼在暗场景中的自动调高曝光的功能。这个功能在UE和我们山海鲸中都有实现。但如果客户没有开自动曝光,有必要主动调亮夜空亮度,做一个艺术向的处理,不能直接用10的六次方的差异。

2.太阳和月亮的尺寸差异还有距离地球的远近差异极大,太阳光我们可以假设成为平行光,但月亮假设为平行光就有些不妥了。因此虽然太阳光在大气层内每一个位置上都可以认为是方向不变的,月亮光却不可以。但这个显然大幅增加的Shader的适配成本,相当于要为月亮再单独写一套逻辑,这里我们要再次发挥一下图形学神功的精髓,假设月光也是平行光。

好了做了这么多无耻的假设我们终于可以用极小的成本适配夜空了,但目前做的本质上和艺术向的设置没有区别。只是调暗主光源光强即可,当然我们需要同步适配大气散射和高度雾的光强。调完之后,我们看下现在的效果:

看着还算可以接受夜空效果

我们把体积云也调整好光强后叠加上来:

加上体积云的夜空

现在的夜空基本已经到了可以勉强接受的范围,但没有月亮和星星的夜空是没有灵魂的,那么我们先参照UE视频中的说法,在夜空的基础上叠加星空Cubemap,同时我们用一个remap函数来控制星空的稠密与否:

nightLuminance += smoothstep(vec3(1. - starry),vec3(1.),starLuminance);

叠加后的效果如下:

 叠加星空后的效果

最后我们再实现月亮,月光的光照其实就是一个简单的球体,如下:

 

我们这里为了整合在天空中一起渲染,因此不能单独用一个球来贴图。我们通过RayIntercept函数来处理球体的渲染:具体是先计算好Ray和月球的交点后,再用交点计算当前点位的法线。最后我们通过控制incoming light的方向来实现月相效果。为了能让大家更好的观察月亮,我们还提供了一个放大月球的功能,效果如下:

月亮升起

 

 月相变化

 

 月球放大,可以看到通过法线实现的环形山效果

 

到这一步夜空基本就已经实现完了,最后还有一个小细节,那就是实际上在夕阳的时候,我们就已经能够看到星空的,不是一定要等到晚上才有。因此我们在太阳接近落山的时候,就选择开始叠加星空贴图:

这样可以进一步增强清晨和黄昏的视觉层次感。到此,整个山海鲸的夜空实现就已经全部完成了,而空气透视和Cesium系统已经自动叠加,因此不需要再做更多的处理就可以很好的和gis系统融合在了一起。

当然还有很多工作值得进一步来做:

1.取消月光是平行光的假设

2.气辉和极光,其实山海鲸第一版的动态天空就有极光,不过确实对于数字孪生来说不是特别适合,毕竟北极不做数字孪生~,气辉倒是后续可以加上进行设置

3.添加夜景中城市灯光和空气污染的影响,这样在城市场景中会让整个画面更加统一。

posted @ 2024-05-11 09:23  山海鲸可视化  阅读(208)  评论(0编辑  收藏  举报