【转载】(UE4)赛博朋克 2077 场景扫描推进效果

365 阅读9分钟

原文链接:【UE4】赛博朋克2077场景扫描推进效果数 | 包小猩

正文

好像又鸽了半年没发东西(来自一位年更UP的喃喃自语)

v2-1456077e283b4e602e7c626523709c9b_b.gif

2077 出来也有一个多星期了,在游玩时发现有许多效果做得很棒,特别是按 tab 扫描时,推动鼠标滚轮会有马赛克过渡的效果,好像图片传输速度很慢,被一层层加载出来一样。话不多说先看游戏内效果:

v2-1456077e283b4e602e7c626523709c9b_b.gif

效果拆解

接下来我们进行效果拆解。在做任何效果之前都需要进行拆解,这样才能明确方向。我决定从颜色元素动画三个方向进行拆解,这样做就更有条理,确保不会漏掉细节。大家对照脑图和上面的动图一起食用,应该可以 get 到我总结的这些部分。

下面我们根据总结的要点展开讲解。

效果制作

在正式讲解之前我想让大家看看我最后实现的效果

v2-1456077e283b4e602e7c626523709c9b_b.gif

整跑测视频版本如下(场景为商城资源 Soul_Slum ):

1. 像素化处理

整个效果中最重要的也是最明显的部分,就是不同大小的像素过渡。在这里,我选择使用最大 64x64 的像素作为首次像素化的尺寸,然后不断细分像素大小,由 64x64 变成 32x32 ,再到 16x16,以此类推下去,最终显示出原始图片。(效果上有点像四叉树)

