实时体积云渲染(地平线):一.云的生成

体积云一直是想尝试的一个东西,最近终于有点自己的时间,花了些功夫实现了“地平线”里用到的体积云算法。实现效果图如下(未加大气散射有空一定补上):

Fredrik的论文"Real-time rendering of volumetric clouds"对地平线的体积云算法做了稍微的调整,算是写的真的非常清晰了,本文依照他的方法展开实现。

算法总览

算法主体思路非常简单明了,1:生成体积云,2:计算光照模型。

生成体积云

想要在天空中绘制体积云,我们首先需要知道要在那里生成体积云,云朵有多高(厚度),云的密度如何。这里我们可是使用一项称为“天气图”的工具,它将云的位置信息保存在图的r通道和g通道,在b通道内保存最高云高,a通道保存云密度。表现形式如下:

上图展示了一种非常常见的积云(Cumulus)的天气图,积云效果如下:

不同的天气,云会有不同的表现,如层云(Stratus)的天气图:

对应的效果为:

其中稍微注意的是:a通道表示低频位置信息,我们可以理解为在非常远处看,这个地方有云。b通道表示高频位置信息,可以表示较近距离观察到云的具体分布。

在引入云的具体计算之前,我们需要用到一些基本的参数和函数:

:控制云出现的基本概率,

:控制云的总体密度,即不透明度,

:天气图的r通道,表示低频位置信息,

:天气图的g通道,表示高频位置信息,

:天气图的b通道,表示最高云高,

:天气图的a通道,表示云密度,

:当前采样点所在的云高相对于云总高的百分比,

重映射函数R(将v值从lo到ho映射为ln到hn):

clamp函数SAT(将值约束为[0,1]):

lerp线性插值函数Li:

这三个函数非常简单,代码如下:

//重映射函数R:将v从lo~ho映射为ln~hn。
float R(float v,float lo,float ho,float ln,float hn){return ln+(v-lo)*(hn-ln)/(ho-lo);
}//clamp函数
float SAT(float v){return clamp(v,0.0,1.0);
}//线性插值函数
float Li(float v0,float v1,float ival){return (1.0-ival)*v0+ival*v1;
}

接下来我们需要计算天空中的一点是否该出现云,该值为WMc,由计算得出:

总体形状函数:

解决云朵在哪里出现后,我们需要获取云朵的形状,我们想要云朵的出现不那么突然,我们设置一个底部渐入函数:

其中是当前采样点云高百分比,该函数就是将从[0,0.07]到[0,1]进行映射。

同样,我们对顶部也设置一个渐出函数:

该函数将从[0.2*,]到[1,0]进行映射。

我们最后的形状函数就为两个形状映射函数的乘积:

总体密度函数:

我们的云朵往往在底部会表现的非常蓬松,顶部有较锐利的形状,因此我们需要调整总体的密度分布,使其满足现实中云朵的表现特性。

我们首先设定一个底部密度渐入函数:

然后同样也有一个顶部的密度渐出函数:

最后联系上我们的天气图密度通道,以及全局密度常量,总体的密度分布函数为:

出现云概率,总体形状函数以及密度函数代码如下(可以根据喜好略微调整参数):

    //天气图信息:w_c0为云的低频覆盖率,w_c1为云高频覆盖率,w_h为最高云高,w_d为云密度float w_c0=cloud_Color.r;float w_c1=cloud_Color.g;float w_h=SAT(cloud_Color.b+0.12);float w_d=cloud_Color.a;//云出现的概率float WMc=max(w_c0,SAT(g_c-0.5)*w_c1*2.0);//确定云总体形状:SRb使底部扁平,SRt使向顶部渐淡。float SRb=SAT(R(p_h,0.0,0.07,0.0,1.0));float SRt=SAT(R(p_h,w_h*0.2,w_h,1.0,0.1));float SA=SRb*SRt;//确定云整体密度:DRb降低底部密度,DRt顶部密度淡出。float DRb=p_h*SAT(R(p_h,0.0,0.15,0.0,1.0));float DRt=SAT(R(p_h,0.9,1.0,1.0,0.2));float DA=g_d*DRb*DRt*w_d*2.0;

云朵细节函数:

到这一步,我们获得的云朵几乎没有任何的细节,如果直接将其绘制,获得这样的效果:

为了给云朵增加细节我们需要给云朵采样噪声。在云朵中最常用的噪声就是Perlin-Worley和Worley噪声,我们将在下一章详细介绍并实现这两个噪声。我们生成3D 的噪声如下图:

