MRが楽しい

MRやVRについて学習したことを書き残す

Unityアプリで画面のキャプチャを保存する

本日は Unity の小ネタ枠です。
Unityアプリで画面のキャプチャを保存する方法について記事にします。

UnityEngine.ScreenCapture.CaptureScreenshot

ScreenCapture.CaptureScreenshot を利用すると PNG ファイルとしてスクリーンショットが撮影・保存されます。
docs.unity3d.com

こちらはアプリの現在の映像がそのまま撮影されて保存されます。
以下のサンプルスクリプトを作成しました。ボタンを押下したとき、本スクリプトが実行されてキャプチャが行われます。
・ScreenshotTest.cs

using System;
using System.IO;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;

public class ScreenshotTest : MonoBehaviour
{
    private Camera captureCamera;

    /// <summary>
    /// キャプチャの実行関数
    /// </summary>
    public void Capture()
    {
        CaptureScreenshotByUnityEngine();
    }
    
    private void Start()
    {
        captureCamera = Camera.main;
    }

    private void CaptureScreenshotByUnityEngine()
    {
        var date = DateTime.Now.ToString("yyyyMMdd");
        string filename = $"screenCapture_{date}.png";
        string path = Path.Combine(Application.persistentDataPath,filename);

        // スクリーンショットを撮影して保存する
        Debug.Log($"ScreenCapture File : {path}");
        File.Delete(path);
        ScreenCapture.CaptureScreenshot(path);

    }
}

撮影された画像は以下のようになります。

RenderTexture

RenderTexture を使って指定のカメラの描画領域を画像として保存することもできます。
docs.unity3d.com

こちらは通常のレンダーパイプラインを通して描画された映像を保存するため、オーバレイのUIは画像に保存されません。
(ワールドスペースのUIなどは通常のレンダーパイプラインを通るため描画されます)

以下のサンプルスクリプトを作成しました。ボタンを押下したとき、本スクリプトが実行されてキャプチャが行われます。
・ScreenshotTest.cs

using System;
using System.IO;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;

public class ScreenshotTest : MonoBehaviour
{
    private Camera captureCamera;

    /// <summary>
    /// キャプチャの実行関数
    /// </summary>
    public void Capture()
    {
        CaptureScreenshotByRenderTexture();
    }
    
    private void Start()
    {
        captureCamera = Camera.main;
    }

    private void CaptureScreenshotByRenderTexture()
    {
        var ct = this.GetCancellationTokenOnDestroy();
        CaptureScreenshotByRenderTextureAsync(ct).Forget();
    }

    private async UniTask CaptureScreenshotByRenderTextureAsync(CancellationToken ct)
    {
        // 任意のフレームの描画処理が終わるまで待機する
        await UniTask.WaitForEndOfFrame(ct);

        // Cameraの描画領域をRenderTextureとして取り出す
        var rt = new RenderTexture(captureCamera.pixelWidth, captureCamera.pixelHeight, 24);
        var prev = captureCamera.targetTexture;
        captureCamera.targetTexture = rt;
        captureCamera.Render();
        captureCamera.targetTexture = prev;
        RenderTexture.active = rt;

        var screenShot = new Texture2D(
            captureCamera.pixelWidth,
            captureCamera.pixelHeight,
            TextureFormat.RGB24,
            false);
        screenShot.ReadPixels(new Rect(0, 0, screenShot.width, screenShot.height), 0, 0);
        screenShot.Apply();

        // 取り出したTexture2DをPNGに変換して保存する
        var date = DateTime.Now.ToString("yyyyMMdd");
        string filename = $"capture_{date}.png";
        var png = screenShot.EncodeToPNG();
        string path = Path.Combine(Application.persistentDataPath,filename);
        File.WriteAllBytes(path, png);

        Debug.Log($"Capture File : {path}");
    }
}

撮影された画像は以下のようになります。
UI のボタンが含まれていないことが分かります。