杨柳657 发表于 2020-12-23 09:14

[译文]Unreal Engine 4 卡通着色(Cel Shading)教程

原文|《Unreal Engine 4 Cel Shading Tutorial》
作者|Tommy Tran
Feb 27 2018 阅读时长|20分钟 内容难度|中等基于PBR渲染在Unreal Engine 4中制作写实风格的游戏是比较容易的。PBR渲染会模拟光照和材质的交互并生成最终结果。然而如果想开发风格化效果的游戏,你可能就要探索其它技术了。
其中一种技术叫做卡通着色(英文名:Cel Shading 或 Toon Shading)。这种技术就是模仿典型卡通或者动画中的着色风格。比如《街头涂鸦》(Jet Set Radio)或者《塞尔达传说 之 风之杖》(The Legend of Zelda: The Wind Waker and Gravity Rush)
在本教程中,你将会学到:
如何创建和使用后期处理材质创建卡通着色器将卡通着色器应用于特定的模型使用查找表(LUT:Lookup table)控制色带(color band)
注意:本文假设你已经有了一定的UE4基础知识本文是Unreal Engine着色器教程四部曲之一:
第一部分: 卡通着色(Cel Shading)第二部分:卡通风轮廓线(Toon Outline) 第三部分:使用HLSL自定义着色器(Custom Shaders Using HLSL) 第四部分:绘画风滤镜(Paint Filter)

开始吧

可以先下载初始工程,打开压缩包中的CelShader.uproject,你就可以看到下面的场景了:


我们将对这个角色使用卡通着色。在开始之前,你要知道什么是卡通着色。
什么是卡通着色?

卡通着色就是使用一个多段的色带来渲染对象,而非使用连续的渐变。




下面就是塞尔达传说之旷野之息中的卡通着色。注意:只有角色是卡通着色,背景并不是。


上图中,有3个色段。一个暗部色段,一个中间区色段,一个高光区色段。
有一个常见的误解,即有轮廓线就是卡通渲染。可以将无主之地(Borderlands)作为一个反例。尽管这个游戏是风格化的,但它不是卡通渲染。参见下图,注意角色的渲染并非使用色段:




尽管轮廓线并非卡通渲染的一部分,但它们经常被一起使用。因为这样画面会更像手绘的。参见类似 龙珠战士Z(Guilty Gear Xrd and Dragon Ball FighterZ)


在下个部分中,你将学习如何实现卡通渲染。
卡通着色原理

最常用的方法就是比较表面方向(即法线方向)和光照方向。通过计算法线和光线的点积,你可以获得一个介于-1和1之间的值。
当值等于-1,说明表面和光线朝向反向;0说明二者垂直;1说明二者朝向相同。




为点积设定阈值,可以定义多个色带。比如,可以将暗色指定为点积大于-0.8.当点积低于-0.8即为亮色。这样就定义了两个色段。




这种方法的局限性在于: - 其它的光源将不能影响卡通着色对象 - 其他物体也无法向卡通着色对象投影




我们需要使用其他方法来修正这些问题。不再计算点积,而是计算表面光照量,然后使用这个值取代点积。




现在你已经知道什么是卡通着色以及它的工作原理,是时候亲手创建一个了。
创建卡通着色器

本文的卡通着色是基于后期处理效果(post process effect)。后期处理允许你在引擎渲染完画面以后对它进行调整。后期处理常用于景深效果(depth of field),动态模糊效果(motion blur)以及光华效果(bloom)。
要创建后期处理效果,你需要使用一种后期处理材质(post process material)。在材质文件夹中创建一个新的材质文件并重命名为“PP_CelShader ”,然后打开它。
将其domain选项由默认的Material Domain改为Post Process,这样就可以将普通材质转换为后期处理材质。


第一步要计算每个像素的光照是多少。我们将其称之为光照缓冲(lighting buffer)。
计算光照缓冲

当虚幻渲染一张图像到屏幕时,它会将批次(pass)存储到一系列缓冲区中。为了计算光照缓存,我们必须访问其中的两个缓冲区
1. 后处理输入(Post Process Input):一旦虚幻完成了光照和后处理,它会将图像存储到这个缓冲区。如果你不在对它做进一步的后期处理,那么这就是虚幻要显示到屏幕的内容。
2. 漫反射颜色(Diffuse Color:) 这个是没有任何光照和后处理的场景。它将包含屏幕上所有对象的漫反射颜色。


