最近學習 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 的法線貼圖

91984-botiigpe6r.png

06680-fm0gux7fyd5.png

||新(URP 深度 + 法線後處理)|原(幾何邊提取)|
|---|---|---|
|外輪廓|有,但較粗、粗細不均|細、均勻、乾淨|
|頭髮、臉部內部|出現很多短碎的「排線」雜線,臉上也有|只有幾條明確的髮絲線|
|線的品質|鋸齒明顯,有斷點和毛邊|平滑|
|袖口、手|黑塊糊在一起|線條分明|

調整參數
Normal Threshold:0.7~1.0
Thickness:0.825

開啓 PostProcessing SMAA 效果,將分叉的邊緣進行修整

97174-5q07p10mmgq.png


眼睛那邊缺少邊緣線,需要加「物件 ID 邊緣」,做法是多畫一張 buffer,每個 Renderer 寫入不同的 ID,ID 不一樣的交界就畫線。這樣 _eye 和 _head、_Fhair 和臉之間就會出現線,而且不受深度和法線影響,很乾淨。業界的後處理描邊通常就是深度 + 法線 + ID 三合一。

接著,要作的話得自己寫一個 ScriptableRendererFeature(Unity 6 的 RenderGraph 版)

  • 用 override material 把角色畫進一張 ID RT,ID 用 Rendering Layer 或 MaterialPropertyBlock 指定。
  • 在描邊 shader 裡多加一組 ID 不連續的判斷。

接著我們看最終效果如下:
31272-o00z2hl9yu.png

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

然後將 DepthNormalOutline.shader 改寫

  • 從 Roberts Cross 換成 3×3 Sobel,加入 ID 邊緣和距離淡出。
  • smoothstep 的過渡區間加寬,線條邊緣會有灰階過渡。
  • 強度做正規化,只是 Sobel 的手感不完全一樣,可能要再微調。

目前的效果看起來可以了,如果需要細節就用 objectID 再分開

無標籤

關注作者:

新增評論