ブループリントおよび Python で詳細度を作成する

Unreal Editor で、ブループリントおよび Python を使用して詳細度 (LOD) を自動設定する方法を説明します。

Windows
MacOS
Linux

メッシュの詳細度 (LOD) を作成することは、ビジュアル クオリティを低下させることなくゲームのパフォーマンスおよびフレームレートを向上させるうえで有効な方法です。

一般的には、メッシュに含まれるトライアングルの数が多いほどこれらの画面での表示が小さくなり、GPU によるレンダリングが困難になります。同時に多くの詳細なメッシュをレンダリングしようとすると、フレームレートが遅くなる場合があります。ただし、シーンに含まれるすべてのメッシュを同じ忠実度でレンダリングする必要は通常はありません。 つまり、遠くにあるメッシュについては、ビジュアル クオリティーの面で違いを際立たせることなく、三角ポリゴンが少ない、細部を省略したバージョンのメッシュに入れ替えることができます。

Unreal Engine 4 には、各フレームでメッシュが占めている画面の範囲に基づいて、ランタイム時での表示に最も適したバージョンのメッシュを自動的に選択する、組み込みの LOD 管理システムが搭載されています。このシステムでは、メッシュの異なる代替バージョンを事前にエディタで設定しておく必要があります。

エディタでは、指定した各しきい値に対してメッシュを段階的に単純化することで、スタティックメッシュ アセットの詳細度を自動的に生成することができます。このシステムの仕組みや、スタティックメッシュ エディタで自動生成を設定する方法については、「自動 LOD 生成」を参照してください。

ただし、エディタでこれらの詳細度を自動生成できても、プロジェクトに含まれるスタティックメッシュ アセットを 1 つずつ開いて設定を行うことは困難な場合があります。アセットをまとめて編集することは可能ですが、異なるスタティックメッシュ アセットにそれらの性質に基づいて異なる設定を適用する場合は有効ではありません。例えば、メッシュ内にある既存の三角ポリゴン数や、アセットの命名規則に基づいて異なる削減設定を適用する場合などがこれにあたります。また、スクリプティングした、より大きなカスタム アセット パイプライン内のサブステップとして LOD を作成する場合も、この方法は有効ではありません。このような場合は、ブループリントまたは Python を使用して、自動 LOD 作成システムをスクリプティングすることができます。

前提条件: 今回の使用が初めての場合は、Editor Scripting Utilities プラグインをインストールしてください。詳細については、「エディタのスクリプティングと自動化」 を参照してください。

詳細度を新規作成する

実装方法を選んでください。

Blueprints

Python

LOD の管理が必要なノードは、[Editor Scripting] > [Static Mesh] カテゴリに表示されます。

これらのノードを使用するには、PlacedEditorUtilityBase クラスなど、エディタのみのクラスから派生したブループリント クラスである必要があります。詳細については、「ブループリントを使用したエディタのスクリプティング」を参照してください。

  • 重要になるのは、渡したスタティックメッシュ アセットの LOD を自動的に作成する Set Lods ノードです。これを使用するには、このノードと共に、画面サイズのしきい値、および作成する各 LOD の相対的な三角ポリゴン割合を定義する一連の削減設定を提供する必要があります。以下の例を見てみましょう。

    EditorScriptingMeshReductionOptions ノードの Reduction Settings 入力に渡す最初の EditorScriptingMeshReductionSettings 項目は無効です。LOD 0 には常にメッシュのすべてのトライアングルが含まれます。

  • スタティックメッシュに対して現在設定されている詳細度に関する情報を取得するには、Get Lod Count および Get Lod Screen Sizes を使用できます。

  • また、既存の LOD をすべて削除するには Remove Lods を使用できます (メッシュのすべてのトライアングルが含まれる LOD = 0 以外の場合)。

  • LOD を設定することで、スタティックメッシュ アセットに変更が加えられます。加える変更を維持する場合は、後から Save Asset または Save Loaded Asset などのノードも使用する必要があります。

