使用Unity的RenderTexture截取屏幕截图时,未应用后处理效果

问题描述 投票:0回答:1

后期处理(在相机上) 在此输入图片描述

未进行后期处理(截屏时) 在此输入图片描述

以下代码用于在运行时使用游戏内相机进行屏幕捕获。

  1. 创建渲染纹理并将新创建的渲染纹理分配给相机目标纹理
  2. 协程 - 运行 WaitForEndOfFrame
  3. 相机渲染
  4. 创建Texture2D以保存到文件路径并运行ReadPixels()和Apply()
 private static IEnumerator RecordFrame(RectTransform rectTransform = null, RawImage rawImage = null)
    {
        // Disable UI to hide
        TurnOffOtherCameras();

        // Save Texture in the Last Frame
        yield return new WaitForEndOfFrame();

        CaptureScreenAndSave(rectTransform, rawImage);

        TurnOnOtherCameras();
    }


private static async UniTask<bool> CaptureScreenAndSave(RectTransform rectTransform = null, RawImage rawImage = null)
    {

...
                // This is the main ScreenCaptrue logic
        string totalPath = TotalPath;
        Texture2D screenTex = null;

        int pixelWidth, pixelHeight;
        pixelWidth = rectTransform == null ? _camera.pixelWidth : (int)rectTransform.rect.width;
        pixelHeight = rectTransform == null ? _camera.pixelHeight : (int)rectTransform.rect.height;

     
            var rt = new RenderTexture(pixelWidth, pixelHeight, 24, RenderTextureFormat.ARGB32);

            var prev = _camera.targetTexture;

            _camera.targetTexture = rt;
            _camera.Render();

            screenTex = new Texture2D(pixelWidth, pixelHeight, TextureFormat.ARGB32, false);
            RenderTexture.active = rt;

            Rect area = new Rect(0f, 0f, pixelWidth, pixelHeight);

            screenTex.ReadPixels(area, 0, 0);
            screenTex.Apply();

            _camera.targetTexture = prev;

            if (Directory.Exists(FolderPath) == false)
            {
                Directory.CreateDirectory(FolderPath);
            }

            File.WriteAllBytes(totalPath, screenTex.EncodeToPNG());

...

}

即使使用协程和 WaitForEndOfFrame 等待最后一帧,后处理效果也不会应用的原因非常有趣。据我所知,渲染顺序应该是相机渲染,场景渲染,然后应用后处理。为什么它可能不起作用?

https://docs.unity3d.com/kr/2022.1/Manual/ExecutionOrder.html

因为渲染管线是URP,我理解使用OnRenderImage无法解决。 此外,诸如 RenderPipelineManager.endCameraRendering 和 endFrameRendering 之类的回调没有产生所需的后处理结果。

Unity Engine 支持一个 ScreenCapture 类,并且有一种方法可以使用它来解决它,但它的 bug 和分辨率问题太多,无法使用。 https://forum.unity.com/threads/how-to-capture-screenshot-with-post-processing.701432/

URP可以使用Scriptable RenderPass来代替OnRenderImage来实现类似OnRenderImage 如果有人熟悉这一点并可以提供见解,将不胜感激。

unity-game-engine screenshot
1个回答
0
投票

我已经确定了此问题的原因。

原因不是渲染顺序,而是 RenderTextureFormat 和 TextureFormat。

在我的代码中,当创建RenderTexture和Texture时,我使用的是ARGB32。 ARGB32将每个通道存储为8位整数,因此其范围为0-255。

这适合存储低动态范围 (LDR) 图像。因此,使用 ARGB32 会导致 HDR 信息丢失,使得屏幕捕获看起来好像没有应用后处理。

因此,如果要包含后处理,建议使用ARGBHalf。 ARGBHalf 用 16 位浮点数存储每个通道,允许存储更广泛的值。这支持 HDR 处理。

通过将RenderTextureFormat更改为ARGBHalf并将TextureFormat更改为RGBAHalf,可以正确应用后处理。

这就是结果

© www.soinside.com 2019 - 2024. All rights reserved.