Unity 6 URP 後處理描邊:從 Built-in 幾何邊到深度+法線+ID
最近學習 URP,找到了一個網上的 built-in 描邊項目,拿來改成 URP 模式,下面進行比較兩者差異
原本的做法是:
- 輪廓邊(第 69 行):一側的面朝向鏡頭、另一側背向鏡頭。
- 稜角邊(第 70 行):兩個面之間的折角夠大(以 60° 作為門檻)。
- 邊界邊:只有一側有三角形的邊(開放網格的邊緣)。
而常見的做法有:
| 做法 | 原理 | 內部輪廓 / 稜角線 | 線寬 | 成本與相容性 |
|---|---|---|---|---|
| 法線外擴(Inverted Hull,最常見) | 第二個 pass 把頂點沿法線往外推,只畫背面 | ❌ 只有外輪廓,畫不出內部的稜角線 | 跟著距離變化,要另外修正 | 很便宜,手機也能跑 |
| 後處理邊緣偵測(深度 / 法線 Sobel) | 對整個畫面的深度圖、法線圖做邊緣偵測 | △ 取決於門檻設定 | 受解析度影響,容易鋸齒、閃爍 | 每幀要做一次全螢幕運算,和模型無關,URP / HDRP 都能用 |
| Rim / Fresnel | 根據視角和法線的夾角把邊緣塗暗 | ❌ | 粗細不均 | 最便宜,但不是真正的線 |
| Stencil 描邊 | 先畫放大的模型,再用模板緩衝把原模型的部分扣掉 | ❌ 只有最外圈 | 同法線外擴 | 便宜 |
| 本專案(幾何邊提取) | 逐邊判斷輪廓和稜角,再用 GS 生成線段 | ✅ 都畫得出來,例如手臂擋在身體前面時的交界線也會出現 | 螢幕空間固定寬度,線條細且銳利 | CPU 和 GPU 成本都高,平台限制多 |
||URP 深度 + 法線後處理|原本built-in做法|
|---|---|---|
|判斷依據|畫面像素的深度、法線差|網格每條邊兩側面的法線|
|能畫的線|輪廓、稜角(受解析度和門檻影響)|輪廓、稜角、邊界,邊緣準確|
|成本|每幀一次全螢幕運算,和模型數量無關|每個模型都要 BakeMesh 並跑 GS|
|平台|幾乎全平台(含手機、WebGL)|不支援 Metal / WebGL|
後來升級到 URP 做法,下面是面板功能
| 選項 | 用途 |
|---|---|
| Final | 最終畫面,角色加上描邊 |
| Edges | 白底黑線,只顯示描邊結果 |
| Depth only | 只用深度偵測(就是「純深度描邊」) |
| Normal only | 只用法線偵測 |
| Scene normals | 直接顯示 URP 的法線貼圖 |


||新(URP 深度 + 法線後處理)|原(幾何邊提取)|
|---|---|---|
|外輪廓|有,但較粗、粗細不均|細、均勻、乾淨|
|頭髮、臉部內部|出現很多短碎的「排線」雜線,臉上也有|只有幾條明確的髮絲線|
|線的品質|鋸齒明顯,有斷點和毛邊|平滑|
|袖口、手|黑塊糊在一起|線條分明|
調整參數
Normal Threshold:0.7~1.0
Thickness:0.825
開啓 PostProcessing SMAA 效果,將分叉的邊緣進行修整

眼睛那邊缺少邊緣線,需要加「物件 ID 邊緣」,做法是多畫一張 buffer,每個 Renderer 寫入不同的 ID,ID 不一樣的交界就畫線。這樣 _eye 和 _head、_Fhair 和臉之間就會出現線,而且不受深度和法線影響,很乾淨。業界的後處理描邊通常就是深度 + 法線 + ID 三合一。
接著,要作的話得自己寫一個 ScriptableRendererFeature(Unity 6 的 RenderGraph 版)
- 用 override material 把角色畫進一張 ID RT,ID 用 Rendering Layer 或 MaterialPropertyBlock 指定。
- 在描邊 shader 裡多加一組 ID 不連續的判斷。
接著我們看最終效果如下:

在每個物件上都挂上脚本設定不同 objectId,這個用來給 Renderer 指定描邊用的物件 ID,而 ID 不同的物件交界處會畫線。

然後將 DepthNormalOutline.shader 改寫
- 從 Roberts Cross 換成 3×3 Sobel,加入 ID 邊緣和距離淡出。
- smoothstep 的過渡區間加寬,線條邊緣會有灰階過渡。
- 強度做正規化,只是 Sobel 的手感不完全一樣,可能要再微調。
目前的效果看起來可以了,如果需要細節就用 objectID 再分開