文章目录
环境
Unity : 2019.4.30f1
URP : 7.7.1
问题
RT
如下图显示先有一个 Base Camera,注意 是在 DontDestroyOnLoad 分类场景下的
再如下图显示,另有 uicamera 也是 DontDestroyOnLoad 下的相机,RenderType 是 Overlay的
再如下图显示,另有 cameraWeapon 也是 SurvivalModeMap 场景下的相机,RenderType 是 Overlay的
按文档来说,只要是 Overlay 类型的相机,都可以设置到 Base 相机下的 Stack 来达到 叠加 或叫 累加 渲染的效果
从之前的情况得知,我们现在有两个 Overlay 的相机,分别为:uicamera, cameraWeapon
但是下图,可以发现,Base 相机下,却没有显示 cameraWeapon 的
原因:在Unity GUI 编辑器下来编辑的话,Base 相机的 Stack 相加列表项必须只能在同属于 Base 场景中的 Overlay 相机
如何解决
如果 Base 相机的 Stack 想要跨 场景设置 Stack,那么可以通过代码的方式,拿到其他场景的 Overlay 相机,然后调用如下代码:
var yourOverlayCam = GameObject.Find("xxx").GetComponent<Camera>();
// 通过脚本的方式,只要能找到 camera 不轮是否跨 base 相机的场景,都可以 Add 进 Stack
_cam.GetComponent<UniversalAdditionalCameraData>().cameraStack.Add(yourOverlayCam);
详细的 DEMO 代码(已验证过可行)
// jave.lin 2021/10/30
// 测试 脚本控制 URP Camera Stack
using UnityEngine;
using UnityEngine.Rendering.Universal;
public class TestURPCameraStack : MonoBehaviour
{
public Camera mainCam;
public Camera pCam;
public Camera weaponCam;
public Camera uiCam;
private UniversalAdditionalCameraData mainCam_uacd;
private UniversalAdditionalCameraData pCam_uacd;
private UniversalAdditionalCameraData weaponCam_uacd;
private UniversalAdditionalCameraData uiCam_uacd;
private void Start()
{
GameObject.DontDestroyOnLoad(this.gameObject);
}
private void GetCam(string name, ref Camera cam)
{
if (cam == null)
{
var go = GameObject.Find(name);
cam = go != null ? go.GetComponent<Camera>() : null;
}
}
private UniversalAdditionalCameraData GetCamAdditionalData(Camera cam)
{
return cam != null ? cam.GetComponent<UniversalAdditionalCameraData>() : null;
}
private void SetOverlayCamData(UniversalAdditionalCameraData data)
{
if (data != null)
{
data.renderType = CameraRenderType.Overlay;
data.renderShadows = false;
data.dithering = false;
data.renderPostProcessing = false;
data.volumeLayerMask = 0;
data.volumeTrigger = null;
}
}
private void AddCameraStack(UniversalAdditionalCameraData data, Camera cam)
{
if (!data.cameraStack.Contains(cam))
{
data.cameraStack.Add(cam);
}
}
private void RemoveCameraStack(UniversalAdditionalCameraData data, Camera cam)
{
data.cameraStack.Remove(cam);
}
private void InputHandle()
{
if (pCam_uacd != null)
{
if (Input.GetKeyDown(KeyCode.T))
{
// p camera add
AddCameraStack(pCam_uacd, weaponCam);
AddCameraStack(pCam_uacd, uiCam);
}
if (Input.GetKeyDown(KeyCode.Y))
{
// p camera remove
RemoveCameraStack(pCam_uacd, weaponCam);
RemoveCameraStack(pCam_uacd, uiCam);
}
}
if (mainCam_uacd != null)
{
if (Input.GetKeyDown(KeyCode.G))
{
// main camera add
AddCameraStack(mainCam_uacd, weaponCam);
AddCameraStack(mainCam_uacd, uiCam);
}
if (Input.GetKeyDown(KeyCode.H))
{
// main camera remove
RemoveCameraStack(mainCam_uacd, weaponCam);
RemoveCameraStack(mainCam_uacd, uiCam);
}
}
}
private void Update()
{
// jave.lin : getting cameras
GetCam("MainCamera", ref mainCam);
GetCam("ParachutingAirshipCamera", ref pCam);
GetCam("cameraWeapon", ref weaponCam);
GetCam("uicamera", ref uiCam);
// jave.lin : getting camera additional data
mainCam_uacd = GetCamAdditionalData(mainCam);
pCam_uacd = GetCamAdditionalData(pCam);
weaponCam_uacd = GetCamAdditionalData(weaponCam);
uiCam_uacd = GetCamAdditionalData(uiCam);
// jave.lin : setting overlay camera additional data
SetOverlayCamData(weaponCam_uacd);
SetOverlayCamData(uiCam_uacd);
// jave.lin : inputing handle
InputHandle();
}
}
如果你的项目中,同一时刻有且仅有一个场景,不会使用 Additive 的方式来加载场景的话,可以不用考虑上面的问题
另外说明一下,通常都是 Base Camera 是渲染 3D 内容, Overlay Camera 都渲染 UI ,但根据项目、需求情况也不一定 Overlay Camera 只是渲染UI的,可以看到 URP 官方的 DEMO 中, Overlay 相机可以是非UI,起到分渲染层级的效果,这个得按你自己的项目需要考量是适合此中方式来制作
References
- Camera Stacking - 2021/11/1 发现的 github 上的 camera stacking 文档
- Clearing, rendering order and overdraw - 延伸阅读一下,还有 camera 的 clearing 操作