カテゴリー別アーカイブ: Unreal Python

Unreal Python: マテリアルスロットにマテリアルを割り当てる

レベル上のスタティックメッシュアクターにマテリアルスロットを参照にして同じ名前のマテリアルを割り当てていきます。

import unreal

selectedActors = unreal.EditorLevelLibrary.get_selected_level_actors()

if len(selectedActors) > 0:
    staticMeshComponent = selectedActors[0].get_component_by_class(unreal.StaticMeshComponent)
    slot_name = staticMeshComponent.get_material_slot_names()
    staticMesh = staticMeshComponent.static_mesh

    asset_path = staticMesh.get_path_name()
    asset_path = asset_path.rsplit('/', 2)[0]
    print asset_path

    allMaterials = unreal.EditorAssetLibrary.list_assets(asset_path, True, True)

    for i in range(staticMesh.get_num_sections(0)):
        for mat in allMaterials:
            if str(slot_name[i]) in mat:
                asset = unreal.EditorAssetLibrary.find_asset_data(mat).get_asset()
                staticMesh.set_material(i, asset)
                break

Unreal Python: マテリアルインスタンスを自動生成する

テクスチャーの数だけマテリアルインスタンスを生成し、テクスチャーサンプラーにテクスチャーを割り当てます。

import unreal

tex_path = '/Game/Textures'
mat_path = '/Game/Materials'
master_path = '/Game/Materials/M_General'

AssetList = unreal.EditorAssetLibrary.list_assets(tex_path, True, False)

if len(AssetList) > 0:
    for asset in AssetList:
        assetData = unreal.EditorAssetLibrary.find_asset_data(asset)
        className = assetData.get_asset().get_class().get_name()

        if className == 'Texture2D':
            tex_name = asset.split(".")[1]
            mat_name = 'MI_' + tex_name

            # マテリアルインスタンスをテクスチャーの名前で生成
            assetTools = unreal.AssetToolsHelpers.get_asset_tools()
            mat_inst = assetTools.create_asset(mat_name, mat_path, unreal.MaterialInstanceConstant, None)

            # マスターマテリアルを設定する
            master_mat = unreal.EditorAssetLibrary.find_asset_data(master_path)
            unreal.MaterialEditingLibrary.set_material_instance_parent(mat_inst, master_mat.get_asset())

            # TextureParameterValue構造体をつくる(MaterialParameterInfo構造体が含まれている)
            materialParam = unreal.MaterialParameterInfo()
            materialParam.name = "BaseTexture"

            texParam = unreal.TextureParameterValue()
            texParam.parameter_info = materialParam
            texParam.parameter_value = unreal.EditorAssetLibrary.find_asset_data(tex_path + '/' + tex_name).get_asset()

            listTexParam = []
            listTexParam.append(texParam)
            mat_inst.set_editor_property('texture_parameter_values', listTexParam)

TextureParameterValue構造体

Unreal Python: ソースファイル関連

ソースファイルのないアセットをリストアップする

import unreal
import re
import os

path = "/Game/"
allAssets = unreal.EditorAssetLibrary.list_assets(path, True, False)

if(len(allAssets) > 0):
    for asset in allAssets:
        assetData = unreal.EditorAssetLibrary.find_asset_data(asset)
        className = assetData.get_asset().get_class().get_name()

        if className == 'Texture2D' or className == 'StaticMesh':
            filePath = assetData.get_asset().get_editor_property('asset_import_data').get_first_filename()
            filePath = re.sub("/", "\\\\", filePath)
            if not os.path.exists(filePath):
                print(asset)

 

コンテントブラウザで選択したアセットからソースファイルのフォルダを開く

選択アセット(複数)のソースファイルのあるフォルダを開きます。ない場合はアセット名をプリントします。

import unreal
import re
import subprocess
import os

utilityBase = unreal.GlobalEditorUtilityBase.get_default_object()
AssetList = utilityBase.get_selected_assets()

if len(AssetList)>0:
    for asset in AssetList:
        name = asset.get_name()
        className = asset.get_class().get_name()
        if className == 'Texture2D' or className == 'StaticMesh':
            filePath = asset.get_editor_property('asset_import_data').get_first_filename()
            print filePath
            filePath = re.sub("/", "\\\\", filePath)
            print filePath

            if os.path.exists(filePath):
                subprocess.Popen(r'explorer /select,%s' % filePath)
            else:
                print('Source file not exists: ' + name)

アセットブラウザーで適当なテクスチャーまたはメッシュを選択した状態で実行します。

 

選択したアクターからソースファイルのフォルダを開く

選択したアクターからソースファイルのあるフォルダを開きます。

