Is it correct to take Screenshot from a camera and then disable it on (WaitForEndOfFrame)?

Viewed 49

I made this very simple script which should be attached to inactive camera Gameobject with renderTexure. If the camera Gameobject is active, this suppose to record only one frame to the renderTexure and then save to a path as a .png. After that the camera should be disabled.

    public static string path;

void Update()
{
    StartCoroutine(SSOT());
}

public static void SaveRTToFileToSharing()
{
    RenderTexture rt = Resources.Load<RenderTexture>(@"Render Texure/ScreenShot") as RenderTexture;

    RenderTexture.active = rt;
    Texture2D tex = new Texture2D(rt.width, rt.height, TextureFormat.RGB24, false);
    tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
    //RenderTexture.active = null;
    tex.Apply();
    byte[] bytes;
    bytes = tex.EncodeToPNG();

    path = Application.persistentDataPath + "Test Shot.png";
    System.IO.File.WriteAllBytes(path, bytes);
    Destroy(tex);
}

IEnumerator SSOT()
{
    yield return new WaitForEndOfFrame();
    SaveRTToFileToSharing();
    gameObject.SetActive(false);
}

The script works as I intended but i'm not sure if it really record only one frame or more. What would you change if you gonna change anything ?

1 Answers

It should be fine since you deactivate the object in the same frame you enabled it.

Anyway just to be sure I would instead of using Update which is called every frame simply move that StartCoroutine call to the OnEnable which is called everytime the GameObject gets activated.

private void OnEnable()
{
    StartCoroutine(SSOT());
}

To make it a bit more performant there are a few things you could do only once and reuse them - depends ofcourse on your priorities: If your priority is little memory usage and performance doesn't matter for the screenshot then you are fine ofcourse. Otherwise I would probably do it like

private RenderTexture rt;
private Texture2D tex;
private string path;

private void Awake ()
{
    // Do this only once and keep it around while the game is running
    rt = (RenderTexture) Resources.Load<RenderTexture>(@"Render Texure/ScreenShot");

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

    path = Application.persistentDataPath + "Test Shot.png";
}

private void SaveRTToFileToSharing()
{
    RenderTexture.active = rt;

    tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
    //RenderTexture.active = null;
    tex.Apply();
    byte[] bytes;
    bytes = tex.EncodeToPNG();

    // This happens async so your game can continue meanwhile 
    using (var fileStream = File.Open(path, FileMode.OpenOrCreate, FileAccess.Write))
    {
        fileStream.WriteAsync(bytes, 0, bytes.Length);
    }
}
Related