效果拆解
接下来我们进行效果拆解。在做任何效果之前都需要进行拆解,这样才能明确方向。我决定从颜色、元素和动画三个方向进行拆解,这样做就更有条理,确保不会漏掉细节。大家对照脑图和上面的动图一起食用,应该可以get到我总结的这些部分。
下面我们根据总结的要点展开讲解。
效果制作
在正式讲解之前我想让大家看看我最后实现的效果
1.像素化处理
整个效果中最重要的也是最明显的部分,就是不同大小的像素过渡。在这里,我选择使用最大64x64的像素作为首次像素化的尺寸,然后不断细分像素大小,由 64x6 4变成 32x32 ,再到16x16,以此类推下去,最终显示出原始图片。(效果上有点像四叉树)
UnitResolution:像素化一个区域的分辨率
这套节点主要思路就是将屏幕像素划分给定像素化大小的区域,然后添加半个像素的宽度来修复floor的偏移(像素化的画面就会和原始图像对齐)
于是我们就能得到如下所示的画面
单元格分辨率:64x64
单元格分辨率:16x16
通过修改像素大小可以得到不同分辨率的结果,这也是画面像素细分后的层级效果。由于像素大小是不断二分的,所以上一层级的像素内刚好能装下4个下一层级的像素块,以此类推最后一层就为原图
2.像素化动画
接下来我们要将不同分辨率的图像混合起来,实现从中心到外围的像素大小渐变。画面中心为小像素块,画面外围为大像素块,如下图所示:
但是单纯这样一张图显然是不够的,我们需要让他动起来。制作动画的大致思路就是先制作n层不同细分的像素化效果,然后对每个层级制作动画偏移并混合。这样不同层级出现会有先后顺序,就能实现从中心扩散,且不断细分的动画效果。
我们首先着手中心向外扩散的效果,使用spheremask最适合不过了,但在spheremask之前我们需要对像素化的uv做一些细节操作。
首先是对uv做屏幕的长宽比修正,因为我们希望不管屏幕比例为多少,最后的扩散区域都是圆形。修复原理主要是对uv做了屏幕比例的反向修正,节点图如下:
左端输入像素化uv,右端输出修正长宽比的uv
然后我们将制作好的uv应用spheremask,并添加两个float输入:Process和ProcessBias,分别控制整体效果 进度 和 进度偏移
可以看到现在已经有多层不同分辨率的层级混合了,但混合的边缘太过于规整,于是我们需要用一张noise贴图进行扰乱,这张noise我选择使用bluenoise,因为得到的效果较为均匀。
这张noise其实也不是单纯的一通道灰度noise,我使用了两个通道,这两个通道中储存了不同的blue noise,然后我用这张noise的红绿通道,对像素化后uv的x和y轴做了随机效果(如果只使用一张噪波对两个轴向做noise的效果很容易得到具有方向性偏移的结果)。
接下来我们只需要控制 Process 数值即可实现从中心扩散的动画效果了。
但 Process 取值的区间是 0-1 吗?
很显然不是的。这里有个细节需要说明,由于每个层级都做了Process Bias的进度偏移,所以我们的 Process 进度数值需要满足最大偏移层的进度完成(最大偏移层就是拥有最大 Process Bias 值的像素化层),具体计算需要将 process 的 0-1 区间变成 “0” 到 “1+最大Bias” 区间,计算过程如下图所示
3.扫描描边加亮
如果仔细观察原图可以发现,在物体边缘和画面高亮部分会有一层描边,如下图所示:
这里我选择采用 画面高亮区域 混合 深度描边 实现这个效果。深度描边我只采用屏幕 V 轴方向偏移,偏移大小为 0.5 个当前层级像素宽度,这样做的好处是描边会出现不连续的断开,效果呈现较为随机。
画面高亮区域:
可以看到当单元格为最大值64时,权重为1,单元格为32时权重为1/2,单元格16时权重为1/4。以此类推,最后一层的单元格权重为1/64。这样就能完美控制每个层级的描边亮度权重,非常好用。
细心的朋友可能会发现在节点中,进度权重后面Pow了一个0.25。这是为了让整个权重变化幅度放缓,在实际使用中可以将 0.25 变成参数供调整。
注:从左到右依此为4个层级的描边,可以看到亮度是逐级递减的
这样通过控制亮度变化,整个动画层次感会大大提高。
深度描边区域:
BaseWeight:上面介绍的随进度变化的权重,但这里我在后面添加了一个 cosine ,让整个权重发生了变化,因为 深度描边是开始和结束时很暗,中间层级很亮
SlightlyScale:非常细节的像素动态追赶调整,后续会详细分析
SkyMask:距离Mask,在一定距离之后描边就不显示了
BiasedUV:计算描边使用的偏移后的UV
DepthEdge:描边计算部分
深度描边我采用了最常规的制作方法,拿到场景深度只计算屏幕v方向偏移描边。
这里需要提及的是,我在深度描边中加入了暗角权重,也就是屏幕中心的深度描边会亮些,周围的会变暗,节点写在DepthEdge下面,可以看到我做了一个乘1.414的操作,这是为了让计算暗角的四周最大值为1,方便后续的1减操作。
而1.414这个值也不是Magic Number,是1除根号0.5的结果,至于为什么要这样算就留给大家自己思考了,其实就是最简单的三角函数计算。
最后结果如下所示:
深度描边(开始和结束较暗,中间阶段变亮)
画面较亮区域描边(亮度不断变暗)
刚刚说到节点中有个叫SlightlyScale的东西,这个究竟是干什么用的呢?我们先来看两张对比动图
画面较亮区域描边(亮度不断变暗)
刚刚说到节点中有个叫SlightlyScale的东西,这个究竟是干什么用的呢?我们先来看两张对比动图
SlightlyScale原理其实非常简单,就是将画面根据像素化进度往画面中间缩放,0.95为第一层级的缩放,1为最后一层级的缩放。lerp下方连入的部分为上面描边部分提及的BaseWeight。
4.细节部分
接下来就是细节部分了,主要设置了角色蓝图中的摄像机推镜动画,以及对上文制作的像素化后处理材质进行切换
最后在后处理材质中添加一张ui。其实这里做Widget会更好,因为懒所以没做(记得这里要对图像做长宽比的修复,最后的长宽比应该是屏幕长宽比和图片长宽比共同作用的结果)
5.总结
看到这里,是不是发现看似复杂的效果,实现起来却异常简单。
其实有时候,作为一名 TA 不一定非要写多牛逼的算法、抄多 dio 的论文、码多晦涩难懂的 code 显得自己多牛逼。反而是一些最不起眼最普通的效果,如果有能力综合完成一套完整出众的技术解决方案,达到最高品质同时满足各方需求,这才是王道。也许这套东西并没有用到多牛逼的技术,但~
Who Cares?
发现写文章比做东西的时间都要长,效果做了一天,写文章却用了两天。。。所以还请大家多多支持点赞关注转发,你的支持就是我更新的动力!!
*文章授权转自微信公众号【包小猩CG杂货店】
加载中