import unreal
import re
import os
import subprocess

selectedActors = unreal.EditorLevelLibrary.get_selected_level_actors()

if len(selectedActors) > 0:
    mesh = selectedActors[0].get_component_by_class(unreal.StaticMeshComponent)

    if mesh != None:
        path = mesh.static_mesh.get_path_name()
        asset = unreal.EditorAssetLibrary.find_asset_data(path).get_asset()

        filePath = asset.get_editor_property('asset_import_data').get_first_filename()
        filePath = re.sub('/', '\\\\', filePath)

        if os.path.exists(filePath):
            subprocess.Popen(r'explorer /select,%s' % filePath)
        else:
            print('Source file not exists')
else:
    print "No Actor Selected!"

スタティックメッシュからアセットの場所を取得し、そこからソースファイルのアドレスを取得します。

Unreal Python: マテリアルの依存関係をプリントする

アウトプットログにフォルダ内のマテリアルの依存関係をプリントするスクリプトです。マテリアルごとに派生しているマテリアルインスタンス数を表示します。

import unreal

utility_base = unreal.GlobalEditorUtilityBase.get_default_object()
AssetList = utility_base.get_selected_assets()

if len(AssetList) > 0:
    name = AssetList[0].get_name()
    path = AssetList[0].get_path_name().split(".")[0]
    path = path.replace(name, "")

    allAssets = unreal.EditorAssetLibrary.list_assets(path, True, False)
    
    index = 0
    if len(allAssets) > 0:
        for asset in allAssets:
            assetData = unreal.EditorAssetLibrary.find_asset_data(asset)
            assetClassName = assetData.get_asset().get_class().get_name()
            if assetClassName == "Material":
                dependencies = unreal.EditorAssetLibrary.find_package_referencers_for_asset(asset, False)
                print assetData.get_asset().get_name() + ": " + str(len(dependencies))
                index += 1
                
        print str(index) + " Materials."

アセットブラウザーで適当なマテリアルを選択した状態で実行します。

Unreal Python: 最小LODの一括設定

環境:Unreal Engine 4.22

選択したアクターと同じアクターすべてに一括で最小LODを設定するスクリプト。

インターフェイスはこのように設定。スライダーでテキストボックスの値を変える仕組みをブループリントで組みます。テキストボックスの値は引数としてPythonファイルに読ませます。

 

ノードはこのような感じ。

 

import unreal
import sys
  
# 同じスタティックメッシュのアクターをフィルタリングする関数
def filterSameMesh(selectedActor, actors):
    staticMesh = selectedActor.get_component_by_class(unreal.StaticMeshComponent)
    staticMeshName = staticMesh.static_mesh.get_name()
    result = []

    for actor in actors:
        mesh = actor.get_component_by_class(unreal.StaticMeshComponent)
        if mesh != None:
            name = mesh.static_mesh.get_name()
        
            if name == staticMeshName:
                result.append(actor)
 
    return result

# 選択アクターのアセット名を取得する
selectedActors = unreal.EditorLevelLibrary.get_selected_level_actors()
if len(selectedActors) > 0:

    # 全体のアクターから一致するものを選ぶ
    sameActors = []
    allActors = unreal.EditorLevelLibrary.get_all_level_actors()

    actors = filterSameMesh(selectedActors[0], allActors)

    for actor in actors:
        staticMesh = actor.get_component_by_class(unreal.StaticMeshComponent)
        num = int(sys.argv[1])
        if num > 0:
            staticMesh.set_editor_property("override_min_lod", True)
            staticMesh.set_editor_property("min_lod", num)
        else:
            staticMesh.set_editor_property("min_lod", num)
            staticMesh.set_editor_property("override_min_lod", False)

else:
    print "No Actor Selected!"

エディタ上のパラメータの値を変えるにはset_editor_propertyを使います。

Unreal Python: アクターの一括選択

環境:Unreal Engine 4.22

選択したアクターから同じレベルにある同じメッシュのアクターを一括選択するスクリプト。今回はインターフェイスを使ってみます。

アセットライブラリ上で右クリックし、メニューからEditor Utility > Editor Widget を選ぶ。ボタンとテキストボックスを配置してUIを作成する。

ボタンを選択して、DetailsのEventの項目からPressedを押すとブループリントの画面に遷移する。

stringの変数を作り、Pythonのファイルのアドレスを入力しておく。

例:D:\UnrealPython\selectSameActorWithDistance.py

stringをつなげて「py D:\UnrealPython\selectSameActorWithDistance.py 1000」という形になるようにする。最後の数字は引数でPythonファイルに読み込ませる。

