ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

UE4后处理材质:用Post Process与Sobel算子实现卡通渲染

2026/9/15 12:26:00 拓冰建站 浏览量
UE4后处理材质:用Post Process与Sobel算子实现卡通渲染 1. 项目概览与效果拆解1.1 这个实例最终做出来是什么效果这次要做的不是某个角色材质也不是地面贴图而是一个挂上去就能让整个场景“变卡通”的Post Process材质球。具体效果是画面里的颜色会被压成几个明显的色阶原本细腻的明暗过渡变成类似动漫风格的硬朗色块同时物体的轮廓会像手绘线稿一样自动描出一圈黑边。静态截图看起来像动画电影的单帧动态镜头扫过去画面也会保持这种统一的风格感。我之所以把这类效果放在“入门实例”这个位置是因为它不依赖复杂的建模或角色绑定只要场景里随便摆几个Static Mesh比如Cube、Sphere、Skeletal Mesh都可以材质球挂上后全部统一生效。对于刚开始接触UE4材质系统、又很想看到“一键换风格”效果的同学来说这是性价比非常高的一次练习。做这个实例需要掌握的UE4知识点主要集中在材质编辑器里Post Process材质域、SceneTexture节点从缓冲中取数据、Sobel算子在屏幕空间做边缘检测、色阶化Posterization的数学表达还有Post Process Volume在场景中的挂载方式。这些知识点拆开看都不复杂但连起来就构成了一条完整的“屏幕空间后处理”管线。做完之后你不仅有了一个卡通滤镜更重要的是理解了UE4后期处理材质的工作原理之后再做描边、水墨、噪点、扫描线这些效果思路就通了。1.2 涉及的UE4核心知识点先说Post Process材质和普通材质的本质区别。普通材质作用是“物体表面的外观”引擎在渲染某个网格体时逐像素计算它而Post Process材质作用的是“整张画面”它在一个全屏Pass里跑画面里每一个像素都会经过这个材质重新计算一遍然后再输出到屏幕上。素材范围上它也能拿到普通材质拿不到的信息。普通材质你可以拿纹理坐标、拿法线、拿世界位置但拿不到“屏幕空间里这个像素旁边是什么”而Post Process材质可以通过SceneTexture节点读取各种缓冲比如SceneColor当前帧颜色、SceneDepth深度缓冲、WorldNormal世界法线、CustomDepth自定义深度。这就是它能做全屏描边的基础。这个实例涉及的关键知识点我列成了一张表方便后续对照知识点作用在实例中的用途Material Domain Post Process让材质变成全屏后处理shader效果作用于最终画面SceneTexture: PostProcessInput0获取当前帧颜色做色阶化的输入颜色SceneTexture: SceneDepth获取场景深度缓冲检测深度不连续处得到轮廓边缘ScreenPosition当前像素的屏幕UV坐标0-1范围作为SceneTexture的采样坐标SceneTextureSize屏幕缓冲的实际像素尺寸换算“一个像素”对应的UV偏移量Posterization色阶化连续颜色压成有限档位产生卡通感色块Sobel算子计算图像梯度强化边缘区域Post Process Volume场景中管理后期效果的体积挂载材质并控制影响范围1.3 准备工作和版本说明我这次使用的是UE4.27但整个材质节点的连接方式在4.24到4.26里都是一样的如果你用的是UE5节点名字上可能有一点出入比如部分版本里SceneTextureSize节点不叫这个名字但搜索SceneTextureSize或TextureSize基本能找回来。场景选择上我建议用第三人称模板默认场景或者随便拖一两个几何体再放一个方向光。不要一上来就用大型开放场景因为后处理材质的调试过程需要频繁看效果场景太大反而干扰判断。目标平台如果是为了测试先在PC上跑就行。如果你想在移动端用后面第4章我会单独讲性能和兼容性问题。关于蓝图和代码这个实例完全不需要写任何一行C或蓝图逻辑纯材质节点就能完成所以即使你是刚接触UE4的小白只要会拖拽节点、会连接引脚就能做出来。2. 核心原理后处理材质如何“看懂”画面2.1 后处理材质的工作位置我们可以把后处理材质理解为“相机镜头前加的一层滤镜”。它在引擎渲染管线末端运行整个场景都绘制完成后引擎把最终画面交给这个Pass材质对屏幕上的每个像素做一次计算。由于它作用的是屏幕空间所以不关心物体是什么材质、有多复杂只关心当前像素及其周围像素的关系。在UE4中Post Process材质可以挂在管线的不同位置由材质细节面板里的Blendable Location属性控制。常用的是Before Tonemapping和After Tonemapping这两个位置。Before Tonemapping是在色调映射之前执行输入颜色是HDR高动态范围的数据适合做Bloom、泛光这些需要在曝光前处理的效果After Tonemapping在色调映射之后执行输入颜色是已经映射到LDR范围的颜色更适合做风格化处理。我做卡通色阶化时把材质放在了After Tonemapping这个位置原因是色阶化的本质是压缩颜色数量在LDR范围里操作最直观输入颜色在0到1之间乘个系数再取整得到的色阶数量基本可控。如果放在Before Tonemapping颜色范围更大取整的档位分布会受曝光影响反而不好调。2.2 SceneTexture节点和你需要的情报SceneTexture节点是后处理材质的关键访问通道。它允许你在材质里读取引擎缓存好的多种屏幕空间数据。它的工作方式有些像采样一张纹理只不过这张“纹理”是全屏缓冲区数据。比如SceneColor记录的是当前帧已经渲染出来的颜色也就是我们在视口里看到的基础画面SceneDepth记录的是每个像素到相机的距离但存储时通常是非线性的深度值WorldNormal记录的是场景中每个像素的世界空间法线方向CustomDepth则是开发者自己控制的深度标记平时默认不写入。在材质编辑器里屏幕UV坐标由ScreenPosition节点给出。它返回当前像素在视口中的UV坐标左下角是(0,0)右上角是(1,1)。这个坐标可以直接接到SceneTexture节点的UV输入。后处理材质运行时SceneTexture节点内部会拿着这个UV去对应缓冲中查数据返回缓冲里存储的实际值。这里有个关键细节如果我们想判断“当前像素左边那个像素”的信息不能直接去改SceneTexture的UV输入因为那会连整个采样位置都变掉。我们需要在ScreenPosition得到的UV上加上或减去一个极小的偏移量这个偏移量正好等于“一个像素”在UV空间中的跨度。屏幕中一个像素的宽度在UV空间里是1/屏幕宽度一个像素的高度是1/屏幕高度这个值可以通过SceneTextureSize节点获得。除以分辨率之后就能得到单个像素对应的UV偏移量。2.3 边缘检测与色阶化卡通效果的两大支柱卡通感从哪里来抛开美术风格的话题从图像处理角度看卡通渲染和写实渲染最明显的差异有两个一是颜色的“量化”二是边缘的“强调”。颜色量化也就是色阶化在数学上非常直接把连续的颜色值除以一个固定值然后取整再乘回来。这个过程的代码表达大概是这样的假设原颜色是C色阶数量为N那么新颜色C round(C * N) / N。N越小颜色档位越少画面越“平”动漫感越强N越大效果越接近原图当N大到一定程度时肉眼已经看不出区别。比如颜色值0.37乘以8后是2.96取整得3再除以8得到0.375于是原来这个0.37的颜色就被统一归到了0.375这一档。边缘检测的核心思路则是对比“相邻像素之间的差异”。如果一个像素和它周围的像素在某个属性上差异很大比如一边是近处的物体一边是远处的天空深度值差距明显那么这个像素大概率位于物体的轮廓上。类似地如果深度差不多但法线方向差很多那它也处于同一个物体的内部棱线上比如立方体的两个面交界处。后处理材质里判断边缘最常用的策略是Sobel算子。它本质上是一组3x3的卷积模板分别计算像素在水平方向和垂直方向上的梯度大小。把9个相邻像素的深度或法线值带进去加权求和之后再取模得到的值越大说明当前像素越可能是边缘。把这个值作为Alpha混合原始颜色和黑色就能渲染出轮廓线。3. 实操步骤从零搭建卡通后处理材质3.1 创建Post Process材质域在Content Browser里右键选择Material命名为PP_Cartoon。双击打开材质编辑器在细节面板最上方的Material Domain选项从默认的Surface改成Post Process。改完之后材质球外观会变输出节点的引脚也会剩下一个EmissiveColor。这里有一个很容易踩的坑材质域改成Post Process之后很多人会忘记调整Blendable Location。这个属性默认是Before Tonemapping不改也能看到效果但颜色色阶化的表现会受HDR范围影响。我建议在细节面板里把它改为After Tonemapping。在开始大段连线之前你可以先临时用一个SceneTexture节点选择PostProcessInput0然后直接连接到EmissiveColor保存并编译。这个动作的目的是验证后处理材质在场景里能不能正常挂载、能不能看到画面变化。如果这一步通过后面再往下接就不会“为什么我做了半天没反应”这种问题了。3.2 色阶化节点组的搭建色阶化的节点组是这个材质里最直观的部分。先在材质编辑器空白处搜索“SceneTexture”创建后把SceneTexture Id设置为PostProcessInput0这样就拿到了当前帧的颜色作为输入。然后按这个顺序连接节点PostProcessInput0的输出接到Multiply节点的一个输入Multiply节点的另一个输入接一个Scalar Parameter命名为Color Levels默认值可以先设为8。Multiply的输出接到Floor节点Floor的输出再接一个Divide节点Divide的第二个输入同样接Color Levels。最后Divide的输出接到最终输出的EmissiveColor。如果你跟着做完并保存预览视频缓冲区里已经可以看到画面变得一档一档的了尤其是天空这种渐变区域最明显。如果直接把效果拉到极致色阶档位太少会非常糊我在调参环节会详细说怎么搭配。这里解释一下为什么要“先乘再取整再除”而不是直接用“乘以一个系数保留小数”。乘以色阶数N是把色阶的区间拉开比如N8时0到1的颜色范围被分成8段每段宽度约0.125。取整后同一段里的颜色会被映射到同一个整数值比如0.10和0.12在乘8后分别是0.8和0.96取整后都是1。再除以8回归到0.125于是这段里的所有颜色最终都变成0.125。有个小细节Floor是向下取整但会让暗部偏黑因为0.9取整到1但0.99取整后也是1实际上0.99和1之间的小数被吞了。我建议用Round节点代替Floor也就是四舍五入取整这样色阶分布的明暗关系更接近原图。两者都可以试喜好不同效果略有差异。3.3 Sobel边缘检测的材质实现现在做整个材质里技术含量最高的一部分屏幕空间边缘检测。先说思想。我们要对目前像素周围的深度值做Sobel卷积计算梯度。假设当前像素的UV坐标是uv单个像素的UV偏移量是offset那么周围8个像素的UV坐标分别是uv(-offset,-offset)、uv(0,-offset)……以此类推。我们需要对这9个位置分别采样SceneDepth得到9个深度值。Sobel算子有两个卷积核一个检测水平方向的梯度Gx一个检测垂直方向的梯度Gy。3x3的Sobel核是Gx模板 -1 0 1 -2 0 2 -1 0 1Gy模板 -1 -2 -1 0 0 0 1 2 1在材质里计算时先创建9个SceneTexture节点全部设置为SceneDepth分别用不同的UV偏移量去采样。然后把Gx模板的系数作为Multiply节点的乘数对9个结果加权求和。同理得到Gy。最后边缘强度近似为|Gx| |Gy|或者用sqrt(Gx^2 Gy^2)。材质里可以用Abs节点求绝对值再用Add节点相加这样比较直观。操作上我不会真的建9个SceneTexture节点手动连这么长的线因为在材质编辑器里这样会乱到不可控。我建议用一个Custom节点写一小段GLSL风格的代码。Post Process材质支持Custom节点双击填入代码就行。下面是简化实现float2 TexelSize 1.0f / View.ViewSizeAndInvSize.xy; float2 uv ScreenAlignedPosition(0.5f); // 或者直接使用传入的 UV 参数 // 采样深度 float depth[9]; depth[0] SceneTextureLookup(uv TexelSize * float2(-1, -1), 6, false).r; depth[1] SceneTextureLookup(uv TexelSize * float2(0, -1), 6, false).r; depth[2] SceneTextureLookup(uv TexelSize * float2(1, -1), 6, false).r; depth[3] SceneTextureLookup(uv TexelSize * float2(-1, 0), 6, false).r; depth[4] SceneTextureLookup(uv, 6, false).r; depth[5] SceneTextureLookup(uv TexelSize * float2(1, 0), 6, false).r; depth[6] SceneTextureLookup(uv TexelSize * float2(-1, 1), 6, false).r; depth[7] SceneTextureLookup(uv TexelSize * float2(0, 1), 6, false).r; depth[8] SceneTextureLookup(uv TexelSize * float2(1, 1), 6, false).r; float gx -depth[0] depth[2] - 2.0f * depth[3] 2.0f * depth[5] - depth[6] depth[8]; float gy -depth[0] - 2.0f * depth[1] - depth[2] depth[6] 2.0f * depth[7] depth[8]; float edge abs(gx) abs(gy); return edge;SceneTexture节点在Custom节点里通过SceneTextureLookup函数访问缓冲第二个参数传SceneTextureId。SceneDepth在UE4里的Id是6但我在实际项目中一般直接用材质编辑器自动化的SceneTexture节点代码版只是作为参考。如果你不想用Custom那就在材质图里手动搭建但务必给节点做注释不然过两天自己都看不懂。这一步有一个比较大的坑深度缓冲中的深度值是非线性的。直接对深度做差分会导致远处物体的微小深度变化被过度放大约束不了。我的经验是在做Sobel之前先对深度取倒数也就是用1.0除以深度把非线性拉平这样近处和远处的边缘灵敏度比较均衡。材质里可以用Divide节点实现也可以写成1.0 / depth。如果你不做倒数处理也不是不能用只是调试阈值时会发现“同一个阈值在近处描边正常到远处就整片变黑”或者反过来。为了避免这种问题我建议一上来就做倒数。3.4 合成描边与色阶颜色的最终输出边缘检测和色阶化都做完之后最后一步是把两路结果合成。边缘强度的输出是一个数值我习惯接一个Scalar Parameter命名为Edge Threshold用于控制灵敏度。用Step节点或者比较节点把边缘强度是否超过阈值转成0或1。这里有一个连续性更好的方式是用SmoothStep给阈值一个软过渡区间这样可以避免边缘出现硬邦邦的锯齿感。材质编辑器里可以直接搜SmoothStep节点。然后用Lerp节点做混合。Lerp的Alpha输入接的是边缘强度和阈值比较后的结果。A输入接DeepColor也就是描边颜色默认用黑色可以后续替换成其他颜色B输入接我们之前做好的色阶化颜色。如果边缘强度大Alpha接近1输出就偏黑否则输出色阶化颜色。我习惯最后再对输出结果做一次Saturate限制在0到1范围然后接到最终的EmissiveColor。这个步骤可以防止HDR溢出导致画面过曝。整个材质编译后保存回到场景就能看效果了。3.5 挂载Post Process Volume并查看效果内容浏览器里把PP_Cartoon拖拽到场景中引擎会自动生成一个Post Process Volume并把材质添加进去。如果你希望整个场景都被这个效果覆盖一定要在细节面板里勾选Unbound也就是无边界。在细节面板的Post Process Materials数组里点加号会多出一个可下拉的槽位我们把PP_Cartoon指定进去。此时场景中的画面应该立刻变成卡通风格。如果场景里已经存在多个Post Process Volume那就要注意Priority值。UE4会把所有后期体积按照Priority从高到低排序越高的越后面执行而且会覆盖或混合同类型的效果。当你有多个后期效果叠加时可以调整Priority来控制叠加顺序。VR或多视图渲染时还要注意Post Process Volume的扩展范围和相机位置。入门阶段用默认的Unbound全屏效果就够了。4. 参数调优与性能控制4.1 常用参数调整逻辑材质搭好之后真正花时间的其实在调参。我在实际项目中见过的现象是节点连完一看效果要么“太卡通了糊成一片”要么“边缘乱七八糟到处是黑线”很少有一次到位。第一个要调的是Color Levels色阶数。默认8档起步然后看画面反馈。如果觉得画面太灰太平减小到4或5如果觉得和原图区别不大试试点到12以上。我个人在卡通风格项目里常用5到8这个范围因为低于4档时暗部细节全部丢失脸部阴影和衣服褶皱都会变成一个毫无层次的黑坨。第二个要调的是Edge Threshold边缘阈值。这个值决定了“多大的深度差算边缘”。阈值太低画面到处都是黑边太高轮廓线又很浅甚至消失。我建议从0.01开始试每次翻倍往上推直到看到清晰轮廓。记住深度值经过倒数处理后不同场景的绝对数值范围差异很大所以阈值不要靠猜边看边改。第三个是描边颜色。默认黑色是最保守的选择但如果场景整体偏亮或者偏暗黑色描边会显得很跳。可以尝试把描边颜色设为深蓝灰色或者用SceneColor亮度反相来做动态描边色这个在第6章我会展开。我加一个实操细节用材质实例而不是直接改材质里的常量参数来调。给每个关键系数都做成Scalar Parameter和Vector Parameter场景中创建材质实例后在实例上拖动数值调比每次改材质图再编译快十倍。材质编辑器里勾选“Use Material Instance”或者在右键创建“Material Instance Constant”之后在细节面板调参数画面立即刷新。参数名类型建议初始值调节方向说明Color LevelsScalar6数值越小色块越大卡通感越强Edge ThresholdScalar0.02数值越小越容易触发描边Edge ColorVector黑色换成深色系会更柔和Edge SoftnessScalar0.05边缘过渡带宽数值越大越平滑4.2 性能优化全屏Shader的省钱之道后处理材质最需要注意的性能特征是它对屏幕上每一个像素都跑一遍计算而且是全屏的所以像素数越多开销越大。在1080P下大约200万个像素在4K下超过800万个像素。如果材质里塞一堆取样节点和复杂运算GPU顶点压力会非常明显。边缘检测里Sobel算子做了9次SceneDepth采样这已经是相对昂贵的操作。如果你的目标是移动端或者低配PC我建议把边缘检测从Sobel退化成Roberts算子它只采样4个角上的像素判断左上和右下、右上和左下的差值计算量直接下降一半还多。虽然边缘精度略低但对卡通效果来说完全够用。另一个思路是给后处理材质做一个“降采样”处理。UE4的Post Process材质默认按实际屏幕分辨率渲染但有时你并不需要全分辨率比如描边只需要低频信息半分辨率做效果肉眼几乎察觉不到。材质内部可以直接使用SceneTextureSize得到尺寸信息但本身没有内置降采样的选项。如果你项目里有RenderTarget基础可以先用SceneCapture一张半分辨率RT再把材质作用上去不过这属于进阶方案入门阶段记住这个概念就行。如果你想在性能和质量之间找一个性价比高的方案还有一招是“分区域检测”。由于深度边缘检测对远距离场景不敏感你可以把Edge Threshold缩放到像素深度的函数比如深度越大阈值越大避免远处细节被躁点干扰。这也就是把之前做的倒数处理反过来用一下让检测权重随着距离衰减。4.3 平台差异与兼容性建议UE4的PC版和移动端的Gbuffer内容不完全一致。后处理材质中读取WorldNormal时PC上默认可用但移动端可能没有写入法线缓冲或者需要额外的RenderFeature设置。为了兼容性入门阶段我建议只做基于深度的边缘检测因为深度缓冲在所有平台都是必有的读它最稳妥。另外Post Process材质的计算结果最后要不要接Bloom。如果你的项目开了Bloom而后处理材质在After Tonemapping阶段输出那么Bloom是在Tonemapping之前的阶段就已经叠加完成色阶化和描边会基于含泛光的效果再处理。如果需要更强烈的日式动漫感我建议在项目设置里先把Bloom强度降低甚至关掉这样色阶会更干净。当然如果你想要的是“在保留写实光照基础上叠加卡通轮廓”那可以适当保留Bloom。这个完全看目标风格没有绝对正确关键是先想清楚你要什么。5. 常见问题与排查技巧实录5.1 材质球挂了但画面完全没变化这是最常见的问题我接到过很多次。先检查Material Domain是否改成Post Process。材质域没有改材质就会按照普通Surface材质处理场景挂载后会出现在物体表面而不是覆盖整个画面。然后是Post Process Volume的设置。你拖入场景后引擎会创建体积但如果Unbound没有勾选相机一旦走出体积范围效果立刻消失。建议直接勾选Unbound。再检查Post Process Materials数组里是否真的添加了材质并且材质处于编译成功状态。如果材质编译报错在材质编辑器里所有节点的连线会变红或提示错误信息这时要先修节点再回来。还有一个容易被忽略的当场景里同时有多个Post Process Volume时低Priority的体积里可能有别的Post Process材质把当前材质覆盖掉了。这时候可以把当前体积的Priority调大或者暂时把所有其他后期体积禁用。5.2 描边粗细不均匀或闪烁边缘时有时无、忽粗忽细通常由两个原因引起阈值太靠近临界值以及深度缓冲在物体边界上的跳变不稳定。先说深度的跳变。在物体轮廓处采样邻域像素时某个像素可能采到物体本身邻域像素采到背景差值很大于是被判定为边缘。但相机稍微一移动采样位置只要跨过了物体边缘线就可能导致边缘强度从高变低。解决思路是把边缘检测的采样范围稍微扩大一点比如取两个像素的偏移而不是一个像素这样边界更容易被捕捉。然后是阈值太敏感。如果阈值卡在某个精确数值上材质会在边缘强度和阈值附近反复横跳形成闪烁。解决办法是用SmoothStep做软阈值把“是边缘/不是边缘”的二值判断换成“0到1之间的渐变过渡”。过渡区间给0.05到0.1的宽度渲染画面会稳定很多。还有一个经验对深度做倒数处理之前先把深度值Saturate到0-1范围可以避免天空等无限远像素产生超大深度值导致边缘强度被污染。5.3 色阶断层明显产生色带色阶化的副作用是颜色越少的区域色带越明显尤其在天空、墙面、纯色材质上会看到一圈一圈的“等高线”。这其实是正常现象但看起来很像压缩失真。解决色带问题最常用的方案是在颜色输出前加一点抖动噪声。这个噪声要非常小比如正负0.5/Color Levels的量级给每一个像素颜色一个微小的随机扰动人眼就不会看到明显的色带边界。材质编辑器里可以用随机节点或者噪声纹理实现也可以用屏幕坐标乘以一个大数取小数来制造伪随机。我在实际项目里加噪声时有两点要注意噪声幅度不能太大否则画面会有“噪点感”尤其在暗部区域会明显噪声纹理的平铺频率要选得合适太低会有块状感太高会浪费GPU计算。我一般用一张32x32的蓝色噪声纹理连续平铺效果最自然。5.4 深度边缘把远处天空也描了一圈场景中如果天空是纯色或带有渐变深度缓冲里天空部分会被判定为“无限远”它与近处物体的深度差巨大Sobel计算后很容易在物体和天空的交界处产生一圈粗黑边。在有些风格里这反而是特征但如果你不想要可以用“只在有限距离内检测边缘”的方式过滤。一个简单做法是在判断边缘强度之前先对采样到的深度做一次判断。如果深度超过某个值比如你认为10米以外的物体不重要就把边缘强度直接置0。材质里用Step或比较节点即可depth MaxDistance 时输出1否则输出0把这个值乘到边缘强度上。另一个更可控的方案是使用CustomDepth或CustomStencil。给需要描边的物体单独写入自定义深度标记这样边缘检测只在这些物体周围进行完全不会被天空干扰。代价是需要在项目设置中开启CustomDepthStencil并且给目标物体设置相应的Mesh Renderer属性。这是目前商业项目里做角色描边最常用的方案后面可以单独开一篇。6. 进阶扩展与个人体会6.1 给描边换成更有风格的配色方案黑边很安全但不一定是最好的选择。很多日系游戏里描边并不是纯黑而是深棕色、深蓝色甚至直接用明度更低的角色固有色来描。这样整体视觉会更柔和不会破坏色彩氛围。想在材质里实现可以把Edge Color从纯黑替换成SceneColor采样后调暗的结果也可以再配一个Lerp节点让描边色根据边缘强度在“黑色”和“固有色暗调”之间过渡。这类做法其实很有讲究画面亮部用暗色描边暗部用更深的暗色这样边缘永远不会抢主光源。如果你的项目有角色换装系统描边色也可以做成动态材质参数方便不同角色使用不同描边颜色。这也是为什么我强调一开始就用材质实例调参后续把这个卡通效果移植到多个角色身上时每个角色可以独立控制描边颜色和粗细。6.2 和其他后期效果的叠加顺序做一个完整的风格化画面通常不只有这个卡通材质。你可能还要开抗锯齿、动态模糊、泛光、色彩分级。它们和卡通材质的叠加顺序会影响最终效果。我个人经验是如果只要干净清晰的卡通画面把后处理材质的Blendable Location设为After Tonemapping同时把Bloom强度整体拉低抗锯齿开启TAA。TAA会把边缘的锯齿消除卡通风格需要平滑的轮廓线锯齿会破坏手绘感。如果追求“写实画面带一点卡通感”那可以保留Bloom甚至保留景深效果。但要注意Bloom会在亮部周围形成一圈光晕色阶化会把光晕压出更多断层这时候需要配合第5章里提到的噪声抖动方式否则画面会有脏感。如果你的项目用到了后期材质叠加多个后处理材质之间是按顺序执行的。排在后面的材质会基于前一个的输出再次处理所以顺序不同效果会有差异。整理好数组的顺序本质上是建立一条可控的后期处理链。6.3 后续还能怎么玩这个实例做完以后你可以沿着几条线继续扩展。第一条线是“描边方法升级”。从基于深度的边缘检测切换成基于法线的边缘检测捕捉到的内部棱线更多适合表现硬表面模型的转折感。再把法线和深度结合用一个Lerp来调整两种检测的权重就可以在一套材质里兼顾角色和场景。第二条线是“颜色控制精细化”。比如对亮部、暗部、中间调分别使用不同的色阶数或者用定义好的颜色映射表也就是Color LUT把色阶化的颜色直接替换成定制的卡通配色这一点非常接近商业项目中做风格化的做法。第三条线是“性能优化工程化”。你可以为这个后处理材质写一个开关蓝图通过按键动态切换材质实例参数把材质放到RenderTarget上做异步计算在不卡主线程的前提下驱动画面风格变化。我对这个实例的定位是“从零理解UE4后处理材质”所以即使最后效果你只是用在了几个测试模型上只要搞清楚了SceneTexture怎么读数据、Sobel算子怎么在屏幕空间工作、色阶化的数学原理是什么后面再遇到任何类似的需求你都会有一个清晰的解决框架。最后说一句做完时别急着发效果图先把相机动起来从正视角、俯视角、逆光角度各录一段视频看看稳定性很多静态看好好的效果一抖动就露馅。这个坑我踩过好几次希望你这次能绕过去。