以下の例では、各スタティックメッシュ アセットを入力パス内に順番にロードします。最小しきい値より多くの頂点が含まれるスタティックメッシュについては、追加の LOD が 3 つ設定されて、後に保存されます。

unreal.EditorStaticMeshLibrary クラスで LOD 管理関数を見つけます。

  • 重要になるのは、渡したスタティックメッシュ アセットの LOD を自動的に作成する unreal.EditorStaticMeshLibrary.set_lods() 関数です。この関数を使用するには、画面サイズのしきい値、および作成する各 LOD の相対的な三角ポリゴン割合を定義する一連の EditorScriptingMeshReductionSettings を含む EditorScriptingMeshReductionOptions オブジェクトを渡す必要があります。以下の例を見てみましょう。

    EditorScriptingMeshReductionOptions.reduction_settings 配列で設定した最初の EditorScriptingMeshReductionSettings アイテムには影響はありません。LOD 0 には常にメッシュのすべての三角ポリゴンが含まれます。

  • スタティックメッシュに対して現在設定されている LOD に関する情報を取得するには、unreal.EditorStaticMeshLibrary.get_lod_count() および unreal.EditorStaticMeshLibrary.get_lod_screen_sizes を使用できます。

  • また、既存の LOD をすべて削除するには unreal.EditorStaticMeshLibrary.remove_lods() を使用できます (メッシュにすべての三角ポリゴンが含まれる LOD = 0 以外の場合)

  • LOD を設定することで、スタティックメッシュ アセットに変更が加えられます。 加える変更を維持する場合は、後から unreal.EditorAssetLibrary.save_asset() または unreal.EditorAssetLibrary.save_loaded_asset() などの関数も使用する必要があります。

以下の例では、各スタティックメッシュ アセットを入力パス内に順番にロードします。最小しきい値より多くの頂点が含まれるスタティックメッシュについては、追加の LOD が 3 つ設定されて、後に保存されます。

import unreal
asset_path = "/Game/studio"
# 特定のスタティックメッシュ アセットに対する新しい LOD を生成する関数を定義します。
def apply_lods(static_mesh):
    # メッシュが十分に複雑かどうかを確認します。
    number_of_vertices = unreal.EditorStaticMeshLibrary.get_number_verts(static_mesh, 0)
    if number_of_vertices < 10:
        return
    print("treating asset: " + static_mesh.get_name())
    print("existing LOD count: " + str(unreal.EditorStaticMeshLibrary.get_lod_count(static_mesh)))
    #  LOD の自動生成のためのオプションを設定します。
    options = unreal.EditorScriptingMeshReductionOptions()
    # 3 つの新しい LOD をリクエストします。 各 LOD には次のものが含まれます。
    # - 完全に細部が表示されるメッシュの三角ポリゴン数に対して、このレベルで維持される三角ポリゴンの割合
    # - この LOD が表示される画面スペースのしきい値。
    options.reduction_settings = [ unreal.EditorScriptingMeshReductionSettings(1.0, 1.0),
        unreal.EditorScriptingMeshReductionSettings(0.8, 0.75),
        unreal.EditorScriptingMeshReductionSettings(0.6, 0.5),
        unreal.EditorScriptingMeshReductionSettings(0.4, 0.25)
    ]
    # 自動計算するのではなく、上で設定された画面スペースのしきい値を使用します。
    options.auto_compute_lod_screen_size = False
    # スタティックメッシュ アセットのオプションを設定します。
    unreal.EditorStaticMeshLibrary.set_lods(static_mesh, options)
    # 変更を保存します。
    unreal.EditorAssetLibrary.save_loaded_asset(static_mesh)
    print("new LOD count: " + str(unreal.EditorStaticMeshLibrary.get_lod_count(static_mesh)))
