You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity URP下Texture2D.ReadPixels读取RenderTexture生成缩略图异常

Unity 2022.3 URP运行时生成指定尺寸缩略图的问题修复

针对你遇到的指定宽高缩略图画面未缩放、读取RenderTexture异常、操作RT导致黑屏灰屏的问题,以下是适配URP的解决方案:

核心问题分析

  1. 画面未缩放:直接复制主相机屏幕尺寸的RT到小尺寸RT时,未做缩放采样,仅做了裁剪/拉伸,导致画面比例、内容显示异常。
  2. 读取RT异常:URP在endCameraRendering回调后,主相机的RT可能被管线后续流程占用或修改,直接读取会获取错误数据。
  3. 黑屏/灰屏:RenderTexture.active和Graphics.CopyTexture会干扰URP的管线状态管理,在SRP渲染周期内直接操作全局RT状态,易导致渲染上下文混乱。

解决方案代码示例

方法一:让相机重新渲染到指定尺寸RT(最可靠)

通过让目标相机重新渲染到缩略图尺寸的RT,自动完成画面缩放,同时用异步GPU读取避免管线冲突:

using UnityEngine;
using UnityEngine.Rendering;
using System.IO;

public class ThumbnailCapture : MonoBehaviour
{
    // 缩略图目标尺寸
    public int thumbnailWidth = 256;
    public int thumbnailHeight = 144;

    void OnEnable()
    {
        RenderPipelineManager.endCameraRendering += CaptureThumbnail;
    }

    void OnDisable()
    {
        RenderPipelineManager.endCameraRendering -= CaptureThumbnail;
    }

    void CaptureThumbnail(ScriptableRenderContext context, Camera camera)
    {
        // 只处理主相机,可根据需求修改目标相机
        if (camera != Camera.main) return;

        // 创建与URP兼容的RenderTexture,匹配相机的深度缓冲和格式
        RenderTexture thumbnailRT = new RenderTexture(thumbnailWidth, thumbnailHeight, 24, RenderTextureFormat.ARGB32);
        thumbnailRT.antiAliasing = QualitySettings.antiAliasing;

        // 临时保存相机原始渲染目标
        RenderTexture originalTarget = camera.targetTexture;

        // 让相机渲染到缩略图RT
        camera.targetTexture = thumbnailRT;
        camera.Render();

        // 异步读取GPU纹理数据,避免阻塞主线程和干扰URP管线
        AsyncGPUReadback.Request(thumbnailRT, 0, TextureFormat.RGBA32, request =>
        {
            if (request.hasError)
            {
                Debug.LogError("缩略图读取失败:GPU回读错误");
                return;
            }

            // 生成最终的缩略图Texture2D
            Texture2D thumbnailTex = new Texture2D(thumbnailWidth, thumbnailHeight, TextureFormat.RGBA32, false);
            thumbnailTex.LoadRawTextureData(request.GetData<byte>());
            thumbnailTex.Apply();

            // 示例:保存到本地
            byte[] pngData = thumbnailTex.EncodeToPNG();
            string savePath = Path.Combine(Application.persistentDataPath, "thumbnail.png");
            File.WriteAllBytes(savePath, pngData);
            Debug.Log($"缩略图已保存至:{savePath}");

            // 清理临时资源
            Destroy(thumbnailTex);
        });

        // 恢复相机原始渲染目标,避免影响后续正常渲染
        camera.targetTexture = originalTarget;
        // 释放缩略图RT资源
        thumbnailRT.Release();
        Destroy(thumbnailRT);
    }
}

方法二:缩放主相机RT(性能更优,需注意时机)

如果不想重复渲染相机,可通过Graphics.Blit缩放主相机的RT到缩略图尺寸,再异步读取:

void CaptureThumbnail(ScriptableRenderContext context, Camera camera)
{
    if (camera != Camera.main) return;

    RenderTexture mainRT = camera.activeTexture;
    if (mainRT == null) return;

    RenderTexture thumbnailRT = new RenderTexture(thumbnailWidth, thumbnailHeight, mainRT.depth, mainRT.format);
    // Blit自动完成缩放采样,使用默认的缩放滤镜
    Graphics.Blit(mainRT, thumbnailRT);

    AsyncGPUReadback.Request(thumbnailRT, request =>
    {
        // 后续处理同方法一...
    });

    thumbnailRT.Release();
    Destroy(thumbnailRT);
}

关键注意事项

  • 避免操作全局RT状态:不要在URP渲染周期内设置RenderTexture.active,改用AsyncGPUReadback读取纹理数据,这是SRP下的标准做法。
  • RT格式匹配:缩略图RT的格式、深度缓冲要和主相机的RT保持一致,避免格式不兼容导致灰屏。
  • 资源清理:必须恢复相机的原始targetTexture,并及时释放临时创建的RenderTexture,防止内存泄漏。

内容的提问来源于stack exchange,提问作者SoMuch SMx

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 09:51:26