Version: 2023.1
言語: 日本語
アセットデータベースの更新
AssetDatabase によるバッチ処理

アセットデータベースワークフローのカスタマイズ

AssetDatabase クラスを使用して、独自のスクリプトでアセットパイプラインをカスタマイズし、アセットにアクセス、ロード、作成、操作するツールを作成し、エディターの動作方法を拡張できます。このクラスは Editor クラスです。そのため、スタンドアロンビルドではランタイムにその機能を利用できません。

アセットワークフローのカスタマイズ

AssetDatabase クラスには多数のメソッドがあります。それらは、Unity エディターが行うのと全く同じようにアセットにアクセスして操作を行うことができます。アセットの作成、インポート、削除、コピー、移動、ロード、保存や、アセットデータベースの検索が可能です。

つまり、Unity の Editor スクリプト と、エディターウィンドウのカスタマイズ を使用して、簡単な調整から強力なツールやプロジェクトのアセットワークフローのカスタマイズまで、あらゆるものを作成できます。

簡単な例として、AssetDatabase.ForceReserializeAssets メソッドのドキュメントを参照してください。これは、Unity の新しいバージョンにプロジェクトをアップグレードするときに、特定のアセットバンドルをアップグレードする方法をより良くコントロールできるように、エディターにメニュー項目を追加する方法を示しています。

利用可能なメソッドの全リストと各メソッドのドキュメントは、AssetDatabase のスクリプティング API ページを参照してください。

アセットオブジェクト

スクリプティングの観点から考えると、Unity が “アセット” とみなすものは、Project ウィンドウに表示されるものとは少し異なります。プロジェクトの Assets フォルダーに置くファイルはアセットのソースファイルですが、Unity エディターが扱うアセットオブジェクトとは概念的に異なります。Unity がアセットファイルをインポートすると、それを処理してインポート結果を生成します。Unity はアセットファイルをインポートすると、それを処理し、インポートの結果 - つまり、UnityEngine.Object から派生したシリアル化された C# オブジェクト - を生成します。スクリプトの観点から見ると、Unity エディターでスクリプトを書くときにアクセスするアセットは、このインポートの成果物です。

例えば、JPEG や PNG の画像ファイルのようなバイナリファイルから始まるアセットは、UnityEngine.Object を特殊化した C# オブジェクトに変換されます。JPEG や PNG ファイルの場合、これらは Texture クラスのシリアル化されたインスタンスに変換され、UnityEngine.Object から継承されます。シリアル化されたオブジェクトデータは、Library フォルダーにアーティファクトとして保存されます。つまり、スクリプトで Texture アセットにアクセスするときは、元の JPEG や PNG ファイルにアクセスしているのではなく、元の画像ファイルをインポートしたときに生成された C# Texture オブジェクトのシリアル化されたバージョンにアクセスしています。インポート処理中に Unity が作成する .meta ファイル は、元のアセットファイルの隣に保存され、アセットのインポート設定と、Unity がアセットデータベースのアーティファクトを含む元のアセットファイルと接続するための GUID を含んでいます。

アセットをインポートすると、Unity は Assets フォルダーに .meta ファイルを作成し、Library フォルダーにアーティファクトファイルを作成します。
アセットをインポートすると、Unity は Assets フォルダーに .meta ファイルを作成し、Library フォルダーにアーティファクトファイルを作成します。

アセットファイルとアーティファクトファイルの内部

.prefab.scene.asset.mat など、Unity 自身が作成するアセットファイルの種類によっては、そのソースファイルにすでにシリアル化されたデータが含まれています。そのため、Unity が生成してキャッシュするアーティファクトファイルはソースファイルと非常によく似ています。これらのソースファイル、例えばプロジェクトの Assets フォルダーにある .mat マテリアルファイルは、人間が読むことができます (ただし Asset Serialization Mode がデフォルト設定の Force Text に設定されている場合)。これは、通常は人間がファイルを読むことができない、テクスチャやオーディオなどの外部ソースからインポートされたバイナリアセットファイルとは対照的です。

アセットファイルは複数のシリアル化されたオブジェクトを含むことができ、AssetDatabase メソッドでスクリプトを作成する際には、これらのオブジェクトをそれぞれ “アセット” とみなすことができます。例えば、.prefab アセットファイルは、複数のコンポーネントがアタッチされたシリアル化されたゲームオブジェクトを含むことができます。これらの各コンポーネントもアセットファイル内のオブジェクトとしてシリアル化されているため、AssetDatabase メソッドを使用してプレハブアセットのコンテンツにアクセスする場合、アセットファイル内のコンポーネントオブジェクトは サブアセット とみなされます (以下で詳しく説明します)。

インポート処理中に生成されたシリアル化されたオブジェクトは アーティファクト 呼ばれ、Unity はプロジェクトの Library フォルダーにあるインポートされたアーティファクトの Asset Database のキャッシュに保存します。Unity は、プロジェクトに保存されているインポーターの設定とプロジェクトの設定を使用して、ソースアセットからそれらをいつでも再生成できるため、それらはキャッシュデータとして扱われます。

Import Activity ウィンドウ を使用すると、プロジェクト内のアセットに対して生成されたアーティファクトを確認できます。このウィンドウでは、Unity が生成した特定のキャッシュされたアーティファクトファイルのほか、インポートがいつ行われたか、どれくらいの時間がかかったかなどの有用な情報が表示されます。

各アーティファクトファイル名は一意のハッシュ(GUID) で、ファイル拡張子はありません。Unity はこれらのファイルをサブフォルダーに分け、各サブフォルダーにはアーティファクトファイル名の最初の 2 文字に一致する名前を与えます。

