Getting 16-Bit Color Depth Images Per Channel / EXR Encoding

I’m having a problem when trying to encode images with .EXR extension. The reason I’m trying to do .EXR is because I need to get images which have more than 24 bits bits of depth (more than 8 bits per channel) and was hoping this would solve my issue as the documentation says it supports 16 and 32 bit floats. I’ve tried doing it with .PNGs but the most I could get is 8 bit channels and some people say that PNGs don’t support more than 8-bits per channel. This brings me to my current problem:

I’m trying to save a screenshot of my scene as a .EXR file. I’ve looked at the Unity documentation on it, but I’m getting weird / wrong behavior. I’m not too sure what their m_Input variable is, but here is the code I replicated:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class SaveRenderTextureToEXR : MonoBehaviour
{
    RenderTexture m_InputTexture = new RenderTexture(Screen.width, Screen.height, 32);
    // Use this for initialization
    void Start ()
    {
        SaveRenderTexture();
    }
   
    // Update is called once per frame
    void Update () {
       
    }

    void SaveRenderTexture()
    {
        int width = m_InputTexture.width;
        int height = m_InputTexture.height;

        Texture2D tex = new Texture2D(width, height, TextureFormat.RGBAFloat, false);

        // Read screen contents into the texture
        Graphics.SetRenderTarget(m_InputTexture);
        tex.ReadPixels(new Rect(0, 0, width, height), 0, 0);
        tex.Apply();

        // Encode texture into the EXR
        byte[] bytes = tex.EncodeToEXR(Texture2D.EXRFlags.CompressZIP);
        File.WriteAllBytes(Application.dataPath + "/SavedRenderTexture.exr", bytes);
    }
}

This code didn’t really work for me. The output was a really tiny image and I couldn’t open it with anything (I tried InfranView and Photoshop).

I’m not too sure what to do and any help would be appreciated.

First off, don’t create the RenderTexture at the field level, this will run during the constructor of your MonoBehaviour which doesn’t occur on the main thread. Use Awake or Start to create the RenderTexture.

As for the EXR issue, I can’t say, I haven’t tested it and I’m not on the latest version of Unity (and won’t be until we build our title).

The file format for PNG supports 16 bits per channel, but Unity does not support encoding to anything but 24/32bit PNGs.

The problem you’re having seems to be the render texture itself, it is completely unnecessary. If you’re just looking to capture the contents of the screen, just call ReadPixels() and it’ll get the contents of the current camera. The trick is when you call it; using a coroutine with yield return new WaitForEndOfFrame() will ensure the current render target is the final rendered image. In fact the documentation for WaitForEndOfFrame has example code for doing just what you’re doing, but saving to PNG.

Basically what your code is doing is creating an empty render texture (which by default will be filled with null pixels) and trying to make an EXR of that, which is probably bugging out the EXR encoding.