Unity如何实现高速自动截取Game视图画面的功能?
Unity Game视图高性能自动截图实现方案
原有脚本适配Game视图方法
你现有可截取Scene视图的脚本本身无视图限制,之前仅能截Scene视图是因为调用时传入了Scene视图的场景相机,只需将传入的相机参数改为Game视图对应的主相机(即Camera.main或你自定义的Game视图渲染相机),即可直接截取Game视图内容。
性能优化核心方案
原有方案卡顿的核心原因是GPU数据回读、PNG编码、文件写入三个步骤均为同步执行,会阻塞主线程,可通过以下改造实现高性能无卡顿截图:
- 用
AsyncGPUReadback替代ReadPixels,实现GPU数据异步回读,不阻塞主线程 - PNG编码、文件写入操作全部放到子线程执行,避免占用主线程时间片
- 复用RenderTexture、Texture2D等资源,避免频繁申请释放显存/内存
优化后代码实现
using System.IO; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Rendering; public class HighPerformanceScreenshot : MonoBehaviour { // 提前缓存的渲染纹理与2D纹理,分辨率变化时会自动更新 private RenderTexture _cachedRT; private Texture2D _cachedTex; private int _currentWidth; private int _currentHeight; /// <summary> /// 异步截取Game视图截图 /// </summary> /// <param name="cam">Game视图主相机,传Camera.main即可</param> /// <param name="width">截图宽度</param> /// <param name="height">截图高度</param> /// <param name="savePath">保存路径,需带.png后缀</param> /// <param name="transparentBackground">是否需要透明背景</param> public async void TakeGameViewScreenshot(Camera cam, int width, int height, string savePath, bool transparentBackground = true) { // 分辨率变化时重新初始化缓存资源 if (_cachedRT == null || _currentWidth != width || _currentHeight != height) { if (_cachedRT != null) _cachedRT.Release(); if (_cachedTex != null) Destroy(_cachedTex); _cachedRT = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32); _cachedTex = new Texture2D(width, height, TextureFormat.ARGB32, false); _currentWidth = width; _currentHeight = height; } // 备份相机原有配置 var originalTargetTex = cam.targetTexture; var originalClearFlags = cam.clearFlags; var originalBgColor = cam.backgroundColor; // 渲染相机内容到缓存渲染纹理 cam.targetTexture = _cachedRT; cam.clearFlags = transparentBackground ? CameraClearFlags.SolidColor : originalClearFlags; cam.backgroundColor = transparentBackground ? Color.clear : originalBgColor; cam.Render(); // 异步回读GPU数据 AsyncGPUReadbackRequest request = AsyncGPUReadback.Request(_cachedRT, 0, TextureFormat.ARGB32); await new WaitUntil(() => request.done); if (request.hasError) { Debug.LogError("截图GPU数据回读失败"); return; } // 填充纹理数据 _cachedTex.LoadRawTextureData(request.GetData<Color32>()); _cachedTex.Apply(); // 恢复相机原有配置 cam.targetTexture = originalTargetTex; cam.clearFlags = originalClearFlags; cam.backgroundColor = originalBgColor; // 子线程执行PNG编码与文件写入 byte[] pngData = _cachedTex.EncodeToPNG(); await Task.Run(() => File.WriteAllBytes(savePath, pngData)); } private void OnDestroy() { // 销毁缓存资源避免内存泄漏 if (_cachedRT != null) _cachedRT.Release(); if (_cachedTex != null) Destroy(_cachedTex); } }
调用示例
// 截取1920*1080的透明背景Game视图截图,保存到应用根目录 GetComponent<HighPerformanceScreenshot>().TakeGameViewScreenshot(Camera.main, 1920, 1080, Application.dataPath + "/../Screenshot/test.png");
注意事项
- 若使用URP/HDRP管线,需确保相机的后处理设置不会覆盖透明通道输出
- 若需要截取UI内容,需确保传入的相机包含UI层的渲染设置,或额外传入UI相机叠加渲染
- 若不需要透明背景,将调用时的最后一个参数设为false即可,性能会有进一步提升
内容的提问来源于stack exchange,提问作者Helen
相关产品推荐
相关产品推荐

