起因
最近在搞 URP
,需要用到 UI
背景 Blur
的效果,突然想起 PostProcessing
中本身可以实现这个效果
基础配置
Unity
我们使用的版本为 2019.4+
Universal RP
Package
目前 2019.4 稳定版 URP
版本号为 7.3.1,但是这个版本没有 Camera Stack
功能
该功能用于实现多个相机叠加画面的效果,我们项目中希望可以实现不同部分参与或不参与
PostProcessing
过程
目前我们用的版本为 7.4.1
2D Renderer 配置
视频中关于如何设置 URP 2D Renderer
的描述很详细,这里仅简单介绍一下
- 创建
UniversalRenderPipelineAsse
文件 - 创建
2D Renderer
文件 - 将
URP
文件中Renderer List
属性设置为刚刚创建好的2D Renderer
Project Setting
->Graphics
->Scriptable Render Pipeline Setting
设置为URP
文件
需要注意的是,
URP
只建议在考虑兼容性上使用Post Processing V2
,我们还是要老老实实选第一个
思路及实现方式
我希望区分部分场景物体参与 PostProcessing
部分不参与,且 UI
部分可以正常显示在游戏画面的最上方
这里我们通过 Culling Mask
+ Camera Stack
功能来实现
Layer
首先我们为参与 PostProcessing
的场景物体创建一个单独的 Layer
,名字就叫 PostProcessing
Camera
我们创建一个 PostProcessing
相机,这个相机是我们游戏中的场景相机,且为主摄像机,它的职责是用来接收后处理,且仅拍摄参与后处理的场景物体
这里
Render Type
一定要选Base
接着在这个相机下面创建一个 NonePostProcessing
相机,如下图所示
这个相机的职责是绘制所有不参与后处理的场景物体,所以 Culling Mask
不要勾选 UI Layer
、PostProcessing Layer
在我们项目中使用到了 Timeline
和 Cinemachine
功能,很多时候需要运镜,我们要让两次绘制的画面一致,所以要在第二个相机下面加上同步主摄像机 Orthographic Size
的功能
[ExecuteInEditMode]
public class NoPPCameraSync : MonoBehaviour {
[SerializeField]
private Camera _mainCamera;
[SerializeField]
private Camera _noPPCamera;
private void Update() { _noPPCamera.orthographicSize = _mainCamera.orthographicSize; }
}
代码也非常简单,因为主相机在被
Virtual Camera
控制时,Size
是一个动态变化的过程,我们干脆就直接在Update
函数中,每帧同步主相机的大小
最后我们需要给这些相机放到 Stack
里面,这样画面才可以正常显示
Volume
我们可以在 Hierarchy
窗口邮件创建一个 Volume
用于设置游戏中的后处理
我使用的是
Global Volume
,可以根据情况使用,具体功能这里不做更详细的介绍
通过对 Depth of Field
的调整,我们可以实现背景虚化的效果
这里要注意的是,挂载
Volume
物体的Layer
必须是Default
,不知道这个是Bug
还是设计如此,我当前使用的版本,不可以根据当前后处理的Layer
分配给不同的相机,选择非Default Layer
则不生效
UI Blur
最终和 UI
实现背景虚化的效果,我想做成一个组件的形式,当开启这个 UI
时,自动开启上述 Volume
,当关闭时,自动关掉当前效果
public class UIBlur : MonoBehaviour {
private void OnEnable() {
PostProcessingManager.SetEffectTween(
PostProcessingType.Bokeh,
0,
1,
1.5f
);
}
private void OnDisable() { PostProcessingManager.SetEffect(PostProcessingType.Bokeh, 0); }
}
我们通过 PostProcessing
提供外部调用的接口,这里只存放通用类型的后处理,平时不用时默认关掉
层级关系如下,当需要创建更多通用的后处理,可以统一放在这里管理
public class PostProcessingManager : MonoBehaviour { private static Dictionary<PostProcessingType, Tween> _tweens = new Dictionary<PostProcessingType, Tween>(); private static Dictionary<PostProcessingType, Volume> _volumes = new Dictionary<PostProcessingType, Volume>(); private void Awake() { Volume component; foreach(PostProcessingType v in Enum.GetValues(typeof(PostProcessingType))){ if(_volumes.ContainsKey(v)){ continue; } component = transform.Find(v.ToString()).GetComponent<Volume>(); if(component == null){ Log.Error(
quot;{v} effect doesn't exist!");
continue;
}_volumes.Add(v, component);
}
}public static void SetEffect(PostProcessingType type, float weight) {
if(!_volumes.ContainsKey(type)){ return; }if(_tweens.ContainsKey(type) && _tweens[type] != null){ _tweens[type].Kill(); }
_volumes[type].weight = weight;
}public static void SetEffectTween(PostProcessingType type,
float from,
float to,
float time) {
if(!_volumes.ContainsKey(type)){ return; }if(_tweens.ContainsKey(type) && _tweens[type] != null){ _tweens[type].Kill(); }
if(!_tweens.ContainsKey(type)){ _tweens.Add(type, null); }
_volumes[type].weight = from;
_tweens[type] = DOTween.To(
() => _volumes[type].weight,
value => _volumes[type].weight = value,
to,
time
);
}
}public enum PostProcessingType {
Bokeh
}
其他效果
如果需要其他触发后处理的方式,比如特定地点使用的特殊后处理,我们可以通过开关当前
Volume
物体的方式实现,或者其他非Global Volume
通过碰撞实现已知的坑
Cinemachine 不会切换 VCam
我被这个问题困扰了很久,设置完后处理之后,之前设置的所有虚拟相机不会自动切换,
Blend
效果也消失了最后发现,用于切换相机的
CinemachineBrain
会根据当前相机的Culling Mask
是否能看到Virtual Camera
来进行切换!!!
有道理,但仍然花了很多时间才找到原因
T^T
如果同样适用
Cinemachine
的同学,记得把虚拟相机的Layer
设置为PostProcessing
和主相机的Culling Mask
一致