# パス内にあるすべてのアセットのリストを取得します。
all_assets = unreal.EditorAssetLibrary.list_assets(asset_path)
# アセットをすべてメモリにロードします。
all_assets_loaded = [unreal.EditorAssetLibrary.load_asset(a) for a in all_assets]
# スタティックメッシュのみを含めるよう、リストをフィルタリングします。
static_mesh_assets = unreal.EditorFilterLibrary.by_class(all_assets_loaded, unreal.StaticMesh)
# リスト内の各スタティックメッシュで上記の関数を実行します。
list(map(apply_lods, static_mesh_assets))

別なアプローチとして、各スタティックメッシュ アセットに対して LOD Group オプションを設定する方法があります。このオプションでは、LevelArchitectureSmallPropLargeProp、または HighDetail など、プロジェクトの「BaseEngine.ini」ファイル内の [StaticMeshLODSettings] セクションで定義されている、事前設定済みの LOD 削減設定の 1 つをメッシュに使用させることができます。

例:

import unreal
asset_path = "/Game/studio/"
def set_high_detail(static_mesh):
    # LOD グループを設定します。
    static_mesh.set_editor_property("lod_group", "HighDetail")
    # アセットを保存します。
    unreal.EditorAssetLibrary.save_loaded_asset(static_mesh)
# パス内にあるすべてのアセットのリストを取得します。
all_assets = unreal.EditorAssetLibrary.list_assets(asset_path)
# アセットをすべてメモリにロードします。
all_assets_loaded = [unreal.EditorAssetLibrary.load_asset(a) for a in all_assets]
# スタティックメッシュのみを含めるよう、リストをフィルタリングします。
static_mesh_assets = unreal.EditorFilterLibrary.by_class(all_assets_loaded, unreal.StaticMesh)
# リスト内の各スタティックメッシュで上記の関数を実行します。
list(map(set_high_detail, static_mesh_assets))

このシステムの仕組みやエディタで使用する方法については、「自動 LOD 生成」を参照してください。

LOD を別のスタティックメッシュから再利用する

前に概要を説明したプロセスで、スタティックメッシュの LOD を自動的に生成する別の方法として、スタティックメッシュ (ソースのスタティックメッシュ) にすでにある LOD を利用して、別のスタティックメッシュ (宛先のスタティックメッシュ) の LOD として再利用します。

実装方法を選んでください。

Blueprints

Python

ブループリント スクリプトで既存の LOD を再利用するには、[Editor Scripting] > [Static Mesh] > [Set Lod From Static Mesh] ノードを使用します。 

Set Lod From Static Mesh

このノードでは次の入力が必要です。

  • 宛先スタティックメッシュへの参照。新しい LOD を作成するスタティックメッシュです。まずこのアセットを [Editor Scripting] > [Asset] > Load Asset ノードを使用してロードする必要があります。

  • 宛先スタティックメッシュで作成する LOD のインデックス。

    宛先スタティックメッシュに同じインデックスの LOD がある場合は、上書きされます。

  • ソース スタティックメッシュへの参照。宛先スタティックメッシュに渡す、既存の LOD を保持するスタティックメッシュです。前と同様に、まずこのアセットを [Editor Scripting] > [Asset] > Load Asset ノードを使用してロードする必要があります。

  • 宛先スタティックメッシュで使用する、ソース スタティックメッシュの LOD のインデックスです。

  • ソース LOD のマテリアル スロットと宛先スタティックメッシュに存在するスロットをマージするかどうかを決定する Boolean パラメータです。この設定を有効にすると、関数は宛先メッシュのセクションと同じマテリアルを割り当てたソース ジオメトリのセクションを検索します。対象が見つかると、LOD のセクションを再マッピングして、宛先スタティックメッシュにある既存のセクションとの一致を試みます。両方のスタティックメッシュが同じマテリアルを使用している場合、これによりメモリをいくらか節約できることがあります。この設定を無効のままにすると、ソース LOD のすべてのメッシュ セクションが宛先スタティックメッシュに追加されます。

LOD の設定は宛先スタティックメッシュ アセットに変更を加えます。加える変更を維持する場合は、後から Save Asset または Save Loaded Asset などのノードも使用する必要があります。

例えば、次のスクリプトはソース スタティックメッシュから指定 LOD を取得し、指定された異なる LOD インデックスで宛先スタティックメッシュでジオメトリを再利用します。

