【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层纹理:

c 复制代码
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通道)选择纹理,减少采样次数。例如:

      c 复制代码
      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 复制代码
    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开始探索游戏渲染】专栏-直达 (欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)

相关推荐
超爱吃士力架11 小时前
程序员的副业 IP 探索之路----小白用AI做了个游戏,发出去第一天居然有300多个人玩!!!
游戏开发
SmalBox1 天前
08-05-热更新-完整热更新流程实战
unity3d·游戏开发
只睡四小时1 天前
Three.js Sub-tick:漏判 60.7%→0
开发语言·javascript·性能优化·ecmascript·游戏开发·three.js·碰撞检测
SmalBox2 天前
08-04-热更新-首包资源策略
unity3d·游戏开发
SmalBox3 天前
08-03-热更新-边玩边下载
unity3d·游戏开发
西风逍遥游3 天前
从 EveScript 到 B站 Toy:一个 WebGPU 游戏发布插件怎样设计
游戏开发
西风逍遥游4 天前
500 单位 RTS 为什么还没到 60 FPS:一次 WebGPU 游戏性能诊断
游戏开发
甲维斯4 天前
Codex,Zcode,KimiCode电脑操作能力对比!
人工智能·游戏开发
SmalBox4 天前
08-02-热更新-差量更新与断点续传
unity3d·游戏开发
UWA4 天前
多人战斗中Lua持续高耗时,是瞬时峰值还是高频调用在作祟
性能优化·lua·游戏开发