こんにちは、株式会社Leon Gameworksの遠藤です。

今回は、アセットのインポート時に任意の設定を自動適用するEditor Utility Blueprint(EUB)を作成します。テクスチャのインポート時にsRGBの設定を自動的に変更する処理を例に、実装方法を解説します。

記事の目次

    0:動作環境

    本記事はUE5.8.3を基に執筆しており、画面のスクリーンショットはエディタの言語設定を「英語」として撮影しています。

    なお、本記事で作成するプロジェクト一式は、以下よりダウンロード可能です。

    今回のプロジェクトデータ

    1:インポート時のイベントを受け取る

    まずは、EditorUtilityObjectを親クラスとするEditor Utility Blueprint(EUB)を作成します。

    ▲EUBの作成

    作成したEUBを開き、[Run]イベントをオーバーライドします。続いて、[Import Subsystem]の[OnAssetPostImport]イベントにカスタムイベントをバインドします。これにより、アセットのインポート完了時に処理を実行できるようになります。


    ▲OnAssetPostImportのバインド

    2:設定の自動適用

    OnAssetPostImportイベントの引数[In Created Object]には、インポートによって生成されたアセットが渡されます。今回はテクスチャを対象とするため、Texture2Dにキャストします。

    ▲Texture2Dでキャスト

    続いて、[Set Editor Property]ノードを使用して、アセットのプロパティを変更します。今回は、テクスチャの[sRGB]を[false]に設定します。

    ▲[Set Editor Property]ノードで値の変更

    これで、インポート時に設定を自動適用する処理が完成しました。最後に、[Class Defaults]の[Run on Start-up]にチェックを入れます。これにより、エディタ起動時にEUBが自動実行されるようになります。ツールの挙動を確認するには、一度エディタを再起動しましょう。


    ▲[Run on Start-up]

    3:Unreal Python

    ここまではEUBを使った実装方法を紹介しましたが、同様の処理はUnreal Pythonでも実現できます。ここでは、インポートしたテクスチャの名前や保存先に応じて設定を自動変更するPythonスクリプトを紹介します。


    """インポート通知に応じて、Texture2Dへ制作ルールを適用する。"""
    
    import traceback
    import unreal
    
    
    ROOT_PATH = "/Game/EUTools24/Textures/"
    UI_PATH = ROOT_PATH + "UI/"
    
    # importlib.reload()でも、登録済みの関数への参照を保持する。
    if "_STATE" not in globals():
        _STATE = {"subsystem": None, "callback": None}
    
    
    def apply_texture_rules(texture):
        """対象に設定を適用する。変更した場合はTrueを返す。"""
        if not isinstance(texture, unreal.Texture2D):
            return False
    
        asset_path = texture.get_path_name()
        if not asset_path.startswith(ROOT_PATH):
            return False
    
        settings = []
    
        # ルール1:末尾が_ORMなら、マスク用の設定を適用する。
        if texture.get_name().upper().endswith("_ORM"):
            settings.extend([
                ("compression_settings", unreal.TextureCompressionSettings.TC_MASKS),
                ("srgb", False),
            ])
    
        # ルール2:UIフォルダ内なら、Texture GroupをUIにする。
        # elifにはせず、両方に一致した場合は両方の設定を適用する。
        if asset_path.startswith(UI_PATH):
            settings.append(("lod_group", unreal.TextureGroup.TEXTUREGROUP_UI))
    
        if not settings:
            return False
    
        changed = []
        for property_name, target_value in settings:
            # 圧縮設定の変更後に、sRGBの現在値を取得する順序になる。
            current_value = texture.get_editor_property(property_name)
            if current_value != target_value:
                texture.set_editor_property(property_name, target_value)
                changed.append(property_name)
    
        if changed:
            unreal.log(f"[AutoTexture] {asset_path}: Updated {', '.join(changed)}")
        else:
            unreal.log(f"[AutoTexture] {asset_path}: No change required")
    
        # 保存は、インポート処理の完了後に通常の保存操作で行う。
        return bool(changed)
    
    
    def _on_asset_post_import(factory, created_object):
        """ImportSubsystemから呼ばれる、2引数のコールバック。"""
        try:
            # NoneやTexture2D以外も、apply_texture_rules内で対象外になる。
            apply_texture_rules(created_object)
        except Exception:
            unreal.log_error("[AutoTexture] Failed to apply settings:\n"
                             + traceback.format_exc())
    
    
    def stop():
        """このモジュールが登録したコールバックだけを解除する。"""
        subsystem = _STATE["subsystem"]
        callback = _STATE["callback"]
    
        if subsystem is not None and callback is not None:
            subsystem.on_asset_post_import.remove_callable(callback)
            unreal.log("[AutoTexture] Stopped")
    
        _STATE["subsystem"] = None
        _STATE["callback"] = None
    
    
    def start():
        """監視を開始する。登録済みであれば、旧コールバックを解除する。"""
        stop()
    
        subsystem = unreal.get_editor_subsystem(unreal.ImportSubsystem)
        if subsystem is None:
            raise RuntimeError("ImportSubsystemを取得できません。")
    
        callback = _on_asset_post_import
        subsystem.on_asset_post_import.add_callable_unique(callback)
    
        _STATE["subsystem"] = subsystem
        _STATE["callback"] = callback
        unreal.log(f"[AutoTexture] Started: {ROOT_PATH}")
    

    4:まとめ

    今回は、アセットのインポート時に設定を自動適用する方法を紹介しました。シンプルな処理ですが、インポート後に毎回行う設定変更を自動化できるため、様々な場面で活用できます。

    今回はテクスチャを例にしましたが、メッシュやサウンドなど、ほかの種類のアセットにも応用可能です。制作環境に合わせて、ぜひ活用してみてください。

    本記事で作成したプロジェクト一式へのリンクはこちらです。
     

    今回のプロジェクトデータ

    株式会社Leon Gameworks

    ●公式サイト
    www.leon-game.co.jp

    ●X(Twitter)
    @Leon_Gameworks

    トンコツ(遠藤俊太)

    ●トンコツ開発ブログ
    shuntaendo.hatenablog.com

    ●X(Twitter)
    @tonkotsu3656

    TEXT_トンコツ(Leon Gameworks)
    EDIT_小村仁美 / Hitomi Komura(CGWORLD)、オムライス駆