Pythonファイルのコードは以下。

import unreal
import sys
  
# 同じスタティックメッシュのアクターをフィルタリングする関数
def filterSameMesh(selectedActor, actors):
    staticMesh = selectedActor.get_component_by_class(unreal.StaticMeshComponent)
    staticMeshName = staticMesh.static_mesh.get_name()
    result = []

    for actor in actors:
        mesh = actor.get_component_by_class(unreal.StaticMeshComponent)
        if mesh != None:
            name = mesh.static_mesh.get_name()
        
            if name == staticMeshName:
                result.append(actor)
 
    return result

# 同じレベルにあるアクターをフィルタリングする関数
def filterSameLevel(selectedActor, actors):
    staticMesh = selectedActor.get_component_by_class(unreal.StaticMeshComponent)
    staticMeshPath = selectedActor.get_path_name().split(':')[0]
    result = []

    for actor in actors:
        mesh = actor.get_component_by_class(unreal.StaticMeshComponent)
        if mesh != None:
            path = actor.get_path_name().split(':')[0]
        
            if path == staticMeshPath:
                result.append(actor)
 
    return result

# 選択アクターのアセット名を取得する
selectedActors = unreal.EditorLevelLibrary.get_selected_level_actors()
if len(selectedActors) > 0:

    # 全体のアクターから一致するものを選ぶ
    sameActors = []
    allActors = unreal.EditorLevelLibrary.get_all_level_actors()

    actors = filterSameMesh(selectedActors[0], allActors)
    actors = filterSameLevel(selectedActors[0], actors)

    limit = float(sys.argv[1])
    print limit
    if(limit > 0):
        for actor in actors:
            dist = selectedActors[0].get_distance_to(actor)
            print dist
            if(dist < limit):
                sameActors.append(actor)
    else:
        sameActors = actors
     
    # 一致するアクターを選択する
    unreal.EditorLevelLibrary.set_selected_level_actors(sameActors)
else:
    print "No Actor Selected!"

argvを使って引数を読み込むようにしている。

Unreal Python

必要に迫られてUnreal Pythonを調べ始めました。とりあえず短いスクリプトを書いていくところから始めてみます。

 

選択しているアクターを書き出す

# 選択アクターをリストする
import unreal
selectedActors = unreal.EditorLevelLibrary.get_selected_level_actors()
for actor in selectedActors:
    print actor
    print actor.get_actor_label()
    print actor.get_actor_location()

レベル上で選択したアクターのラベルや座標等の情報をprintで書き出してみました。まずはここからですね。

unreal.Actorクラス

unreal.EditorLevelLibraryクラス

 

使われていないアセットを書き出す

# 使われていないアセットをリストするスクリプト
import unreal
path = "/Game/"
allAssets = unreal.EditorAssetLibrary.list_assets(path, True, False)

if(len(allAssets) > 0):
    for asset in allAssets:
        dependencies = unreal.EditorAssetLibrary.find_package_referencers_for_asset(asset, False)
        if(len(dependencies) == 0):
            print asset

アセットライブラリの中から依存関係のないアセットのみを書き出しています。

unreal.EditorAssetLibraryクラス

 

選択しているアクターから同じメッシュのアクターを一括選択する

# 選択しているアクターと同じアクターを選択するスクリプト
import unreal
 
# 選択アクターのアセット名を取得する
selectedActors = unreal.EditorLevelLibrary.get_selected_level_actors()
if len(selectedActors) > 0:
    staticMesh = selectedActors[0].get_component_by_class(unreal.StaticMeshComponent)
    staticMeshName = staticMesh.static_mesh.get_name()
 
    # 全体のアクターから一致するものを選ぶ
    sameActors = []
    
    allActors = unreal.EditorLevelLibrary.get_all_level_actors()
    for actor in allActors:
        staticMesh = actor.get_component_by_class(unreal.StaticMeshComponent)
        if staticMesh != None:
            name = staticMesh.static_mesh.get_name()
            if name == staticMeshName:
                sameActors.append(actor)
    
    # 一致するアクターを選択する
    unreal.EditorLevelLibrary.set_selected_level_actors(sameActors)
else:
    print "No Actor Selected!"

少し応用して実用的なスクリプト。手動での選択は面倒なことが多いので条件をつけて一括選択するスクリプトは重宝しますよね。

unreal._ObjectBaseクラス

unreal.StaticMeshComponentクラス

 

参考

Python環境の準備
https://docs.unrealengine.com/ja/Engine/Editor/ScriptingAndAutomation/Python/index.html

クラスのリスト
https://docs.unrealengine.com/en-US/PythonAPI/index.html