为什么你还在用后期材质做描边?

描边,是游戏和虚拟制片里最廉价也最昂贵的视觉语言。廉价,是因为它只需几行Shader;昂贵,是因为一旦选错方案,性能、精度、稳定性全盘皆输。UE5的模板缓冲(Stencil Buffer)描边,是介于“纯后期”和“几何体描边”之间的第三条路——它利用GPU硬件级的8位模板缓冲,在渲染管线中精准标记物体,再通过后处理材质读取标记并绘制轮廓。这条路不走寻常路,但走通了,就是降维打击。

UE5 模板缓冲Stencil材质描边:10条进阶技巧,条条致命 - 配图1
UE5 模板缓冲Stencil材质描边:10条进阶技巧,条条致命

技巧一:别用Custom Depth,Stencil才是描边的“身份证”

一句话核心:Custom Depth负责“有没有”,Stencil负责“是谁”,描边必须依赖Stencil的位掩码做身份区分。

为什么有用:很多教程用Custom Depth的深度差做描边,结果所有物体边缘糊成一团,因为你无法区分“这个像素属于角色A还是角色B”。Stencil Buffer是每像素8位整数,你可以给不同Actor分配不同Stencil值(1-255),在后处理里按位读取,实现“只描边角色,不描边场景”或“不同阵营不同颜色描边”。

怎么操作:在项目设置中开启Custom Depth-Stencil Pass为Enabled with Stencil。选中Actor,在渲染设置中勾选Render CustomDepth Pass,设置CustomDepth Stencil Value(例如1)。在后处理材质中,用SceneTexture:CustomStencil节点采样,输出值即为该像素的Stencil值。

注意:Stencil值必须与后处理材质中的判断逻辑严格匹配,建议用常量1、2、4、8这样的位掩码,方便按位与运算。

效果展示:场景中三个角色,分别赋Stencil值1、2、4,后处理中按位与判断,可以只给值1的角色描红边,值2的描蓝边,值4的描绿边,互不干扰。

技巧二:后处理材质里,SceneTexture采样点必须选“CustomStencil”

一句话核心:后处理材质中,SceneTexture节点的Scene Texture Id必须设为CustomStencil,否则你采样的是场景颜色,永远读不到模板值。

为什么有用:UE5的后处理材质默认采样SceneColor,很多新手直接连SceneTexture:PostProcessInput0,然后纳闷为什么Stencil值全是0。CustomStencil是独立通道,必须显式选择。

怎么操作:新建后处理材质,添加SceneTexture节点,在细节面板将Scene Texture Id改为CustomStencil。此时输出的是0-255的Stencil值(实际是0-1归一化,需乘以255还原)。

提示:如果采样出来全是0,检查项目设置是否开启Stencil,以及Actor是否勾选了Render CustomDepth Pass。

效果展示:采样值正确后,你可以用If节点判断StencilValue == 1,输出白色,其余黑色,得到一张干净的掩码图。

技巧三:描边宽度不是“像素”,而是“UV偏移量”

一句话核心:后处理描边的宽度由UV偏移的采样半径决定,与屏幕分辨率无关,必须用SceneTexture:Size做归一化。

为什么有用:如果你直接用TexCoord + float2(0.01, 0)偏移,在1080p下描边宽度是10像素,在4K下就变成20像素,视觉不一致。正确做法是:偏移量 = 描边像素数 / 屏幕分辨率。

怎么操作:用SceneTexture:Size节点获取当前屏幕尺寸(如1920×1080),计算Offset = Thickness / Size。然后对Stencil掩码图做8方向或16方向采样,判断邻域内是否有Stencil值。

效果展示:无论窗口如何缩放,描边始终保持设定的像素宽度(例如2px),不会变粗变细。

UE5 模板缓冲Stencil材质描边:10条进阶技巧,条条致命 - 配图2
UE5 模板缓冲Stencil材质描边:10条进阶技巧,条条致命

