首发于Grfx.IO

Procedure Cloud

游戏内云层的渲染在之前大多采用"贴图+模型"或者"Matt Paint"的方式:

左侧的体积云效果实际是特别的shader模拟光照+模型摆拍,

这种方式非常的不灵活, 跟Guerrilla做KILLZONE时候的方法差不多:

背景云层也是固定做好的, KILLZONE

, 这种方式做出来的效果相对固定, 当然美术也更可控一些. 但是当我们想要打造更加真实随机的天气环境时, 之前的做法就显得不够顺手了. 画面效果优秀的Horizon Zero Dawn 提出了一种方法可以巧妙的制作随机的天气环境, 让云层的渲染可以更加真实.

Cloud Rendering in Horizon Zero Dawn,Guerrilla

Guerrilla的Schneider[1]使用了fBm和Volume Rendering来完成这项任务.由于上篇文章[2]也刚好对Ray Marching做了介绍,所以本篇可以看做是Ray Marching的一个实际应用.

fBm

fBm全称是Fractal Brownian Motion[3], fBm是一种常用的生成噪声图的方法, 其本身的数学特性可以生成很多有意思的图形. 又由于它本身的分形特性,所以如果对fBm进行Domain Wrap[4]操作,可以生成很多精美的图像:

Inigo Quiles (2002)

虽然完全使用fBm来做云层渲染没问题,但是为了节省计算量,Guerrilla是把一组fBm存储在3D Texture里,而我试验用的是UE4,暂时没有3D Texture,所以我用的是多通道贴图. 每个贴图分成多个子块,使用Z值索引每个子块:

2D Tile 模拟 3D texture

另外我没有使用Worley Noise + PerlinNoise,直接用的UE4内置的Noise节点里的Voronoi Noise:

Worley + Perlin
Voronoi
不是3D texture,每个通道存储一种Noise

使用RayMarching采样上述数据,得到一个density值. 接着我们利用这个值计算光照和通透程度.

Lighting

云团的散射是需要模拟的重点, 根据Beer's Law可以近似计算光线经过均匀介质后的耗损:

T = e^{-t} \tag{1}

另外还需要描述一种光线经过云团的物理现象: 散射. 云对光线的散射是各向异性的:

截图来自Andrew,GDC 2015

Henyey-Greenstein模型在1941年诞生,起初用来解决天文学家计算星系间光的传播问题. 后来被拿来用于计算云的各向异性散射特性. 我们可以在公式(1)的基础上增加进这个计算模型:

HG=\frac{1}{4\pi}\cdot\frac{1-g^{2}}{(1+g^{2}-2g\cdot cos(\theta))^\frac{3}{2}} \tag{2}

Energy = T * HG \tag{3}

基本的光照模型就是如此,Guerrilla那个PPT里还有很多细节优化,有兴趣可以深入读下. 目前我只是简单的试了下基本框架:

根据Cover值控制云层浓密

https://www.zhihu.com/video/960240983070445568

加一些扰动可以增加云的变换,为了明显点看到特意加快了速度。

https://www.zhihu.com/video/960241393650798592

经过调整后的截图:


[1]Andrew Schneider, GDC2015, Real-time Volumetric Cloudscapes of Horizon: Zero Dawn, 2015.

[2]Ray Marching 101

[3]Fractional Brownian motion

[4]Inigo Quiles, Domain Warping, 2002.

发布于 2018-03-23

文章被以下专栏收录