In-Editor Screenshot Script for Unity

This little script can take a Screenshot in custom resolution and with the option to render a transparent background. This might come in handy when you want to create renderings of in-game assets from within the Unity Editor, like characters or vehicles.

How the Screenshot Component looks in the Editor
Screenshot in the Editor

The perspective of the Screenshot is defined by a Camera component that is attached to the same GameObject. So it is possible to modify the position, rotation and focal length through the Transform of the GameObject. All of this is possible without the need to run the scene. Simply click the “Take Screenshot” button in the Inspector.

Download Screenshot Unitypackage
Download Screenshot Unitypackage

Here is the implementation:

using System;
using System.IO;
using UnityEngine;

[RequireComponent(typeof(Camera))]
public class Screenshot : MonoBehaviour {

    [SerializeField] int width = 1024;
    [SerializeField] int height = 512;
    [SerializeField] string folder = "Screenshots";
    [SerializeField] string filenamePrefix = "screenshot";
    [SerializeField] bool ensureTransparentBackground = false;


    [ContextMenu("Take Screenshot")]
    public void TakeScreenshot() {
        folder = GetSafePath(folder.Trim('/'));
        filenamePrefix = GetSafeFilename(filenamePrefix);

        string dir = Application.dataPath + "/" + folder + "/";
        string filename = filenamePrefix + "_" + DateTime.Now.ToString("yyMMdd_HHmmss") + ".png";
        string path = dir + filename;

        Camera cam = GetComponent<Camera>();

        // Create Render Texture with width and height.
        RenderTexture rt = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32);
        
        // Assign Render Texture to camera.
        cam.targetTexture = rt;

        // save current background settings of the camera
        CameraClearFlags clearFlags = cam.clearFlags;
        Color backgroundColor = cam.backgroundColor;

        // make the background transparent when enabled
        if(ensureTransparentBackground) {
            cam.clearFlags = CameraClearFlags.SolidColor;
            cam.backgroundColor = new Color(); // alpha is zero
        }

        // Render the camera's view to the Target Texture.
        cam.Render();

        // restore the camera's background settings if they were changed before rendering
        if(ensureTransparentBackground) {
            cam.clearFlags = clearFlags;
            cam.backgroundColor = backgroundColor;
        }

        // Save the currently active Render Texture so we can override it.
        RenderTexture currentRT = RenderTexture.active;

        // ReadPixels reads from the active Render Texture.
        RenderTexture.active = cam.targetTexture;

        // Make a new texture and read the active Render Texture into it.
        Texture2D screenshot = new Texture2D(width, height, TextureFormat.ARGB32, false);
        screenshot.ReadPixels(new Rect(0, 0, width, height), 0, 0, false);

        // PNGs should be sRGB so convert to sRGB color space when rendering in linear.
        if(QualitySettings.activeColorSpace == ColorSpace.Linear) {
            Color[] pixels = screenshot.GetPixels();
            for(int p = 0; p < pixels.Length; p++) {
                pixels[p] = pixels[p].gamma;
            }
            screenshot.SetPixels(pixels);
        }

        // Apply the changes to the screenshot texture.
        screenshot.Apply(false);

        // Save the screnshot.
        Directory.CreateDirectory(dir);
        byte[] png = screenshot.EncodeToPNG();
        File.WriteAllBytes(path, png);

        // Remove the reference to the Target Texture so our Render Texture is garbage collected.
        cam.targetTexture = null;

        // Replace the original active Render Texture.
        RenderTexture.active = currentRT;

        Debug.Log("Screenshot saved to:\n" + path);
    }

    public string GetSafePath(string path) {
        return string.Join("_", path.Split(Path.GetInvalidPathChars()));
    }

    public string GetSafeFilename(string filename) {
        return string.Join("_", filename.Split(Path.GetInvalidFileNameChars()));
    }
}

And the Editor script to show the “Take Screenshot” button in addition to the context menu entry:

using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(Screenshot))]
public class ScreenshotEditor : Editor {

    public override void OnInspectorGUI() {
        DrawDefaultInspector();

        if(GUILayout.Button("Take Screenshot")) {
            ((Screenshot)serializedObject.targetObject).TakeScreenshot();
        }
    }
}

Make sure the ScreenshotEditor is saved to a folder named “Editor” since it is using the UnityEditor assembly. Or simply download the Unitypackage.

Download Screenshot Unitypackage
Download Screenshot Unitypackage

Feel free to copy and adjust the code to your needs. Please write a comment and tell me what you think or when there is something I could improve!

Published by

Chris

Christian Kauppert is a freelance game engine developer and VFX compositor living in Berlin. He uses this blog to show and write about selected works. Occasionally Chris also writes about issues and solutions he stumbles upon while developing interactive experiences and games.

Leave a Reply

Your email address will not be published. Required fields are marked *