Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

Python / BlueprintによるUnreal Engineの自動化 / GTMF2019

1.254 visualizaciones

Publicado el

Unreal EngineにはPythonやBlueprintを使って手軽に自動化・効率化できる機能があります。
UE4.22で追加されたEditor Utility WidgetやDatasmithのカスタムインポートなど、自動化・効率化に関する機能の紹介と、Python / Blueprintによる実装例などをご紹介したいと思います。

Publicado en: Tecnología
  • Inicia sesión para ver los comentarios

Python / BlueprintによるUnreal Engineの自動化 / GTMF2019

  1. 1. Python / Blueprintによる Unreal Engineの自動化 Epic Games Japan / Technical Artist 小林浩之
  2. 2. #UE4 | @UNREALENGINE 自己紹介 小林 浩之 Epic Games Japan / Technical Artist スクウェア・エニックス大阪で背景TAを2年ほど 今年2月からEGJのエンタープライズ分野のサポートとして入社
  3. 3. #UE4 | @UNREALENGINE 目次 • 大規模開発における作業効率化・自動化の需要 • Unreal Engine 4の作業効率化・自動化ツール紹介 • 実装例 • Datasmithインポートの効率化 Blueprint • 命名規則に応じたアセットリネーム Editor Utility Widget & Blueprint • Pythonによるインスタンシング Python • インスタンスを個別のStatic Meshに変換 Python
  4. 4. #UE4 | @UNREALENGINE 目次 • 大規模開発における作業効率化・自動化の需要 • Unreal Engine 4の作業効率化・自動化ツール紹介 • 実装例 • Datasmithインポートの効率化 Blueprint • 命名規則に応じたアセットリネーム Editor Utility Widget & Blueprint • Pythonによるインスタンシング Python • インスタンスを個別のStatic Meshに変換 Python
  5. 5. #UE4 | @UNREALENGINE 大規模開発における作業効率化・自動化の需要 大量に配置されたオブジェクトの整理、膨大なアセットの管理など、 手作業でやっているとコストがかかるりすぎる・・・ 時間が足りない・・・ クオリティアップにコストを割けない・・・
  6. 6. #UE4 | @UNREALENGINE 大規模開発における作業効率化・自動化の需要 オブジェクト整理作業 アセット管理作業 などなど 自動化
  7. 7. #UE4 | @UNREALENGINE McLarenによる事例 Unreal Engineへの CADデータインポートの自動化
  8. 8. #UE4 | @UNREALENGINE McLarenによる事例 インポートフローの改善
  9. 9. #UE4 | @UNREALENGINE 目次 • 大規模開発における作業効率化・自動化の需要 • Unreal Engine 4の作業効率化・自動化ツール紹介 • 実装例 • Datasmithインポートの効率化 Blueprint • 命名規則に応じたアセットリネーム Editor Utility Widget & Blueprint • Pythonによるインスタンシング Python • インスタンスを個別のStatic Meshに変換 Python
  10. 10. #UE4 | @UNREALENGINE Bluetility (Blueprint Utility) Blueprintを使ったスクリプティング
  11. 11. #UE4 | @UNREALENGINE Bluetility プラグイン > Editor Scripting Utilities
  12. 12. #UE4 | @UNREALENGINE Unreal Python Pythonによるエディタスクリプティング
  13. 13. #UE4 | @UNREALENGINE Unreal Python プラグイン > Python Editor Script Pluginにチェックで有効化
  14. 14. #UE4 | @UNREALENGINE Unreal Python アウトプットログから直接入力 実行方法
  15. 15. #UE4 | @UNREALENGINE Unreal Python .pyファイルのパス指定で実行 実行方法
  16. 16. #UE4 | @UNREALENGINE Unreal Python エディタ起動時に実行
  17. 17. #UE4 | @UNREALENGINE Editor Utility Widget UMG&Blueprintでエディタ拡張
  18. 18. #UE4 | @UNREALENGINE Editor Utility Widget コンテンツブラウザで右クリック>Editor Utilities>Editor Widgetから作成
  19. 19. #UE4 | @UNREALENGINE Editor Utility Widget
  20. 20. #UE4 | @UNREALENGINE Editor Utility Widget UIに必要な機能(ボタンやテキストなど)をD&Dで置く
  21. 21. #UE4 | @UNREALENGINE Editor Utility Widget UIからの処理をBlueprintで作成
  22. 22. #UE4 | @UNREALENGINE Editor Utility Widget アセット右クリック>Run Editor Utility WidgetでWindow立ち上げ、実行
  23. 23. #UE4 | @UNREALENGINE Editor Utility Widget EGJ 岡田による解説記事 [UE4]エディタ上で動作するツール・エディタ拡張をUMGで簡単に作れる Editor Utility Widget について https://qiita.com/EGJ-Kaz_Okada/items/9f530db3b53d0fde3f20 [UE4]Editor Utility Widgetでツール・エディタ拡張を作る際のUndo/Redo の実装方法について https://qiita.com/EGJ-Kaz_Okada/items/985b98fb934d751f4f69
  24. 24. #UE4 | @UNREALENGINE 目次 • 大規模開発における作業効率化・自動化の需要 • Unreal Engine 4の作業効率化・自動化ツール紹介 • 実装例 • Datasmithインポートの効率化 Blueprint • 命名規則に応じたアセットリネーム Editor Utility Widget & Blueprint • Pythonによるインスタンシング Python • インスタンスを個別のStatic Meshに変換 Python
  25. 25. #UE4 | @UNREALENGINE 実装例:Datasmithインポートの効率化
  26. 26. #UE4 | @UNREALENGINE Datasmithとは CADソフトなどのデータをUE4用に変換してインポートする機能 (Unreal Studioのみ) Datasmith
  27. 27. #UE4 | @UNREALENGINE Datasmithによって大幅に効率化されるが・・・ CADデータの場合細かいネジなどのパーツまで含んだデータになっている場合が多い 環境によっては処理負荷が高くなってしまう可能性も
  28. 28. #UE4 | @UNREALENGINE Datasmithによって大幅に効率化されるが・・・ リアルタイムエンジンでスムーズに描画するためには ほとんど描画されないような小さいパーツは削除したり、一つにまとめる必要がある
  29. 29. #UE4 | @UNREALENGINE 普通にインポートして後から削除しようとするとする場合 パーツ数が膨大だと作業コストが高くなってしまう インポート 小さいパーツを探す 削除 数百パーツを手作業でとか・・・
  30. 30. #UE4 | @UNREALENGINE BlueprintやPythonを使うことでこれらの作業を自動化できる インポート 小さいパーツを探す 削除 自動化
  31. 31. #UE4 | @UNREALENGINE 小さいパーツを除外してインポート
  32. 32. #UE4 | @UNREALENGINE 小さいパーツを除外してインポート
  33. 33. #UE4 | @UNREALENGINE Blueprint ※拡大して解説していきます
  34. 34. #UE4 | @UNREALENGINE 解説 インポートするデータからDatasmith Sceneを構築
  35. 35. #UE4 | @UNREALENGINE Datasmith Scene Datasmithでは、実際にデータをインポートする前に メモリ上で一度シーン構築を行う インポート Datasmith Scene in Memory メモリ上でシーンを構築 CADデータ
  36. 36. #UE4 | @UNREALENGINE Datasmith Scene Datasmithでは、実際にデータをインポートする前に メモリ上で一度シーン構築を行う インポート Datasmith Scene in Memory メモリ上でシーンを構築 CADデータ
  37. 37. #UE4 | @UNREALENGINE 解説 Datasmith Scene内のアクタを取得
  38. 38. #UE4 | @UNREALENGINE 解説 バウンディングボックスの大きさを評価
  39. 39. #UE4 | @UNREALENGINE 解説 バウンディングボックス オブジェクトを囲む最小の立方体 この立方体の幅、奥行き、高さから オブジェクトの大体の大きさを測る
  40. 40. #UE4 | @UNREALENGINE 解説 条件に当てはまればアクタを削除
  41. 41. #UE4 | @UNREALENGINE 解説 インポートオプションを設定
  42. 42. #UE4 | @UNREALENGINE 解説 実際にインポートし、最後にDatasmith Sceneを削除
  43. 43. #UE4 | @UNREALENGINE 実装例:命名規則に応じたアセットリネーム
  44. 44. #UE4 | @UNREALENGINE 命名規則について アセットの種類や用途に応じて名前の前後に付ける文字列
  45. 45. #UE4 | @UNREALENGINE 命名規則について アセットの種類や用途に応じて名前の前後に付ける文字列 例えば・・・ Static Mesh アセット「Table」があるとしたら Static Meshの省略 SM を付け 「SM_Table」 バリエーションがある場合は 番号やアルファベットを付け「 SM_Table _A」にする
  46. 46. #UE4 | @UNREALENGINE 命名規則について 参考 Unreal Engine Assets Naming Convention https://wiki.unrealengine.com/Assets_Naming_Convention_JP
  47. 47. #UE4 | @UNREALENGINE 命名規則について プロジェクトが大規模化するにつれ、命名規則はより重要に
  48. 48. #UE4 | @UNREALENGINE 命名規則について プロジェクトが大規模化するにつれ、命名規則はより重要に 作業者が自由に名前を付けていると・・・ ● 他の作業者から見たとき用途や種類が判別しにくい ● 特定のアセットを探しずらい
  49. 49. #UE4 | @UNREALENGINE 実装例:命名規則に応じたアセットリネーム
  50. 50. #UE4 | @UNREALENGINE 解説 UI エディットできるText BoxやButtonなどを置いただけ シンプルな構成
  51. 51. #UE4 | @UNREALENGINE 解説 UI エディットできるText BoxやButtonなどを置いただけ シンプルな構成
  52. 52. #UE4 | @UNREALENGINE 解説 Blueprint
  53. 53. #UE4 | @UNREALENGINE 解説 Blueprint ボタンが押されたら選択しているアセットを取得
  54. 54. #UE4 | @UNREALENGINE 解説 Blueprint アセットの種類毎にリネーム処理
  55. 55. #UE4 | @UNREALENGINE 解説 Blueprint 関数Asset Renameの中身
  56. 56. #UE4 | @UNREALENGINE 解説 Blueprint 処理するクラスを設定
  57. 57. #UE4 | @UNREALENGINE 解説 Blueprint リネーム処理
  58. 58. #UE4 | @UNREALENGINE 実装例:Pythonによるインスタンシング
  59. 59. #UE4 | @UNREALENGINE インスタンシング 大量のオブジェクトを描画する際に有効な手法 ドローコールを削減し、描画コストを下げる ドローコール 現在の画面を描画するために必要な情報を呼び出す命令のこと 回数が多いほど処理負荷につながる可能性がある
  60. 60. #UE4 | @UNREALENGINE インスタンス化によるドローコールの削減 非インスタンス インスタンス 9回分のドローコール 1回分のドローコール
  61. 61. #UE4 | @UNREALENGINE Instanced Static Mesh Unreal Engineでのインスタンス化メッシュ
  62. 62. #UE4 | @UNREALENGINE Instanced Static Mesh
  63. 63. #UE4 | @UNREALENGINE Instanced Static Mesh • Static Mesh
  64. 64. #UE4 | @UNREALENGINE Instanced Static Mesh • Static Mesh • インスタンス数分の位置、回転、スケール
  65. 65. #UE4 | @UNREALENGINE Static Meshをインスタンス化 ツールやスクリプトを使わずに 手作業で変換しようとすると・・・ アクタ一つ一つの位置、回転、 スケールをコピーして・・・
  66. 66. #UE4 | @UNREALENGINE Static Meshをインスタンス化 ツールやスクリプトを使わずに 手作業で変換しようとすると・・・ インスタンスに追加
  67. 67. #UE4 | @UNREALENGINE Static Meshをインスタンス化 Merge Actors 選択アクタを一つのインスタンスに変換
  68. 68. #UE4 | @UNREALENGINE Static Meshをインスタンス化 Merge Actors 選択アクタを一つのインスタンスに変換 複数インスタンスを一度に生成はできない
  69. 69. #UE4 | @UNREALENGINE Static Meshをインスタンス化 Merge Actors 多数のアクタがあるとして・・・
  70. 70. #UE4 | @UNREALENGINE Static Meshをインスタンス化 Merge Actors 複数グループに分けてインスタンス化したい場合 インスタンス化したいグループ毎に 選択して変換する作業が必要
  71. 71. #UE4 | @UNREALENGINE インスタンス化によるドローコールの削減 大量のアクタを複数インスタンス化していくのは高コスト なるべく自動で、いい感じのグループに分けてインスタンス化したい・・・
  72. 72. #UE4 | @UNREALENGINE インスタンス化によるドローコールの削減 大量のアクタを複数インスタンス化していくのは高コスト なるべく自動で、いい感じのグループに分けてインスタンス化したい・・・ Python外部ライブラリからK-means法を使ってインスタンシング!
  73. 73. #UE4 | @UNREALENGINE K-means法とは ざっくり解説 クラスタ分析を行う手法の一つ Pythonの外部ライブラリScikit Learnに含まれている
  74. 74. #UE4 | @UNREALENGINE K-means法とは ざっくり解説 バラバラな座標のリストがあるとして・・・
  75. 75. #UE4 | @UNREALENGINE K-means法とは ざっくり解説 クラスタ数=5 設定したクラスタ数に応じて、近い属性同士のグループを作る
  76. 76. #UE4 | @UNREALENGINE Unreal Pythonで外部ライブラリを使う ライブラリインストール後、PythonLibsite-packagesを EngineBinariesThirdPartyPythonWin64Lib以下に丸ごとコピー import 〇〇でインポート出来るようになる
  77. 77. #UE4 | @UNREALENGINE K-means法によるインスタンシング
  78. 78. #UE4 | @UNREALENGINE コード 1/2 import unreal import numpy as np import sklearn from sklearn.cluster import KMeans bp_instance = unreal.EditorAssetLibrary.load_blueprint_class('/Game/BP_Instance.BP_Instance') list_actors = unreal.EditorLevelLibrary.get_selected_level_actors() list_static_mesh_actors = unreal.EditorFilterLibrary.by_class(list_actors,unreal.StaticMeshActor) list_unique = np.array([]) for lsm in list_static_mesh_actors: static_mesh = lsm.get_component_by_class(unreal.StaticMeshComponent).get_editor_property("StaticMesh") list_unique = np.append(list_unique,static_mesh) list_unique = np.unique(list_unique) for lu in list_unique: list_transform = np.array([]) list_locations = np.array([[0,0,0]])
  79. 79. #UE4 | @UNREALENGINE コード 2/2 for lsm in list_static_mesh_actors: if lsm.get_component_by_class(unreal.StaticMeshComponent).get_editor_property("StaticMesh") == lu: list_transform = np.append(list_transform,lsm.get_actor_transform()) location = np.array([[lsm.get_actor_location().x,lsm.get_actor_location().y,lsm.get_actor_location().z]]) list_locations = np.append(list_locations,location,axis=0) list_locations = np.delete(list_locations,0,axis=0) num_clusters = 3 pred = KMeans(n_clusters=num_clusters).fit_predict(list_locations) instanced_components = np.array([]) for i in range(num_clusters): instanced_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(bp_instance,(0,0,0),(0,0,0)) instanced_component = instanced_actor.get_component_by_class(unreal.InstancedStaticMeshComponent) instanced_components = np.append(instanced_components,instanced_component) for j, pd in enumerate(pred): instanced_components[pd].add_instance(list_transform[j]) for k in range(num_clusters): instanced_components[k].set_editor_property("StaticMesh",lu) for lsm in list_static_mesh_actors: lsm.destroy_actor()
  80. 80. #UE4 | @UNREALENGINE 解説 1/5 #ライブラリをインポート import unreal import numpy as np import sklearn from sklearn.cluster import KMeans #インスタンス用のクラスをロード bp_instance = unreal.EditorAssetLibrary.load_blueprint_class('/Game/BP_Instance.BP_Instance') #選択しているアクタを取得 list_actors = unreal.EditorLevelLibrary.get_selected_level_actors() list_static_mesh_actors = unreal.EditorFilterLibrary.by_class(list_actors,unreal.StaticMeshActor)
  81. 81. #UE4 | @UNREALENGINE 解説 1/5 #ライブラリをインポート import unreal import numpy as np import sklearn from sklearn.cluster import KMeans #インスタンス用のクラスをロード bp_instance = unreal.EditorAssetLibrary.load_blueprint_class('/Game/BP_Instance.BP_Instance') #選択しているアクタを取得 list_actors = unreal.EditorLevelLibrary.get_selected_level_actors() list_static_mesh_actors = unreal.EditorFilterLibrary.by_class(list_actors,unreal.StaticMeshActor)
  82. 82. #UE4 | @UNREALENGINE 解説 1/5 #ライブラリをインポート import unreal import numpy as np import sklearn from sklearn.cluster import KMeans #インスタンス用のクラスをロード bp_instance = unreal.EditorAssetLibrary.load_blueprint_class('/Game/BP_Instance.BP_Instance') #選択しているアクタを取得 list_actors = unreal.EditorLevelLibrary.get_selected_level_actors() list_static_mesh_actors = unreal.EditorFilterLibrary.by_class(list_actors,unreal.StaticMeshActor)
  83. 83. #UE4 | @UNREALENGINE 解説 1/5 #ライブラリをインポート import unreal import numpy as np import sklearn from sklearn.cluster import KMeans #インスタンス用のクラスをロード bp_instance = unreal.EditorAssetLibrary.load_blueprint_class('/Game/BP_Instance.BP_Instance') #選択しているアクタを取得 list_actors = unreal.EditorLevelLibrary.get_selected_level_actors() list_static_mesh_actors = unreal.EditorFilterLibrary.by_class(list_actors,unreal.StaticMeshActor) 後で選択アクタから 位置、回転、メッシュ情報などを取得
  84. 84. #UE4 | @UNREALENGINE 解説 2/5 #メッシュの種類毎にクラスタリングするため、アクタのリストからメッシュの種類がいくつあるかを求める list_unique = np.array([]) for lsm in list_static_mesh_actors: static_mesh = lsm.get_component_by_class(unreal.StaticMeshComponent).get_editor_property("StaticMesh") list_unique = np.append(list_unique,static_mesh) list_unique = np.unique(list_unique) #インスタンスに追加するトランスフォームリストと、クラスタリングに使うための位置リストを作成 for lu in list_unique: list_transform = np.array([]) list_locations = np.array([[0,0,0]])
  85. 85. #UE4 | @UNREALENGINE 複数種類のメッシュがあった場合 Instanced Static Meshが 持てるメッシュは一種類のみ
  86. 86. #UE4 | @UNREALENGINE 複数種類のメッシュがあった場合 クラスタ数=3
  87. 87. #UE4 | @UNREALENGINE 複数種類のメッシュがあった場合 種類ごとにクラスタリング クラスタ数=3
  88. 88. #UE4 | @UNREALENGINE 複数種類のメッシュがあった場合 クラスタ数=3 種類ごとにクラスタリング
  89. 89. #UE4 | @UNREALENGINE 解説 3/5 #インスタンスに追加するトランスフォームリストと、クラスタリングに使うための位置リストを作成 for lsm in list_static_mesh_actors: if lsm.get_component_by_class(unreal.StaticMeshComponent).get_editor_property("StaticMesh") == lu: list_transform = np.append(list_transform,lsm.get_actor_transform()) location = np.array([[lsm.get_actor_location().x,lsm.get_actor_location().y,lsm.get_actor_location().z]]) list_locations = np.append(list_locations,location,axis=0) list_locations = np.delete(list_locations,0,axis=0) #クラスタリング num_clusters = 3 pred = KMeans(n_clusters=num_clusters).fit_predict(list_locations)
  90. 90. #UE4 | @UNREALENGINE 解説 3/5 #インスタンスに追加するトランスフォームリストと、クラスタリングに使うための位置リストを作成 for lsm in list_static_mesh_actors: if lsm.get_component_by_class(unreal.StaticMeshComponent).get_editor_property("StaticMesh") == lu: list_transform = np.append(list_transform,lsm.get_actor_transform()) location = np.array([[lsm.get_actor_location().x,lsm.get_actor_location().y,lsm.get_actor_location().z]]) list_locations = np.append(list_locations,location,axis=0) list_locations = np.delete(list_locations,0,axis=0) #クラスタリング num_clusters = 3 pred = KMeans(n_clusters=num_clusters).fit_predict(list_locations)
  91. 91. #UE4 | @UNREALENGINE 解説 3/5 #インスタンスに追加するトランスフォームリストと、クラスタリングに使うための位置リストを作成 for lsm in list_static_mesh_actors: if lsm.get_component_by_class(unreal.StaticMeshComponent).get_editor_property("StaticMesh") == lu: list_transform = np.append(list_transform,lsm.get_actor_transform()) location = np.array([[lsm.get_actor_location().x,lsm.get_actor_location().y,lsm.get_actor_location().z]]) list_locations = np.append(list_locations,location,axis=0) list_locations = np.delete(list_locations,0,axis=0) #クラスタリング num_clusters = 3 pred = KMeans(n_clusters=num_clusters).fit_predict(list_locations) Get_actor_location() ・・・Unreal Vector型を返す
  92. 92. #UE4 | @UNREALENGINE Unreal Vector型 Unreal Engine上でVector型をやり取りするための型 Kmeansでも使えるように
  93. 93. #UE4 | @UNREALENGINE 解説 3/5 #インスタンスに追加するトランスフォームリストと、クラスタリングに使うための位置リストを作成 for lsm in list_static_mesh_actors: if lsm.get_component_by_class(unreal.StaticMeshComponent).get_editor_property("StaticMesh") == lu: list_transform = np.append(list_transform,lsm.get_actor_transform()) location = np.array([[lsm.get_actor_location().x,lsm.get_actor_location().y,lsm.get_actor_location().z]]) list_locations = np.append(list_locations,location,axis=0) list_locations = np.delete(list_locations,0,axis=0) #クラスタリング num_clusters = 3 pred = KMeans(n_clusters=num_clusters).fit_predict(list_locations)
  94. 94. #UE4 | @UNREALENGINE 解説 3/5 #インスタンスに追加するトランスフォームリストと、クラスタリングに使うための位置リストを作成 for lsm in list_static_mesh_actors: if lsm.get_component_by_class(unreal.StaticMeshComponent).get_editor_property("StaticMesh") == lu: list_transform = np.append(list_transform,lsm.get_actor_transform()) location = np.array([[lsm.get_actor_location().x,lsm.get_actor_location().y,lsm.get_actor_location().z]]) list_locations = np.append(list_locations,location,axis=0) list_locations = np.delete(list_locations,0,axis=0) #クラスタリング num_clusters = 3 pred = KMeans(n_clusters=num_clusters).fit_predict(list_locations)
  95. 95. #UE4 | @UNREALENGINE 解説 3/5 #インスタンスに追加するトランスフォームリストと、クラスタリングに使うための位置リストを作成 for lsm in list_static_mesh_actors: if lsm.get_component_by_class(unreal.StaticMeshComponent).get_editor_property("StaticMesh") == lu: list_transform = np.append(list_transform,lsm.get_actor_transform()) location = np.array([[lsm.get_actor_location().x,lsm.get_actor_location().y,lsm.get_actor_location().z]]) list_locations = np.append(list_locations,location,axis=0) list_locations = np.delete(list_locations,0,axis=0) #クラスタリング num_clusters = 5 pred = KMeans(n_clusters=num_clusters).fit_predict(list_locations) n_clusters = 5
  96. 96. #UE4 | @UNREALENGINE 解説 3/5 #インスタンスに追加するトランスフォームリストと、クラスタリングに使うための位置リストを作成 for lsm in list_static_mesh_actors: if lsm.get_component_by_class(unreal.StaticMeshComponent).get_editor_property("StaticMesh") == lu: list_transform = np.append(list_transform,lsm.get_actor_transform()) location = np.array([[lsm.get_actor_location().x,lsm.get_actor_location().y,lsm.get_actor_location().z]]) list_locations = np.append(list_locations,location,axis=0) list_locations = np.delete(list_locations,0,axis=0) #クラスタリング num_clusters = 5 pred = KMeans(n_clusters=num_clusters).fit_predict(list_locations) 0 1 2 3 4 0 0 0 1 1 1 2 2 2 2 3 3 3 4 4 4 fit_predict
  97. 97. #UE4 | @UNREALENGINE 解説 4/5 #コンポーネントのリストを作成 instanced_components = np.array([]) #クラスタ毎にアクタをスポーン、コンポーネントをリストに入れる for i in range(num_clusters): instanced_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(bp_instance,(0,0,0),(0,0,0)) instanced_component = instanced_actor.get_component_by_class(unreal.InstancedStaticMeshComponent) instanced_components = np.append(instanced_components,instanced_component)
  98. 98. #UE4 | @UNREALENGINE 解説 4/5 #コンポーネントのリストを作成 instanced_components = np.array([]) #クラスタ毎にアクタをスポーン、コンポーネントをリストに入れる for i in range(num_clusters): instanced_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(bp_instance,(0,0,0),(0,0,0)) instanced_component = instanced_actor.get_component_by_class(unreal.InstancedStaticMeshComponent) instanced_components = np.append(instanced_components,instanced_component)
  99. 99. #UE4 | @UNREALENGINE 解説 4/5 #コンポーネントのリストを作成 instanced_components = np.array([]) #クラスタ毎にアクタをスポーン、コンポーネントをリストに入れる for i in range(num_clusters): instanced_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(bp_instance,(0,0,0),(0,0,0)) instanced_component = instanced_actor.get_component_by_class(unreal.InstancedStaticMeshComponent) instanced_components = np.append(instanced_components,instanced_component)
  100. 100. #UE4 | @UNREALENGINE 解説 4/5 #コンポーネントのリストを作成 instanced_components = np.array([]) #クラスタ毎にアクタをスポーン、コンポーネントをリストに入れる for i in range(num_clusters): instanced_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(bp_instance,(0,0,0),(0,0,0)) instanced_component = instanced_actor.get_component_by_class(unreal.InstancedStaticMeshComponent) instanced_components = np.append(instanced_components,instanced_component) スポーンするアクタは あらかじめ用意しておく Blueprintを作成し Instanced Static Meshを追加
  101. 101. #UE4 | @UNREALENGINE 解説 4/5 #コンポーネントのリストを作成 instanced_components = np.array([]) #クラスタ毎にアクタをスポーン、コンポーネントをリストに入れる for i in range(num_clusters): instanced_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(bp_instance,(0,0,0),(0,0,0)) instanced_component = instanced_actor.get_component_by_class(unreal.InstancedStaticMeshComponent) instanced_components = np.append(instanced_components,instanced_component)
  102. 102. #UE4 | @UNREALENGINE 解説 5/5 #クラスタ番号を元に親となるインスタンスを選択し、トランスフォームを追加 for j, pd in enumerate(pred): instanced_components[pd].add_instance(list_transform[j]) #スタティックメッシュを割り当て for k in range(num_clusters): instanced_components[k].set_editor_property("StaticMesh",lu) #最初に選択していたアクタを削除 for lsm in list_static_mesh_actors: lsm.destroy_actor()
  103. 103. #UE4 | @UNREALENGINE 解説 5/5 #クラスタ番号を元に親となるインスタンスを選択し、トランスフォームを追加 for j, pd in enumerate(pred): instanced_components[pd].add_instance(list_transform[j]) #スタティックメッシュを割り当て for k in range(num_clusters): instanced_components[k].set_editor_property("StaticMesh",lu) #最初に選択していたアクタを削除 for lsm in list_static_mesh_actors: lsm.destroy_actor()
  104. 104. #UE4 | @UNREALENGINE 解説 5/5 #クラスタ番号を元に親となるインスタンスを選択し、トランスフォームを追加 for j, pd in enumerate(pred): instanced_components[pd].add_instance(list_transform[j]) #スタティックメッシュを割り当て for k in range(num_clusters): instanced_components[k].set_editor_property("StaticMesh",lu) #最初に選択していたアクタを削除 for lsm in list_static_mesh_actors: lsm.destroy_actor() 空のインスタンス
  105. 105. #UE4 | @UNREALENGINE 解説 5/5 #クラスタ番号を元に親となるインスタンスを選択し、トランスフォームを追加 for j, pd in enumerate(pred): instanced_components[pd].add_instance(list_transform[j]) #スタティックメッシュを割り当て for k in range(num_clusters): instanced_components[k].set_editor_property("StaticMesh",lu) #最初に選択していたアクタを削除 for lsm in list_static_mesh_actors: lsm.destroy_actor()
  106. 106. #UE4 | @UNREALENGINE 解説 5/5 #クラスタ番号を元に親となるインスタンスを選択し、トランスフォームを追加 for j, pd in enumerate(pred): instanced_components[pd].add_instance(list_transform[j]) #スタティックメッシュを割り当て for k in range(num_clusters): instanced_components[k].set_editor_property("StaticMesh",lu) #最初に選択していたアクタを削除 for lsm in list_static_mesh_actors: lsm.destroy_actor()
  107. 107. #UE4 | @UNREALENGINE 解説 5/5 #クラスタ番号を元に親となるインスタンスを選択し、トランスフォームを追加 for j, pd in enumerate(pred): instanced_components[pd].add_instance(list_transform[j]) #スタティックメッシュを割り当て for k in range(num_clusters): instanced_components[k].set_editor_property("StaticMesh",lu) #最初に選択していたアクタを削除 for lsm in list_static_mesh_actors: lsm.destroy_actor()
  108. 108. #UE4 | @UNREALENGINE これでインスタンス化できたが・・・ 再調整したい場合は元のバラバラな状態に戻す必要がある
  109. 109. #UE4 | @UNREALENGINE 実装例:インスタンスを個別のStaticMeshに変換
  110. 110. #UE4 | @UNREALENGINE インスタンスを個別のStaticMeshに変換
  111. 111. #UE4 | @UNREALENGINE コード import unreal import numpy as np selected_actors = unreal.EditorLevelLibrary.get_selected_level_actors() for sa in selected_actors: instanced_components = np.array([]) instanced_component = sa.get_components_by_class(unreal.InstancedStaticMeshComponent) instanced_components = np.append(instanced_components,instanced_component) for ic in instanced_components: instance_transform = np.array([]) instance_count = ic.get_instance_count() for j in range(instance_count): instance_transform = np.append(instance_transform,ic.get_instance_transform(j,1)) spawned_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(unreal.StaticMeshActor,(0,0,0),(0,0,0)) spawned_actor.set_actor_transform(instance_transform[j],0,0) smc = spawned_actor.get_component_by_class(unreal.StaticMeshComponent) smc.set_editor_property("StaticMesh",ic.get_editor_property("StaticMesh")) for sa in selected_actors: sa.destroy_actor()
  112. 112. #UE4 | @UNREALENGINE 解説 1/3 #ライブラリをインポート import unreal import numpy as np #選択したアクタを取得 selected_actors = unreal.EditorLevelLibrary.get_selected_level_actors()
  113. 113. #UE4 | @UNREALENGINE 解説 1/3 #ライブラリをインポート import unreal import numpy as np #選択したアクタを取得 selected_actors = unreal.EditorLevelLibrary.get_selected_level_actors()
  114. 114. #UE4 | @UNREALENGINE 解説 1/3 #ライブラリをインポート import unreal import numpy as np #選択したアクタを取得 selected_actors = unreal.EditorLevelLibrary.get_selected_level_actors()
  115. 115. #UE4 | @UNREALENGINE 解説 2/3 #インスタンスコンポーネントを配列に入れる for sa in selected_actors: instanced_components = np.array([]) instanced_component = sa.get_components_by_class(unreal.InstancedStaticMeshComponent) instanced_components = np.append(instanced_components,instanced_component) #インスタンス数を取得 for ic in instanced_components: instance_transform = np.array([]) instance_count = ic.get_instance_count()
  116. 116. #UE4 | @UNREALENGINE 解説 2/3 #インスタンスコンポーネントを配列に入れる for sa in selected_actors: instanced_components = np.array([]) instanced_component = sa.get_components_by_class(unreal.InstancedStaticMeshComponent) instanced_components = np.append(instanced_components,instanced_component) #インスタンス数を取得 for ic in instanced_components: instance_transform = np.array([]) instance_count = ic.get_instance_count()
  117. 117. #UE4 | @UNREALENGINE 解説 2/3 #インスタンスコンポーネントを配列に入れる for sa in selected_actors: instanced_components = np.array([]) instanced_component = sa.get_components_by_class(unreal.InstancedStaticMeshComponent) instanced_components = np.append(instanced_components,instanced_component) #インスタンス数を取得 for ic in instanced_components: instance_transform = np.array([]) instance_count = ic.get_instance_count()
  118. 118. #UE4 | @UNREALENGINE 解説 2/3 #インスタンスコンポーネントを配列に入れる for sa in selected_actors: instanced_components = np.array([]) instanced_component = sa.get_components_by_class(unreal.InstancedStaticMeshComponent) instanced_components = np.append(instanced_components,instanced_component) #インスタンス数を取得 for ic in instanced_components: instance_transform = np.array([]) instance_count = ic.get_instance_count() インスタンスがいくつあるか取得し、 その数分新たにアクタをスポーンしていく
  119. 119. #UE4 | @UNREALENGINE 解説 3/3 #インスタンス数の分だけトランスフォーム値を取得 for j in range(instance_count): instance_transform = np.append(instance_transform,ic.get_instance_transform(j,1)) #スポーンしてトランスフォームを適用 spawned_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(unreal.StaticMeshActor,(0,0,0),(0,0,0)) spawned_actor.set_actor_transform(instance_transform[j],0,0) smc = spawned_actor.get_component_by_class(unreal.StaticMeshComponent) #スタティックメッシュを割り当て smc.set_editor_property("StaticMesh",ic.get_editor_property("StaticMesh")) #最初に選択していたアクタを削除 for sa in selected_actors: sa.destroy_actor()
  120. 120. #UE4 | @UNREALENGINE 解説 3/3 #インスタンス数の分だけトランスフォーム値を取得 for j in range(instance_count): instance_transform = np.append(instance_transform,ic.get_instance_transform(j,1)) #スポーンしてトランスフォームを適用 spawned_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(unreal.StaticMeshActor,(0,0,0),(0,0,0)) spawned_actor.set_actor_transform(instance_transform[j],0,0) smc = spawned_actor.get_component_by_class(unreal.StaticMeshComponent) #スタティックメッシュを割り当て smc.set_editor_property("StaticMesh",ic.get_editor_property("StaticMesh")) #最初に選択していたアクタを削除 for sa in selected_actors: sa.destroy_actor()
  121. 121. #UE4 | @UNREALENGINE 解説 3/3 #インスタンス数の分だけトランスフォーム値を取得 for j in range(instance_count): instance_transform = np.append(instance_transform,ic.get_instance_transform(j,1)) #スポーンしてトランスフォームを適用 spawned_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(unreal.StaticMeshActor,(0,0,0),(0,0,0)) spawned_actor.set_actor_transform(instance_transform[j],0,0) #スタティックメッシュを割り当て smc = spawned_actor.get_component_by_class(unreal.StaticMeshComponent) smc.set_editor_property("StaticMesh",ic.get_editor_property("StaticMesh")) #最初に選択していたアクタを削除 for sa in selected_actors: sa.destroy_actor()
  122. 122. #UE4 | @UNREALENGINE 解説 3/3 #インスタンス数の分だけトランスフォーム値を取得 for j in range(instance_count): instance_transform = np.append(instance_transform,ic.get_instance_transform(j,1)) #スポーンしてトランスフォームを適用 spawned_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(unreal.StaticMeshActor,(0,0,0),(0,0,0)) spawned_actor.set_actor_transform(instance_transform[j],0,0) #スタティックメッシュを割り当て smc = spawned_actor.get_component_by_class(unreal.StaticMeshComponent) smc.set_editor_property("StaticMesh",ic.get_editor_property("StaticMesh")) #最初に選択していたアクタを削除 for sa in selected_actors: sa.destroy_actor()
  123. 123. #UE4 | @UNREALENGINE 解説 3/3 #インスタンス数の分だけトランスフォーム値を取得 for j in range(instance_count): instance_transform = np.append(instance_transform,ic.get_instance_transform(j,1)) #スポーンしてトランスフォームを適用 spawned_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(unreal.StaticMeshActor,(0,0,0),(0,0,0)) spawned_actor.set_actor_transform(instance_transform[j],0,0) #スタティックメッシュを割り当て smc = spawned_actor.get_component_by_class(unreal.StaticMeshComponent) smc.set_editor_property("StaticMesh",ic.get_editor_property("StaticMesh")) #最初に選択していたアクタを削除 for sa in selected_actors: sa.destroy_actor()
  124. 124. #UE4 | @UNREALENGINE おまけ:UIを作る
  125. 125. #UE4 | @UNREALENGINE おまけ:UIを作る
  126. 126. #UE4 | @UNREALENGINE おまけ:UIを作る 特定のアクタを選択
  127. 127. #UE4 | @UNREALENGINE おまけ:UIを作る 特定のアクタを選択
  128. 128. #UE4 | @UNREALENGINE おまけ:UIを作る
  129. 129. #UE4 | @UNREALENGINE 実装例は後日Git Hubなどで公開予定 ※あくまで一例として作ったものなので、より実用的にするには改良が必要 ※公開した実装例の保守、サポートは致しません
  130. 130. #UE4 | @UNREALENGINE 参考 Unreal Python API リファレンス https://api.unrealengine.com/INT/PythonAPI/
  131. 131. #UE4 | @UNREALENGINE 参考 Mclarenによる事例:ホワイトペーパー Unreal Studio を使用した CAD データの準備および リアルタイム ビジュアライゼーションでの自動化 https://cdn2.unrealengine.com/Unreal+Engine%2Fresources%2FMcLaren+W hitepaper%2FADCaV-Whitepaper-JPN-V2- f4fd0b09e8b279171149eef9220370e1b7495092.pdf
  132. 132. #UE4 | @UNREALENGINE ご清聴ありがとうございました

×