452.6K Views
June 10, 20
スライド概要
2020年6月10日に公開された「GAME CREATORS CONFERENCE '20」の動画配信で使用した資料です。
・公式HP
http://www.gc-conf.com/
・Youtube動画ページ
https://www.youtube.com/watch?v=x67C_RqRVrg
Unreal Engineを開発・提供しているエピック ゲームズ ジャパンによる公式アカウントです。 勉強会や配信などで行った講演資料を公開しています。 公式サイトはこちら https://www.unrealengine.com/ja/
UE4で作成するUIと最適化手法 Epic Games Japan Software Engineer, Developer Relations 鍬農 健二郎 #UE4 | #gcconf2020
何故UIをやるのか? #UE4 | #gcconf2020
概要 ● 目的 ● UMGを使って効率的にUIを構築できる ● UIの最適化方法を適用できる ● 対象 ● UMGを利用するアーティスト ● 実装や最適化をするエンジニア、TA ● 適用範囲 UE 4.25 #UE4 | #gcconf2020
本日のお題 設計 仕組み #UE4 | #gcconf2020 最適化
本日のお題 ● 設計 ● レイアウト設計 ● クラス設計 … アート … エンジニア ● 仕組み ● ライフサイクル … エンジニア ● 最適化 ● オプション ● デバッグ #UE4 | #gcconf2020 … アート、エンジニア … アート、エンジニア
https://www.slideshare.net/EpicGamesJapan/umg-80334310 UMGを基礎から学びたい方はコチラがおすすめ #UE4 | #gcconf2020
目次 ● 設計 ● レイアウト設計 ● クラス設計 ● 仕組み ● 最適化 #UE4 | #gcconf2020
レイアウト設計 #UE4 | #gcconf2020
レイアウト設計は悩む 再利用 見栄え 無駄なく #UE4 | #gcconf2020
おさらい ● Widget 小さな機能単位の表示要素 ● User Widget Widgetを組み合わせて作成する表示要素 ⇒ Main Widget, Sub Widget #UE4 | #gcconf2020
Widget Sub Widget Widget #UE4 | #gcconf2020
User Widget レイアウト Main Widget #UE4 | #gcconf2020 ボタンセット アタックボタン Sub Widget
レイアウト設計での課題 ● ● ● ● ウィジェットを配置する基準は? ウィジェットの使い分け方は? ウィジェットを再利用する方法は? アニメーションを再利用する方法は? #UE4 | #gcconf2020
課題1:ウィジェットを配置する基準は? ● ウィジェットを配置する理由を意識する 何故それを使ったか説明できるように配置する ● レイアウトが常に変わることを意識する レイアウト変更、マルチプラットフォームに対応 #UE4 | #gcconf2020
Widgetの配置例 #UE4 | #gcconf2020
Widgetの配置例 複数の子Widgetをレイヤー管理するため ポーズ中に背景をぼかすため (ブラー効果) 子Widgetにアンカーを適用するため 子Widgetで埋めるため #UE4 | #gcconf2020
Widgetの配置例 範囲を必ず指定の大きさにするため ボタンで横幅を埋めるため ポーズメニュー上にオプション画面を被せるため #UE4 | #gcconf2020
Main Widgetの配置例 Switcher Named Slot Safe Zone (表示物を切り替えて表示) (上位レイヤーに被せて表示) (可変レイアウト表示) #UE4 | #gcconf2020
Sub Widgetの配置例 #UE4 | #gcconf2020
Sub Widgetの配置例 全体をスケールするため 複数の子Widgetを管理するため #UE4 | #gcconf2020
Sub Widgetの配置例 コンテンツを縦に敷き詰めて配置するため ポップアップの説明欄は固定サイズで表示するため #UE4 | #gcconf2020
課題2: ウィジェットの使い分け方は? ● 機能を実現できるもの やりたいことを実現できるものを選択する ● 拡張性が良いもの コンテンツの追加や削除など変更に強いものを選択する ● コストが低いもの 同じ機能でもWidget別でコストの違いがある #UE4 | #gcconf2020
Widgetの使い分け 例:複数の子Widgetをレイヤ管理 Canvas Panel vs Overlay 例:スクロール表示と操作 Scroll Box vs List View #UE4 | #gcconf2020
課題3: ウィジェットを再利用するには? ● Widgetを拡張する コンテンツに併せてWidgetを使いやすくする ● Widgetを組み合わせる コンテンツに合った新しいWidgetを作成する #UE4 | #gcconf2020
Widget (Text Block) [問題点] テキストの設定を毎回調整する必要がある #UE4 | #gcconf2020
Textのフォントやサイズを簡単に設定できるようにした例 #UE4 | #gcconf2020
テキストスタイルを指定して適用する例 #UE4 | #gcconf2020
カスタムテキストスタイルの例 #UE4 | #gcconf2020
Widget (Button) [問題点] 似たような機能やデザインのボタンが増える #UE4 | #gcconf2020
例えばこのようなOK/Cancelの選択肢で同じボタンを使い回したい... #UE4 | #gcconf2020
サブウィジェット上に配置した共有Widgetを選択して書き換え #UE4 | #gcconf2020
課題4: アニメーションを再利用するには? ● 共通のWidgetを利用してリソースのみ差し替え 共通Widgetのアニメーションを常に利用する ● 親子関係を利用してアニメーションを適用 スケールやカラーなど親Widgetの変更に追従させる #UE4 | #gcconf2020
アニメーションの再利用 ● 共通のWidgetを利用してリソースのみ差し替え Texture A Image Basic Button Animation Common Widget #UE4 | #gcconf2020 リソース 差し替え Basic Button Animation
共有するWidgetにアニメーションを仕込んでおく #UE4 | #gcconf2020
例えば、ボタンの場合はプレス時のアニメーション #UE4 | #gcconf2020
配置先でリソースを差し替えておくことで、 #UE4 | #gcconf2020
同じアニメーションを再生することが可能になる #UE4 | #gcconf2020
ボタンイメージの更新 ボタンテキストの更新 共有Widgetは上書きするプロパティをDesignerに反映させるためにPreConstructでセット #UE4 | #gcconf2020
アニメーションの再利用 ● 親子関係を利用してアニメーションを適用 Content Root 対象を 子に追加 Popup Content Root Animation #UE4 | #gcconf2020 Animation
ポップアップを管理するためのマネージャクラス (親Widget)を準備 #UE4 | #gcconf2020
ポップアップ共通のアニメーションを親のWidgetに仕込んでおく #UE4 | #gcconf2020
アニメーションを適用するWidgetの子に対象を追加 #UE4 | #gcconf2020
子Widgetに対してScale変更やOpacity変更が伝搬 #UE4 | #gcconf2020
その他考察事項 ● キャンバスパネルの多用を避ける ● ネガティブパディングの設定を避ける ● 複製するならサブウィジェット化する、など #UE4 | #gcconf2020
レイアウト設計のまとめ ● わかりやすさ、再利用、コストを意識する ● デザインするUIとの折り合いをつける #UE4 | #gcconf2020
クラス設計 #UE4 | #gcconf2020
クラス設計も迷う 再利用 複雑さ 分担 #UE4 | #gcconf2020
Widgetのクラス設計についての例 UMGのベストプラクティス 公式ブログで紹介しているので参考になります #UE4 | #gcconf2020
おさらい ウィジェットブループリントを新規作成する時にデフォルト のParent classはUser Widgetである #UE4 | #gcconf2020
おさらい User Widgetクラスはレイアウトに配置したり追加したり 削除することができる #UE4 | #gcconf2020
おさらい [!] Widget Blueprintの制約 ● Widget Blueprintは Designer上の配置情報を継承しない ● Parent #UE4 | #gcconf2020 配置情報が継承されないことを前提に設計する必要がある Child
クラス設計での課題 ● Widgetの構造をどうするか? ● Widgetの実装をどうするか? ● Widgetの接続をどうするか? #UE4 | #gcconf2020
課題1: Widgetの構造をどうするか? ● Widgetの役割に応じて適切に配置する Engineの機能とクラスを理解しておく ● ネイティブクラスを作成する プロジェクト独自の機能を追加して使いやすくする #UE4 | #gcconf2020
Widget/UMG関連のEngineクラスの一部 UObject UVisual UWidget UPanelSlot UUserWidget UPanelWidget UImage Widget Blueprint UCanvasPanel UHorizontalBox ここだけは最低限覚えておく (それ以外はイメージだけでOK) #UE4 | #gcconf2020 UContentWidget UButton
Widget/UMG関連のEngineクラスの一部 UObject UVisual UWidget UPanelSlot UUserWidget UPanelWidget UImage UCanvasPanel UHorizontalBox ユーザー定義のWidget #UE4 | #gcconf2020 UContentWidget UButton
Widget/UMG関連のEngineクラスの一部 UObject UVisual 子を格納可能なWidget UWidget UPanelSlot UUserWidget UPanelWidget UImage UCanvasPanel UHorizontalBox UContentWidget UButton #UE4 | #gcconf2020
Widget/UMG関連のEngineクラスの一部 UObject UVisual 水平方向に格納可能なWidget UWidget UPanelSlot UUserWidget UPanelWidget UImage UCanvasPanel UHorizontalBox レイヤー管理可能なWidget #UE4 | #gcconf2020 UContentWidget UButton
Widget/UMG関連のEngineクラスの一部 UObject UVisual 1つの子を格納可能なWidget UWidget UPanelSlot UUserWidget UPanelWidget UImage UCanvasPanel UHorizontalBox UContentWidget UButton #UE4 | #gcconf2020
Widget/UMG関連のEngineクラスの一部 UObject UVisual UWidget UPanelSlot UUserWidget UPanelWidget UImage UCanvasPanel UHorizontalBox UContentWidget UButton 独自の機能を持つWidget #UE4 | #gcconf2020
Widget/UMG関連のEngineクラスの一部 Engine Native Blueprint UObject プロジェクトで作成するWidgetの クラス構成はどうする? UVisual UWidget UPanelSlot UUserWidget UPanelWidget UImage Widget Blueprint UCanvasPanel UHorizontalBox UContentWidget UButton #UE4 | #gcconf2020
ActionRPG サンプルの場合 入力ボタン 入力ラベル #UE4 | #gcconf2020
ActionRPG のクラス Engine Native UWidget UUserWidget シンプルな構成なので Parent Classは全てUserWidget WB_InputLabel #UE4 | #gcconf2020 WB_InputButton Blueprint
ActionRPG のクラスを拡張 Engine Native UWidget UUserWidget プロジェクト独自の ネイティブクラスを追加 UCustomWidget UCustomButton WB_InputLabel #UE4 | #gcconf2020 WB_InputButton Blueprint
ActionRPG のクラスを拡張 Engine UWidget UUserWidget プロジェクト独自の 共通Widget UCustomWidget UCustomButton WB_InputLabel #UE4 | #gcconf2020 WB_InputButton Native Blueprint
ActionRPG のクラスを拡張 Engine UWidget 基本的にWidgetは 共通Widgetから作成 UUserWidget UCustomWidget UCustomButton WB_InputLabel #UE4 | #gcconf2020 WB_InputButton Native Blueprint
ActionRPG のクラスを拡張 Engine UWidget ボタンWidget 共通の処理 UUserWidget UCustomWidget UCustomButton WB_InputLabel #UE4 | #gcconf2020 WB_InputButton Native Blueprint
ActionRPG のクラスを拡張 Engine Native Blueprint UWidget UUserWidget 追加になっても 変更点のみの追加でOK UCustomWidget UCustomButton WB_InputLabel #UE4 | #gcconf2020 WB_InputButton WB_ButtonText
プロジェクトで拡張するカスタムテキスト例 UWidget UTextLayoutWidget UTextBlock #UE4 | #gcconf2020 エンジンのデフォルトテキスト Engine Native Blueprint
プロジェクトで拡張するカスタムテキスト例 UWidget UTextLayoutWidget UTextBlock UCustomText #UE4 | #gcconf2020 Engine プロジェクトのカスタムテキスト Native Blueprint
課題2: Widgetの実装をどうするか? ● BlueprintとC++の線引きをしておく 責任の範囲を決めて実装する ● 可能な限り小さなWidgetに分割する 作業の競合、ロードなどに影響 #UE4 | #gcconf2020
Widget実装の分担 Blueprint Class ● ● ● デザイナに配置したWidgetの制御 アニメーションの制御 C++から提供されたAPI アート Native Class (C++) ● ● ● #UE4 | #gcconf2020 データの受け渡し 複雑でコストが高い計算や処理 他クラスとのやりとり、UI更新の通知 エンジニア
Widgetの実装分担 (Blueprint) 作業者A ● Designerの内容 ● Widget表示切替 ● アニメーション再生 #UE4 | #gcconf2020
Widgetの実装分担 (C++) 作業者B ● トリガーイベント ● コンテンツ情報 ● BPで使用するAPI #UE4 | #gcconf2020
Widgetの実装分担 (C++の実装ルール) ● Abstract Native Classは常に抽象化する ● NotBlueprintable 他のNative Classの基底クラスになるもの ● Blueprintable 派生してBlueprintで継承可能なもの #UE4 | #gcconf2020
課題3: Widgetの接続をどうするか? ● Native ClassとSubsystemを活用する Widget Blueprint から直接別のクラスに参照するすることもできるが、 サブウィジェットはできる限り他のクラスと参照を持たない方が望ましい #UE4 | #gcconf2020
https://www.slideshare.net/EpicGamesJapan/ue4-subsystem SubSystemを基礎から学びたい方はコチラがおすすめ #UE4 | #gcconf2020
ネイティブクラス経由でWidgetの内容を更新する Engine Native Blueprint ● Initialize Health Bar Bar Widget Custom Player OnChangeValue() ● Update Apply Damage Health Bar Update Bar Widget Custom Player OnChangeValue() #UE4 | #gcconf2020 Action Apply Heal Item
サブシステム経由でWidgetの内容を更新する Engine Native Blueprint ● Initialize Weather Icon Custom Widget Weather SubSystem OnChangeStatus() ● Update Change Weather Weather Icon Custom Widget Weather SubSystem OnChangeStatus() #UE4 | #gcconf2020 Action Time
クラス設計のまとめ ● クラスの役割を明確にして分離する ● ネイティブクラスを効果的に利用する #UE4 | #gcconf2020
目次 ● 設計 ● 仕組み ライフサイクル ● 最適化 #UE4 | #gcconf2020
仕組みを理解するのは色々と役に立つ ● Widgetへの機能追加が容易になる ● ボトルネックの勘所が分かるようになる ● 最適化のオプションを理解して適用できる 効率化! #UE4 | #gcconf2020
例:UIの処理が重いらしい とりあえずUnreal Insightsのグラフをみても 何が原因なのか分からない #UE4 | #gcconf2020
UIの処理の仕組みが分かっていれば Tick SlatePrepass Paint AddElement たしかこう動いていたので #UE4 | #gcconf2020
なんかUIの処理が重いらしい Misc SlatePrepass Paint Slateはこんなに処理負荷があった ⇒ 〇〇の最適化を入れよう #UE4 | #gcconf2020 Add Element
おさらい Widgetは内部的に2つのパーツで構成される ● ● UWidget SWidget Engine :Slateに対する制御など他のObjectと対話 :レイアウトやインタラクションなどユーザーと対話 UWidget SWidget (制御部) (表示部) Widget #UE4 | #gcconf2020 User
シンプルなWidgetの開始と終了 #UE4 | #gcconf2020
シンプルなWidgetの開始と終了 Create OnScreen Remove #UE4 | #gcconf2020
Widget Lifecycle Create OnScreen Tick Remove Destroy 生成 追加 更新 除去 破棄 5つのステップ #UE4 | #gcconf2020
フローとオブジェクトの変化 フロー Create OnScreen Tick Remove Destroy オブジェクト UWidget #UE4 | #gcconf2020 UWidget UWidget SWidget SWidget UWidget
Widget Lifecycle 生成 Create #UE4 | #gcconf2020 OnScreen Tick Remove Destroy
Create Widget Create CreateWidget NewObject Initialize 生成処理開始 UWidgetと 関連するUObjectの生成 1度だけ呼ばれる #UE4 | #gcconf2020
Create Widget (負荷ポイント) Create 参照オブジェクトの過多で ロード時のヒッチ等に注意 CreateWidget NewObject Widgetと関連 オブジェクトのロード Widgetと関連 オブジェクトの生成 #UE4 | #gcconf2020 Initialize
Widget Lifecycle 追加 Create #UE4 | #gcconf2020 OnScreen Tick Remove Destroy
OnScreen Widget OnScreen AddToViewport TakeWidget RebuildWidget Viewportに登録 SWidgetの生成開始 SWidgetの生成 Construct PreConstruct Synchronize Properties 構築完了 構築完了 (Begin Play) (Construction Script) #UE4 | #gcconf2020 UWidgetとSWidget の同期
OnScreen Widget (負荷ポイント) 対象が多いとヒッチ発生 初期化の負荷分散も検討 OnScreen AddToViewport TakeWidget RebuildWidget スレート インスタンス生成 Construct PreConstruct Widget Blueprintの 初期化処理が集中 #UE4 | #gcconf2020 Synchronize Properties
Widget Lifecycle 更新 Create #UE4 | #gcconf2020 OnScreen Tick Remove Destroy
Tick Widget Tick SlatePrepass 子Widgetを含む スケールの適用 #UE4 | #gcconf2020 Paint AddElement 子Widgetを含む Render Batchの作成
Tick Widget (負荷ポイント) Tick SlatePrepass 全てのWidgetを 走査してスケール適用 #UE4 | #gcconf2020 Widgetが多いと負荷になりがち キャッシュを使って負荷制御を Paint AddElement 全てのWidgetを 走査して描画情報作成
Tick Widget …… …… …… …… …… x2.0 x1.0 x2.0 x1.0 x1.2 Id:1 Id:2 Id:3 Id:4 SlatePrepass Paint AddElement レイアウト決め 下書き作成 設計書作成 #UE4 | #gcconf2020
スレッドを跨いで描画情報を通知 Game Threadは描画に必要な情報を作成するだけ ⇒ Render ThreadがRHIコマンドを作成してGPUに転送 Game Thread Render Thread #UE4 | #gcconf2020 レイアウト 決め 下書き 作成 設計書 作成 RHI Cmd 作成
Widget Lifecycle 除去 Create #UE4 | #gcconf2020 OnScreen Tick Remove Destroy
Remove Widget Remove RemoveFrom Parent Destruct ReleaseSlate Resources Viewportから削除 除去開始 (End Play) SWidgetの削除 #UE4 | #gcconf2020
Remove Widget (負荷ポイント) Remove RemoveFrom Viewport Destruct ReleaseSlate Resources SWidgetの削除 #UE4 | #gcconf2020
Widget Lifecycle 破棄 Create #UE4 | #gcconf2020 OnScreen Tick Remove Destroy
Destroy Widget マップ遷移等によるGC Destroy BeginDestroy Destructor Widgetの破棄開始 UWidgetの削除 #UE4 | #gcconf2020
Destroy Widget (負荷ポイント) マップ遷移等によるGC Destroy BeginDestroy GC対象のObject過多による ヒッチに注意 Destructor UWidgetと関連する オブジェクトの破棄 #UE4 | #gcconf2020
ライフサイクルのまとめ ● フロー毎の負荷ポイントに注意する ● 動作を理解した上で次章の最適化を適用する #UE4 | #gcconf2020
目次 ● 設計 ● 仕組み ● 最適化 #UE4 | #gcconf2020
目次 ● デザイン ● メカニズム ● 最適化 ● オプション ● ツール #UE4 | #gcconf2020
最適化オプション ● ● ● ● ● ● ● バインディング Tick Visibility Widget Blueprint Option Text Option Invalidation Box Global Invalidation #UE4 | #gcconf2020 ● ● ● ● Retainer Box リソース ネイティブ化 ウィジェットアニメーション
バインディング Widgetへの値の反映はイベント駆動の実質一択 プロパティバインド、関数バインドは毎フレーム値の更新をチェックする ので高コスト故、殆ど使わない ● プロパティバインド #UE4 | #gcconf2020 イベント駆動
Tick ● Tickでの実装 ● BlueprintのTickはコストが高いので極力避ける ● 必要な場合はNativeコードのTickを使う #UE4 | #gcconf2020
Tick ● Tickの設定 ● デフォルトはAutoで自動的にON/OFFを切り替え ● NeverにするとTickを停止できるが以下の機能が制限される ● ● ● ● #UE4 | #gcconf2020 Widget Animation Latent Action Native Tick Blueprint Tick
Tick ● 補足 Autoに設定されたNative TickはいつONとなるか? ● ● ● ● Latent Action (Delayなど)がトリガーされる アニメーションがトリガーされる BlueprintのTickイベントが実装されている ネイティブクラスで指定されていない UCLASS(meta = (DisableNativeTick)) Tickを利用しない場合は、meta指定がおススメ #UE4 | #gcconf2020
Visibility Widgetの可視性やヒットテスト可否の設定 ● インタラクションだけでなくパフォーマンスにも影響 ● その時の状況に応じて適切にコントロールする必要がある #UE4 | #gcconf2020
Visibility ● ● ● デフォルトは Visbility (最もコストが高い) 設定になっている Widgetを表示する場合は判定が不要ならNot Hit-Testableを利用 Widgetを表示しない場合はCollapsedがコスト的に望ましい プリセット 表示 ヒット判定 レイアウト更新 Visible あり あり あり Not Hit-Testable (Self Only) あり 自身はなし あり Not Hit-Testable (Self&All childeren) あり なし あり Hidden なし なし あり Collapsed なし なし なし #UE4 | #gcconf2020 高 コ ス ト 低
Widget Blueprint Option ● Force Slow Construction Path ● ● 無効にすると、Widget Templateを利用して高速にTreeを構築 有効にすると、構築コストがかかるがアセットサイズを抑制 ● Support Dynamic Creation ● ● #UE4 | #gcconf2020 無効にすると、動的な生成を許可しない代わりにアセットサイズを抑制 有効にすると、CreateWidget()による動的生成を許可する
Text Option ● Wrap with Invalidation Panel ● ● Invalidation Panelを生成してText Blockを自動でラップする機能 Text BlockとInvalidation Panelの更新のトレードオフ ● Simple Text Mode ● ● #UE4 | #gcconf2020 テキスト整形, 折り返し, 位置補正処理を無効化して高速化する テキスト機能とパフォーマンスのトレードオフ
Invalidation Box ● 機能 子Widgetをキャッシュすることで更新処理をスキップして高速化 フレーム1 Invalidation Box 未適用 フレーム2 フレーム3 フレーム4 処理 Invalidation Box 適用 IBを適用することで更新処理による負荷を軽減 #UE4 | #gcconf2020 フレーム5
Invalidation Box ● 使い方 Invalidation Boxで対象のWidget をラップ、効果はラップした対象 全てに影響 ● 設定 CanCacheを有効にする (デフォルト有効) #UE4 | #gcconf2020
Invalidation Box 適用することで定常的なwidgetの更新コストを抑制する 適用前 #UE4 | #gcconf2020 適用後
適用前 Tick SlatePrepass Paint AddElement 適用後 Tick SlatePrepass #UE4 | #gcconf2020 キャッシュを利用して処理スキップ Paint AddElement
Global Invalidation ● 機能 (早期公開版) ● Invalidation Panelのキャッシュ効果をSlate全体に適用する機能 ● Invalidation BoxとGlobal Invalidationの併用は不可 ● レイアウト変更が生じた際にも自動的にキャッシュを無効化 ● 使い方 ● ”Slate.EnableGlobalInvalidation 1”を入力 ● #UE4 | #gcconf2020 PIE時は ”New Editor Window (PIE)”のみ有効
Global Invalidation ● 効果検証 単にImageを2000枚並べただけのケース #UE4 | #gcconf2020
Global Invalidation Disable Enable Invalidation Panelを配置せずとも Slate全体にキャッシュ適用されてコストダウン #UE4 | #gcconf2020
Global Invalidation Disable Enable 全てのBatch Elementはキャッシュされる 毎フレームのPaint処理もキャッシュによってコスト削減 #UE4 | #gcconf2020
Retainer Box ● 機能 Render Targetに描画して更新処理を任意にスキップする フレーム1 Retainer Box 未適用 フレーム2 フレーム3 フレーム4 処理 Retainer Box 適用 RBを適用することで更新処理による負荷を軽減 #UE4 | #gcconf2020 フレーム5
Retainer Box ● 使い方 Retainer Boxで対象のWidgetを ラップ、効果はラップした対象全 てに影響 ● 設定 5フレームの周期で、フェーズ0 (1フレーム目)で更新処理を行う場 合は右図のように設定する #UE4 | #gcconf2020
Retainer Box 結果として下記のように, 1フレーム, 6フレーム, ...と、5フレーム毎 に更新が継続して実行されるように #UE4 | #gcconf2020
リソース (Texture) Export形式 .png/.tgaでエクスポート、圧縮の観点から2のべき乗サイズを利用 ● 圧縮形式 [UserInterface2D]は非圧縮 通常は[DXT]が使用されるが用途次第で変える Texture Groupは[UI]を利用 ● ● ● アルファ ● ● #UE4 | #gcconf2020 リソースサイズが大きくなるため必要なものに限定して利用 単なるフェードで半透明を適用するならWidgetの機能で可能
リソース (Texture) Texture Size ● ● テクスチャでメモリを占有しすぎないようにテクスチャサイズを調整 小さい表示物、重要でない表示物に巨大なサイズを割り当てない ● ● テクスチャ解像度がターゲットと一致しない場合は[No Mip Maps] テクスチャを縮小して使用する場合などは[From Texture Group] Mips #UE4 | #gcconf2020
ネイティブ化 Widget Blueprintをネイティブ化は効果がある...? メリット ● ● UObjectが減ることでロードやGC時間が改善できるが効果は実装次第 CPU処理はBlueprintアクセスのコストが削減されて恩恵を受ける デメリット ネイティブ化されたコードを含むサイズの増加 ● Widgetで発生した問題の切り分けの複雑化 ● #UE4 | #gcconf2020
ネイティブ化 変数などのUObjectは変わらず、マクロなどBPに影響 ネイティブ化前 #UE4 | #gcconf2020 ネイティブ化後
ウィジェットアニメーション ● 今までの課題 ● ● 複雑なアニメーションの高い評価コスト インスタンス化されたアニメーションによる長いロード ● 改善された点 ● ● #UE4 | #gcconf2020 UE4.22 : Widget Animationを共通化 UE4.25:UProperty → FProperty に置き換え
● 4.22以前 (オブジェクト数が多かった) Button Blueprint Open Anim ボタンを2つ 追加 Press Anim Hover Anim ● Button Button Blueprint Button Blueprint Blueprint Open Anim Open Anim PressOpen AnimAnim Press Anim Hover AnimAnim Press Hover Anim Hover Anim 4.22以降 (オブジェクト数が削減された) Button Blueprint Open Anim Press Anim Hover Anim #UE4 | #gcconf2020 ボタンを2つ 追加 Button Button Blueprint Button Blueprint Blueprint Open Anim Press Anim Hover Anim
Widget AnimationとUObject数の推移 Case1 :アニメーションなしの状態 アニメーション なし Class Total #UE4 | #gcconf2020 Count 39 NumKB 11.89
Widget AnimationとUObject数の推移 Case2 :アニメーション1つ追加 1アニメーション Class Total #UE4 | #gcconf2020 Count 42 NumKB 13.42
Widget AnimationとUObject数の推移 Case3 :アニメーション1つとTransformトラック1つを追加 1アニメーション+1トラック Class Total #UE4 | #gcconf2020 Count 46 NumKB 16.17
Widget AnimationとUObject数の推移 アニメーションやトラックを追加するとコストが増えます #UE4 | #gcconf2020
Widget AnimationとUObject数の推移 アニメーションやトラック追加時のObject数の変化 (UE4.24) #UE4 | #gcconf2020
Engine VersionとUObject推移 バージョンによる推移は? 1アニメーション+1トラック (UE4.24) Class Total Count NumKB 46 16.17 1アニメーション+1トラック (UE4.25) Class Total #UE4 | #gcconf2020 Count ??? NumKB ???
Engine VersionとUObject推移 Object数は以前の40%削減、サイズは50%超の削減 #UE4 | #gcconf2020
Engine VersionとUObject推移 Widget数による傾向は? 1アニメーション+1トラック × 1 Class Total Count 46 NumKB 16.17 1アニメーション+1トラック × 10 Class Total #UE4 | #gcconf2020 Count ??? NumKB ???
Engine VersionとUObject推移 以前に比べてWidget数が増えても Object数は54%削減、サイズは71%縮小 #UE4 | #gcconf2020
Engine VersionとUObject推移 Engine Versionの更新に伴うAnimation付きWidgetのObject数の変化 #UE4 | #gcconf2020
デバッグ ● パフォーマンス計測 ● ● Stats Unreal Insights ● 設定の確認 ● ● #UE4 | #gcconf2020 Widget Reflector Asset Audit ● 動作の追跡 ● ● Slate Debugger Debug Tools
デバッグ コンソールコマンド:Stat Slate ● スレートに関するパフォーマンスを計測するコマンド ● Statsを描画するコストが追加されるので目安程度に ● ただしボトルネックのポイントを特定するのに有用 #UE4 | #gcconf2020
Stat Slate レイアウト更新処理 ⇒ 表示物(ジオメトリ)が多い エレメント追加処理 ⇒ バッチ処理が多い #UE4 | #gcconf2020
デバッグ Unreal Insights ● アプリケーションのパフォーマンスをプロファイルする ● Slate専用イベント (“Stat Slate”の対象)もキャプチャ可能 #UE4 | #gcconf2020
Unreal Insights レイアウト更新処理 ⇒ 表示物(ジオメトリ)が多い Tick処理 ⇒ Tickが動いているSlateが多い #UE4 | #gcconf2020
デバッグ Widget Reflector ● 利用中のリソースや設定をキャプチャして解析できるツール [UE4] Widget Reflectorを使ってリソースや設定を調べよう #UE4 | #gcconf2020
デバッグ Asset Audit ● アセットの情報をリスト化して確認できるツール #UE4 | #gcconf2020
Asset Audit Tick駆動予測 ⇒ 適切な稼働か? Property Bind数 ⇒ イベント駆動の方法に変更? #UE4 | #gcconf2020
デバッグ コンソールコマンド:SlateDebugger.Start ● フォーカスの移行、キャプチャ、入力系イベントなどの Slateイベントをログに出力 #UE4 | #gcconf2020
デバッグ Debug Tools ● Slateに関連する様々なデバッグ機能を提供するツール #UE4 | #gcconf2020
Test Suite #UE4 | #gcconf2020
関連リンク ● 公式ドキュメント UMG (Unreal Motion Graphics) のベスト プラクティス ● 公式ブログ UMG のベスト プラクティス ● 公式スライド 猫でも分かるUMG ● UE4 ANSWERHUB 情報共有:UMGミーティングの資料 #UE4 | #gcconf2020
#UE4 | #gcconf2020