Set Lod from Static Mesh ノードを実行すると、ソース スタティックメッシュの LOD のコピーを宛先スタティックメッシュに追加します。スタティックメッシュ アセット間に継続的な接続はありません。したがってこの時点以降のスタティックメッシュへの変更は宛先スタティックメッシュに自動的に反映されません。

Python スクリプトで LOD を再利用するには、unreal.EditorStaticMeshLibrary.set_lod_from_static_mesh() 関数を呼び出します。次の項目をこの関数に渡す必要があります。

  • 宛先スタティックメッシュ。新しい LOD を作成するスタティックメッシュです。まずこのアセットを unreal.EditorAssetLibrary.load_asset() 関数を使用してロードする必要があります。

  • 宛先スタティックメッシュで作成する LOD のインデックス。これには 0 より大きい値が必要です。宛先スタティックメッシュの LOD 0 を置き換えることはできません。

    宛先スタティックメッシュに同じインデックスの LOD がある場合は、上書きされます。

  • ソース スタティックメッシュ。宛先スタティックメッシュに渡す、既存の LOD を保持するスタティックメッシュです。前と同様に、まずこのアセットを unreal.EditorAssetLibrary.load_asset() 関数を使用してロードする必要があります。

  • 宛先スタティックメッシュで使用する、ソース スタティックメッシュの LOD のインデックスです。

  • 宛先スタティックメッシュのマテリアル スロットをマージするかどうかを決定する Boolean パラメータです。このパラメータを True に設定すると、この関数は宛先メッシュのセクションと同じマテリアルを割り当てたソース ジオメトリのセクションを検索します。対象が見つかると、LOD のセクションを再マッピングして、宛先スタティックメッシュにある既存のセクションとの一致を試みます。このパラメータを False に設定すると、ソース LOD のすべてのメッシュ セクションは宛先スタティックメッシュに追加されます。

この LOD を設定することで、スタティックメッシュ アセットに変更が加えられます。加える変更を維持する場合は、後から unreal.EditorAssetLibrary.save_asset() または unreal.EditorAssetLibrary.save_loaded_asset() などの関数も使用する必要があります。

例えば、次のスクリプトは指定したソース スタティックメッシュの LOD 0 を取得し、複雑な宛先スタティックメッシュの LOD 1 としてジオメトリを再利用します。

import unreal
destination_name = "/Game/MyGeometries/Accumulator_case"
source_name = "/Game/MyGeometries/Simplified_box"
def set_mesh_as_lod(destination_name, source_name):
    destination_mesh = unreal.EditorAssetLibrary.load_asset(destination_name)
    source_mesh = unreal.EditorAssetLibrary.load_asset(source_name)
    lod_count = unreal.EditorStaticMeshLibrary.get_lod_count(destination_mesh)
    print("Current LOD count: " + str(lod_count))
    slot_replaced = unreal.EditorStaticMeshLibrary.set_lod_from_static_mesh(destination_mesh, 1, source_mesh, 0, True)
    if slot_replaced > 0:
        print("Added mesh as LOD for slot " + str(slot_replaced))
        lod_count = unreal.EditorStaticMeshLibrary.get_lod_count(destination_mesh)
        print("New LOD count: " + str(lod_count))
        unreal.EditorAssetLibrary.save_loaded_asset(destination_mesh)
    else
        unreal.log_error("Unable to add mesh as LOD!")
set_mesh_as_lod(destination_name, source_name)

unreal.EditorStaticMeshLibrary.set_lod_from_static_mesh() 関数を実行すると、ソース スタティックメッシュの LOD のコピーを宛先スタティックメッシュに追加します。スタティックメッシュ アセット間に継続的な接続はありません。したがってこの時点以降のスタティックメッシュへの変更は宛先スタティックメッシュに自動的に反映されません。

Unreal Engine のドキュメントを改善するために協力をお願いします!どのような改善を望んでいるかご意見をお聞かせください。
調査に参加する
閉じる