【UnrealEngine4】距离场的使用技巧与应用

原来想开一个专栏的

后来还没搞懂怎么开

就先写下这篇文章

文章或者专栏都会分享一下我在虚幻四中的制作经验,以蓝图和材质为主,讲述如何在图形学的思想中,不使用c++,不改动usf的情况下,蓝图和材质能做到的极限。


目前规划的文章内容有:

一.虚幻四中的 距离场(本文)

二.材质中的伪体素(三維紋理)

1.【UnrealEngine4】材质系统中的伪三维纹理

2.【UnrealEngine4】体渲染和Tri-Planar Mapping

三.基于NS方程的流体模拟 在虚幻四中

1.用蓝图模拟pass,进行伪compute stage的运算

2.用蓝图模拟ubo,向材质系统传输数据

3.NS方程的解析和实际模拟

4.烟体、流体的渲染

四.metaball 在虚幻四中(本人的实例已在虚幻商城中上架)

原理与在材质中的实现

五.path tracing 在虚幻四中

1.相机内参、简单物体变换信息的处理

2.path tracing的解析,temporal的思路

3.在材质中进行path tracing

六.透明材质造假技巧与解析


本文内容如下

一.距离场简述

二.虚幻四中的距离场及作用

三.距离场梯度及应用

四.距离场梯度的计算


一.距离场简述

距离场在文字渲染,矢量图渲染中应用广泛。本文提到的距离场为表示三维物体的距离场。关于其概念鄙人不在此多做阐述。


(图源自 libgdx/libgdx Wiki)


二.虚幻四中的距离场及作用



在虚幻四中,如果在项目设置中开启了自动生成模型距离场,重启项目后将会构建网格物体的距离场。

这个过程虽然比较缓慢,但是不影响主线程工作,和编译材质的情形类似。生成完后,场景中的所有网格物体都会被赋予一个距离场。换而言之,整个场景会被一个叫距离场的东西替代(正常渲染时不可见)

在显示-可视化-中选择预览距离场

可以根据预览的距离场质量来调整网格物体的距离场分辨率。



有破漏:


无破漏:


距离场最直接的应用,在虚幻中可能是DFAO了(DFGI暂不考虑)

要开启利用距离场进行加速的AO,可在SkyLight中找到该选项,并启用。



使用距离场AO的好处与弊端:

AO的计算本质为被积表面上的半球积分。在屏幕空间上进行采样积分不是均匀和完整的,因为屏幕空间中的信息不足,而且受限于采样次数,和地毯式的搜寻(很多采样点是无效的),屏幕空间的AO往往是近距离的(虽然现在也有新的方法可以计算远距离AO,FFAO)。

而使用距离场进行AO的计算恰好可以避免此问题的出现,因为前面提到,距离场可以当作是一个物体的“替代”,原场景的高频信息可以被很好地保留下来,并且是完整的,因此AO的计算可以算是全局性的,无论是近还是远的几何信息,一律能被积分到。

前面提到,场景是高频信息,而距离场的表达实际上已经有信息的缺损。比如一个面片,或是一条缝隙,距离场是不能很好地表示的,因此在积分的过程中,这些高频信息会被平均化,某些视角甚至会出现错误的信息,导致漏光。这个可以通过调整距离场的分辨率来改善。

其次,由于距离场的采样实际上是一个raymarch的过程。因此采样次数对最终的精确度也会有影响。半球上的积分需要多条射线,射线的数目对最终结果的方差也会有影响。这里会出现的问题是躁点。

(噪点和漏光等瑕疵在这张图中很好地暴露出来了)



三.距离场梯度及应用

距离场梯度,可以算是距离场的进阶内容。

首先我们需要了解梯度这个概念。梯度,拉普拉斯,旋度,在后面章节的流体中将会反复提到,这里不做赘述。


距离场梯度的意义。距离场是场景的“替代物”。将场景看作一个自变量为三维,因变量为一微实数的函数(可看作密度函数),其梯度的几何意义是因变量的变化趋势。在图形学中其意义是对该函数按照一个阈值进行分割后得到的表面的法线(LevelSet)。但是对于一个世界坐标而言,他还有一个意义,便是周围物体对他的遮挡程度和方向(距离场与密度函数的梯度方向应该是相反的)。


用距离场快速造假阴影

类似SSDO,我们可以通过对场景几何信息的采样来还原遮挡信息。SSDO的原理在这里不具体阐述。由上面的几何意义可以知道,给出一个世界坐标,我们可以根据距离场梯度来获得这个点被遮挡的方向。(想象一个球体,表面上任何一点都会被法线以下部分遮挡,因此距离场梯度为法线相反方向)

根据距离场的梯度,和给出的光源位置(LightDirection),我们可以计算出遮蔽和阴影。

(对天光的遮蔽,每帧只对距离场进行4次采样,不含Temporal)


