D日記

モーションアーティストの技術ブログだよ。日常も書くよ。

MENU

【Unity.Editor】UnitySceneSequenceCapture【超シンプル】

経緯

Unity上のエフェクト素材を他ツールでも活用したかったので作成。
Unityエディター上のSceneビューを定期的にPNG画像としてキャプチャします!背景の透過にも対応!

使い方

  • 「Tools > Scene View Capture」からウィンドウを開きます。
  • 保存先、FPS、透過設定を調整して「キャプチャ開始」ボタンを押す。
  • もう一度ボタンを押すとキャプチャ停止。
  • 対応バージョン: Unity6 以降

コード

下記をSceneViewCapture.csで保存し、Editorフォルダに配置!

using UnityEngine;
using UnityEditor;
using System.IO;

public class SceneViewCapture : EditorWindow
{
    private bool capturing = false;
    private string saveDirectory = "D:\\Downloads\\aaaa";
    private int captureCount = 0;
    private double lastCaptureTime = 0;
    private double captureInterval = 0.5;
    private int fps = 30;
    private bool transparentBackground = false;
    private Camera tempCamera;

    [MenuItem("Tools/Scene View Capture")]
    public static void ShowWindow()
    {
        GetWindow<SceneViewCapture>("Scene View Capture");
    }

    private void OnEnable()
    {
        EditorApplication.update += OnEditorUpdate;
    }

    private void OnDisable()
    {
        EditorApplication.update -= OnEditorUpdate;
        CleanupTempCamera();
    }

    private void OnGUI()
    {
        GUILayout.Label("保存先:", EditorStyles.boldLabel);
        saveDirectory = EditorGUILayout.TextField(saveDirectory);

        GUILayout.Space(5);

        GUILayout.Label("FPS:", EditorStyles.boldLabel);
        fps = EditorGUILayout.IntField(fps);
        if (fps < 1) fps = 1;
        captureInterval = 1.0 / fps;

        GUILayout.Space(5);

        transparentBackground = EditorGUILayout.Toggle("背景を透過にする", transparentBackground);

        GUILayout.Space(10);

        if (!capturing)
        {
            if (GUILayout.Button("キャプチャ開始"))
            {
                captureCount = 0;
                capturing = true;
                lastCaptureTime = EditorApplication.timeSinceStartup;
                SetupTempCamera();
                Debug.Log("キャプチャ開始");
            }
        }
        else
        {
            if (GUILayout.Button("キャプチャ停止"))
            {
                capturing = false;
                CleanupTempCamera();
                Debug.Log("キャプチャ停止");
            }
        }
    }

    private void OnEditorUpdate()
    {
        if (!capturing) return;

        double currentTime = EditorApplication.timeSinceStartup;
        if (currentTime - lastCaptureTime >= captureInterval)
        {
            lastCaptureTime = currentTime;
            CaptureSceneView();
        }
    }

    private void SetupTempCamera()
    {
        var sceneView = SceneView.lastActiveSceneView;
        if (sceneView == null || sceneView.camera == null) return;

        GameObject camObj = new GameObject("TempSceneCaptureCamera");
        tempCamera = camObj.AddComponent<Camera>();
        tempCamera.CopyFrom(sceneView.camera);
        tempCamera.cullingMask = -1;

        tempCamera.clearFlags = CameraClearFlags.SolidColor;
        tempCamera.backgroundColor = Color.black;
        tempCamera.enabled = false;
    }

    private void CleanupTempCamera()
    {
        if (tempCamera != null)
        {
            DestroyImmediate(tempCamera.gameObject);
            tempCamera = null;
        }
    }

    private void CaptureSceneView()
    {
        if (tempCamera == null) return;

        int width = (int)SceneView.lastActiveSceneView.position.width;
        int height = (int)SceneView.lastActiveSceneView.position.height;

        RenderTexture rt = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32);
        Texture2D texture = new Texture2D(width, height, TextureFormat.ARGB32, false);

        RenderTexture currentRT = RenderTexture.active;
        RenderTexture.active = rt;
        var originalRT = tempCamera.targetTexture;
        tempCamera.targetTexture = rt;

        Color originalBackground = tempCamera.backgroundColor;
        CameraClearFlags originalClearFlags = tempCamera.clearFlags;

        tempCamera.backgroundColor = Color.black;
        tempCamera.clearFlags = CameraClearFlags.SolidColor;
        tempCamera.Render();
        texture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
        Color32[] blackPixels = texture.GetPixels32();

        tempCamera.backgroundColor = Color.white;
        tempCamera.Render();
        texture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
        Color32[] whitePixels = texture.GetPixels32();

        for (int i = 0; i < blackPixels.Length; i++)
        {
            byte alpha = (byte)(255 - (whitePixels[i].r - blackPixels[i].r));
            blackPixels[i].a = alpha;
        }

        texture.SetPixels32(blackPixels);
        texture.Apply();

        tempCamera.targetTexture = originalRT;
        tempCamera.backgroundColor = originalBackground;
        tempCamera.clearFlags = originalClearFlags;

        RenderTexture.active = currentRT;
        DestroyImmediate(rt);

        if (!Directory.Exists(saveDirectory))
        {
            Directory.CreateDirectory(saveDirectory);
        }

        string filename = string.Format("SceneCapture_{0:D4}.png", captureCount);
        string path = Path.Combine(saveDirectory, filename);
        byte[] bytes = texture.EncodeToPNG();
        File.WriteAllBytes(path, bytes);
        Debug.Log("保存しました: " + path);
        captureCount++;

        AssetDatabase.Refresh();
    }
}


既出バグ

未発見(募集中!