模板缓冲区(Stencil Buffer)详解
1. 是什么?
模板缓冲区是 GPU 中一个与深度缓冲区大小相同、像素一一对应的整数缓冲区。每个像素通常占用 8 位(取值范围 0~255),也可以配置为 1、2 或 4 位。
它与深度缓冲区经常共享同一块显存(例如 24 位深度 + 8 位模板 = 32 位),所以常被合称为“深度模板缓冲区”。
核心功能:按照每个像素的“模板值”有条件地拒绝或接受后续绘制。你可以把它想象成一张数字化的模板纸:先在某些像素上盖个章(写入非 0 值),然后在画其他东西时,只允许在盖过特定章的像素上绘制。
2. 工作原理(两个阶段)
模板缓冲区的使用分为两个阶段:
阶段一:写入模板值
-
绘制某些物体时,不改变颜色和深度,只修改模板缓冲区。
-
例如:绘制一个圆形区域,把模板值设为 1。
阶段二:测试模板值
-
绘制其他物体时,设置一个测试条件,例如:
-
Equal(等于)—— 仅当当前模板值 == 参考值才绘制 -
NotEqual(不等于) -
Less(小于) -
Greater(大于) -
Always(总是通过) -
Never(总是不通过)
-
-
测试失败的像素直接被丢弃,不会更新颜色和深度。
关键点:每个像素的模板值可以单独控制,且测试和写入可以同时发生。
3. 常用操作符
在图形 API(如 OpenGL、DirectX、Vulkan)或引擎(如 Unreal)中,你可以为模板测试配置三个操作:
| 操作 | 含义 |
|---|---|
Keep |
保持当前模板值不变 |
Zero |
将模板值清零 |
Replace |
用参考值替换当前模板值 |
Increment |
加 1(饱和到最大值) |
Decrement |
减 1(饱和到最小值) |
Invert |
按位取反 |
这些操作可以分别在三种情况下执行:
-
模板测试失败时
-
模板测试通过但深度测试失败时
-
模板测试和深度测试都通过时
4. 经典应用举例
例子 1:镜子 / 平面反射
需求:只在镜面区域内显示反射的图像。
步骤:
-
写入模板:绘制镜面形状(例如一个矩形),设置模板操作:通过时替换为 1。此时镜面区域所有像素的模板值 = 1,其他区域 = 0。
-
绘制反射内容:开启模板测试,条件设为
Equal 1。只会在模板值为 1 的像素上绘制反射场景,其他像素被丢弃。 -
绘制镜子表面:最后正常绘制镜面材质(半透明或带高光),覆盖在反射图像上。
效果:只有镜子区域显示反射,不会“漏”到墙壁上。
例子 2:物体轮廓描边(非后处理方式)
需求:给一个角色绘制彩色轮廓(比如红色外发光)。
步骤:
-
写入模板:正常绘制角色,同时把角色占据的像素的模板值设为 1。
-
放大绘制轮廓:稍微放大角色模型,关闭深度写入,开启模板测试条件为
NotEqual 1。此时,放大后的模型只在角色外部的像素上绘制(因为内部像素模板值为 1,不满足NotEqual 1)。 -
轮廓颜色:用纯色(红色)绘制放大后的模型,就得到了一个围绕角色的红边。
注意:这种是几何放大法,不如后处理描边平滑,但适合风格化游戏。
例子 3:体积光 / 聚光灯遮罩
需求:让聚光灯只照亮某个形状内的物体(比如一个窗户形状)。
步骤:
-
写入模板:绘制窗户的几何体,设置模板为 1。
-
绘制光照:在渲染光照时,模板测试条件设为
Equal 1,光线只出现在窗户形状内。 -
结果:光就像透过窗户打进来一样。
例子 4:Stencil Shadow Volumes(传统阴影体)
需求:生成硬阴影。
步骤:
-
从光源方向计算物体的阴影轮廓,拉伸成一个无限长的“阴影体”。
-
第一次绘制阴影体:正面朝向相机时模板值 +1,背面朝向相机时模板值 -1。
-
最后,模板值为 0 的像素在阴影外,非 0 的像素在阴影内。
-
将阴影内的像素变暗。
现在多使用 Shadow Map,但 Stencil Shadow Volumes 仍是学习渲染原理的经典案例。
5. 虚幻引擎中的 Custom Stencil
在虚幻引擎里,引擎自身会用模板缓冲区做某些内部处理(例如遮挡标记、景分离等)。为了避免冲突,UE 额外提供了一个 Custom Stencil 通道,专门留给开发者自由使用。
-
Set Custom Depth Stencil Value节点就是往这个自定义通道里写入一个值(1~255)。 -
后处理材质中通过
SceneTexture:CustomStencil节点读取这个值。
典型用法(Lyra 项目的描边):
-
给红队角色所有网格体设置 Custom Stencil = 1,蓝队 = 2。
-
后处理材质读取每个像素的 Custom Stencil 值。
-
如果当前像素值为 0(背景),但相邻像素值为 1 或 2,就把该像素染成红或蓝——这就是轮廓描边的本质。
6. 总结一句话
模板缓冲区就是一张像素级的“标签贴纸”,你可以先在某些地方贴上数字标签,然后在画别的东西时,只允许在贴了特定标签的地方下笔。它是实现镜子、轮廓描边、体积光、阴影体等大量特效的基础工具。