一转眼自上一篇文章已经过去半年之久,承诺的CesiumJS的天气文章竟然又又又又跳票了,没办法。开发任务时间紧,任务重。GIS的进一步整合进入深水区,每向前迈一步都是步履维艰,好不容易把体积雾,接触阴影,云影,眼部适应的功能整合完了,正打算把这篇鸽了半年的天气整合文章给补上。不料突然刷到体积云渲染的祖师爷-Guerrilla Games,也就是《地平线》游戏的制作团队,竟然又在SIGGRAPH 2022和SIGGRAPH 2023发了两篇升级体积云的渲染文章。本着宁可累死自己,也要卷死同行的国际主义精神,必须研究下看看能不能再提升一下山海鲸云层的渲染效果。
看完之后确实感慨国际友人的分享精神。对于一些性能上的提升点,确实需要慢慢消化。同时关于地形云层和风暴云层暂时在孪生和GIS系统中用的还不多,最让我心动的便是这个卷云了。
什么,这个云的名字怎么都这么卷?我们先看看这个云家族中的卷王长什么样子:
卷云
可以看到卷云其实我们在生活中还是非常常见的,特点就是又高又卷,非常符合我们产品的气质。那说干就干,看看如何结合到现有的云层渲染当中。
1.分层渲染
首先从ppt中可以看到,新的算法拆分了两个渲染层,分别是Cirrus Sub-Layer和 Stratus Sub-Layer,其中这个Cirrus Sub-Layer就是我们这次的主角卷云层。
虽说它山之石可以攻玉,但他山之代码那是真不好直接整合,之前写到半死的体积云步进算法如果直接按照这个算法拆分,这个工作量下去怕是又是10杯超大杯的咖啡因都叫不醒了。为了快速整合,我们对这个算法进行简化,在原来的步进过程中取height为最高处10%的采样点作为卷云层的采样点,剩下的90%的高度重映射为100%之后作为原算法的采样输入,这样只需要在采样函数这里做一次分支就可以几乎不动代码的将卷云层加入进来。
2. 卷云层建模
之前的体积云建模核心都是采用3d的Perlin-Worley噪声材质来建模的。卷云层在ppt中被称为2.5d,建模无需3d材质,只需要2d噪声材质即可。作者还贴心的公布了3种卷云的噪声材质,我这里也很贴心的帮大家处理进了一张贴图的三个通道:
卷云的噪声贴图
我测了一个发现这三张贴图竟然都不是无缝贴图,不过似乎也并不影响最终的渲染效果,因此也就不做过多处理了。
贴图处理好之后,就是采样算法了,这个代码ppt里也写了,直接拿来用。
float density = ValueRemap(cloud_type, 0.5, 1.0, ValueRemap(cloud_type, 0.0, 0.5, cr_streaky, cr_wispy), cr_round);
density = pow(density, 1.0 - ValueRemap(cloud_coverage, 0.0, 1.0, -0.9, 0.9));
density *= ValueRemap(pow(cloud_coverage, 3.0), 0.0, 0.5, 0.0, 1.0);
唯一的问题是山海鲸现在的云层是完全随机生成的,并没有先生成类似他的NDF的文件,因此这里暂时先不处理不同卷云融合的情况,就把三种卷云分开做吧。(将来也许要做云层笔刷,再把这口锅甩给设计)。
3. 卷云层光照
卷云层光照几乎完全复用其他云层光照的代码,唯一的区别就是步进次数可以减少为4次,这里就不再赘述了。
最后看一下整合后的效果,卷云的类型可以选择条纹状,絮装和点状(请原谅我草率的翻译):
条纹状卷云
絮状卷云
点状卷云
再结合之前的体积云效果可以得到更加逼真的天空效果。
积雨云叠加条纹状卷云
虽然通过一定程度的Hack很快速的把卷云整合到了系统中来,也带来了一个小的弊端,就是步进的距离被拉长了,这样当步进步数不够的时候,就会出现非常强烈的闪烁,特别是在地平线附近距离相机很远的地方会非常严重,目前只能通过增加步进步数解决,将来看估计还是得拆分成两个layer进行分别步进才有可能解决这个问题。
最新的卷云功能将在山海鲸可视化4.2.0版本中与大家见面,欢迎大家前往下载体验。