小米 发表于 2024-7-15 18:25

【Catlike Coding Custom SRP学习之旅——11】Post Processing

【Catlike Coding Custom SRP学习之旅——11】Post Processing

写在前面

本篇来到了后措置,后措置算是衬着管线斗劲重要的一个部门吧,通过后措置的方式,可以极大程度地提升画面效果,常见的后措置包罗色调映射、Bloom、抗锯齿等等。除了一些整体的画面效果,后措置还可以用来实现描边等各类美术效果。本篇主要涉及到的内容有:后措置仓库、Bloom效果等。
前3章节为长篇文章,考虑到篇幅问题与工作量,从第4章节后半部门开始以及未来章节,考虑以提炼原教程为主,尽量减少篇幅与实际代码,在我的Github工程中包含了对源代码的详细注释,如需深入代码细节可以查看我的Github工程。文章写的不合错误的处所,欢迎大师批评赐正~
以下是原教程链接与我的Github工程(Github上会实时同步最新进度):
CatlikeCoding-SRP-Tutorial
我的Github工程
<hr/>

1 后措置仓库 Post-FX Stack

FX,其全称为Special Effects,即特殊效果,凡是也称为VFX(Visual Special Effects),即视觉特效。
参考维基百科,视觉效果(Visual effects,简称VFX),是在电影制作中,在真人动作镜头之外缔造或独霸图像的过程。操作影片和电脑生成的图像或影像合成,来缔造一个看起来真实的效果或场景,可代替较为危险、昂贵、或者底子不成能实现的状况,例如使用视觉效果代替危险的爆破效果或高空场景,避免演员搏命表演。
仔细想来,游戏很多技术城市沿用影视技术上的一些技术,比如在色调映射时,可以采用ACES(电影色调映射)等。此外,我也一直好奇为啥Special Effects叫FX,而不是叫SE,查了下网上,似乎只是因为FX谐音Effects,真是不知道从哪吐槽斗劲好。
凡是来说,因为后措置会包含很多分歧的效果,如色调映射、Bloom、抗锯齿等等,因此后措置在衬着管线中的布局往往是一个仓库式的布局(URP中也是如此,使用了Post Process Volume),即一步一步按挨次执行每一个后措置效果。因此在本篇中,会搭建这样一个仓库布局,而且实现Bloom效果。
1.1 配置资源 Settings Asset

首先,我们定义PostFXSettings资源,即Scriptable Object,将其作为衬着管线的一项可配置属性,这样就便利我们去配置分歧的后措置仓库,并可以便利地切换。在URP中也是使用类似的布局(Volume Profile)来实现的。
1.2 栈对象 Stack Object

类似于Light和Shadows,我们同样使用一个类来存储包罗Camera、ScriptableRenderContext、PostFXSettings,并在此中执行后措置仓库。
在进行后措置前,我们首先需要获取当前摄像机画面的标识RenderTargetIdentifier,RenderTargetIdentifier用于标识CommandBuffer的RenderTexture,Identifier有很多种形式,例如RenderTexture对象、内置衬着纹理BulitinRenderTextureType、TemporaryRT等等,其布局用于一种纹理标识方式,使用隐式转换运算符,其主要的用途就是可以隐式转换分歧RT标识符吧,避免了我们代码显式去做各种变换。在这里我们使用一个简单的int来标识sourceRT。
对于一个后措置效果而言,其实现过程说来很简单,传入一个矩形Mesh(其纹理即当前画面),使用一个Shader衬着该矩形Mesh,将其覆盖回Camera的RT上,我们通过Blit函数来实现该功能。Blit函数很重要,其定义为从一个纹理颠末自定义着色器措置后复制到其他纹理。对于后措置,我们需要知道,其无非就是在绘制一个矩形Mesh。
1.3 使用仓库 Using the Stack

