Cooooding!!

Unity(C#)を使ったゲーム開発関連Tipsなど

CameraFilterPack用のデモシーンを作る【Unity】

概要

少し前にCamera Filter Packという300種類以上のカメラエフェクトを集めたAssetを買いました。使い方はシンプルでカメラにスクリプトをAdd Componentしてパラメーターを設定するだけです。簡単なのですがこのAssetにはデモシーンが含まれておらず一つ一つ表示を確認するのがめんどうだったのでデモシーンを作ってみました。

デモシーン用スクリプト

フィルターをかけたいシーンが既にある場合は以下のスクリプトを適当なGameObjectにAdd Componentするだけです。シーンをまるごと作る話は後述します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraFilterPackDemo : MonoBehaviour
{
    [SerializeField]
    private Camera m_Camera;    // nullならMainCameraが使われる
    [SerializeField]
    private Camera m_SecondCamera;  // Blend2Camera系フィルター用の2つ目のカメラ
    [SerializeField]
    private int m_FontSize = 40;
    [SerializeField]
    private Color m_FontColor = Color.red;
    [SerializeField]
    private KeyCode m_NextKey = KeyCode.L;
    [SerializeField]
    private KeyCode m_PrevKey = KeyCode.K;

    private string m_NamePrefix = "CameraFilterPack_";

    private int m_CurrentIndex;

    private System.Type[] m_ComponentTypes;

    private Component m_LastComponent;

    protected new Camera camera
    {
        get
        {
            if(m_Camera == null)
            {
                return Camera.main;
            }
            return m_Camera;
        }
    }

#if UNITY_EDITOR
    [UnityEditor.CustomEditor(typeof(CameraFilterPackDemo))]
    private class Editor : UnityEditor.Editor
    {
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            var self = target as CameraFilterPackDemo;

            // 再生中のみフィルターのリストをInspectorに表示する
            if (UnityEditor.EditorApplication.isPlaying)
            {
                m_Foldout = UnityEditor.EditorGUILayout.Foldout(
                    m_Foldout, "Filter Name List"
                );
                if (m_Foldout)
                {
                    ++UnityEditor.EditorGUI.indentLevel;
                    foreach (var type in self.m_ComponentTypes)
                    {
                        // Prefixを除いた名前を使う
                        var name = type.Name.Substring(self.m_NamePrefix.Length);
                        // 選択中のフィルター名には目印を付ける
                        if (type == self.m_ComponentTypes[self.m_CurrentIndex])
                        {
                            name = "→ " + name;
                        }
                        UnityEditor.EditorGUILayout.LabelField(name);
                    }
                    --UnityEditor.EditorGUI.indentLevel;
                }
            }
        }

        private bool m_Foldout;
    }
#endif

    protected void Start()
    {
        m_ComponentTypes = GetFilterComponentTypes();
        UpdateComponentType();
    }

    protected void Update()
    {
        // 前にフィルターに切り替える
        if(Input.GetKeyDown(m_PrevKey))
        {
            m_CurrentIndex = Mathf.Max(m_CurrentIndex - 1, 0);
            UpdateComponentType();
        }
        // 次のフィルターに切り替える
        else if(Input.GetKeyDown(m_NextKey))
        {
            m_CurrentIndex = Mathf.Min(m_CurrentIndex + 1, m_ComponentTypes.Length-1);
            UpdateComponentType();
        }
    }

    protected void UpdateComponentType()
    {
        // 最後に使ったフィルターを削除する
        if(m_LastComponent != null)
        {
            DestroyImmediate(m_LastComponent);
        }
        // 次に使うフィルターをカメラに付ける
        var type = m_ComponentTypes[m_CurrentIndex];
        m_LastComponent = camera.gameObject.AddComponent(type);
        // Blend2Camera系のフィルターであれば2つ目のカメラを設定する
        var camera2Field = m_LastComponent.GetType().GetField("Camera2");
        if(camera2Field != null)
        {
            camera2Field.SetValue(m_LastComponent, m_SecondCamera);
        }
    }

    protected void OnGUI()
    {
        // 現在のフィルター名を表示する
        GUI.skin.label.fontSize = m_FontSize;
        GUI.color = m_FontColor;
        var type = m_ComponentTypes[m_CurrentIndex];
        GUILayout.Label(type.Name.Substring(m_NamePrefix.Length));
    }

    public System.Type[] GetFilterComponentTypes()
    {
        // フィルターをリストアップする
        var baseType = typeof(MonoBehaviour);
        var result = new List<System.Type>();
        foreach (var assembly in System.AppDomain.CurrentDomain.GetAssemblies())
        {
            foreach(var type in assembly.GetTypes())
            {
                if(
                    baseType.IsAssignableFrom(type) &&
                    type.Name.StartsWith(m_NamePrefix)
                )
                {
                    result.Add(type);
                }
            }
        }
        return result.ToArray();
    }
}

画面左上に現在のフィルター名が表示されます。Lキーを押すと次のフィルターに変わり、Kキーを押すと前のフィルターに変わります。各フィルターのパラメーターはMainCameraのInspectorから変更して下さい。
f:id:nyama41:20190526141312p:plain

デモ用スクリプトのInspectorからキー設定や左上の文字サイズや色などを変更することができます。またSecond Cameraに2つ目のカメラを設定するとBlend2Camera系のフィルターで二つ目のカメラを自動的に設定してくれます。

このデモ用スクリプトは"CameraFilterPack_"で始まる名前のコンポーネントをCamera Filter Packのフィルターとして認識します。そのため、今後Camera Filter Packがバージョンアップしても同じ命名規則ならば追加されたスクリプトも表示確認することができます。逆に、命名規則が異なるフィルターが追加されたり、全く無関係のスクリプトが同じ命名規則になっていると正しく動作しない可能性があります。

デモシーンを作る

CameraFilterPackには3D用のエフェクトも含まれているので3D地形上でUnityちゃんが動き回れるシーンを作ります。

  1. Medieval Town Exteriors という無料のAssetをインポートする
  2. このAssetにDemoシーンが含まれているので開く(このシーンをベースに改造する)
  3. Unityちゃん(Unity-Chan)をノンプログラミングで動かす!』を参考にUnityちゃんを動かせるようにする
    1. Unityちゃんをインポート
    2. Unityちゃんを地形の家付近に配置
    3. Unityちゃん以下にカメラを配置してUnityちゃんに追従させる
  4. 適当なGameObjectにCameraFilterPackDemo(上記スクリプト)を付ける
  5. Blend2Camera系のフィルターの表示確認もしたいならもう一つカメラを配置してデモ用スクリプトにセットする(2つ目のカメラにはMainCameraタグを付けないこと)

完成品を撮影した動画がこちら(圧縮した時点で画質が結構劣化しています)。Unityちゃんを操作しながらでも簡単にフィルターを切り替えられています。

上記動画では各フィルターのパラメーターが未調整であることにご注意下さい。各フィルターについての詳細はこちらに書かれています。

環境

  • Unity 2018.4.01f
  • Camera Filter Pack 4.0.0