【URP】Unity[后处理]景深DepthOfField

【从UnityURP开始探索游戏渲染】专栏-直达

Unity URP中的景深(Depth of Field)是一种模拟真实相机光学特性的后处理效果,通过模糊近处或远处的物体来突出焦点区域,增强画面层次感和真实感。其发展经历了从Built-in管线的基础实现到URP/HDRP的物理化演进过程,早期采用高斯模糊近似,现代则引入散景(Bokeh)等更接近真实光学特性的算法。

核心作用

  • 视觉引导‌:突出主体对象,弱化背景干扰
  • 增强真实感‌:模拟摄影镜头物理特性
  • 艺术表现‌:通过散景光斑创造氛围

实现原理

基于深度缓冲区计算弥散圈(Circle of Confusion),通过多Pass模糊处理非焦点区域。URP提供两种模式:

  • 高斯模式‌:性能优先,仅支持远场模糊
  • 散景模式‌:质量优先,模拟光圈叶片光学特性

Unity URP中的景深(Depth of Field)效果基于光学透镜的物理特性模拟,其核心原理是通过计算混淆圈(Circle of Confusion, CoC)来实现虚实分层。

光学基础原理

  • 透镜成像特性‌:真实相机中,只有特定距离(焦平面)的物体能清晰成像,其他距离的物体会在传感器上形成弥散圆斑(CoC),其直径与光圈大小成正比。URP通过高斯模糊或散景模式模拟这一现象,前者计算效率高但物理准确性较低,后者更接近真实光学效果。

  • CoC计算‌:每个像素的模糊程度取决于其深度值与焦点距离的差值。计算公式为:

    CoC = |(d_l * f * (z - z_f)) / (z * (f + z_f))|

    其中d_l为光圈直径,f为焦距,z为物体距离,z_f为对焦平面距离5。URP在Shader中通过深度纹理(_CameraDepthTexture)获取每个像素的z值。

URP实现流程

  • 预处理阶段‌:生成包含CoC数据的纹理。通过比较像素深度与焦点距离,标记需要模糊的区域(近景或远景)。示例参数包括:

    csharp 复制代码
    csharp
    [Range(0.1f, 100f)] public float focusDistance = 10f;// 焦点距离
    [Range(0.1f, 10f)] public float focusRange = 3f;// 清晰范围
    [Range(1f, 10f)] public float bokehRadius = 4f;// 散景强度
  • 模糊处理‌:根据CoC数据对非焦点区域进行分层模糊。URP提供两种方式:

    • 高斯模糊‌:使用降采样+上采样的多Pass模糊,适合性能敏感场景
    • 散景模糊‌:模拟光学透镜的虚化效果,在高亮区域生成光斑(Bokeh),需额外计算亮度阈值
  • 合成阶段‌:将模糊后的图像与原图按CoC权重混合。清晰区域的权重为,模糊区域根据CoC半径插值。

示例代码逻辑

以下为简化版CoC计算Shader代码片段:

c 复制代码
hlsl
float4 Frag(Attributes input) : SV_Target {
    float depth = SampleDepthTexture(_CameraDepthTexture, input.uv);
    float linearDepth = Linear01Depth(depth);
    float coc = saturate(abs(linearDepth - _FocusDistance) / _FocusRange);
    return float4(coc, coc, coc, 1);
}

该代码生成CoC图,白色表示完全模糊,黑色表示完全清晰。完整实现还需结合多尺度模糊和色调映射处理。

性能优化

  • 降采样‌:在Half/Quarter分辨率下计算模糊,减少像素处理量
  • 动态调整‌:根据平台性能切换高斯/散景模式,移动端建议使用高斯模糊
  • 焦点追踪 ‌:通过射线检测动态更新focusDistance,实现自动对焦效果

完整实现流程

  • URP_DepthOfFieldSetup.cs

    csharp 复制代码
    using UnityEngine;
    using UnityEngine.Rendering;
    using UnityEngine.Rendering.Universal;
    
    public class URP_DepthOfFieldSetup : MonoBehaviour
    {
        [SerializeField] private VolumeProfile volumeProfile;
    
        void Start()
        {
            var depthOfField = volumeProfile.Add<DepthOfField>();
            depthOfField.mode.value = DepthOfFieldMode.Bokeh;
            depthOfField.focusDistance.value = 5f;
            depthOfField.aperture.value = 5.6f;
            depthOfField.focalLength.value = 50f;
        }
    }
  • DoF_Shader.shader

    csharp 复制代码
    Shader "Custom/DoF"
    {
        Properties { _MainTex ("Texture", 2D) = "white" {} }
        SubShader
        {
            Pass {
                // 深度采样与模糊处理
            }
        }
    }

参数详解

参数 作用 典型值
Focus Distance 焦点平面距离 3-10m
Aperture 光圈大小(f值) 1.4-16
Focal Length 镜头焦距(mm) 35-200mm
Blade Count 光圈叶片数 5-9片

实际应用案例

  • 角色特写‌:聚焦角色面部,模糊环境
  • 场景过渡‌:动态调整焦点实现镜头语言
  • UI突出‌:模糊游戏界面背景

性能优化建议

  • 移动端使用高斯模式
  • 控制Blur Iterations≤3
  • 采用DownSample降低分辨率

【从UnityURP开始探索游戏渲染】专栏-直达

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