其中r通道为低频的Perlin-Worley噪声,g通道为中等频率的Worley噪声,b通道为高频Worley噪声,a通道为更高频的Worley噪声。这些噪声组成128*128*128的4通道3D噪声。我们通过采样该噪声,并加权其值,公式如下:

其中sn是我们采样的4通道噪声值。之后我们可以使用SNsample值去和总体形状参数SA去乘积,获得最后的形状值。再根据之前的参数计算最后采样点获取的密度SN,SN公式如下:

我们利用SN绘制出的效果如下图:

这已经有云的形状了,但是我们可能会觉得这云还是缺少细节,我们可在再增加一个3D的3通道32*32*32噪声图,形式如下:

我们仍然使用三个由低到高的Worley噪声。同样我们采样方式为:

其中dn为采样的3通道噪声。我们使用一个新的函数去修改细节噪声,函数如下:

其中e是自然数,细节噪声的整体影响降低到最大值的0.35*,其影响随着全局覆盖率增大而减小。并且线性插值确保云向底部更蓬松,向高处更陡峭。

现在我们最终获取密度d的函数为:

其中SNnd和SN几乎一样,只是未乘DA,其形式为:

利用新的采样值d我们绘制的云效果为:

由于电脑性能问题- -,采样步长只能设到80,更高的步长会产生更好的效果,但也就称不上实时了。

我们贴出获取密度的全部代码:

//计算密度
vec2 getDensity(vec3 samplePos,float p_h){samplePos=((samplePos)*world_texScale);vec4 cloud_Color=vec4(texture(weatherMap,(vec2(texOffset)+samplePos.xz)));vec4 sn=texture(noiseMap,mirror(16*samplePos));vec3 dn=texture(dnoiseMap,mirror(16*samplePos)).xyz;//天气图信息:w_c0为云的低频覆盖率,w_c1为云高频覆盖率,w_h为最高云高,w_d为云密度float w_c0=cloud_Color.r;float w_c1=cloud_Color.g;float w_h=SAT(cloud_Color.b+0.12);float w_d=cloud_Color.a;//云出现的概率float WMc=max(w_c0,SAT(g_c-0.5)*w_c1*2.0);//确定云总体形状:SRb使底部扁平,SRt使向顶部渐淡。float SRb=SAT(R(p_h,0.0,0.07,0.0,1.0));float SRt=SAT(R(p_h,w_h*0.2,w_h,1.0,0.1));float SA=SRb*SRt;//确定云整体密度:DRb降低底部密度,DRt顶部密度淡出。float DRb=p_h*SAT(R(p_h,0.0,0.15,0.0,1.0));float DRt=SAT(R(p_h,0.9,1.0,1.0,0.2));float DA=g_d*DRb*DRt*w_d*2.0;float SNsample=R(sn.r,(sn.g*0.625+sn.b*0.25+sn.a*0.125)-1.0,1.0,0.0,1.0);float SN=SAT(R(SNsample*SA,1.0-g_c*WMc,1.0,0.0,1.0))*DA;//细节噪声float DNfbm=dn.r*0.625+dn.g*0.25+dn.b*0.125;float DNmod=0.35*exp(-g_c*0.75)*Li(DNfbm,1.0-DNfbm,SAT(p_h*5.0));float SNnd=SAT(R(SNsample*SA,1.0-g_c*WMc,1.0,0.0,1.0));float d=SAT(R(SNnd,DNmod,1.0,0.0,1.0))*DA;return vec2(d,SN);
}

我们这里将SN和d都返回的原因是我们之后的光照计算可以利用较低精度的SN,而真正的密度则使用d,原因如下图:

图中外层红色为低精度的SN,内部绿色为d。我们之后的raymatching对SN进行计算可以更加高效。

