博客 / 詳情

返回

【URP】Unity[內置Shader]地形光照TerrainLit

【從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)
  • 溶解效果移植‌:

    • 複製TerrainLit的混合邏輯到Shader Graph
    • 添加Noise節點連接Alpha通道實現地形局部溶解
    • 關鍵節點鏈:

      • Noise → Step → Alpha Clipping
        Color → Emission(邊緣發光)

該着色器通過模塊化設計平衡了性能與效果,在URP 12.x版本後已完全支持Shader Graph的自定義擴展


【從UnityURP開始探索遊戲渲染】專欄-直達
(歡迎點贊留言探討,更多人加入進來能更加完善這個探索的過程,🙏)
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.