ATMWRIによるUE5の記録

Unreal Engine 5 を使い始めました

Unreal Pythonを使ったオブジェクトの配置とマテリアルの設定まで

UEでpython使ってみた。という記事はヒットするけれど、その先のちょっとした使い方までとなると検索力不足のためか中々見つからなかった。『UE5で星空を作る』の前段階としてUnreal Pythonの始め方からオブジェクトの配置・マテリアルの設定までを記録しておく

0. Unreal Pythonの始め方

ハローワールド

Output LogのドロップダウンメニューからPythonを選択すると使える

UE5では最初からpythonプラグインは有効になっていたっぽい?

ファイルを実行する準備

pythonスクリプトを作成するディレクトリを適当な場所に作成してAdditional Pathsへパスを追加する。この時Developer Modeにチェックを入れてstubファイルを生成するとTextエディタのオートコンプリートに使用できる

Project Settings -> Plugins -> Pythonでパスの追加

VScodeの設定

VScodeの設定でpythonオートコンプリートにUE5が生成したstubのpathを指定する

VScodeでpreferences -> settings [python auto] とかで検索

ファイルのimportとreload

import [ファイル名(py抜き)]でインポートとスクリプトの実行がされる。ファイルを編集を反映させるにはimportlibreloadが必要になる

importlibのreload関数?が必要

1. 目標

  1. コンテンツブラウザからアセットを選択
  2. 選択したアクターをワールドに配置
  3. 配置したアクターのマテリアルを設定

2. 結果

unreal pythonで生成したアクター

3.ソース

import unreal

def get_Basic_ShapeData(shape:str) -> unreal.AssetData:
    """ベーシックシェイプの名前からAssetDataを返す
    shape : 'Cube', 'Sphere', 'Plane' ..  
    """
    EAL = unreal.EditorAssetLibrary
    shapeList = EAL.list_assets('/Engine//BasicShapes')

    for shapePath in shapeList:
        if(shape in shapePath):
            shapeData = EAL.find_asset_data(shapePath)
            return shapeData

def create_StaticMeshActor_from_BasicShapeData(assetData:unreal.AssetData, x:float, y:float, z:float) -> unreal.StaticMeshActor:
    """StaticMeshActorをワールドにスポーン、生成したアクターを返す
    assetData: ベーシックシェイプのアセットデータ
    return: 生成したアクター
    """
    EAS = unreal.EditorActorSubsystem()
    return EAS.spawn_actor_from_object(assetData.get_asset(), location=[x, y, z])

def set_New_Material(actor:unreal.Actor, materialName:str):
    """アクターに新しいマテリアルをセットする
    actor: ワールド内に配置されているアクター
    materialName: Content下に保存されているアセット名
    """
    materialObj = None
    EAL = unreal.EditorAssetLibrary
    assetList = EAL.list_assets('/Game')

    for path in assetList:
        if(materialName in path):
            materialObj = EAL.find_asset_data(path).get_asset()
    
    smc = get_Static_Mesh_Component(actor)
    smc.set_material(0, materialObj)

def get_Static_Mesh_Component(actor:unreal.StaticMeshActor) -> unreal.StaticMeshComponent:
    """インテリセンスが効かないので get_editor_propertyをラップした関数
    """
    return actor.get_editor_property("static_mesh_component")

def set_position(actor:unreal.StaticMeshActor, x:float, y:float, z:float):
    newlocation = unreal.Vector(x, y, z)
    actor.set_actor_location(newlocation, False, False)
    
def resize_actor(actor:unreal.StaticMeshActor, size:float):
    newSize = unreal.Vector(size,size,size)
    actor.set_actor_scale3d(newSize)

def rename_actor(actor:unreal.StaticMeshActor, label:str):
    actor.set_actor_label(label)

# サンプル用の処理
def test():
    shape = get_Basic_ShapeData('Cone')
    newActor = create_StaticMeshActor_from_BasicShapeData(shape, 0, 0, 100)
    set_New_Material(newActor, 'M_Ground_Moss')
    rename_actor(newActor,'HappyCone')
    resize_actor(newActor, 2.5)

4. ソースのメモ

基本は以下の2つのクラスを使用していく

  • EditorAssetLibrary: コンテンツブラウザを操作する
  • EditorActorSubsystem:アウトライナーを操作する感じ?

アセットpathのリストの取得

EAL = unreal.EditorAssetLibrary
shapeList = EAL.list_assets('/Engine//BasicShapes')

たまたまベーシックシェイプの場所はEngineディレクトリ下だったので問題はなかったが、Contentディレクトリの場合は/Gameとする必要がある

インテリセンスが効いたり効かなかったり

smc = get_Static_Mesh_Component(actor)
    smc.set_material(0, materialObj)

def get_Static_Mesh_Component(actor:unreal.StaticMeshActor) -> unreal.StaticMeshComponent:
    return actor.get_editor_property("static_mesh_component")

もともとこの部分はactor.get_editor_property("static_mesh_component").set_material(0, materialObj)とまとめて書いてたが、プロパティ部分の操作でインテリセンスが効かないのが不安なので戻り値のクラスを指定する関数でラップした。

5. 感想

記事にするまでpythonの戻り値の型指定を知らなかったレベルの素人がいうのもなんだけどプロパティをドキュメントで調べないと指定できなかったりクラスを継承しまくりで使いづらいなぁという印象。使いこなすうちに慣れるはず・・・