type
status
date
slug
summary
tags
category
icon
password
在项目里,描边是在后处理实现

我们先来聊聊我们熟悉的方案:对模型物体进行顶点偏移扩大,这个方案前向渲染,对模型顶点做向外偏移,渲染一个扩大的 “轮廓网格”(通常用纯色),再渲染原模型,靠两层叠加形成描边 —— 这种方案需要为每个要描边的模型单独处理(改 Shader / 加轮廓网格)。
屏幕空间后处理描边(属于 “像素级描边”):完全脱离模型 / 顶点,在场景渲染完成后,对「屏幕纹理 + 深度纹理」做像素级计算,识别出需要描边的屏幕像素区域并着色 —— 全程在 2D 屏幕空间操作,不碰任何 3D 模型 / 顶点,这是两者最核心的区别。
输入贴图:
输入资源 | 类型 | 作用(核心:判定描边的核心依据) |
t_tex0(Texture0) | 2D 纹理 | 描边掩码纹理 / 目标纹理:▸ 核心作用:标记 “需要描边的物体区域”—— 需要描边的物体像素值≠0(比如纯色 / ID 值),不需要的 = 0;▸ 举例:若只想给角色描边,渲染场景时会单独输出 “角色区域为白色、其他区域为黑色” 的纹理作为t_tex0。 |
t_tex1(Texture1) | 2D 纹理 | 原场景颜色纹理:▸ 非 FrameBuffer Fetch 模式下,作为原场景的基础颜色,最终描边会叠加到这个纹理上;▸ 若启用 FrameBuffer Fetch(移动端 Metal 优化),则直接读取帧缓冲,无需传入t_tex1。 |
t_scene_depth | 深度纹理 | 场景深度缓冲:▸ 记录每个屏幕像素的深度值(距离相机的距离);▸ 用于 “深度过滤”(比如outline_depth_threshold_clip_player参数:过滤掉过远 / 过近的物体,避免给背景 / 超近物体描边)。 |
u_rt_size | float4 | 渲染目标(RT)的尺寸(宽 / 高 + 1 / 宽、1 / 高):用于计算屏幕空间的采样偏移(描边宽度)。 |
width | float | 描边宽度:控制邻域采样的偏移量,值越大描边越宽。 |
outline_depth_threshold_clip_player | float | 深度阈值:过滤不需要描边的深度区域(比如值 = 0.9 时,深度值超过 0.9 的像素不描边,避免给远处物体描边)。 |

这个tex怎么来的?(tex0判定需要描边物体的核心)
- 渲染场景时,先执行一个 “预处理 Pass”:
- 对需要描边的物体(比如角色、交互道具),渲染到
t_tex0时输出 “非 0 值”(比如白色、物体 ID、纯色); - 对不需要描边的物体(比如场景、背景、水体),渲染到
t_tex0时输出 “0 值”(黑色);
- 后处理 Pass 中,Shader 采样
t_tex0,只有 “非 0 值区域的边缘” 会被判定为 “需要描边的边缘”,最终生成描边。
Ps:
顶点阶段不处理任何模型,只针对 “全屏四边形”(后处理的标准做法:用一个覆盖整个屏幕的四边形作为渲染载体)做操作:
- 接收全屏四边形的顶点坐标(input_position)和 UV 坐标(input_texcoord0,范围 0~1,对应屏幕像素);
- 计算采样偏移量:u_rt_size.zw是1/屏幕宽、1/屏幕高(归一化的像素尺寸),乘以width(描边宽度),得到 “单个像素的偏移量”(_v_0);
- 生成 5 个采样坐标:
- _Varying_texcoord0:当前像素的 UV(中心坐标);
- _Varying_texcoord1/_Varying_texcoord2:当前像素上下偏移后的 UV;
- _Varying_texcoord3/_Varying_texcoord4:当前像素左右偏移后的 UV;→ 这 5 个坐标是为像素阶段 “邻域采样” 做准备(检测上下左右像素的差值)。
Vs
对每个像素做:

具体步骤:
- 邻域采样:用顶点阶段生成的 5 个 UV,采样t_tex0(描边掩码纹理),得到 5 个像素值:
- _p_4:当前像素的 t_tex0 值;
- _p_5/_p_6/_p_7/_p_8:上下左右四个方向偏移后的 t_tex0 值;
- 边缘检测(核心!判定哪里需要描边):
- 计算 “当前像素” 与 “上下左右像素平均值” 的差值:_p_4 - (((_p_5 + _p_6) + _p_7) + _p_8) * 0.25f;
- 用sign(length(差值))判断是否为边缘:▸ 若差值≠0 → sign返回 1 → 判定为 “物体边缘”(需要描边);▸ 若差值 = 0 → sign返回 0 → 非边缘(不需要描边);→ 本质:t_tex0中 “需要描边的物体区域” 和 “背景区域” 的交界像素,差值会显著变大,从而被判定为边缘。
- 深度过滤(筛选需要描边的物体):
- 采样深度纹理t_scene_depth,得到当前像素的深度值_p_10;
- 适配深度范围(SYSTEM_DEPTH_RANGE_NEGATIVE/USE_REVERSED_Z):处理不同 API(D3D/OpenGL)的深度值范围差异(0~1 或 - 1~1);
- 用outline_depth_threshold_clip_player过滤:1.0f - step(...) → 深度值超过阈值的像素,描边强度置 0(不描边)。
- 描边叠加 + 输出:
- 取邻域采样的最大值_p_11(强化边缘对比度);
- 把边缘检测得到的描边颜色,叠加到原场景颜色(_p_0,来自t_tex1/FrameBuffer Fetch)上;
- 最终输出_entryPointOutput:叠加描边后的屏幕像素颜色。