我们需要使用ScreenTexture节点来访问这些缓冲区。创建并选择该节点,在其细节面板(Details panel)上设置要访问的缓冲区。
要访问Post Process Input缓冲区,将Scene Texture Id改为PostProcessInput0




要访问Diffuse Color缓冲区,将Scene Texture Id改为DiffuseColor




光照缓冲(lighting buffer)仅包含描述光照量的灰度值。这意味着我们不需要两个缓冲区中的颜色信息。我们可以将两个SceneTexture节点的颜色输出连接到一个Desaturation节点(去饱和度节点)来去除颜色信息。这样两个缓冲区的颜色就被完全去除了。


用SceneTexture:PostProcessInput0除以SceneTexture:DiffuseColor,这样光照缓冲就很简单地得到了。


然后,使用一个Clamp节点将输出值限制在0到1之间,这样更方便我们设置(色段的)阈值了。


下图就是一个可视化表示的光照缓冲:


如你所见,光照区偏白色,非光照区偏黑色。下一步,我们就可以使用光照缓冲来创建阈值。
创建阈值

本例中,对于任何像素如果其计算结果大于0.5,则使用正常的漫反射颜色;如果小于0.5将使用亮度减半的漫反射色。




注意: 你可以改变B的输入从而改变阈值
再创建一个SceneTexture节点,并将Scene Texture Id改为Diffuse Color,然后用Color乘以0.5从而获得亮度减半的漫反射颜色值。




最后,如下连接所有的节点:


小结:
Desaturation节点将把Post Process Input和Diffuse Color转换成灰度图像用Divide节点将Post Process Input除以Diffuse Color,是我们获得光照缓存。Clamp节点是出数值介于0到1之间。使用If节点,使光照值高于0.5的像素输出正常颜色,使小于0.5的像素输出亮度减半的颜色。
这样你就得到了你的卡通着色器,你需要把它应用到场景中。
使用后期处理材质(Post Process Materials)

我们需要创建一个叫做后期处理体积(Post Process Volume)的东西,才能使用后期处理材质。 后期处理体积常用于控制诸如白平衡(white balance)、饱和度(saturation)以及对比度(contrast)等后期处理效果。
点击Apply然后主编辑器。在模式面板(Mode Panel)的体积(Volumes)分类中找到后期处理体积(Post Process Volume),然后将它拖拽入视口。


接下来,需要告诉后期处理体积使用卡通着色器。先选择后期处理体积,在其细节面板上找到Rendering Features\Post Process Materials并点击+号标记。
然后点击名为Choose的下拉菜单并选择Asset Reference。




然后点击当前显示None的下拉菜单,选择之前创建的“PP_CelShader”材质。




默认情况下,后期处理体积只会影响其范围内的对象,但本例中,我们想让它影响这个世界,所以要启用它的Infinite Extent (Unbound)选项。




这样,卡通着色器就被应用到了整个画面,你将看到下图的样子:


“等等!这看起来和你最初展示的卡通着色并不时很像哦!”
这个区别的主要原因是引擎是在色调映射(tonemaping)之后应用的卡通着色器。要修正这个问题,我们需要让引擎在色调映射之前应用卡通着色器。
在色调映射之前应用卡通着色器

在显示一幅画面之前,虚幻引擎需要进行一个叫做色调映射(tonemaping)的处理。它的作用是让画面看起来更逼真。其实现原理是将输入的颜色通过曲线转换成新的值。
下面是两幅后处理输入缓冲的图像。一个是色调映射前的一个是色调映射后的:


如你所见,色调映射前高光部分太亮了,而色调映射后高光区柔和了很多。
色调映射在多数场合都表现良好。但因为我们要对后处理输入缓冲进行重新计算,所以我们需要它的原始值。
打开PP_CelShader并确认你没有选择任何东西,然后再其细节面板找到Post Process Material将Blendable Location 设为Before Tonemapping。




点击应用并回到主编辑器,这时颜色看起来好多了。


在下一个部分,你将学习如何将卡通着色应用到特定的对象。
孤立卡通着色器(Isolating the Cel Shader)

我们需要使用一种叫做自定义深度(Custom Depth)的特性来孤立后处理效果。如同Post Process Input和Diffuse Color一样,自定义深度也是一个可以在后处理材质中访问的缓冲。
在学习自定义深度之前,我们先来了解一下什么是场景深度(Scene Depth)缓冲。场景深度存储着每个像素距摄像机平面的距离。下图是一个可视化的场景深度图:


自定义深度存储着同样的信息,只不过它只针对你指定的模型存储。下图是这个维京模型的可视化自定义深度图:


通过对比场景深度和自定义深度,我们可以将效果孤立出来。如果场景深度低于自定义深度,则使用普通画面,如果场景深度高于自定义深度则使用可通着色画面。
首先用自定义深度渲染维京模型。
使用自定义深度

在世界大纲( World Outliner)中选择SK_Viking,然后再细节面板找到Rendering部分,启用Render CustomDepth Pass。




接下来进行深度对比。打开“PP_CelShader”并创建下面的节点连接:




注意: Mask (R)节点是组件遮罩。它们可以将多个通道数据转换成标量。之所以要对场景深度和自定义深度进行遮罩,是因为If节点的A和B只能接受标量。
接下来,进行如下连接:




现在只有在自定义深度中渲染的模型才可以获得卡通着色了。
点击应用并回到主编辑器,你会看到只有维京人模型有卡通渲染:


这个卡通着色器效果不错,但是还有点太简单。比如,如果我们想要多于2个段的色彩怎么办?如果我们想在段与段之间创建一些柔和的过渡怎么办?我们可以使用查找表(Lookup Tables 即LUT)来实现这一需求。
什么是查找表(Lookup Table 即 LUT)

我们小时候刚学乘法时,每人都会背诵乘法表。当计算乘法题时,与其说是计算,不如说是在乘法表中查找答案。


这个乘法表本质上就是一个查找表(LUT)。它是一个可以通过输入值查找预计算的数组。在乘法表中,输入值就是乘数和被乘数。
在卡通着色器中 LUT就是一个拥有一些渐变的图片。下图就是LUT的大致长相:




之前我们计算暗部颜色是通过漫反射色乘以0.5。接下来我们不再让它乘以常数0.5,而是使用LUT中的值。这样你可以灵活地控制段数和过渡。通过LUT的样子,你可能已经想到着色时如何查找它了。 在使用LUT之前,我们需要对它的纹理设置做一些修改。
修改LUT设置

在“Textures”文件夹中找到“T_Lut_01”。这个就是LUT的样子:




第一个需要修改的设置是sRGB。在渲染过程中虚幻引擎会将所有启用sRGB的纹理转换成线性颜色。这样更便于引擎进行渲染计算。
sRGB设置对那些要用于显示的纹理非常有益的,但是对于法线贴图以及LUT等存储数值并用于数学计算的纹理就不行了。因此应该停用sRGB,使虚幻引擎不再对这些纹理进行转换。
在纹理区取消sRGB的勾选。




另外一个需要设置的是纹理的瓦片化。因为我们并非要显示这个纹理,所以没有必要对其瓦片化。并且如果依旧保留其瓦片化的勾选将会导致其边缘抽样时的一些问题。
将其X-axis Tiling Method和Y-axis Tiling Method都设置为Clamp




将这些设置完毕,我们需要将LUT应用到后处理材质中。
使用LUT

关闭“T_Lut_01”并打开“PP_CelShader”。首先删除下图中高亮的节点:


然后创建一个Texture Sample节点并将其Texture设置为“T_Lut_01”。这个LUT将会产生3个带有柔和过渡的色段。




还记得么?LUT需要依据输入值来决定输出值。本例中我们将使用光照缓冲作为输入值。
将Clamp节点连接到Texture Sample节点的UVs上。




因为光照缓冲和纹理坐标的值域都是0到1,所以这样的连接是可行的。比如纹理缓冲中的某像素值为0.5,那么LUT的输出值将为纹理中间的值。
接下来,我们通过下图所示重新连接节点来实现漫反射色和LUT的相乘:




之所以要用Append节点将Texture Sample 节点的输出转换为4维向量。因为3维向量无法和4维向量(场景纹理)相乘。
最终,节点连接图如下所示:




现在,我们不再让漫反射色和常量相乘,取而代之,让它乘以一个LUT的值。这样就可以用LUT来控制色段的数量以及它们之间的过渡。光照缓冲将决定LUT的输出。
点击应用并关闭“PP_CelShader”。此时,卡通着色将有3个带柔和过渡的色段。


下面是使用不同LUT获得效果的对比。这些LUT也包含在项目中。




接下来干什么

你可以在这里下载完整的项目。
如你所见,后处理材质相当强大。它们可以让你创建很多逼真的以及风格化的效果。
页: [1]
查看完整版本: [译文]Unreal Engine 4 卡通着色(Cel Shading)教程