【從UnityURP開始探索遊戲渲染】專欄-直達
TerrainLit Shader是Unity URP(通用渲染管線)中專為地形系統設計的內置着色器,主要用於高效渲染大規模地形表面並支持多紋理混合。
作用與原理
核心功能:
- 支持最多8層紋理混合,通過高度圖或遮罩圖控制混合過渡
- 採用基於物理的渲染(PBR)模型處理光照和材質反射
- 優化了LOD(細節層次)系統,適應遠距離地形渲染
發展歷史
- 2018年:隨URP首次推出,僅支持4層紋理混合
- 2019年:升級至支持8層混合,增加PBR支持
- 2020年:優化GPU實例化,提升大規模地形渲染性能
技術原理:
- 使用SplatMap技術混合多張紋理,通過RGBA通道存儲混合權重
- 在頂點着色階段計算地形高度和法線,片段着色階段進行紋理採樣混合
SplatMap技術
SplatMap技術通過紋理的RGBA通道存儲多層紋理權重信息,在片段着色器中實現動態混合。
存儲機制
-
通道分配:
- 每個RGBA通道對應一個紋理層的權重值(0-1範圍),例如R通道存儲第1層權重,G通道存儲第2層權重,依此類推。當需要超過4層時,會使用多張SplatMap(如第二張SplatMap的R通道存儲第5層權重)。
-
數據編碼:
- 權重值通常以8位精度存儲(0-255映射到0.0-1.0),在着色器中通過歸一化還原。例如,R通道值0.5表示第1層權重為50%。
着色器實現示例
以下是一個基於Unity的片段着色器代碼片段,演示如何採樣並混合4層紋理:
hlsl
half4 frag(v2f input) : SV_Target {
// 採樣SplatMap獲取權重
half4 splat = SAMPLE_TEXTURE2D(_SplatMap, sampler_SplatMap, input.uv);
// 採樣各層紋理
half4 tex1 = SAMPLE_TEXTURE2D(_Layer1, sampler_Layer1, input.uv);
half4 tex2 = SAMPLE_TEXTURE2D(_Layer2, sampler_Layer2, input.uv);
half4 tex3 = SAMPLE_TEXTURE2D(_Layer3, sampler_Layer3, input.uv);
half4 tex4 = SAMPLE_TEXTURE2D(_Layer4, sampler_Layer4, input.uv);
// 動態混合(權重歸一化處理)
half sumWeights = splat.r + splat.g + splat.b + splat.a;
half3 finalColor = (tex1.rgb * splat.r + tex2.rgb * splat.g +
tex3.rgb * splat.b + tex4.rgb * splat.a) / sumWeights;
return half4(finalColor, 1.0);
}
性能優化
-
紋理數組替代:
-
使用Texture2DArray將多張紋理合併為單一資源,通過索引值(存儲在SplatMap的R/G通道)選擇紋理,減少採樣次數。例如:
hlsl half4 var_Main = SAMPLE_TEXTURE2D_ARRAY(_TexArray, sampler_TexArray, uv, splat.r * 255) * splat.b; half4 var_Sec = SAMPLE_TEXTURE2D_ARRAY(_TexArray, sampler_TexArray, uv, splat.g * 255) * (1 - splat.b); half4 finalRGB = var_Main + var_Sec;
-
-
高度混合增強:
- 結合高度圖(存儲在SplatMap的B通道)實現更自然的過渡效果,通過比較各層高度值動態調整權重。
限制與改進
- 通道限制:傳統SplatMap每張僅支持4層,超過時需要多張紋理,增加帶寬壓力。
- 混合精度:8位通道可能導致可見的帶狀偽影,可通過16位浮點紋理或抖動技術緩解。
具體使用示例
基礎配置
- 創建Terrain對象
- 在Inspector面板選擇Material為"Custom"
- 指定Shader為"Universal Render Pipeline/Terrain/Lit"
通過SplatMap控制紋理混合時,需在Terrain Layers中配置各層紋理的金屬度/光滑度等PBR參數
-
腳本控制混合:
csharp // 動態修改第2層紋理權重 Terrain terrain = GetComponent<Terrain>(); float[,,] map = terrain.terrainData.GetAlphamaps(0, 0, 1, 1); map[0,0,1] = 0.5f;// 設置權重為50% terrain.terrainData.SetAlphamaps(0, 0, map);
Shader Graph應用
-
擴展案例(雪地效果):
- 創建Unlit Shader Graph,添加Height節點檢測地形高度5
-
使用Lerp節點混合雪地紋理和基礎紋理:最終輸出到Base Color和Normal通道
- Height → Step → Lerp(T)
基礎紋理 → Lerp(A)
雪地紋理 → Lerp(B)
- Height → Step → Lerp(T)
-
溶解效果移植:
- 複製TerrainLit的混合邏輯到Shader Graph
- 添加Noise節點連接Alpha通道實現地形局部溶解
-
關鍵節點鏈:
- Noise → Step → Alpha Clipping
Color → Emission(邊緣發光)
- Noise → Step → Alpha Clipping
該着色器通過模塊化設計平衡了性能與效果,在URP 12.x版本後已完全支持Shader Graph的自定義擴展
【從UnityURP開始探索遊戲渲染】專欄-直達
(歡迎點贊留言探討,更多人加入進來能更加完善這個探索的過程,🙏)