これらのアーティファクトファイルにはバイナリデータが含まれており、人間が読めるようには設計されていません。これらのファイルにはアセットデータベースで使用されるデータが含まれていることを理解しておくと便利ですが、Unity での作業中にこれらのファイルを直接表示、編集、使用する必要はありません。代わりに、AssetDatabase クラスはエディター内でアセットを扱うために必要なメソッドを提供します。

主なアセットとサブアセット

Unity は同じアセットファイル内に複数のシリアル化されたオブジェクトを格納できるため、Unity にはすべてのアセットファイル内で メインアセット という概念があります。Unity がマテリアルなどの単一のアセットを含むアセットファイルを作成する場合、メインアセットは常にその単一のアセットです。複数のシリアル化されたアセットオブジェクトを含む他のタイプの場合、SetMainObject メソッドで特に指定しない限り、常に、メインアセットはファイルに加えられた最初のアセットになります。

エディターの Project ウィンドウで、サブアセットが特定のタイプである場合、表示されることがあります。例えば、“Space Frigate ”モデルを含むこの FBX アセットファイルを Project ウィンドウで展開すると、サブアセットとしてマテリアルとメッシュを持っていることがわかります。

プロジェクトウィンドウに表示された FBX アセットファイル。2 つのサブアセット、マテリアルとメッシュが表示されています
プロジェクトウィンドウに表示された FBX アセットファイル。2 つのサブアセット、マテリアルとメッシュが表示されています

アセットには、このように Project ウインドウに表示されないサブアセットタイプもあります。例えば、上記の “Space Frigate” アセットファイルには、Project ウィンドウに表示されている 2 つ以上のサブアセットが実際に含まれています。以下のスクリプトのように、AssetDatabase メソッドを使用してアセットファイルにアクセスすると、実際のアセット数を確認できます。

using UnityEngine;
using UnityEditor;

public class Example : MonoBehaviour
{
    [MenuItem("AssetDatabase/InspectAssets")]

    private static void InspectAssets()
    {
        Object[] data = AssetDatabase.LoadAllAssetsAtPath("Assets/Space Frigate.fbx");

        Debug.Log(data.Length + " Assets");
        foreach (Object o in data)
        {
            Debug.Log(o);
        }
    }
}

この場合、インポートされたシリアル化されたファイルには 6 つのアセットが含まれていることが出力されます。

6 Assets
Space Frigate (UnityEngine.GameObject)
space_frigate_0 (UnityEngine.Material)
space_frigate_0 (UnityEngine.Mesh)
Space Frigate (UnityEngine.Transform)
Space Frigate (UnityEngine.MeshRenderer)
Space Frigate (UnityEngine.MeshFilter)

これは、ゲームオブジェクト、マテリアル、メッシュデータそのもの、そして Unity がインポート処理中にゲームオブジェクトに自動的に加えた各コンポーネント (Transform、MeshFilter、MeshRenderer) が、それぞれ別のシリアル化されたオブジェクトとされるためです。したがって、これらはアセットファイルのサブアセットであり、Asset Database API を考える限り、それぞれ別のアセットです。

アセットインポートの順序

AssetDatabase クラスを使用してスクリプトを作成する場合、Unity のインポート処理の順序がスクリプトにどのような影響を与えるかを理解することが重要です。さもないと、予期しない結果になることがあります。順番は以下の通りです。

  1. スクリプトアセット (.cs、.dll、.asmdef ファイル) のインポート
  2. コンパイル
  3. ドメインの再ロード
  4. InitializeOnLoad コールバック
  5. 他のすべてのアセットのインポート

エディターは、プロジェクトにカスタムの アセットのポストプロセッサースクリプトインポーター があるかどうかを知る必要があるため、スクリプトは常に、他のすべての通常のアセットより先にインポートされ、コンパイルされます。これにより、エディターは、スクリプト以外の残りのアセットをインポートするときに、新規または変更されたインポータやポストプロセッサーを使用します。

InitializeOnLoad コールバックは、プロジェクトの起動時やスクリプトの変更時にコードを実行するためによく使用されます。上のリストにあるように、このコールバックは Unity がドメインを再ロードした後、アセットのインポートを開始する前に実行されます。つまり、InitializeOnLoad コールバックを使用してアセットにアクセスする場合、現在のアセットインポートサイクルが完了する 前に コードが実行されます。

  • アセットが初めてインポートされる場合、AssetDatabase.LoadAssetAtPath、AssetDatabase.FindAssets、Shader.Find、Resources.Load などのメソッドは、これらのアセットがまだインポートされていないため、NULL を返します。

  • 少なくとも一度インポート済みのアセットについては、AssetDatabase.LoadAssetAtPath、AssetDatabase.FindAssets、Shader.Find、Resources.Load などのメソッドは、ドメインの再ロード前に変更された場合は以前の (古い) バージョンのアセットを返します。これは、ドメインの再ロードが通常のアセットインポートフェーズの前に発生するためです。

スクリプトインポーター、アセットプリプロセッサー、アセットポストプロセッサーを記述する場合、他の特定のアセットが特定の順序に従って既にインポートされていることを前提にコードを記述すべきではありません。インポートするとき、Unity はアセットをタイプ別にキューにグループ化し、タイプは事前に定義された順序でインポートされますが、ScriptedImporter.GatherDependenciesFromSourceFile を使用しない限り、同じタイプのキュー内のアセットは任意の順序でインポートされます。GatherDependenciesFromSourceFile を使用すると、アセット間の依存関係も作成されます。そのため、一方のアセットが変更されると、それに依存するもう一方のアセットが再インポートされます。

アセットデータベースの更新
AssetDatabase によるバッチ処理