实时体积云渲染(地平线):一.云的生成相关推荐

  1. 实时体积云渲染(地平线):二.Perlin噪声和Worley噪声

    实时体积云渲染(地平线):二.Perlin噪声和Worley噪声 Perlin噪声 Perlin噪声同样是网格点噪声的一种,不同于之间在网格点生成随机值的白噪声,Perlin噪声在网格点生成一个随机的 ...

  2. 实时体积云渲染(地平线):三.云体渲染

    实时体积云渲染(地平线):三.云体渲染 体渲染 最常见的体可视化方法就是Ray-marching法.该方法如下图: 在像云这样的部分透明的介质的情况下,采样点将沿着视线进一步增加到场景中,并增加固定的 ...

  3. Renderbus瑞云渲染正式支持UE云渲染!离线渲染+实时渲染=渲染起飞!

    2022年已经到了尾声,回顾今年CG圈里最具讨论性的话题,除了AI绘图,就是虚幻引擎了,这两者如同一股风潮,从概念创意到后期制作,一路以"席卷"之势影响到了视觉领域的各个行业. R ...

  4. 空手套白狼,不花一分钱体验实时云渲染

    前不久,花了点时间研究了一下各大云厂商(AWS.华为.阿里)支持情况,主要分为三类: 渲染解决方案:以上三家都有渲染解决方案,主要方式是基于公有云的计算(GPU为主).存储(对象存储.块存储).网络以 ...

  5. 快讯 | 51VR联手阿里云共推实时VR云渲染平台

    3月21日,2019阿里云峰会·北京站上,阿里云发布了GPU云产品vGN5i,该产品针对轻量级GPU计算应用场景,可大幅降低AR/VR.云游戏及轻量级AI推理等GPU计算场景下用户的使用成本,在提高业 ...

  6. 华为云客户端_效果图云渲染已成趋势,云渲染如何选择?

    成年人的字典里没有容易二字,设计师们亦是如此 每天都在作图和改图中循环 加班到凌晨两三点已是家常便饭 突如其来的Max崩溃又使本就不浓密的头发雪上加霜 现在,云渲染,他来了 云渲染是什么? 云渲染就是 ...

  7. 云渲染和渲染农场有什么区别?看完你就明白了

    目前的市场主要集群渲染主要有: 云渲染和渲染农场. 云渲染是近几年才普及开来的概念. 以前是大量渲染一般都会搭建渲染农场,或者找"租用"一个渲染农场以满足自己的渲染需求. 渲染对计 ...

  8. 云渲染和渲染农场的区别,什么是真正的云渲染

    在云计算推广开来以前,有大量渲染需求的人一般都会搭建渲染农场,或者找"租用"一个渲染农场以满足自己的渲染需求.但是搭建一个渲染农场需要耗费的金钱和时间是一般的小公司或者小的工作室负 ...

  9. 你知道云渲染和自己渲染有什么区别吗?

    随着计算机技术不断发展,计算机图形学(Computer Graphics,下文简称CG)的发展也进入了快车道,从前需要化妆和布景才能实现的特技画面,现在都可以用CG后期来进行电脑合成,效果甚至更加真实 ...

最新文章

  1. 如何在无人机上部署YOLOv4
  2. java项目怎样提高性能_Java程序员成长之路(如何提高Java程序性能?)
  3. boost::math::boost::math::interpolators::cardinal_cubic_b_spline用法的测试程序
  4. ping通网关 ping不通dns
  5. KNN分类python实现
  6. cdoj 1092 韩爷的梦
  7. mysql 6.17,mysql小结篇2(17.6.27)
  8. php7 imagick扩展,php7如何安装imagick扩展
  9. 海康相机IP搜索协议研究
  10. 解读汽车机械工作原理GIF图 懂得三个算你牛!
  11. 使用mimikatz抓取windows管理员密码
  12. Lecture 2 Asymptotic Notation
  13. NLP实验一:形式语言和自动机
  14. xss.haozi.me靶场详解
  15. 【必看】没用的旧手机还能换钱,换换回收手机回收价格表曝光
  16. 《17.Deep Pyramidal Residual Networks》
  17. 买手机时几GB+几GB啥意思
  18. linux系统宝塔安装nodejs,node安装,nodejs安装,Windows nodejs安装,Linux nodejs安装
  19. (转)查看USB设备
  20. 拳打DALL-E 2脚踢Imagen,谷歌最新Muse模型刷新文本图像合成排行榜

热门文章

  1. java 当前时间小时数,java获取当前时间前几个小时的时间
  2. 消消乐实现下坠_手把手教你如何实现iOS消消乐小游戏Demo
  3. python程序多次运行_Python内怎么使同一个.py文件多次运行?
  4. 赋值运算符(AssignmentOperator)
  5. 服务器虚拟化相关问题分析,服务器虚拟化后引入的问题分析
  6. 在jupyter编写代码列出HTML,Jupyter ~ 像写文章般的 Coding (附:同一个ipynb文件,执行多语言代码)...
  7. spark java pom.xml_使用maven方式创建spark项目(配置pom.xml文件)
  8. 怎么查看过程xact_abort 是否开启_空调噪音大怎么办?
  9. linux vim 添加注释_vim基础教程
  10. 解决Hadoop总是处于安全模式的问题