(水面的天光遮蔽)


(水下Caustics的遮蔽效果,不过此处SSR效果有BUG。。。。)

由于上面的着色模型均不是虚幻四中管线默认存在的,假阴影,或者说假阴影的质感对画面起到锦上添花的作用。


四.距离场梯度的计算

距离场梯度在虚幻四的材质系统中有现成的函数,但是在这里并不推荐使用。

根据梯度定义

我们可以得到

即在xyz三个方向对距离场进行采样,然后求出xyz三个方向的导数。然后进行单位化。


这里我们可以注意到步长是可控的。而自带的距离场却无法控制该数值。这个步长的意义,鄙人难以用语言描述,不过考虑导数的动态过程,类比可以得到那种“逼近”的感觉,即是ε-N,ε-δ语言的三维版本,在接近极限之前不断做割线的感觉。

在渲染中步长也不一定有个最优值,自带的函数我没有发现控制步长的参数,因此得到效果很有可能是不是自己想要的。


受限于采样点的数目(七个),得到的梯度会有瑕疵。如何利用虚幻四的特性进行改进,这是一个问题。虚幻四中使用了许多Temporal的算法,其中在材质中暴露了一个叫DitherAA的函数。该函数给出了一个根据Pattern和桢画面进行运算的期望值为E[a],(a为输入值)的伪随机数。

首先对该数值进行拆解,拆解为一个三维向量:


得到一个 \left( 0,1 \right)^{3} 的向量,然后将其转换至半径小于等于d/2的均匀分布的全球空间。

我们得到了一个随机的偏移向量。只需将这个偏移向量作用在采样点中,便能在每一帧对梯度进行多次采样,得到采样点d/2半径周围点的梯度的期望值,可以输出为最终结果。

注:这里全球半径是否需要均匀分布待讨论。因为这里是一个Trick,如果按照DSSDO的算法采样出来的梯度应该与球半径平方成反比,但是由于每桢只能采样一次,最后单位化会得到相同结果。如果不进行单位化处理,全屏幕中一次梯度的计算得到的结果方差将会十分大,出现的结果就会是黑白燥点的混合。因此这里采用了折中的办法,对最大半径球内进行均匀采样)


最终效果

(经过处理,将 \left( -1,1 \right)^{3} 转换为了 \left( 0,1 \right)^{3} 方便显示出来(不要在意开闭区间了。。。))





(水面最终效果。采用了上述的阴影算法。光源方向与落地窗垂直,能很好地模拟天光的照明,使更有质感)


9.13:注:密度场梯度应该与距离场梯度方向是相反的,如果物体内部密度为1的话。

另本文最后求的“梯度”实际只为一个割面法线,是再运算次数少的情况下近似周围遮蔽方向的值(这里是Trick,前面也有提到),而且可以将三个方向改为半球上任意方向,有兴趣可以推导证明。这里只是分享了我的一个经验,不一定准确(事实上我想写的全部都只是我的经验),但从实验结果上看是可行的。而且这种方法适用范围小,举几个例子,烟雾渲染,水面渲染,都可以使用这个方法造假阴影。但是如果说同样使用距离场来制作精确阴影,可能只支持一个光源方向,沿光源方向采样,这样做的采样次数会更多(而遮蔽方向却可以重复使用),并且会在材质系统里用到custom node(除非真的需要,我都会把之前写的custom node全部拆解,但是循环无法拆解,因为循环次数不是硬编码的)。因此我觉得,在本文出现的场景中,水下Caustic,水面,这两个在虚幻里面没有的着色模型,可以适用。

另,场景未烘培,模型没有分过UV和光照UV,因为没什么时间。所见到的全局光效果是LPV产生的,(并不是说烘培之后的效果就只有那么简陋)。

另感谢评论区提到的DFAO残影的问题。残影出现的原因可能有两个,一是TAA的原因,二是DFAO本来就会分桢采样(temporal)的原因。打开DFAO预览,移动视角,会发现他的确需要经过几帧的时间才能收敛完全。要减少这种情况的发生,可以将Tint从黑色调为灰色,或者适中得范围,来中和因为天光遮蔽计算错误产生的噪点。


10.29

更新一下,关于局部距离场和全局距离场的分辨率的问题,使用材质中到最近表面距离会获取全局距离场,而默认的全局分辨率是有上限的。可以通过控制台命令打破此上限。


再次感谢阅读,鄙人不才,还望各位以后继续指出纰漏和斧正 (๑•̀ω•́ ๑)


本期文章就到此为止了。鄙人写下此文仅为了分享和交流经验,无任何商业性质与目的,望各位斧正,提出想法,谢谢。


参考文献:Approximating Dynamic Global Illumination in Image Space, TobiasRitschel

ScreenSpace FarField Ambient Obscurance,Ville Timonen

编辑于 2017-10-29

文章被以下专栏收录