げぇむぷろぐらみんぐ

日々の生活で得た知識、経験を書きます

【Unity】ディレクトリごとにアセットのインポート設定を変える

はじめに

アセットをインポートするとき、AssetPostprocessorを用いることでインポート設定を変更したり加工したりできます。 例えば、OnPreprocessTextureだとテクスチャのインポート時にこのメソッドが呼ばれ、処理を行うことができます。 しかし、このままだとインポートした全テクスチャに対して同じ処理が適用されてしまうことになるので、今回はインポートしたディレクトリごとに設定を変える実装をしてみました。 Postprocessor系の勉強で実装したので、実用性があるかはわかりません。

方針

ディレクトリごとに設定を変えるために、ScriptableObjectを用います。 ScriptableObjectは、様々なパラメータをアセットデータとして保持しておくことができるものです。

これをTextureならテクスチャ用の設定パラメータを含んだもの、Audioならオーディオ用の設定パラメータを含んだものとして作成します。

あとは、アセットがインポートされたときにそのアセットの種類に応じた設定用ScriptableObjectがフォルダ内にあるかを確かめて、あればその設定を適用してやるという方針で良さそうです。

実装(コード)

まず、全アセットタイプの共通の処理を行う部分です。

using System;
using UnityEngine;
using UnityEditor;
using System.IO;

public class CommonProcessor<T> where T : ScriptableObject {

    public void Process(string assetPath, Action<T> onSetup) {
        string dirPath = Path.GetDirectoryName(assetPath);

        T setting = FindSetting(dirPath);

        if (setting == null) {
            Debug.LogWarning($"{typeof(T)} not found at {dirPath}");
            return;
        }

        onSetup?.Invoke(setting);
    }

    private T FindSetting(string dirPath) {
        string[] assetFilePaths = Directory.GetFiles(dirPath, "*.asset");

        foreach (var assetPath in assetFilePaths) {
            T setting = AssetDatabase.LoadAssetAtPath<T>(assetPath);
            if (setting != null) {
                return setting;
            }
        }

        return null;
    }
}

アセットがインポートされたとき、ディレクトリ内のScriptableObjectを探索して、あったら設定ファイルとしてロードしています。

ロードした設定ファイルを使った処理は、コールバックで与えます。余談ですが、C# 6.0から使えるNull条件演算子がいい感じです。Unityだと、nullの扱いが特殊なのでこういったActionとかにしか使えませんが…

次に、例としてTextureに関しての設定を行っている部分です。

using UnityEngine;
using UnityEditor;
using Scriptable;

namespace Processor {
    public class TextureProcessor : AssetPostprocessor {

        private void OnPreprocessTexture() {
            CommonProcessor<TextureSetting> commonProcessor = new CommonProcessor<TextureSetting>();
            commonProcessor.Process(assetPath, OnSetup);
        }

        private void OnSetup(TextureSetting setting) {
            TextureImporter textureImporter = assetImporter as TextureImporter;
            textureImporter.textureType = setting.importerType;
            textureImporter.spriteImportMode = setting.importMode;
            textureImporter.filterMode = setting.filterMode;
            textureImporter.wrapMode = setting.wrapMode;
            textureImporter.spritePixelsPerUnit = setting.pixelPerUnits;
        }
    }
}

こちらでは、先程作成したCommonProcessorを利用して、処理を行います。 やることは、読み込まれた設定ファイルの値をどう入れるかだけです。

最後に、参考までにTextureのパラメータの設定も載せておきます。

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

namespace Scriptable {
    public class TextureSetting : ScriptableObject {

        [Header("テクスチャのインポートタイプ")]
        public TextureImporterType importerType;

        [Header("スプライトのインポートモード")]
        public SpriteImportMode importMode;

        [Header("テクスチャのピクセル補完方法")]
        public FilterMode filterMode;

        [Header("テクスチャの範囲外の設定")]
        public TextureWrapMode wrapMode;

        [Header("1mを何ピクセルとするかの設定")]
        public int pixelPerUnits;
    }
}

テクスチャをあるフォルダにロードしたときに、同じディレクトリ内にこの設定ファイルがあるかを見て処理をします。

まとめ

テクスチャとかは設定が複雑なので実際に使う場合は、パラメータ増えてまくって大変そう… あと、Unity2018からはPresetを使えばよさそう…?