【URP】Unity[RendererFeatures]贴花Decal

【从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核心逻辑:

c 复制代码
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 DistanceStart 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 复制代码
    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开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)