// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; using System.IO; using UnityEditor; using UnityEngine; using UnityEditor.ShortcutManagement; namespace Microsoft.MixedReality.GraphicsTools.Editor { /// /// Utility class to aide in taking screenshots via menu items and public APIs. Screenshots can /// be capture at various resolutions and with the current camera's clear color or a transparent /// clear color for use in easy post compositing of images. /// public class ScreenshotUtilities { [Shortcut("Graphics Tools/Take Screenshot 1x", KeyCode.Alpha1, ShortcutModifiers.Alt)] [MenuItem("Window/Graphics Tools/Take Screenshot/Native Resolution")] private static void CaptureScreenshot1x() { CaptureScreenshot(GetScreenshotPath(), 1); EditorUtility.RevealInFinder(GetScreenshotDirectory()); } [Shortcut("Graphics Tools/Take Screenshot 1x Alpha", KeyCode.Alpha1, ShortcutModifiers.Shift)] [MenuItem("Window/Graphics Tools/Take Screenshot/Native Resolution (Transparent Background)")] private static void CaptureScreenshot1xAlphaComposite() { CaptureScreenshot(GetScreenshotPath(), 1, true); EditorUtility.RevealInFinder(GetScreenshotDirectory()); } [Shortcut("Graphics Tools/Take Screenshot 2x", KeyCode.Alpha2, ShortcutModifiers.Alt)] [MenuItem("Window/Graphics Tools/Take Screenshot/2x Resolution")] private static void CaptureScreenshot2x() { CaptureScreenshot(GetScreenshotPath(), 2); EditorUtility.RevealInFinder(GetScreenshotDirectory()); } [Shortcut("Graphics Tools/Take Screenshot 2x Alpha", KeyCode.Alpha2, ShortcutModifiers.Shift)] [MenuItem("Window/Graphics Tools/Take Screenshot/2x Resolution (Transparent Background)")] private static void CaptureScreenshot2xAlphaComposite() { CaptureScreenshot(GetScreenshotPath(), 2, true); EditorUtility.RevealInFinder(GetScreenshotDirectory()); } [Shortcut("Graphics Tools/Take Screenshot 4x", KeyCode.Alpha4, ShortcutModifiers.Alt)] [MenuItem("Window/Graphics Tools/Take Screenshot/4x Resolution")] private static void CaptureScreenshot4x() { CaptureScreenshot(GetScreenshotPath(), 4); EditorUtility.RevealInFinder(GetScreenshotDirectory()); } [Shortcut("Graphics Tools/Take Screenshot 4x Alpha", KeyCode.Alpha4, ShortcutModifiers.Shift)] [MenuItem("Window/Graphics Tools/Take Screenshot/4x Resolution (Transparent Background)")] private static void CaptureScreenshot4xAlphaComposite() { CaptureScreenshot(GetScreenshotPath(), 4, true); EditorUtility.RevealInFinder(GetScreenshotDirectory()); } /// /// Captures a screenshot with the current main camera's clear color. /// /// The path to save the screenshot to. /// The multiplication factor to apply to the native resolution. /// True if the captured screenshot should have a transparent clear color. Which can be used for screenshot overlays. /// The optional camera to take the screenshot from. /// True on successful screenshot capture, false otherwise. public static bool CaptureScreenshot(string path, int superSize = 1, bool transparentClearColor = false, Camera camera = null) { if (string.IsNullOrEmpty(path) || superSize <= 0) { return false; } // Make sure we have a valid camera to render from. if (camera == null) { camera = Camera.main; if (camera == null) { #if UNITY_2023_1_OR_NEWER camera = GameObject.FindFirstObjectByType(); #else camera = GameObject.FindObjectOfType(); #endif if (camera == null) { Debug.LogError("Failed to find a any cameras to capture a screenshot from."); return false; } else { Debug.LogWarning($"Capturing screenshot from a camera named \"{camera.name}\" because there is no camera tagged \"MainCamera\"."); } } } // Create a camera clone. var renderCamera = new GameObject().AddComponent(); renderCamera.CopyFrom(camera); renderCamera.orthographic = camera.orthographic; renderCamera.transform.position = camera.transform.position; renderCamera.transform.rotation = camera.transform.rotation; renderCamera.clearFlags = transparentClearColor ? CameraClearFlags.Color : camera.clearFlags; renderCamera.backgroundColor = transparentClearColor ? new Color(0.0f, 0.0f, 0.0f, 0.0f) : new Color(camera.backgroundColor.r, camera.backgroundColor.g, camera.backgroundColor.b, 1.0f); // Create a render texture for the camera clone to render into. var width = Screen.width * superSize; var height = Screen.height * superSize; var renderTexture = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32); renderTexture.antiAliasing = 8; renderCamera.targetTexture = renderTexture; // Render from the camera clone. renderCamera.Render(); // Copy the render from the camera and save it to disk. var outputTexture = new Texture2D(width, height, TextureFormat.ARGB32, false); RenderTexture previousRenderTexture = RenderTexture.active; RenderTexture.active = renderTexture; outputTexture.ReadPixels(new Rect(0.0f, 0.0f, width, height), 0, 0); outputTexture.Apply(); RenderTexture.active = previousRenderTexture; try { File.WriteAllBytes(path, outputTexture.EncodeToPNG()); } catch (Exception e) { Debug.LogException(e); return false; } finally { UnityEngine.Object.DestroyImmediate(outputTexture); UnityEngine.Object.DestroyImmediate(renderCamera.gameObject); UnityEngine.Object.DestroyImmediate(renderTexture); } Debug.LogFormat("Screenshot captured to: {0}", path); return true; } /// /// Gets a directory which is safe for saving screenshots. /// /// A directory safe for saving screenshots. public static string GetScreenshotDirectory() { return Application.temporaryCachePath; } /// /// Gets a unique screenshot path with a file name based on date and time. /// /// A unique screenshot path. public static string GetScreenshotPath() { return Path.Combine(GetScreenshotDirectory(), string.Format("Screenshot_{0:yyyy-MM-dd_hh-mm-ss-tt}_{1}.png", DateTime.Now, GUID.Generate())); } } }