在之前,我们的摄像机RenderTarget都是FrameBuffer,而FrameBuffer只可写,不成读。为了在后措置前读取到摄像机的RenderTarget,我们需要创建一个中间RT(_CameraFrameBuffer),来存储摄像机的衬着成果,再对其进行后措置。在每一帧开始,我们会创建该临时RT,在每一帧结束,会释放该临时RT。
在实现该框架后,我们可以在截帧中看到后措置Step,如下图所示(目前只是将_CameraFrameBuffer直接复制到Frame Buffer中。


1.4 强制断根 Forced Clearing

因为我们将摄像机衬着到了中间RT上,我们虽然会在每帧结束时释放该RT空间,但是基于Unity自身对RT的打点策略,其并不会真正地断根该RT,因此我们不才一帧时,该RT中会留存上一帧的衬着成果,导致了每一帧画面都是在前一帧的成果之上绘制的。如果我们每一帧衬着前清理该RT,那显然没问题。但是要是设置了不正确的ClearFlag,可能会导致衬着画面异常,如下图所示,我将ClearFlag设置成了Depth Only,上一帧的Color会和当前帧重叠,发生鬼影。


因此,我们需要手动强制设置ClearFlags。
1.5 Gizmos

我们还需要在后措置前后绘制分歧的Gizmos部门,这部门略~
1.6 自定义绘制 Custom Drawing

使用Blit方式绘制后措置,实际上会绘制一个矩形,也就是2个三角面,即6个顶点。但我们完全可以只用一个三角面来绘制整个画面,因此我们使用自定义的绘制函数代替Blit。
对于这个三角面,其形状如下图所示(图源自原教程),顶点坐标如图,应该很容易大白,当然这个三角面会有一部门空间被浪费,但是其效果也比Blit好。


在使用Blit时,在两个三角面片的接缝处,GPU会绘制两遍这些像素,如下图所示(图源自原教程),这也是使用一个三角面的好处之一。


剩下便是构造该三角面的Shader,我们直接在顶点着色器中设置三角面每个顶点的CS坐标和UV坐标,并不需要在CPU端做这些操作。在实现后,我们先直接输出uv颜色,如下图所示。


1.7 屏蔽部门FX Don&#39;t Always Apply FX

目前,我们对于所有摄像机都执行了后措置。但是,我们但愿只对Game视图和Scene视图摄像机进行后措置,并对分歧Scene视图提供单独的开关控制。很简单,通过判断摄像机类型来屏蔽。
1.8 复制 Copying

接下来,完善下Copy Pass。我们在片元着色器中,对原画面进行采样,而且由于其不存在Mip,我们可以指定mip等级0进行采样,避免一部门性能消耗。此外,Unity会存在一些情况,无法自动修正uv坐标的v轴翻转,因此我们需要手动判断下,解决v轴翻转。
2 辉光 Bloom

目前,我们已经实现了后措置仓库的框架,接下来实现一个Bloom效果。Bloom效果应该非常常见,也是经常被用于美化画面,其主要感化就是让画面亮的区域更亮。以前也跟着《Shader入门精要》做过一次,其实际并不复杂。
2.1 Bloom金字塔 Bloom Pyramid

为了实现Bloom效果,我们需要提取画面中亮的像素,并让这些亮的像素影响周围暗的像素。因此,需要首先实现RT的降采样。通过降采样,我们可以很等闲地实现模糊功能。对于SourceRT,每次降低其1/2的尺寸,再使用Bilinear采样器进行采样,每次可以得到4个像素的模糊成果,由此构建出Bloom Pyramid。简单来说,Bloom Pyramid即将SourceRT每次降低1/2尺寸后得到的RT数组。
在实现的过程中有一点值得注意,我们在申请PropertyToID时,Unity会将一批持续申请的标识符以挨次形式标识,因此,我们只需知道第0层Pyramid即可索引到所有Pyramid,只要我们持续申请了这批标识符。
Bloom Pyramid效果图如下,即每次降采样一半。




2.2 配置辉光 Configurable Bloom

凡是来说,我们并不需要降采样到很小的尺寸,因此我们将最大降采样迭代次数和最小尺寸作为可配置选项。下图为最大迭代次数为5的效果图。


2.3 高斯滤波 Gaussian Filtering

目前,我们使用双线性滤波来实现降采样,这样的成果会有很多颗粒感,因此我们可以使用高斯滤波,而且使用更大的高斯核函数,通过9x9的高斯滤波加上双线性采样,实现18x18的模糊效果。
理论上,9x9的高斯滤波,对于每一个片元,需要采样81次,但其实,相邻像素之间的采样成果是可以复用的,因此我们可以先横向滤波,再纵向滤波,花费18次采样达到81次的效果。但其代价是,需要使用中间RT来保留临时成果,也就是典型的空间换时间了。
最后高斯滤波的降采样效果如下(5次迭代),效果比2x2滤波强很多,虽然一次降采样会花费更多采样操作,但是我们可以降低采样迭代次数。


2.4 叠加模糊 Additive Blurring

对于Bloom的增亮,我们直接将每次降采样后的Pyramid一步步叠加到原RT上,即直接让两张分歧尺寸的图片以不异尺寸采样,叠加颜色,这一步也叫上采样,其意为将一个较小尺寸的RT看作较大尺寸来进行采样。在叠加的过程中,反复操作了生成Horizontal高斯滤波的中间临时RT。这一步也很简单,具体不展开~最后效果图如下,看起来像过曝了一样,之后会措置。


2.5 双三次上采样 Bicubic Upsampling

在上采样过程中,我们使用了双线性采样,这样可能依然会导致块状的模糊效果,因此我们可以增加双三次采样Bicubic Sampling的可选项,以此提供更高质量的上采样。
2.6 半分辩率 Half Resolution

由于Bloom会衬着多张Pyramid,因此其消耗是斗劲大的,其实我们完全没必要从初始分辩率开始降采样,从一半的分辩率开始采样的效果也很好。
2.7 阈值 Threshold

目前,我们对整个RT的每个像素都进行了增亮,这让这个画面看起来过曝了一般,但其实Bloom只需要对亮的区域增亮,本身暗的处所就不需要增亮了。因此,我们在生成半分辩率的时候,直接将暗的像素颜色值设置为0,这样在之后降采样过程中这些像素也就依然维持在一个较小值。而且,我们通过一个亮度阈值来筛选亮的像素,并通过膝盖函数来平滑过渡。膝盖函数如下图所示(图片源自原教程),增加阈值后,效果正常了很多。




2.8 强度 Intensity

最后,提供一个Intensity选项,控制Bloom的整体强度。在我们完成所有的上采样后,会将其成果叠加到原RT上,此时将Intensity作为权重感化到上采样成果上,以此来达到控制强度的效果,非常简单。最后给出Intensity很大的效果图。


结束语

大功告成,我们在衬着管线中增加了后措置仓库,以及实现了一个Bloom效果,其实在做完这篇之后,我感觉这个衬着管线才算基本上达成了大部门需要的功能,也算是一个里程碑吧。虽然在后措置仓库的编纂形式上,可能远不如URP的Volume组件来的便利。在此中,我们也实现了通过一个三角面来实现后措置,对比Blit会更高效。
参考


[*]https://catlikecoding.com/unity/tutorials/custom-srp/point-and-spot-shadows/
[*]https://zh.wikipedia.org/wiki/%E8%A7%86%E8%A7%89%E6%95%88%E6%9E%9C
[*]https://docs.unity3d.com/cn/2021.3/ScriptReference/Rendering.RenderTargetIdentifier.html
[*]题图来自Wlop大大。
页: [1]
查看完整版本: 【Catlike Coding Custom SRP学习之旅——11】Post Processing