【從UnityURP開始探索遊戲渲染】專欄-直達
Unity URP中的Decal(貼花)系統是一種用於將材質投射到場景幾何體表面的技術,主要用於實現血跡、彈孔、塗鴉等動態表面裝飾效果。以下是詳細解析:
核心功能與用途
- 動態投影:通過Decal Projector組件將材質動態投射到任意表面,包括曲面和複雜幾何體
- 光照交互:支持與場景光照系統交互,可模擬陰影、高光等物理效果
-
典型應用場景:
- 遊戲中的彈孔、血跡、塗鴉
- 環境細節增強(如牆面裂縫、污漬)
- 技能範圍指示器(如Dota2的地面標記)
技術演進
| 版本階段 | 實現方式 | 特性差異 |
|---|---|---|
| 傳統實現 | 基於面片Mesh | 僅支持平面投影,無法適應複雜曲面 |
| URP早期 | Projector組件 | 存在深度衝突(Z-fighting)問題,性能開銷大 |
| URP 12+ | Decal Renderer Feature | 支持PBR材質,與SRP深度集成,性能優化 |
原理
Unity URP中的Decal系統通過深度緩衝重建世界座標和材質投影技術實現動態貼花效果,其核心原理可分為以下技術層級:
底層渲染流程
-
深度圖採樣
Decal Renderer Feature在渲染管線中插入自定義Pass,通過
_CameraDepthTexture獲取像素深度值,結合攝像機參數重建世界座標。關鍵公式:worldPos = _CameraToWorld矩陣 × (屏幕UV + 深度值 × 視錐向量)
-
投影體積裁剪
使用Decal Projector定義的立方體邊界(Size參數)進行空間裁剪,通過射線與AABB碰撞檢測判斷像素是否在投影範圍內。超出範圍的像素會被剔除。
-
材質混合
採用延遲渲染路徑的GBuffer修改策略,通過
Blend指令將Decal的Albedo/Normal/Metallic等屬性與場景材質混合,支持PBR光照交互。
關鍵代碼實現示例
以下為簡化版Shader核心邏輯:
hlsl
// 深度重建世界座標
float3 ReconstructWorldPos(float2 uv, float depth) {
float4 clipPos = float4(uv * 2 - 1, depth, 1);
float4 worldPos = mul(_ClipToWorld, clipPos);
return worldPos.xyz / worldPos.w;
}
// 投影體積判斷
bool IsInDecalVolume(float3 worldPos, float3 decalPos, float3 size) {
float3 localPos = mul(_WorldToDecal, float4(worldPos, 1)).xyz;
return all(abs(localPos) < 0.5);
}
技術演進對比
| 版本 | 技術方案 | 缺陷 | 改進點 |
|---|---|---|---|
| 傳統實現 | 基於Mesh面片投影 | 無法適應曲面 | - |
| URP 10 | 屏幕空間深度採樣 | 透明物體不支持 | 減少Z-fighting |
| URP 12+ | GBuffer混合+體積裁剪 | 性能開銷較高 | 支持PBR和動態光照 |
性能優化要點
- 層級剔除:通過
Decal Layer分類控制不同Decal的渲染層級 - 距離淡出:
Draw Distance和Start Fade參數動態減少遠處Decal計算 - 批處理:相同材質的Decal Projector會自動合併繪製調用
典型問題解決方案
- 透明物體支持:需自定義Shader重寫
AlphaTest邏輯 - 曲面變形:增加
Normal Smoothing參數修正法線插值 - 移動端適配:降低深度圖精度或使用
Depth Prepass策略
完整實現流程
-
創建URP Asset:
- 菜單欄 Edit > Project Settings > Graphics
- 指定URP Pipeline Asset
-
添加Decal Renderer Feature:
- 在URP Renderer Data中添加Decal Renderer Feature
- 設置Priority控制渲染順序
-
創建Decal材質:
- Shader選擇"Universal Render Pipeline/Decal"
- 配置Albedo、Normal等貼圖通道
-
放置Decal Projector:
- 創建空GameObject
- 添加Decal Projector組件
- 關聯步驟創建的材質
關鍵參數詳解
| 參數 | 類型 | 作用 | 典型值 |
|---|---|---|---|
| Size | Vector3 | 控制投影體積尺寸 | (2,2,2) |
| Fade Factor | Float [0-1] | 邊緣漸變強度 | 0.8 |
| Draw Distance | Float | 渲染距離閾值 | 20 |
| Start Fade | Float | 開始淡出的距離 | 15 |
| Angle Fade | Vector2 | 基於表面角度的淡出 | (0.5,0.8) |
| Affects Transparent | Bool | 是否影響透明表面 | False |
案例:彈孔效果
-
材質準備:
- 使用8K掃描的彈孔貼圖(Quixel Megascans)
- 法線貼圖增強立體感
-
動態生成:
csharp void CreateBulletHole(Vector3 hitPoint, Vector3 normal) { var decal = new GameObject("BulletHole"); var projector = decal.AddComponent<DecalProjector>(); projector.material = bulletHoleMaterial; decal.transform.position = hitPoint + normal * 0.1f; decal.transform.rotation = Quaternion.LookRotation(-normal); } -
性能優化:
- 使用對象池管理Decal實例
- 設置合理的Draw Distance避免過度渲染
注意事項
- 深度衝突:適當調整Projector的Offset參數(建議0.05-0.1)
- 移動平台:需測試ES3.0設備兼容性,必要時降低貼圖分辨率
- 透明表面:默認不支持透明物體接收Decal,需特殊Shader處理
【從UnityURP開始探索遊戲渲染】專欄-直達
(歡迎點贊留言探討,更多人加入進來能更加完善這個探索的過程,🙏)