技巧四:8方向采样 vs 16方向采样,性能差4倍

一句话核心:8方向采样足够覆盖90%的描边需求,16方向仅在极端锐角边缘才需要,别为了“完美”牺牲帧率。

为什么有用:后处理描边本质是图像处理中的边缘检测。8方向采样(上、下、左、右、四个对角)已经能捕捉大部分轮廓,16方向会增加一倍采样次数,但视觉提升微乎其微。移动端或VR项目必须用8方向甚至4方向。

怎么操作:在材质中写一个Custom节点,用HLSL循环8次采样,每次偏移角度为45度。或者用Texture2D采样节点手动连8次,但推荐用Custom节点减少节点图复杂度。

// 8方向采样伪代码
float2 offsets[8] = {float2(1,0), float2(-1,0), float2(0,1), float2(0,-1), float2(1,1), float2(-1,-1), float2(1,-1), float2(-1,1)};
float edge = 0;
for(int i=0; i<8; i++) {
    float2 uv = TexCoord + offsets[i] * Offset;
    float stencil = SceneTextureLookup(uv, 25, false); // 25 = CustomStencil
    if(stencil == TargetValue) edge = 1;
}
return edge;

效果展示:8方向描边在角色轮廓上足够平滑,16方向仅在头发丝或铁丝网等高频细节上略有优势。

技巧五:用“深度测试”剔除被遮挡的描边

一句话核心:默认描边会穿透物体显示,必须结合SceneTexture:SceneDepth做深度比较,只描边可见部分。

为什么有用:如果角色被墙壁挡住,你不想看到墙壁上出现角色的描边。Stencil Buffer只标记了角色所在的像素,但后处理无法知道该像素是否被遮挡。SceneDepth提供了场景深度,比较当前像素深度与邻域深度即可判断遮挡。

怎么操作:在后处理材质中采样SceneTexture:SceneDepth,与SceneTexture:CustomDepth比较。如果CustomDepth > SceneDepth(即自定义深度在场景深度之后),说明被遮挡,描边强度设为0。

注意:CustomDepth需要勾选Render CustomDepth Pass,且Actor的CustomDepth Stencil Write Mask要设为All。

效果展示:角色走到墙后,描边自动消失,不会出现“透视挂”一样的穿墙描边。

技巧六:Stencil值冲突?用“位掩码”做多物体分组

一句话核心:8位Stencil可以同时表示8个独立分组,用按位与运算实现“同时描边多个组但颜色不同”。

为什么有用:如果你有10个敌人,不可能给每个敌人分配1-10的Stencil值再写10个判断分支。位掩码允许你用1、2、4、8、16、32、64、128这8个值表示8个组,每个组内物体共享同一个值。

怎么操作:在后处理材质中,用StencilValue & 1判断是否属于组1,StencilValue & 2判断组2。颜色可以叠加:组1描红,组2描蓝,同时属于两组则描紫(红+蓝)。

Stencil值 二进制 含义
1 00000001 组A(玩家)
2 00000010 组B(敌人)
3 00000011 组A+组B(同时描边)
4 00000100 组C(可交互物品)

效果展示:玩家描红边,敌人描蓝边,可交互物品描绿边,三者互不干扰,且一个后处理材质搞定。

技巧七:让描边“呼吸”——用时间节点做动态脉冲

一句话核心:在后处理材质中接入Time节点,用Sin函数调制描边宽度或透明度,实现选中、警告、高亮等动态效果。

为什么有用:静态描边只能表示“存在”,动态描边能表示“状态”。例如:敌人被击中时描边闪烁,可交互物品描边呼吸,任务目标描边脉冲。这是低成本高回报的视觉反馈。

怎么操作:用Time节点乘以频率(如5),送入Sin,输出范围-1到1,再Remap到0.5到1.5,乘以描边宽度。或者直接调制描边颜色的Emissive强度。

