You need to enable JavaScript to run this app. Unity如何实现高速自动截取Game视图画面的功能?
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 06:57:01