UE5.6 レベルに配置しているオブジェクトのマテリアルの複製を作成してオーバーライドする
code:python
import unreal
# ==========================================
# 設定パラメータ
# ==========================================
DEST_FOLDER = "/Game/DuplicatedMaterials" # 複製先フォルダ(先頭は /Game )
SUFFIX = "_Copy" # 付与するサフィックス
def duplicate_and_replace_level_materials():
editor_asset_subs = unreal.get_editor_subsystem(unreal.EditorAssetSubsystem)
editor_actor_subs = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
# 1. EditorActorSubsystem を使用して、現在開いているすべてのレベル(サブレベル含む)から全アクターを取得
# これにより、Levelオブジェクトの互換性問題を完全に回避します
actors = editor_actor_subs.get_all_level_actors()
if not actors:
unreal.log_warning("アクターが見つかりませんでした、またはレベルが空です。")
return
# 複製済みマテリアルのキャッシュ(キー: オリジナルパス, 値: 複製後オブジェクト)
duplicated_cache = {}
# 変更を追跡するためのカウント
replace_count = 0
duplicate_count = 0
unreal.log(f"--- マテリアル複製&置換処理を開始 (対象アクター数: {len(actors)}) ---")
# 2. すべてのアクターを走査
for actor in actors:
if not actor:
continue
# アクター内の全コンポーネントをチェック
components = actor.get_components_by_class(unreal.PrimitiveComponent)
for comp in components:
# コンポーネントが持つマテリアル(スロット数)を走査
num_mats = comp.get_num_materials()
for i in range(num_mats):
mat = comp.get_material(i)
# マテリアルインスタンス(MaterialInstanceConstant)のみを対象とする
if mat and isinstance(mat, unreal.MaterialInstanceConstant):
orig_path = mat.get_path_name()
# すでに今回の実行、またはフォルダ内に同名で存在するかチェック
if orig_path in duplicated_cache:
new_mat = duplicated_cacheorig_path
else:
# 複製先の新規パスを生成
orig_name = mat.get_name()
new_name = f"{orig_name}{SUFFIX}"
new_path = f"{DEST_FOLDER}/{new_name}"
# すでにアセットとして存在しているか確認
if editor_asset_subs.does_asset_exist(new_path):
new_mat = unreal.load_asset(new_path)
duplicated_cacheorig_path = new_mat
unreal.log(f"既存の複製マテリアルを流用: {new_path}")
else:
# 存在しない場合は新規に複製
new_mat = editor_asset_subs.duplicate_asset(orig_path, new_path)
if new_mat:
duplicated_cacheorig_path = new_mat
duplicate_count += 1
unreal.log(f"マテリアルを複製しました: {new_path}")
else:
unreal.log_error(f"複製に失敗しました: {orig_path}")
continue
# コンポーネントのマテリアルをオーバーライド(差し替え)
if new_mat and comp.get_material(i) != new_mat:
comp.set_material(i, new_mat)
replace_count += 1
# アクターに変更があったことをエディタに通知
actor.modify()
unreal.log(f"--- 処理完了: 新規複製={duplicate_count}件 / 置換適応={replace_count}件 ---")
# スクリプトの実行
duplicate_and_replace_level_materials()
code:python
import unreal
# ==========================================
# 設定パラメータ
# ==========================================
DEST_FOLDER = "/Game/DuplicatedMaterials" # 複製先フォルダ(先頭は /Game )
SUFFIX = "_Copy" # 付与するサフィックス
def duplicate_and_replace_selected_skeletal_materials():
editor_asset_subs = unreal.get_editor_subsystem(unreal.EditorAssetSubsystem)
editor_actor_subs = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
# 1. 現在エディタ上で選択されているアクターのみを取得
selected_actors = editor_actor_subs.get_selected_level_actors()
if not selected_actors:
unreal.log_warning("アクターが選択されていません。エディタ上で対象のスケルタルメッシュアクターを選択してください。")
return
# 選択されたアクターの中から SkeletalMeshActor のみを抽出
skeletal_actors = actor for actor in selected_actors if isinstance(actor, unreal.SkeletalMeshActor)
if not skeletal_actors:
unreal.log_warning(f"選択中のアクター({len(selected_actors)}件)の中にスケルタルメッシュアクター(SkeletalMeshActor)が見つかりませんでした。")
return
# 複製済みマテリアルのキャッシュ(キー: オリジナルパス, 値: 複製後オブジェクト)
duplicated_cache = {}
# 変更を追跡するためのカウント
replace_count = 0
duplicate_count = 0
unreal.log(f"--- スケルタルメッシュマテリアル複製&置換処理を開始 (対象アクター数: {len(skeletal_actors)}) ---")
# 2. 選択されたスケルタルメッシュアクターのみを走査
for actor in skeletal_actors:
if not actor:ち
continue
unreal.log(f"アクターを処理中: {actor.get_actor_label()}")
# スケルタルメッシュコンポーネント(SkeletalMeshComponent)のみを取得
components = actor.get_components_by_class(unreal.SkeletalMeshComponent)
if not components:
unreal.log_warning(f" -> SkeletalMeshComponent が見つかりませんでした: {actor.get_actor_label()}")
continue
for comp in components:
# SkeletalMeshComponent から参照されている SkeletalMesh アセットを取得
mesh_asset = None
if hasattr(comp, "get_skeletal_mesh_asset"):
mesh_asset = comp.get_skeletal_mesh_asset()
elif hasattr(comp, "skeletal_mesh"):
mesh_asset = comp.skeletal_mesh
if not mesh_asset:
unreal.log_warning(f" -> コンポーネント {comp.get_name()} にスケルタルメッシュアセットが設定されていません。")
continue
unreal.log(f" -> スケルタルメッシュアセットを特定: {mesh_asset.get_name()}")
# メッシュアセットがデフォルトで持っているマテリアルリスト(Skeletal Materials)を参照
skeletal_materials = mesh_asset.materials
num_mats = len(skeletal_materials)
unreal.log(f" -> スロット数: {num_mats}")
for i in range(num_mats):
skeletal_mat = skeletal_materialsi
mat = skeletal_mat.material_interface
if not mat:
unreal.log(f" - スロット {i}: 元のメッシュアセット側にマテリアルが設定されていません (Empty)")
continue
# スケルタルメッシュにアサインされている元のマテリアルアセット情報を取得
orig_path = mat.get_path_name()
orig_name = mat.get_name()
# すでに今回の実行、またはフォルダ内に同名で存在するかチェック
if orig_path in duplicated_cache:
new_mat = duplicated_cacheorig_path
else:
# 複製先の新規パスを生成
new_name = f"{orig_name}{SUFFIX}"
new_path = f"{DEST_FOLDER}/{new_name}"
# すでにアセットとして存在しているか確認
if editor_asset_subs.does_asset_exist(new_path):
new_mat = unreal.load_asset(new_path)
duplicated_cacheorig_path = new_mat
unreal.log(f" - スロット {i}: 既存の複製マテリアルを流用します: {new_path}")
else:
# 元のマテリアルアセットを直接複製
new_mat = editor_asset_subs.duplicate_asset(orig_path, new_path)
if new_mat:
duplicated_cacheorig_path = new_mat
duplicate_count += 1
unreal.log(f" - スロット {i}: マテリアルを新規複製しました: {new_path}")
else:
unreal.log_error(f" - スロット {i}: 複製に失敗しました: {orig_path}")
continue
# コンポーネントのマテリアルをオーバーライド(差し替え)
if new_mat:
if comp.get_material(i) != new_mat:
comp.set_material(i, new_mat)
replace_count += 1
# アクターに変更があったことをエディタに通知
actor.modify()
unreal.log(f" - スロット {i}: 新規複製マテリアルをコンポーネントにオーバーライド適用しました -> {new_name}")
else:
unreal.log(f" - スロット {i}: すでに複製後のマテリアルが適用済みです")
unreal.log(f"--- 処理完了: 新規複製={duplicate_count}件 / 置換適応={replace_count}件 ---")
# スクリプトの実行
duplicate_and_replace_selected_skeletal_materials()