目录

 

介绍

准备

设置

基于Unity Builtin 管线

基于Unity URP

基于Unity HDRP


 

介绍:

景深效果Depth Of Field是摄影界的老常客了,在游戏中也非常多见,它能够大幅提升游戏画面体验和真实度,使得物体看起来更有细节。

ddb77236d1744e4e8e7e79c1d3f13d7e.png

GTA5中的景深效果

Unity 当然提供了景深支持: Creative Core: Post-processing - Unity Learn

本文我将介绍最简单直接的实现方法,不需要任何复杂的物理学只是,直截了当的就能出效果。

准备

本节将分别介绍Built-in Render,URP,HDRP中的基础景深效果。所有的管线景深都需要用到PostProcessing功能。

首先,三种管线都需要先把简单的前置设置部署好:Built-in Render需要额外安装package,另外两个不用,在package manager中搜索安装 Post Processing,这个插件早晚会用,它提供了全方位的画质颜色和视觉提升。


设置

  • 基于Unity Builtin 管线

更多参考:Post Process Volumes - Unity Learn
基于Unity Builtin 管线, 需要额外安装 PostProcessing package,安装完成后,你需要:

  1. 在Layer设置中增加一个Layer,可以随便命名,但是建议就叫 PostProcessing” ;然后在你想要设置的Camera中增加Post-process Layer组件;接着设置这个组件的Layer为你刚刚新添加的“PostProcessing” ,确组件的Trigger是你想要的相机;
  2. 创建一个空物体,或者你可以继续在Camera中添加,(只要确保和PostProcessing有关的所有对象都有“PostProcessing” Layer!),在这个物体中添加Post-Process Volume
  3. 创建并保存你的Profile,并在Add effect选项中添加Depth Of Field效果,一般来说Apture小一些Focal Length大一些可以得到一个不错的景深效果,之后你就只需要调整焦距Focus Distance就可以了!
  4. d25b81fd5a0d4a8d8293af3fb111b735.png

    b2000b55db004f94bb8f19c63c9c1a1c.png

    d66ff03dda8b4206980ab595b68333f5.png

    55a39e74cad049228fddb855ace33d09.png

    cb971c922872492e906f612c544e6e30.png

     

392a3ae7d3527c6ff4463cf7b4221789.png

如果你需要动态根据距离来调整的话,需要代码接入来更改volume的 Focus Distance,可以动过简单计算相机和焦点物体的距离来更改;另一种方案是通过屏幕中心发射一道射线来判断距离,这里介绍简单的:


using UnityEngine;
using UnityEngine.Rendering.PostProcessing;

public class cameraDist : MonoBehaviour
{
[SerializeField] PostProcessVolume postProcessVolume;
[SerializeField] DepthOfField df;
[SerializeField] Transform player,mainCamera;

void Start()
    {
      
          postProcessVolume.sharedProfile.TryGetSettings<DepthOfField>(out df);

    }
}
void Update()
    {
        df.focusDistance.value = Vector3.Distance(player.position, mainCamera.position);
    }
  • 基于Unity URP

基于Unity URP, PostProcessing 已经默认包含,而且不需要设置Layer。其它设置和Buit-in基本一致,但是确保在相机设置中启用Post Processing功能! 然后直接在相机中添加Volume组件就可以了,其它步骤基本不变,景深设置中可选用Bokeh

 970ee9a6579747cbbcaf8f4516b5ec22.png6d3de5693bec4dcf80ada0ddb3cae913.png

e54cf4b0943148b193b4f00576d2fc9e.png

 

b94cdc49532079d4d0b8c2d29985f7f8.png

动态更改焦距,这里和Built-in类似,只是引用的API不一样,此外,这里使用简单的射线检测,从相机发出一条射线,射到谁就用谁到相机的距离,但这个方法不适用在复杂场景和运动条件下


using UnityEngine;


public class cameraDist : MonoBehaviour
{
    [SerializeField] private UnityEngine.Rendering.Volume postProcessVolume;
    [SerializeField] private UnityEngine.Rendering.Universal.DepthOfField dof;

void Start()
    {
      
              postProcessVolume.profile.TryGet<UnityEngine.Rendering.Universal.DepthOfField>(out dof);

    }
}
void Update()
    {
        RaycastHit hit;
            if (Physics.Raycast(mainCamera.transform.position, mainCamera.transform.forward, out hit, Mathf.Infinity))
            {
                dof.focusDistance.value = hit.distance;
            }
    }
  • 基于Unity HDRP

HDRP就更神奇了,由于更高渲染技术的加持,其图像原理看起来很不一样,这里的相机看起来更像显示世界里的相机了,相机直接按如图设置:

fc24644946ce43708a8619206b638a3e.png

 Volume和景深效果的添加和URP一样,但是它的参数可以被相机的物理信息直接控制了:

800b7c54ffbe43df80f2f5fd91721190.png

5feca6ffc0d6483b864257e686569675.png

hHDRP的动态对焦,脚本这时候就需要直接更改相机属性就行了,但是注意,相机必须设置为物理相机!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;

public class CameraFocus : MonoBehaviour
{
    public Transform target;
    [SerializeField] Camera cam;
    // Update is called once per frame
    private void OnValidate()
    {
        cam = GetComponent<Camera>();
        cam.usePhysicalProperties = true;
        cam.GetComponent<HDAdditionalCameraData>().physicalParameters.focusDistance = Vector3.Distance(transform.position, target.position);
    }
    private void Start()
    {
        cam = GetComponent<Camera>();
        cam.usePhysicalProperties = true;
    }
    void Update()
    {
        FocusByRaycast();
    }
    void FocusByTransform(Transform target)
    {
        // change camera focus distance 
        cam.GetComponent<HDAdditionalCameraData>().physicalParameters.focusDistance = Vector3.Distance(transform.position, target.position);
    }
    void FocusByRaycast()
    {
        //raycast to target hit distance
        RaycastHit hit;
        if (Physics.Raycast(transform.position, transform.forward, out hit))
        {
            // change camera focus distance 
            cam.GetComponent<HDAdditionalCameraData>().physicalParameters.focusDistance = hit.distance;
        }

    }
}

 

 

 

 

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