Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

なぜなにFProperty - 対応方法と改善点 -

5.961 Aufrufe

Veröffentlicht am

講演動画:https://www.youtube.com/watch?v=tqzJSVrnqgY

UE4.25にてUProperty は FProperty にリファクタリングされました。この対応によりロード時間・パフォーマンス・メモリ消費量が改善されましたが、プロジェクトやエンジンのカスタムした箇所のC++コードに変更を加える必要があります。この動画ではそれらの詳細について解説いたします。

講師:Software Engineer Developer Relations, 鈴木 孝司 ( https://twitter.com/wankotank )

#EGJオンラインラーニング
https://www.unrealengine.com/ja/blog/connect-with-the-unreal-engine-community-online

Veröffentlicht in: Ingenieurwesen
  • Als Erste(r) kommentieren

なぜなにFProperty - 対応方法と改善点 -

  1. 1. なぜなにFProperty 対応方法と改善点 Epic games Japan Software Engineer, Developer Relations 鈴木孝司
  2. 2. #UE4 | @UNREALENGINE はじめに UnrealEngine4は常に開発者が使うエディタやプレイヤーが触れるランタイムの パフォーマンスについて全ての面で改善を続けています。 先ほどリリースされたUnrealEngine4.25でも多数の様々な華々しい新機能の他に も重要な改善がいくつも盛り込まれています。 今日はそのうちの一つ、FPropertyを解説します。 UnrealEngine 4.25 Release Highlights https://www.youtube.com/watch?v=TzfeMiJPlVs
  3. 3. #UE4 | @UNREALENGINE UnrealEngine 4.25 Release Note https://docs.unrealengine.com/ja/Support/Builds/ReleaseNotes/4_25/index.html
  4. 4. #UE4 | @UNREALENGINE 目次 ・本日の主役紹介 ・[寄り道]リフレクション ・FProperty ・対応方法 ・改善点 ・まとめ
  5. 5. #UE4 | @UNREALENGINE 目次 ・本日の主役紹介 ・[寄り道]リフレクション ・FProperty ・対応方法 ・改善点 ・まとめ
  6. 6. #UE4 | @UNREALENGINE 本日の主役たちの紹介 UPropertyUObject UClass
  7. 7. #UE4 | @UNREALENGINE UObject UE4で接頭詞UがつくクラスはUObject派生クラスです。 UObjectはクラス(UClass)を持ちます。 アンリアルエンジンのコアとなる部分でこれによってメモリ管理や各種機能の基 盤が作られています。 UObject GetClass() UClass UMyObject::StaticClass() UClass
  8. 8. #UE4 | @UNREALENGINE クラス UClass UClassはそのオブジェクトの構造を保持しています。 内部にUFunction,UEnum,UPropertyなどの要素のリストを持ち、 これらが組み合わさって「リフレクション」を提供します UClass UFunction 生成されたオブジェクト UProperty NewObject() このUClassを参考に 新しいオブジェクトを 作ってください!
  9. 9. #UE4 | @UNREALENGINE プロパティ UProperty プロパティはクラスの構成要素として変数を定義します。 ピチピチの代役が設定されて降板が決まった今回の主役です。 UClass UFunction UVectorProperty 名前 : Velocity UMapProperty 名前 : ConvertionMap UFloatProperty 名前 : Health UFunction
  10. 10. #UE4 | @UNREALENGINE プロパティ - ブループリント ネイティブクラスと同様にブループリントクラスにも クラスの構造などの定義のためにプロパティが利用されています。 C++ネイティブクラス UClass 関数 UProperty(変数) 列挙子 ブループリントクラス UBlueprintGeneratedClass 関数 UProperty(変数) 列挙子
  11. 11. #UE4 | @UNREALENGINE プロパティ - ブループリント ブループリントの変数やノード、実行ノードの戻り値などもプロパティです。
  12. 12. #UE4 | @UNREALENGINE 目次 ・本日の主役紹介 ・[寄り道]リフレクション ・FProperty ・対応方法 ・改善点 ・まとめ
  13. 13. #UE4 | @UNREALENGINE リフレクション 通常c++では関数名や変数名などのソースファイルが持っていた情報は コンパイル時にその本来の名前は省略された形で機械語に翻訳されます。 例えば関数 HogeHogeFunc を定義したとしてもプログラム中から HoegeHogeFunc という名前や定義を使ってなにか処理することは出来ません。 リフレクションはこれらの情報を静的または動的に構築しランタイム時に利用す ることです。 UE4は静的にリフレクションを作成します。
  14. 14. #UE4 | @UNREALENGINE 素のC++ class FYourClass { static void HogeHogeFunc(); FVector FooLocation; } コンパイル
  15. 15. #UE4 | @UNREALENGINE class FYourClass { static void HogeHogeFunc(); FVector FooLocation; } 素のC++ コンパイル “FYourClass”の “HogeHogeFunc” はありますか?
  16. 16. #UE4 | @UNREALENGINE 素のC++ class FYourClass { static void HogeHogeFunc(); FVector FooLocation; } コンパイル “FYourClass”の “HogeHogeFunc” はありますか? 知りません
  17. 17. #UE4 | @UNREALENGINE UnrealC++ UCLASS() Class UYourClass { UFUNCTION(BlueprintCallable) Static void HogeHogeFunc(); UPROPEPTY(BlueprintReadOnly) FVector FooLocation; } 解析 .cpp .h UHT(UnrealHeaderTool)がヘッダファイルを解析して 「ソースファイル名.gen.cpp」と 「ソースファイル名.generated.h」を生成します。 これらにはリフレクションや ブループリントから関数を呼び出すための グルーコードなどが入っています。
  18. 18. #UE4 | @UNREALENGINE UnrealC++ UCLASS() Class UYourClass { UFUNCTION(BlueprintCallable) Static void HogeHogeFunc(); UPROPEPTY(BlueprintReadOnly) FVector FooLocation; } コンパイル 解析 .cpp .h
  19. 19. #UE4 | @UNREALENGINE UnrealC++ UCLASS() Class UYourClass { UFUNCTION(BlueprintCallable) Static void HogeHogeFunc(); UPROPEPTY(BlueprintReadOnly) FVector FooLocation; } コンパイル 解析 .cpp .h “UYourClass”の “HogeHogeFunc” はありますか?
  20. 20. #UE4 | @UNREALENGINE UnrealC++ UCLASS() Class UYourClass { UFUNCTION(BlueprintCallable) Static void HogeHogeFunc(); UPROPEPTY(BlueprintReadOnly) FVector FooLocation; } 知っていますとも! コンパイル 解析 .cpp .h “UYourClass”の “HogeHogeFunc” はありますか? 知りません
  21. 21. #UE4 | @UNREALENGINE リフレクションの使用例 - FindObject クラスはFindObjectを通じて名前で獲得することが可能です。 次のコードはコマンドレットクラスを取得する例です。 次のコードはSkeletalMeshComponentを名前から生成する例です。 //注 : Token はコマンドレットオプション(“run=xxx” )で与えられたクラス名が入っている if (!bHasEditorToken) { UClass* CommandletClass = nullptr; if (!bIsRegularClient) { CommandletClass = FindObject<UClass>(ANY_PACKAGE,*Token,false); UClass* SkeletalMeshClass = FindObject<UClass>(ANY_PACKAGE, TEXT("SkeletalMeshComponent"), false); check( SkeletalMeshClass ); USceneComponent* Object = NewObject<USceneComponent>(this, SkeletalMeshClass, NAME_None);
  22. 22. #UE4 | @UNREALENGINE リフレクションの使用例 - PostEditChangeProperty エディタ上でパラメータが変更されたときに名前を頼りになにか処理をする void UMyComponent ::PostEditChangeProperty (FPropertyChangedEvent & PropertyChangedEvent) { if( PropertyChangedEvent.Property ) { FName PropertyName = PropertyChangedEvent.Property-> GetFName (); if(PropertyName == GET_MEMBER_NAME_CHECKED( UMyComponent , MyVariable)) { ApplyVariable ( MyVariable ); } } Super::PostEditChangeProperty (PropertyChangedEvent); }
  23. 23. #UE4 | @UNREALENGINE リフレクションの使用例 - 関数呼び出し ● 【UE4】ConsoleCommand「CE,KE」について【★★☆】 - キンアジのブログ 様 ● http://kinnaji.com/2019/11/20/cekeevent/ ● UE4 Unreal C++のリフレクションを使って文字列で関数を呼び出す方法に ついて - Let’s Enjoy Unreal Engine 様 ● http://unrealengine.hatenablog.com/entry/2016/06/28/220854 ● [UE4] 関数を文字列で呼び出して実行する - Takezoh 様 ● https://qiita.com/Takezoh/items/9eff92f5da8f20c47fdc
  24. 24. #UE4 | @UNREALENGINE 前半のまとめ ● プロパティはUE4のリフレクションの要素です ● クラスがリフレクション情報を持っています ● ネイティブコードのリフレクションはUHTがソースを解析し作り出します ● クラス ● 関数名 ● 変数名 ● 型情報 ● ブループリントクラスも同様にプロパティを使ってクラスの構造をもってい ます ● ブループリントノードが増えるごとにプロパティが増えて行く傾向があります
  25. 25. #UE4 | @UNREALENGINE 目次 ・本日の主役紹介 ・[寄り道]リフレクション ・FProperty ・対応方法 ・改善点 ・まとめ
  26. 26. #UE4 | @UNREALENGINE 背景 プロパティはブループリントクラスも含みクラスを作成すると大量に生成されま す。タイトルによっては数十万を超える数のUPropertyがあり、UObjectを継承 している事によって様々な面でオーバーヘッドを生み出します。 -余分なメモリスペース -UProperty構築/破壊コスト -ガベージコレクションパフォーマンス -などなどエンジン全般に幅広く影響 エンジンのコアチームはこの改善に取り組みました。
  27. 27. #UE4 | @UNREALENGINE UPropertyからFPropertyへ 4.25からこのUPropertyがFPropertyに全面的に変更されました。 接頭詞”F”はUObjectを継承していない構造体の宣言です。 Note: UPropertyクラスの定義は残っていますが バージョンアップ時に旧バージョンで作られたアセットを FPropertyへの変換する前に一度読み込むためにあるだけです
  28. 28. #UE4 | @UNREALENGINE プロパティ関連クラス継承関係 4.24 UObject UField UStruct UClass UFunction UBlueprintGeneratedClass UEnumUProperty UObjectProperty UBoolProperty
  29. 29. #UE4 | @UNREALENGINE プロパティ関連クラス継承関係 4.25 UObject UField UStruct UClass UFunction UBlueprintGeneratedClass UEnumFProperty FObjectProperty FBoolProperty FField 依存関係が 切れている
  30. 30. #UE4 | @UNREALENGINE プロパティ関連クラス継承関係 4.25 FProperty FObjectProperty FBoolProperty FField このFFieldがUObjectやUFieldが持っていた ほとんどの関数を同じ名前で持っているため、 エンジンを更新するとなってもUxxPropertyか らFxxPropertyにリネームするだけで ほぼ動作するようになっています。
  31. 31. #UE4 | @UNREALENGINE プロパティ関連クラス継承関係 4.25 FProperty FObjectProperty FBoolProperty FField 実際にFPropertyの宣言や実装をコードレベルで 見比べてみると、UPropertyとあまり変わっていな いことが判ります。
  32. 32. #UE4 | @UNREALENGINE 目次 ・本日の主役紹介 ・[寄り道]リフレクション ・FProperty ・対応方法 ・改善点 ・まとめ
  33. 33. #UE4 | @UNREALENGINE まずはブループリントに関して C++コード以外の例えばブループリントのプロパティなどは自動的に変換される ので作業は不要です。
  34. 34. #UE4 | @UNREALENGINE
  35. 35. #UE4 | @UNREALENGINE UnrealEngine 4.25 Release Note # Uproperty マイナー リリースノート https://docs.unrealengine.com/ja/Support/Builds/ReleaseNotes/4_25/index.html#bookmarkuproperty
  36. 36. #UE4 | @UNREALENGINE C++の対応 ● アプリケーションコード中の U*Property を F*Property にリネーム ● プロパティのCastはCastFieldに ● メンバ変数のPropertyはTFieldPathで囲う ● TFieldIterator<UField>はプロパティを含まないので TFieldIterator<FProperty>を使う ● FPropertyを新たにアロケートするときはNewObjectではなくnewを使う ● UStruct::Childrenリンクリストはプロパティを含まないので UStruct::ChildPropertyを使う ● FPropertyの所有者を取得する場合はGetOuterではなく、GetOwnerを使う ● FPropertyとUFunctionやUEnumを統一的に扱いたいときは FFieldVariantを利用する
  37. 37. #UE4 | @UNREALENGINE U*PropertyをF*Propertyに置換 基本的にアプリケーションコード内にU*Propertyを書くことはありません。 UBoolProperty UFloatProperty UVectorProperty UObjectProperty UMapProperty などなど FBoolProperty FFloatProperty FVectorProperty FObjectProperty FMapProperty などなど 古いコードがあった場合はこのような警告がでます。 warning C4996: UArrayProperty has been renamed to FArrayProperty Please update your code to the new API before upgrading to the next release, otherwise your project will no longer compile.
  38. 38. #UE4 | @UNREALENGINE FPropertyの生成は new で 他の構造体と同様に自分で生成する場合はc++標準のnewを使います。 newでアロケートされたメモリポインタはUEのGCで回収されないので、 アプリケーションのコードで削除する必要があります。
  39. 39. #UE4 | @UNREALENGINE プロパティのCastはCastFieldに void USkeletalMesh::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { ... UProperty* PropertyThatChanged = PropertyChangedEvent.Property; ... if( GIsEditor && Cast<UObjectProperty>(PropertyThatChanged) && Cast<UObjectProperty>(PropertyThatChanged)->PropertyClass == UMorphTarget::StaticClass() ) { // A morph target has changed, reinitialize morph target maps InitMorphTargets(); void USkeletalMesh::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { ... FProperty* PropertyThatChanged = PropertyChangedEvent.Property; ... if( GIsEditor && CastField<FObjectProperty>(PropertyThatChanged) && CastField<FObjectProperty>(PropertyThatChanged)->PropertyClass == UMorphTarget::StaticClass() ) { // A morph target has changed, reinitialize morph target maps InitMorphTargets();
  40. 40. #UE4 | @UNREALENGINE メンバ変数プロパティはTFiledPathで囲う 以下のようにメンバ変数にFPropertyのポインタを持っているケースでは、名前 を置換しただけではコンパイルエラーになります。 class AMyCharacter : public ACharacter { ... UPROPERTY() FStructProperty* ValueHandlerNodeProperty; } MyCharacter.h(75): error : Unrecognized type 'FStructProperty' - type must be a UCLASS, USTRUCT or UENUM
  41. 41. #UE4 | @UNREALENGINE メンバ変数プロパティはTFiledPathで囲う この場合はTFieldPath<F*Property> に書き換えます。 UPropertyで宣言されたときと同じ挙動、サービスが提供されます。 USTRUCT() struct ENGINE_API FExposedValueHandler { ... UPROPERTY() UStructProperty* ValueHandlerNodeProperty; USTRUCT() struct ENGINE_API FExposedValueHandler { ... UPROPERTY() TFieldPath<FStructProperty> ValueHandlerNodeProperty;
  42. 42. #UE4 | @UNREALENGINE UStructのChildrenリンクリストが分離 UStruct::Children リンクリストにはプロパティは含まれません。 代わりに UStruct::ChildProperties に プロパティ専用のリンクリストがあります。 class COREUOBJECT_API UStruct : public UField #if USTRUCT_FAST_ISCHILDOF_IMPL == USTRUCT_ISCHILDOF_STRUCTARRAY , private FStructBaseChain #endif { DECLARE_CASTED_CLASS_INTRINSIC(UStruct, UField, CLASS_MatchedSerializers, TEXT("/Script/CoreUObject"), CASTCLASS_UStruct) // Variables. protected: friend struct Z_Construct_UClass_UStruct_Statics; private: /** Struct this inherits from, may be null */ UStruct* SuperStruct; public: /** Pointer to start of linked list of child fields */ UField* Children; /** Pointer to start of linked list of child fields */ FField* ChildProperties;
  43. 43. #UE4 | @UNREALENGINE Children プロパティが 含まれている 4.24
  44. 44. #UE4 | @UNREALENGINE Children プロパティ以外 ChildProperties プロパティは 全てこちら 4.25
  45. 45. #UE4 | @UNREALENGINE TFieldIterator<FProperty>を使う TFieldIterator<UField> はプロパティを含まなくなりました。 プロパティをイテレートする時は TFieldIterator<FProperty> を利用します。
  46. 46. #UE4 | @UNREALENGINE FFieldVariant ヘルパー FField 派生の FProperty と、UField 派生の UFunction や UEnum を統一的に扱 いたい場合は FFieldVariant を利用できます。 いくつかこのFFieldVariantを使ったFFieldとUFieldを統一的に扱うヘルパー関数 が用意されています。 FFieldVariant Field = FindUFieldOrFProperty (YourClass, FieldName ); FBoolProperty * BoolProperty = Field. Get<FBoolProperty >(); if( BoolProperty ) { DoSomething ( BoolProperty ); } UEnum* Enum = Field. Get<UEnum>(); if( Enum ) { DoSomething ( Enum ); }
  47. 47. #UE4 | @UNREALENGINE GetOuterはGetOwnerに変更します GetOuter() を利用していた所はGetOwner() を使います。 GetOuter()はUObjectのための定義なのでFPropetyには適しません。 Ownerは内部にFFieldVariantを使っているので 受け取る型が判っているときはテンプレート引数付きのGetOwner()を、 型が推測出来ない場合はGetOwnerVariant() を使うと良さそうです。
  48. 48. #UE4 | @UNREALENGINE 目次 ・本日の主役紹介 ・[寄り道]リフレクション ・FProperty ・対応方法 ・改善点 ・まとめ
  49. 49. #UE4 | @UNREALENGINE
  50. 50. #UE4 | @UNREALENGINE UObjectの数が減りました! アプリケーション全体で使っているUObjectの内、 Propertyは40%以上、場合によっては60%を超える程あると思います。 特に多数の関数呼び出しを含むブループリントがたくさんある場合に 多くなりがちです。 ThirdPersonTemplateでは UE4.24でUObjectは合計で 5万強ほどあり そのうち70%程がPropertyでした。 これがまるっと無くなります。
  51. 51. #UE4 | @UNREALENGINE 例えばこんなブループリントで改善を見てみます
  52. 52. #UE4 | @UNREALENGINE 例えばこんなブループリントで改善を見てみます マクロをつかってBoolPropertyの戻り値が8個ある関数を 2304回呼び出します。 obj list forget → ブループリントのロード → obj list の手順でブループリントが持つObject数を計測しました。
  53. 53. #UE4 | @UNREALENGINE Obj listによる計測 BoolProperty数 TotalObject 数 Total(MB) 2304回 呼び出した時の 増加分(MB) 1関数 呼び出し辺り(KB) 4.24 0回関数呼び出し 32 5694 2.544MB 10.573MB 4.699KB 4.24 2304回関数呼び出し 55,332 61,005 13.117MB 4.25 0回関数呼び出し 0 5026 2.220MB 1.132MB 0.503KB4.25 2304回関数呼び出し 0 5643 3.352MB
  54. 54. #UE4 | @UNREALENGINE 生成と破壊がシンプルに 前述の通りプロパティの生成と破壊もシンプルになり 素早く処理できるようになりました。 ● UProperty ○ NewObject<> や AllocateObject ○ GC ● FProperty ○ C++ 標準の ‘new’ ○ C++ 標準の ‘delete’ 4.25では様々なアセット読み込みに関する高速化が組み込まれましたが その一端はFPropety化が担っています。 同様にアプリケーションの起動時間の短縮効果も期待できます。
  55. 55. #UE4 | @UNREALENGINE メモリ/ストレージ消費量が減りました UObjectを継承していたことによる、 1つのプロパティあたり余分な100バイト強のメモリが不要になりました。 一つ一つの容量は微々たるものですが、 数が多いため合計すると数10MByte以上メモリ使用量が削減される事もありま す。
  56. 56. #UE4 | @UNREALENGINE MallocProfilerによる計測 MallocProfilerについては弊社鍬農の記事が詳しいです。 https://qiita.com/donbutsu17/items/a72a282587390f43d12d (または MallocProfiler ue4 でググる)
  57. 57. #UE4 | @UNREALENGINE MallocProfilerによる計測 呼び出し回数 合計メモリ使用量 4.24 2304回関数呼び出し 18,456 6.92MB 4.25 2304回関数呼び出し 18,440 2.25MB
  58. 58. #UE4 | @UNREALENGINE エクスポートテーブルに配置されなくなりました 4.24以前のプロパティはuassetファイルのエクスポートテーブルに配置されてい ましたがされなくなり、アセットの実コンテンツ側に配置されます。 この変更はeditor用uassetをクックした後に(cooked)uassetとubulkに分割され たもので顕著に観測できます。 (cooked)uasset アセットがどのアセットと 関連しているのかを含むファイル uexp ファイルの実コンテンツ (editor)uasset エディタで読み込まれるアセット Cook FPropertyUProperty
  59. 59. #UE4 | @UNREALENGINE ファイルサイズ-ThirdPersonCharacter ThirdPersonCharacter uasset uexp total 4.24 16,682 Byte 7,643 Byte 24,325 Byte 4.25 10,552 Byte 10,552 Byte 21,104 Byte
  60. 60. #UE4 | @UNREALENGINE ファイルサイ ズ-ThirdPersonGameMode ThirdPersonGameMode uasset uexp total 4.24 2,936 Byte 490 Byte 3,426 Byte 4.25 2,732 Byte 504 Byte 3,236 Byte
  61. 61. #UE4 | @UNREALENGINE ファイルサイズ-テスト用ブループリント 2304回関数呼び出し uasset uexp total 4.24 2,143,821 Byte 837,607 Byte 2,981,428 Byte 4.25 3,493 Byte 1,685,099 Byte 1,688,592 Byte 43%減!
  62. 62. #UE4 | @UNREALENGINE 目次 ・本日の主役紹介 ・[寄り道]リフレクション ・FProperty ・対応方法 ・改善点 ・まとめ
  63. 63. #UE4 | @UNREALENGINE 本日のまとめ ● 4.25でUPropertyがFPropertyに変わりました ● UObjectを継承していたことによるオーバーヘッドが無くなりました ● アプリケーションのネイティブコード内で利用していた場合はコードの修正が必要です ● ブループリントに書かれたコードは自動で変換されます ● 様々な部分でパフォーマンスが向上します ● 起動時間 ● プロパティを含むアセットの読み込み ● GC処理時間の改善 ● メモリ使用量の減少 ● パッケージ後のストレージサイズの減少 ● などなど横断的に改善の影響があります
  64. 64. #UE4 | @UNREALENGINE ご視聴ありがとうございました! ● エピック ゲームズ ジャパン による オンラインラーニング ● https://www.unrealengine.com/ja/blog/connect-with-the-unreal-engine-community-online ● 「次世代機を見据えた新アセットローディングシステム」を近日公開予定 ● Unreal オンラインラーニング ● https://www.unrealengine.com/ja/onlinelearning-courses ● Unreal Engine 5 初公開 ● https://www.unrealengine.com/ja/blog/a-first-look-at-unreal-engine-5 ● アンリアルエンジン Twitter ● @UnrealEngineJP

×