今天学习的是Unreal Engine在GDC 2019上所分享的Distance Field的使用技巧,分享人是Epic的资深TA Ryan Brucks
![](https://img.haomeiwen.com/i19200103/fae95bd26778f852.png)
![](https://img.haomeiwen.com/i19200103/9f21717142f2f902.png)
![](https://img.haomeiwen.com/i19200103/07c444a3618d0b9a.png)
分享主要分为三部分:
- 基于解析的模拟方式:即基于数学公式完成效果的驱动
- 基于VS来实现效果的方案
- 使用DF与UV来模拟变化的效果
![](https://img.haomeiwen.com/i19200103/d1968249a744d984.png)
所谓的解析模拟,指的是:
- 基于函数来完成效果的模拟
- 使用参数作为输入
- 而’regular simulation‘则是通过将模拟结果写入某个每帧更新的buffer来模拟
UE中的大部分特效都是采用regular simulation方式实现的,带来的问题就是即使是非常简单的效果,也需要通过更新buffer的方式来完成,代价较高。
![](https://img.haomeiwen.com/i19200103/36203e901e23c059.png)
解析模拟有如下优点:
- 效果可以很容易在多端进行同步
- 内存消耗低
- Tick消耗低
- 表现稳定,一致性高
![](https://img.haomeiwen.com/i19200103/1bc4e794b864a6b5.png)
线性函数就是一个非常简单的函数
![](https://img.haomeiwen.com/i19200103/3fac0d591942c875.png)
回顾一下函数的定义
![](https://img.haomeiwen.com/i19200103/5624b1d63368500c.png)
来看下常用的正弦函数在实际项目开发中是如何用起来的
![](https://img.haomeiwen.com/i19200103/04b1620ce8ea1b2c.png)
这里做一个取绝对值的处理,就将下半部分翻转上来
![](https://img.haomeiwen.com/i19200103/c9df6133d149f5c5.png)
这个函数就可以用来模拟小球在地表上的跳动效果
![](https://img.haomeiwen.com/i19200103/b08979242a61f20d.png)
将之转换为材质实现
![](https://img.haomeiwen.com/i19200103/8f941bea5ffeb062.png)
效果要怎么暴露给项目,基于玩法进行调制呢?
![](https://img.haomeiwen.com/i19200103/072deb06360894c7.png)
同样给出材质实现,需要做一个max运算,避免结果异常
![](https://img.haomeiwen.com/i19200103/3c27997b070fc737.png)
通过Time - StartTime运算,可以实现贴花或者其他mesh效果的fading。
![](https://img.haomeiwen.com/i19200103/c50bca636f38c43a.png)
这里给了一个实现案例
![](https://img.haomeiwen.com/i19200103/ee1a03a2cd6f6a25.png)
通过对spawnTime,lifeTime进行处理
![](https://img.haomeiwen.com/i19200103/f1cb6731407096ea.png)
这里应该给了一个视频演示效果,用于控制物件的渐变移动
![](https://img.haomeiwen.com/i19200103/3a6366606212cb4b.png)
![](https://img.haomeiwen.com/i19200103/8c2d664214efac62.png)
![](https://img.haomeiwen.com/i19200103/c50de1e9aecd9706.png)
![](https://img.haomeiwen.com/i19200103/a07a2fe72416eeeb.png)
这里依然是材质的处理,比较简单,就不展开介绍了
![](https://img.haomeiwen.com/i19200103/7c52e41102e930f5.png)
Frac指令可以用来实现效果的循环
![](https://img.haomeiwen.com/i19200103/2ca9e7cc50682264.png)
日常debug tips
![](https://img.haomeiwen.com/i19200103/0c4df662be6b2701.png)
通过vector noise实现随机效果
![](https://img.haomeiwen.com/i19200103/bc2ae3728b60ff3d.png)
通常用一个byte来存储数据,用定点数表示,精度是1/255,
![](https://img.haomeiwen.com/i19200103/7b055afa06a78af9.png)
直接用可能会有精度问题,通过+0.5可以解决
![](https://img.haomeiwen.com/i19200103/3b33badb0860c8ff.png)
这里给了具体的效果展示
![](https://img.haomeiwen.com/i19200103/794636e365660c85.png)
接下来用一个复杂的例子来对上面介绍的内容做阐释
![](https://img.haomeiwen.com/i19200103/84774d25d578a1bb.png)
static mesh的wireframe效果如上图,由众多的quads组成,顶点色是随机的,支持控制时间来实现缩放
![](https://img.haomeiwen.com/i19200103/9ec3f5f3821cee4e.png)
![](https://img.haomeiwen.com/i19200103/206186bf7d41e929.png)
基于法线添加位置的抖动
![](https://img.haomeiwen.com/i19200103/b88c0cf9eda87262.png)
将标量参数替换成一个动态的参数,实现offset的动态变化
![](https://img.haomeiwen.com/i19200103/1149768979706ffe.png)
另一个烟花也使用了同样的方法
![](https://img.haomeiwen.com/i19200103/2d868bb72b6c7aae.png)
通过这种方法,可以用一些小尺寸的静态mesh来实现环境的点缀,比如这里用作fog haze cards或者dust modes
逻辑跟前面的类似,通过随机的算法来控制颜色、尺寸、速度等,基本上没有额外的消耗。
![](https://img.haomeiwen.com/i19200103/9dc62a436923b3b3.png)
这里介绍了一个基于spline的billboard方法,从而以2D的方法实现3D的效果。这种方法在UE3就存在了,已经是一种非常成熟常见的方案。
![](https://img.haomeiwen.com/i19200103/e01650302122fa2d.png)
上面两种效果都可以通过上述方法实现。
![](https://img.haomeiwen.com/i19200103/6c6dc6815f8d7e56.png)
材质函数节点是Spline Thicken
![](https://img.haomeiwen.com/i19200103/db172e8a41330907.png)
Gears5中原来的粒子效果是CPU模拟的,计算消耗太高,换成GPU,则由于需要跟CPU交互,同样具有不低的消耗。
最后采用的是基于VS来实现的方案,用来点缀环境、实现部分武器、gameplay特效,从而以较低的消耗实现了同样的效果。
![](https://img.haomeiwen.com/i19200103/fc59540487a51331.png)
![](https://img.haomeiwen.com/i19200103/45041d99f5b754c9.png)
Gerstner Wave基本介绍
![](https://img.haomeiwen.com/i19200103/17addc6498955808.png)
基于顶点实现的材质蓝图
![](https://img.haomeiwen.com/i19200103/b111707c75f42d68.png)
这种方法可以自动在多端进行同步,而且可以不用tick就实现splash效果
![](https://img.haomeiwen.com/i19200103/aac82295e32500d5.png)
基于波浪的周期来调用frac,同时基于当前点到波峰的距离,来控制相位。
基于这个解析逻辑,还可以在水波达到波峰的时候,添加一个粒子特效,以实现更逼真的效果。
![](https://img.haomeiwen.com/i19200103/e3202318afeaa52b.png)
这里是效果展示。
![](https://img.haomeiwen.com/i19200103/36dcb5bbab097684.png)
基于DF,我们可以拿到到岸边的距离,并基于这个来控制海浪的相位。
![](https://img.haomeiwen.com/i19200103/723adb4446ff522f.png)
同样,还可以用来模拟海浪跟海中的石头或者障碍物交互的效果:即在有障碍物的地方,添加一些resistance,避免水波溜过去(见蓝色线条,黄色是原始的)
![](https://img.haomeiwen.com/i19200103/8310dcacec997d4e.png)
这里是通过DistanceToNearestSurface这个节点来获取数据的
![](https://img.haomeiwen.com/i19200103/fd2b0457e12f5f6c.png)
用debug颜色显示
![](https://img.haomeiwen.com/i19200103/d12e6877232ffa96.png)
具体的表现效果
![](https://img.haomeiwen.com/i19200103/ddbe11ef13eed95d.png)
传统的海浪实现中,相位是一个常量,可能在不同的波浪上,数值不同,但基本整个生命周期是一个常量,但是这并不是必要的,按照上面的,我们增加对相位的动态调整可以得到更好的效果。
![](https://img.haomeiwen.com/i19200103/770a452eaae4088b.png)
将海浪的方向与地形高度的梯度(基于这个应该可以大致计算出到岸边的距离,这样也可以省去distance field贴图的消耗)结合起来,还可以实现更逼真的模拟效果。
![](https://img.haomeiwen.com/i19200103/40a07887d058535b.png)
Distance Field的梯度用于描述海岸的方向,这个方向可以用于控制海浪的方向。
![](https://img.haomeiwen.com/i19200103/1557073d9ac64ad7.png)
通过点乘,可以知道障碍物的那一面需要产生碰撞后的浮沫。
![](https://img.haomeiwen.com/i19200103/982f0f8dde28252f.png)
这里介绍了flowmap的实现原理,flowmap用于控制水流的方向。
flowmap会通过UV动画来实现水流的效果,但是如果UV偏移过大,效果就会有问题,所以通常会用两张贴图来弱化瑕疵:
- 在一个区间里,用第一张贴图来控制水流的扰动
- 当到达阈值时,替换成第二张贴图主导
- 当达到第二个阈值时,第一张贴图就回复到原点,如此交替反复
上图中的红色跟灰色曲线表示两张贴图的权重值。
需要注意的是,UE的flowmap用的是triangle wave而不是正弦波,不过区别不大。
![](https://img.haomeiwen.com/i19200103/17c06b59e802de00.png)
Flowmap叠加DF贴图跟法线贴图,可以进一步加强表现。
上图是一个河流的效果,近岸的flowmap会对地面的法线贴图进行采样,并基于结果对水流进行调制,使得水流看起来像是部分浸没石头的样子。
![](https://img.haomeiwen.com/i19200103/926144d3aecd295f.png)
这里展示的是如何基于Distance Field来调整flow的,从而实现水流在障碍物周边绕行波动的效果。
![](https://img.haomeiwen.com/i19200103/38faa09d75d950bf.png)
这里给了实现的算法细节。
![](https://img.haomeiwen.com/i19200103/c2f2c5630aa522e7.png)
总结
![](https://img.haomeiwen.com/i19200103/a9da4734587168d0.png)
参考
![](https://img.haomeiwen.com/i19200103/0f54be12d353ab25.png)
Gerstner Wave实现方式
![](https://img.haomeiwen.com/i19200103/fe0b181d0fa74cf9.png)
Lagged Wave实现方式
![](https://img.haomeiwen.com/i19200103/7e3a60e971449647.png)
Curl Noise在很多场合中有应用,比如给水体添加扰动等,具体可以看一下Siggraph 2007的文章。
![](https://img.haomeiwen.com/i19200103/4073219fede93530.png)
海洋效果中,会使用scale flowmap来实现浮沫从石头上流下来的效果。流动的频率跟最大尺寸的wave的周期相匹配,UE有一个ScaleUVsbyCenter节点可以用于替换Flowmap内部的传动函数,这里介绍了具体的实现方法。
网友评论