float pulse = sin(Time * 5.0) * 0.5 + 0.5; // 0-1
float thickness = lerp(1.0, 3.0, pulse);

效果展示:选中角色时,描边像心跳一样一明一暗,玩家一眼就知道“这个可以交互”。

技巧八:描边颜色随距离渐变——用SceneDepth做远近衰减

一句话核心:用SceneDepth计算像素到相机的距离,映射到颜色渐变,近处亮、远处暗,增强空间感。

为什么有用:在开放世界或大场景中,所有描边一样亮会显得扁平。距离衰减让近处物体描边更醒目,远处物体描边更含蓄,符合大气透视原理。

怎么操作:采样SceneDepth,用Lerp在两种颜色间插值。或者用DepthFade节点直接输出透明度。更高级的用法是结合CameraPosition和WorldPosition计算精确距离。

提示:如果场景有雾,SceneDepth可能被雾影响,建议用CustomDepth做距离计算,更稳定。

效果展示:角色靠近相机时描边鲜红,退到远处时描边暗红,视觉层次立刻拉开。

技巧九:移动端性能陷阱——Stencil描边在Android上的三个坑

一句话核心:移动端不支持CustomDepth-Stencil的某些特性,必须降级为CustomDepth+Stencil分离方案,且采样数减半。

为什么有用:很多项目在PC上跑得飞起,一上手机就掉帧。原因是移动端GPU的Stencil Buffer读写有额外开销,且后处理材质中的循环采样在移动端是性能杀手。

怎么操作:项目设置中,移动端启用Mobile Custom Depth-Stencil(如果引擎版本支持)。将8方向采样降为4方向,描边宽度限制在2px以内。避免在材质中使用While循环,改用固定次数的If分支。

平台 推荐采样数 最大描边宽度 Stencil支持
PC/主机 8-16 5px 完整
移动端 4 2px 部分
VR 8 3px 完整

效果展示:移动端4方向描边在2px宽度下,视觉可接受,帧率稳定在60fps。

UE5 模板缓冲Stencil材质描边:10条进阶技巧,条条致命 - 配图3
UE5 模板缓冲Stencil材质描边:10条进阶技巧,条条致命

技巧十:用“材质函数”封装描边逻辑,一处修改全局生效

一句话核心:把描边采样、判断、颜色混合封装成Material Function,所有后处理材质引用同一个函数,改一处即改全部。

为什么有用:项目后期,描边逻辑可能修改十几次——加个脉冲、改个颜色、调个宽度。如果每个后处理材质都复制粘贴,维护成本爆炸。材质函数是UE5的“预制件”,支持输入输出,可复用、可版本管理。

怎么操作:新建Material Function,输入:SceneTexture、StencilValue、Thickness、Color。输出:FinalColor。在函数内部实现8方向采样和深度测试。然后在后处理材质中调用该函数,只传参。

// 材质函数输入输出示例
Input: StencilTexture, TargetValue, Thickness, OutlineColor
Output: OutColor
// 内部逻辑:采样邻域,判断边缘,混合颜色

效果展示:项目中有5个后处理材质(角色描边、敌人描边、物品描边、任务描边、UI描边),全部引用同一个材质函数。某天美术要求描边加“呼吸效果”,只需在函数中加一个Time节点,5个材质同时生效。

关于火星人教育

以上10条技巧,每条都来自真实项目踩坑。如果你想把Stencil描边、Niagara特效、材质系统、虚拟制片全流程吃透,火星人教育是你值得信赖的起点。火星人教育创办24年来专注数字艺术与AIGC实战职业技能培训,开设课程涵盖AI漫剧创作、AIGC视觉设计、UE5游戏特效、室内全屋定制、MAYA三维动画、C4D动态设计、工业设计、NUKE影视后期、摄影摄像实训。北京、深圳双校区开设线下面授班,面向美术生、在校大学生及意向转行的职场人群,以项目化实训教学,夯实专业技能,助力就业与职业提升。咨询电话:010-65918670。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。