Sehyup
Sehyup

Reputation: 11

When taking a screenshot using Unity's RenderTexture, the post-processing effects are not being applied

Post-processed (On the Camera) enter image description here

Not Post-processed (When taking a screen captrue) enter image description here

The following code is for screen capture with an in-game camera at runtime.

  1. Create render textures and assign newly created render textures to camera target textures
  2. Coroutine - Run WaitForEndOfFrame
  3. Camera Render
  4. Create Texture2D to save to file path and run ReadPixels() and 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());

...

}

The reason why post-processing effects are not applied even when waiting for the last frame with a coroutine and WaitForEndOfFrame is quite intriguing. As far as I know, the rendering order is supposed to be camera rendering, scene rendering, and then the application of post-processing. Why might it not be working?

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

Because the rendering pipeline is URP, I understand that it cannot be resolved using OnRenderImage. Additionally, callbacks such as RenderPipelineManager.endCameraRendering and endFrameRendering didn't yield the desired post-processing results.

There is a ScreenCapture class supported by Unity Engine, and there is a way to solve it using this, but it was too buggy and resolution issue to use. https://forum.unity.com/threads/how-to-capture-screenshot-with-post-processing.701432/

Instead of OnRenderImage, URP can use Scriptable RenderPass to implement it similar to OnRenderImage If anyone is familiar with this and can provide insights, it would be greatly appreciated.

Upvotes: 0

Views: 573

Answers (1)

Sehyup
Sehyup

Reputation: 11

I have identified the cause of this issue.

It wasn't the rendering order but rather the RenderTextureFormat and TextureFormat that were the cause.

In my code, when creating RenderTexture and Texture, I was using ARGB32. ARGB32 stores each channel with 8-bit integers, so it has a range of 0-255.

This is suitable for storing Low Dynamic Range (LDR) images. Therefore, using ARGB32 results in the loss of HDR information, making the screen capture appear as if post-processing is not applied.

Therefore, if you want to include post-processing, it is recommended to use ARGBHalf. ARGBHalf stores each channel with 16-bit floating-point numbers, allowing for a much wider range of values to be stored. This supports HDR processing.

By changing RenderTextureFormat to ARGBHalf and TextureFormat to RGBAHalf, post-processing is applied correctly.

This is the result: result screenshot

Upvotes: 1

Related Questions