加入收藏 | 设为首页 | 会员中心 | 我要投稿 393游戏网 (https://www.393youxi.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 手机游戏 > 手游新闻 > 正文

玩手游也能体验风霜雪雨?天气渲染技术带你领略云端魅力

发布时间:2022-09-23 04:14:24 所属栏目:手游新闻 来源:互联网
导读:导语:暴雨、狂风、雷电,相信大家都十分熟悉现实中的这些天气现象。这些现象体现了大自然的威能,给人极大的感官冲击。在如今的端游大作中,我们经常能感受到游戏制作组在这方面下的大功夫,然而在手游上,由于手机的组件的功效远低于PC端,如何平衡效能

导语:暴雨、狂风、雷电,相信大家都十分熟悉现实中的这些天气现象。这些现象体现了大自然的威能,给人极大的感官冲击。在如今的端游大作中,我们经常能感受到游戏制作组在这方面下的大功夫,然而在手游上,由于手机的组件的功效远低于PC端,如何平衡效能并充分利

  暴雨、狂风、雷电,相信大家都十分熟悉现实中的这些天气现象。这些现象体现了大自然的威能,给人极大的感官冲击。在如今的端游大作中,我们经常能感受到游戏制作组在这方面下的大功夫,然而在手游上,由于手机的组件的功效远低于PC端,如何平衡效能并充分利用手机上的设备来进行模拟渲染,就成为了开发者重要的研究课题。
 
  在由腾讯游戏学堂举办的TGDC2022腾讯游戏开发者大会上,腾讯互娱魔方工作室群引擎中心专家工程师陈家铭以手游《暗区突围》为例,向大家展示了如何通技术渲染优化手段使得手游获得了只有主机游戏才能享受的特性。
 玩手游也能体验风霜雪雨?天气渲染技术带你领略云端魅力
  以下是演讲实录:
 
  大家好我是魔方引擎中心的技术专家陈家铭,很荣幸今年又可以在TGDC分享自己的工作成果,这一次要和大家分享的是手游《暗区突围》里的动态天气渲染技术。
 
  首先介绍一下我所属于的Studio魔方工作室群它成立于2010年是腾讯IEG四大游戏工作室群之一,魔方包括了魔术师、魔镜、魔王还有我所在的技术中心,我们拥有多个全球顶级的IP项目,包括了知名的《火影忍者》《航海王》《一人之下》《秦时明月世界》。还有自研的IP,包括《暗区突围》《洛克王国》《王牌战士》等等。
 
 
 
  《暗区突围》是一款拟真的第一人称射击游戏,为了让玩家有更深的代入感,策划希望把以前只有主机游戏才能享受的特性都放在这款手游里面,也包括了今天的我要讲的主题,动态天气效果和体积云等效果。
 
 
 
  上图是今天的内容大纲,首先我会讲讲大气产生的基础原理,以及我们在放到手里面最后的一些相关定制以及优化,之后会讲体积云的渲染系统,还有里面的一些技术细节,最后是一些相关的天气效果的分享。我们先从天空大气开始。
 
 
 
  大家可能会问为什么我们手游的天空不能简单地用曲线来定义天空的颜色就好,而要搞很复杂的大气呈现呢?其实天空的颜色是千变万化的,会受到时间、地理位置、天气和污染等因素所影响。举个例子,同样是黄昏有可能这像左边这一张图,天空大部分的颜色都是蓝色,而只有接近地平线的才呈现橙色,也有可能像右边的图片,整个天空都是偏红色的。所以在写实的游戏里面,如果要模拟各种的天气变化,单单只是以曲线去做这个模拟,它的组合性是爆炸的,很难去编辑和维护。因此我们就会通过一个物理的方法去计算,那么我们是如何计算呢?其实大气是由不同的大小的粒子所组成的,天空的颜色都是由这些粒子对太阳光所构成的散射现象所确定的。为了渲染出大气散射的效果,我们一般都需要在视点以光线行进来计算每个方向所得到的颜色。
 
 
 
  比如说在大气层的A点方向到B点,我们就需要在这条射线上的位置,P0, P1, P2 利用相位函数算出所接受到的散射,然后呢再计算他们的积,那就是这个方向可以看到天空颜色的结果。然而这个方法其实在游戏里面实时算是很难实现的, 因为每个方向都可能要考虑到几十到上百个采样点。
 
 
 
  我们再看看虚幻引擎里面是怎么解决这个性能问题的。它利用了一系列的查找表来减少计算量,具体而言,虚幻引擎在每一帧里面可以使用这个计算着色器来生成4个基本的查找表分别为:透光度的查找表,它记录了光线在场景里面的传递情况。另外一个是多重散射的查找表,就是用来快速算出多重散射的结果;还有一个是天空图示的查找表,它是基于透光度还有多重散射两个表格,预先算好一个天空颜色;以及我们最终会有一张用来算天空透视效果的一个3D纹理表。
 
  虚幻引擎的方案不单是基于物理的,对美术也挺友好,在中高端的移动设备上也有良好的性能。可是在比较老的手机上,因为它们的带宽非常有限也负担不起每帧计算这么多的查找表,所以我们对它做了一些优化。
 
 
 
  首先我们会舍弃了空气透视的数据,就改成用高度雾来代替它的效果,这样的话我们场景里的shader也可以节省一次的3D纹理的采样,同时呢,舍弃了这一部分的数据之后,所剩下的查找表都是二维的,因此我们可以利用上述着色器来更新它。
 
  这是非常重要的,因为有许多的移动设备依然对这个计算着色器的支持不太完善。由于我们游戏里面的局内时间变化比较慢,所以呢我们也可以分帧去计算每个LUT。就是说,我们每帧只计算里面的一部分的像素,这样的话在低端的移动设备上也可以承受。
 
  为了做进一步的优化,我们也将天空图示的查找表改用了半八面体的参数化,同时也丢弃了地平线以下的内容。这不但节省了50%的光线行进的计算,也避免了查找这个结果的时候,需要调用一个平方根指令的步骤。做了以上优化之后我们发现其实也可以把这个(shader)移植到CPU里面去计算,而每帧的耗时大概是0.5ms左右吧,所以呢我们预留了这个方法在最老的手机上去使用。
 
 
 
  这是原始版本以及经过我们优化版本之后,在一天里面三个不同时间段的一个比较。我们可以看到其实在太阳周围稍微有一点点的偏差,但是在游戏中其实是不容易观测出来的。
 
 
 
  我们再看看优化之后天空渲染的性能,就从原始的1.35毫秒就降到了优化之后的0.78毫秒。所以,我们用半八面体投影之后节省了大概是40%的GPU耗时,同时性能也有一个明显的提升。
 
 
 
  接下来我会继续分享体积云的处理。
 
  有同学也可能会问,既然是手游,为什么不可以用带法线贴图的面片云?
 
  而要搞体积云呢?我们主要有两个原因,第一 ,我们刚开始的时候我们其实也尝试过面片云这个方案的,但美术觉得不太能表现他们要求的体积感,而且面片云也比较难去模拟多重散射独有的光照特性。第二个是面片云一般都是预先烘焙的,而我们的游戏要求在局内的天气有一个实时的变化,云的密度也会跟随着天气所改变的,面片云就比较难去支持这样的效果。
 
 
 
  所以我们的方案参考了《地平线:零之曙光》团队在2015年GDC上分享的案例,我在这里做一个快速的回顾。当我们要从一个固定的方向望向云层的时候,云的颜色是从这个方向所散射而来的阳光和环境光所确定的。我们一般只考虑地面上距离2.4到6公里之间的云层。因此我们在这两个高度之间以光线行进来计算出这个方向而来的一个散射的亮度。
 
  首先我们会在这条射线上平均分布一些采样点,然后计算出每个点上我们所可以接受的一个光照,之后呢我们会根据云层的密度算出该点有多少个光可以散射到相机里面,再把所有散射过来的光线能量相加就可以得到云从这个方向散射而来的颜色。
 
  但是我们还有三个疑问:
 
  第一是云层的密度是怎么去定义呢?
 
  第二个就是采样点所接受到的光照到底有多少,如何给散射?
 
  第三个是怎么可以把这一个计算的性能优化到可以在手机上去跑?
 
  我们后面会一个一个展开来讨论。
 
 
 
  首先是云的建模,就是怎么去定义云层的密度。我们会使用Worley噪声生成3D纹理,然后呢让它平铺在天空中,这样就可以定义出基础的云的密度。我们使用了基础和细节两层的噪声,最终的结果都是把基础的噪声再减去细节所得到的结果。细节的噪声会平铺更多的次数,这样的话,我们就不需要一个特别高的分辨率就可以获得足够的细节。
 
  但是仅仅是这样的话也不可以创造出整个覆盖天空的云层。所以我们引入了一张称为Weather Map的贴图,这样美术可以控制不同天气状态之下,云的形状以及分布。它其实是一张正交投影的2D纹理,覆盖了大概是地面40公里的一个范围。Weather Map的R通道是云的覆盖率,这代表它的数字越高云的密度也等于越高,G通道是用来定义云的种类。此外我们还有一张称为Cloud profile的2D纹理,主要是用来模拟云在不同高度有不同形态的一个特性。
 
 
 
  刚才提到,我们是通过动态生成的Weather Map来控制云层随着天气的变化。在我们的系统里面,Weather Map是由Cloud Mask所组成的。美术可以在地图中摆放的各种的Cloud Mask,就像右边的动图所展示的一样。每个Cloud Mask都有一个材质来定义它所绘制到Weather Map里面的内容,例如当材质输出一个白色的圆形的一个特效的时候,对应的云层就会变得更密集。
 
  我们也可以输出黑色则该位置的云将被擦除。为了方便控制不同天气下的云层我们有两个全局的参数,一个是全局的云的覆盖率,一个是全局的云的形态。这两个值我们作为材质输入传递给Cloud Mask并且进行内容的绘制。
 
  一般情况下,我们会以Worley噪声生成一个很大的Cloud Mask来定义基础的密度,之后再补一些小的mask作为局部的调优。
 
 
 
  在进一步讲解云的光照之前,我先介绍一下光吸收的物理定律:比尔-朗伯定律。假如阳光的亮度是1.0,当它经过云层照射到采样点的时候,采样点所接受到的亮度是多少呢?而最终能到达相机的又有多少呢?要回答这个问题,我们首先要算出阳光到达采样点,以及采样点到达相机的透光度Transmittance。
 
  根据这个比尔·朗伯定律,透光度是由光线的光学深度Optica Depth所计算的,而这个光学深度就是从这个路径上云层的密度的积所得到的,单次散射其实就是一般通过太阳光阴影和三维函数相乘出来的一个结果,我们是用了四个样本来评估太阳方向的光学深度,所计算出来的透光度就等于云层的自阴影。
 
 
 
  就像上图所示,我们是用了四个样本,就分别以一个2次方的距离来分布。主要是优化了比较接近的一个遮挡效果。作为一个LOD策略在阴影采样云层的时候,我们也会忽略了细节噪声。刚才提到的相位函数,我们是用了一个经典的方法,就是把两个相反方向的HG函数混合作为最终的相函数这里列出了我们的一些默认参数,其中的VoL就是太阳跟视线的方向的一个点积。
 
  为了节省性能,环境光方面我们采用了一个比较简单的处理方法。天空的环境光是参考UE4中的方法,根据采样点的高度来计算相关的颜色,就是说云越高,天空环境光的亮度就会越亮。
 
 
 
  上图就是天空环境光效果的对比。我们发现如果没有环境光,云大部分在阴影的时候都会很难区别它的形状。而在开启了环境光之后,云在阴影部分的造型也清晰很多了。我们也加了一个用来模拟地面反射光线的地面环境光,主要是用来模拟地面反弹到云层的光线。
 
  这也是以同样的方法来计算,但就是把高度的参数反转,就是说越低的云层就可以接收到越多的地面环境光。地面环境光的颜色是通过是通过将地面视为一个纯Lambertian的表面计算出光源的反弹所得到的。举个例子SkyLight的底部颜色就是作为地面环境光很好的一个数据。
 
  这里我们可以看到没有地面环境光的时候,云的底部是比较暗的,而打开地面环境光之后云层的底部会变得更亮,更接近我们在日常生活中看到的一个结果。接着是多次散射模拟,也是计算出云正确光照非常重要的一环。因为云主要是从水蒸气和小的冰块所组成的,当阳光进入到比较薄的云层的时候会经历过很多遍的散射才到达我们的眼睛里面。从这一张照片里面我们可以观察到一个很有趣的现象。
 
 
 
  云深处会比外面更亮。这是因为深处的云会经历过更多遍的散射。我们参考了彼思动画和寒霜引擎中用来计算多次散射的一个近似值的方法。我尝试简单说一下它的思路。
 
 
 
  假设每一次散射的时候,阳光和阴影都会有一定程度的衰减,而相位函数也会越来越接近一个均向性。在这个公式中,我们定义了ABC三个0到1之间的参数来控制这个衰减的关系。注意一下为了保持能量守恒呢,A是需要小于B的,因此在光线行进的时候,我们就利用这个方法对每一个采样点计算出三遍的多次散射的一个亮度,在寒霜和虚幻引擎的实现里面,基于性能的关系,一般只会算3遍的散射。
 
  针对这一点我们做了一个小小的改进。通过固定的ABC三个参数,我们可以预先算出一张查找表用来算出任何次数的散射效果,这个查找表是在归一化的亮度所计算出来的。我们是通过采样点的光学深度和太阳与视线的点积来进行一个索引。

(编辑:393游戏网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读