Unity中如何正确暂停/冻结AR Camera并保留冻结帧画面?
AR 相机临时暂停(冻结帧效果)实现方案
问题原因
直接通过Time.timeScale = 0实现全局暂停会触发黑屏、崩溃,核心原因两点:
- AR Foundation的
ARCameraBackground、ARSession更新逻辑与引擎时间轴绑定,时间缩放为0时会停止相机纹理提交,但底层硬件相机仍在推送帧数据,队列堆积、纹理引用失效就会出现黑屏。 AROcclusionManager需要逐帧同步相机彩色帧与硬件深度数据,时间停滞时两类数据不同步,会直接触发内存访问错误导致应用崩溃。
实现步骤
不要在AR组件运行状态下直接修改全局时间缩放,按以下顺序处理即可实现冻结帧暂停效果,无黑屏、崩溃问题:
- 暂停前先抓取当前帧作为冻结覆盖层:提前在场景中添加一个铺满全屏的
RawImage,放在所有场景内容、UI的最下层(仅盖住AR渲染层),暂停触发时第一时间把当前屏幕的AR渲染结果拷贝到这个RawImage上,作为暂停时的静态显示画面。 - 关闭所有AR相关组件:抓帧完成后,依次禁用
ARSession、ARCameraBackground、AROcclusionManager组件,切断AR底层的帧更新、深度计算逻辑,从根源避免时间停滞后的数据不同步问题。 - 再执行全局暂停逻辑:AR组件全部禁用后,再设置
Time.timeScale = 0暂停自身游戏逻辑即可,此时AR相关逻辑已经停止运行,不会触发异常。 - 恢复时按反向顺序执行:先把
Time.timeScale设回1,再启用ARSession、ARCameraBackground,等待AR跟踪状态恢复正常(ARSession.state == SessionTracking)后,最后启用AROcclusionManager,隐藏冻结帧覆盖层并销毁临时纹理释放内存。
参考实现代码
using System.Collections; using UnityEngine; using UnityEngine.UI; using UnityEngine.XR.ARFoundation; public class ARPauseHandler : MonoBehaviour { [Header("AR Core References")] [SerializeField] private ARSession _arSession; [SerializeField] private ARCameraBackground _arCameraBg; [SerializeField] private AROcclusionManager _arOcclusion; [Header("UI Reference")] [SerializeField] private RawImage _freezeOverlay; private bool _isPaused; public void SwitchPauseState() { _isPaused = !_isPaused; if (_isPaused) { // 抓取当前AR帧 var currentFrame = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false); currentFrame.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0); currentFrame.Apply(); _freezeOverlay.texture = currentFrame; _freezeOverlay.gameObject.SetActive(true); // 关闭所有AR组件 _arSession.enabled = false; _arCameraBg.enabled = false; _arOcclusion.enabled = false; // 最后暂停游戏逻辑 Time.timeScale = 0; } else { StartCoroutine(ResumeRoutine()); } } private IEnumerator ResumeRoutine() { // 先恢复时间轴 Time.timeScale = 1; // 启动AR Session等待跟踪恢复 _arSession.enabled = true; _arCameraBg.enabled = true; while (ARSession.state != ARSessionState.SessionTracking) { yield return null; } // 跟踪恢复后再开遮挡 _arOcclusion.enabled = true; // 隐藏冻结层释放内存 _freezeOverlay.gameObject.SetActive(false); Destroy(_freezeOverlay.texture); } }
避坑提示
- 所有AR组件的启用/禁用操作必须在
Time.timeScale = 1的状态下执行,不要在时间暂停状态下操作AR组件。 - 冻结帧的
RawImage记得开启preserveAspect选项,避免不同屏幕比例下画面拉伸。 - 如果项目使用自定义渲染管线,要确认AR背景渲染Pass在抓帧逻辑前执行,避免抓到全黑/空帧。
内容的提问来源于stack exchange,提问作者yuuun
相关产品推荐
相关产品推荐