由于像素化制作很简单,直接上节点图 (这里将功能写成material function) :(对像素化制作不清楚的同学可以看这篇文章: #像素艺术# - 使用 UE4 还原 CRT 像素效果的思路及方法

image.png

UnitResolution: 像素化一个区域的分辨率

这套节点主要思路就是将屏幕像素划分给定像素化大小的区域,然后添加半个像素的宽度来修复 floor 的偏移(像素化的画面就会和原始图像对齐)

于是我们就能得到如下所示的画面

  • 单元格分辨率:64x64 image.png

  • 元格分辨率:32x32

image.png

  • 单元格分辨率:16x16

image.png

通过修改像素大小可以得到不同分辨率的结果,这也是画面像素细分后的层级效果。由于像素大小是不断二分的,所以上一层级的像素内刚好能装下 4 个下一层级的像素块,以此类推最后一层就为原图

image.png

2. 像素化动画

接下来我们要将不同分辨率的图像混合起来,实现从中心到外围的像素大小渐变。画面中心为小像素块,画面外围为大像素块,如下图所示:

但是单纯这样一张图显然是不够的,我们需要让他动起来。制作动画的大致思路就是先制作 n 层不同细分的像素化效果,然后对每个层级制作动画偏移并混合。这样不同层级出现会有先后顺序,就能实现从中心扩散,且不断细分的动画效果。

我们首先着手中心向外扩散的效果,使用 SphereMask 最适合不过了,但在 SphereMask 之前我们需要对像素化的 uv 做一些细节操作。

首先是对 uv 做屏幕的长宽比修正,因为我们希望不管屏幕比例为多少,最后的扩散区域都是圆形。修复原理主要是对 uv 做了屏幕比例的反向修正,节点图如下:

image.png

端输入像素化 uv,右端输出修正长宽比的 uv

  • 未修正长宽比 image.png

  • 修正长宽比 image.png

然后我们将制作好的 uv 应用 SphereMask,并添加两个 float 输入:ProcessProcessBias,分别控制整体效果 进度 和 进度偏移

image.png

随后我们在外层按照不同分辨率排布 n 个刚刚写好的像素化功能,再将每层的 ProcessBias 调整下,混合输出的 mask ,通过调整 Process 即可得到如下动图效果

  • 混合节点图

image.png

  • 不同层级混合 mask 可视化

image.png

  • 最终屏幕结果(将 function 中的像素化 uv 采样了屏幕纹理)

image.png

可以看到现在已经有多层不同分辨率的层级混合了,但混合的边缘太过于规整,于是我们需要用一张 noise 贴图进行扰乱,这张 noise 我选择使用 BlueNoise ,因为得到的效果较为均匀。

这张 noise 其实也不是单纯的一通道灰度 noise ,我使用了两个通道,这两个通道中储存了不同的 BlueNoise,然后我用这张 noise 的红绿通道,对像素化后 uv 的 x 和 y 轴做了随机效果(如果只使用一张噪波对两个轴向做 noise 的效果很容易得到具有方向性偏移的结果)。

  • 双通道 BlueNoise image.png

image.png

可以看到蓝色框内的是 Noise 节点部分。这里需要注意的是,Noise 需要做一下范围映射再和 UV 混合,映射操作将 Noise 本身 0~1 的区间变成 -1~1 的区间。目的是为了在轴的正反都有随机位移,使结果更加随机,而不会出现方向性

  • 随机过后不同像素大小层级 mask image.png

  • 随机过后屏幕最终结果 image.png

接下来我们只需要控制 Process 数值即可实现从中心扩散的动画效果了。

但 Process 取值的区间是 0~1 吗?

很显然不是的。这里有个细节需要说明,由于每个层级都做了Process Bias 的进度偏移,所以我们的 Process 进度数值需要满足最大偏移层的进度完成(最大偏移层就是拥有最大 ProcessBias 值的像素化层),具体计算需要将 Process0~1 区间变成 0 ~ 1+最大Bias 区间,计算过程如下图所示

image.png

做到这里我们可以得到如下的动画效果:

v2-1456077e283b4e602e7c626523709c9b_b.gif

3. 扫描描边加亮

如果仔细观察原图可以发现,在物体边缘和画面高亮部分会有一层描边,如下图所示:

image.png

这里我选择采用 画面高亮区域 混合 深度描边 实现这个效果。深度描边我只采用屏幕 V 轴方向偏移,偏移大小为 0.5 个当前层级像素宽度,这样做的好处是描边会出现不连续的断开,效果呈现较为随机。

画面高亮区域:

image.png

在节点中有个进度权重输入是之前没有提及的,在这里解释一下:因为描边亮度在整个进度范围内肯定不是统一的,在原图中观察得出 —— 进度开始时最亮,进度最后会慢慢变暗。所以我在这里用每层不同单元格大小计算分配了权重,节点如下图所示:

image.png

可以看到当单元格为最大值 64 时,权重为 1,单元格为 32 时权重为 1/2,单元格 16 时权重为 1/4。以此类推,最后一层的单元格权重为 1/64 。这样就能完美控制每个层级的描边亮度权重,非常好用。

细心的朋友可能会发现在节点中,进度权重后面 Pow 了一个 0.25。这是为了让整个权重变化幅度放缓,在实际使用中可以将 0.25 变成参数供调整。

image.png

注:从左到右依此为 4 个层级的描边,可以看到亮度是逐级递减的

这样通过控制亮度变化,整个动画层次感会大大提高。

深度描边区域:

image.png

BaseWeight: 上面介绍的随进度变化的权重,但这里我在后面添加了一个 cosine ,让整个权重发生了变化,因为 深度描边是开始和结束时很暗,中间层级很亮

image.png

  • SlightlyScale: 非常细节的像素动态追赶调整,后续会详细分析
  • SkyMask: 距离 Mask,在一定距离之后描边就不显示了
  • BiasedUV: 计算描边使用的偏移后的 UV
  • DepthEdge: 描边计算部分

深度描边我采用了最常规的制作方法,拿到场景深度只计算屏幕 V 方向偏移描边。

这里需要提及的是,我在深度描边中加入了暗角权重,也就是屏幕中心的深度描边会亮些,周围的会变暗,节点写在 DepthEdge 下面,可以看到我做了一个乘 1.414 的操作,这是为了让计算暗角的四周最大值为 1,方便后续的 1 减操作。

而 1.414 这个值也不是 Magic Number,是 1 除根号 0.5 的结果,至于为什么要这样算就留给大家自己思考了,其实就是最简单的三角函数计算。

最后结果如下所示:

  • 深度描边(开始和结束较暗,中间阶段变亮)

v2-1456077e283b4e602e7c626523709c9b_b.gif

  • 画面较亮区域描边(亮度不断变暗)

v2-1456077e283b4e602e7c626523709c9b_b.gif

刚刚说到节点中有个叫 SlightlyScale 的东西,这个究竟是干什么用的呢?我们先来看两张对比动图

  • SlightlyScale v2-1456077e283b4e602e7c626523709c9b_b.gif

  • SlightlyScale

v2-1456077e283b4e602e7c626523709c9b_b.gif

对比可以看到无 SlightlyScale 的像素点永远都在原图的高亮区域附近,而有 SlightlyScale 的像素点在不同进度下会有一个从左下到右上的位移效果。这就是 SlightlyScale 的作用。

image.png

SlightlyScale 原理其实非常简单,就是将画面根据像素化进度往画面中间缩放,0.95 为第一层级的缩放,1 为最后一层级的缩放。lerp 下方连入的部分为上面描边部分提及的BaseWeight

4. 细节部分

接下来就是细节部分了,主要设置了角色蓝图中的摄像机推镜动画,以及对上文制作的像素化后处理材质进行切换

image.png

最后在后处理材质中添加一张 ui。其实这里做 Widget 会更好,因为懒所以没做(记得这里要对图像做长宽比的修复,最后的长宽比应该是屏幕长宽比和图片长宽比共同作用的结果)

image.png

image.png

5. 总结

看到这里,是不是发现看似复杂的效果,实现起来却异常简单。

其实有时候,作为一名 TA 不一定非要写多牛逼的算法、抄多 dio 的论文、码多晦涩难懂的 code 显得自己多牛逼。反而是一些最不起眼最普通的效果,如果有能力综合完成一套完整出众的技术解决方案,达到最高品质同时满足各方需求,这才是王道。也许这套东西并没有用到多牛逼的技术,但~

Who Cares?

v2-ddbf9d7b1e03f93cba754ef78fc43ac0_b.webp

你学会了吗?

发现写文章比做东西的时间都要长,效果做了一天,写文章却用了两天。。。所以还请大家多多支持点赞关注转发,你的支持就是我更新的动力!!