Real Unreal Engine C++ 2017-12 (part-4/5)
(はてなブログの記事あたりの容量制限のため前の部分 §1.9.4 までは前の記事でどうぞ→http://usagi.hatenablog.jp/entry/2017/12/01/ac_ue4_2_p3)
1.9.5 FMath
に含まれる型
FMath
には3次元の可視空間を扱う上で必要な形状や数値を扱うための型も定義されている。
数が多いので表に概要を整理する:
概要 | 型 |
---|---|
std::numeric_limits<T> のとてもしょぼい版。Min , Max , Lowest くらいしか実装されていないので std::numeric_limits<T> を使っておけばよい。 |
TNumericLimits |
任意精度整数 | TBigInt |
浮動小数点数のバイナリー表現を一般化する template 型 | TFloatPacker |
IEEE754/Binary16 相当の浮動小数点数型 | FFloat16 |
ソボル準乱数 | FSobal |
EUnit で定義される単位間の変換 |
FNumericUnit |
単位変換 | FUnitConversion |
FUnitConversion が単位の表示名などに使うための補助的な型 |
FUnitSettings |
D3D DirectX::XMVECTOR のエイリアス |
VectorRegister |
SSEレジスター __m128d のエイリアス |
VectorRegisterDouble |
SSEレジスター __m128i のエイリアス |
VectorRegisterInt |
随意型(オプショナル型)std::optiona<T> (C++17) や boost::optional<T> 相当だが operator bool , operator* の実装都合、 TOptional<T> は地味に扱いが面倒。 UE4 が C++17 標準対応完了すれば要らなくなる子。( TArray のようにBlueprintでも使用可能になるなどすればまた別だが・・・) |
TOptional |
成功値の型と失敗値の型を指定可能な TOptional のごつくなったようなやつ |
TValueOrError |
補間 | FInterpCurve FInterpCurveFloat FInterpCurveLinearColor FInterpCurvePoint FInterpCurveQuat FInterpCurveTwoVectors FInterpCurveVector FInterpCurveVector2D 注:FInterpCurve は F 始まりの型だが template |
球面座標 | TSHVector |
RGB色用の球面座標 | TSHVectorRGB |
3次元ベクター | FVector FIntVector |
2次元ベクター | FVector2D FIntPoint |
半精度浮動小数点数型の2次元ベクター | FVector2DHalf |
4次元ベクター | FVector4 FIntVector4 FUintVector4 |
線形色 RGBAを値域 [0..1] に正規化した表現 |
FLinearColor |
2 点を保持(するだけ) | TInterval FFloatInterval FInt32Interval |
2 点を保持(多機能) | TRange FAnimatedRange FDateRange FDoubleRange FFloatRange FInt8Range FInt16Range FInt32Range FInt64Range |
Rangeの内外の制御を行う型 | TRangeBound FDateRangeBound FDoubleRangeBound FFloatRangeBound FInt8RangeBound FInt16RangeBound FInt32RangeBound FInt64RangeBound |
Range 集合用の template 型 Add や Contains など集合に対する操作を行える。 |
TRangeSet |
2つの3次元ベクターの対 | FTwoVectors |
2つのベクターで表される角(かど) | FEdge |
立方体 | FBox |
球 | FSphere |
同一原点の軸平行直方体(AABB)と球の組み合わせ形状 | FBoxSphereBounds |
平面 | FPlane |
カプセル形状 | FCapsuleShape |
中心と軸方位と軸方位への広がり量を基に任意回転した立方体(の頂点位置)を表現する型 | FOrientedBox |
矩形 | FBox2D FIntRect |
uin32 範囲で行数と列数をそれぞれ任意に template で与えられる行列型 | TMatrix |
4x4行列 | FMatrix |
2x2行列 | FMatrix2x2 |
回転変換行列 | FRotationMatrix |
回転と平行移動の変換行列 | FRotationTranslationMatrix |
四元数を基にした回転の変換行列 | FQuatRotationMatrix |
四元数を基にした回転と平行移動の変換行列 | FQuatRotationTranslationMatrix |
逆回転変換行列 | FInverseRotationMatrix |
点を中心に回転する変換行列 | FRotationAboutPointMatrix |
拡大縮小変換行列 | FScaleMatrix |
拡大縮小と回転と平行移動の変換行列 | FScaleRotationTranslationMatrix |
変形(拡大縮小、回転、平行移動)変換行列 | FTranslationMatrix |
視線変換行列 | FLookAtMatrix |
正射影変換行列 | FOrthoMatrix |
遠近法変換行列 | FPerspectiveMatrix |
逆Z軸正射影変換行列 | FReversedZOrthoMatrix |
逆Z軸遠近法変換行列 | FReversedZParspectiveMatrix |
鏡像行列 ある平面で鏡像化するための変換行列 |
FMirrorMatrix |
行列を他の表現に変換するための変換器 | TransformConverter |
オイラー角に基づく回転型 | FRotator |
四元数による3次元の回転型 | FQuat |
四元数風の2次元の回転型 | FQuat2D |
3次元の拡大縮小を表す型 | FScale |
2次元の拡大縮小を表す型 | FScale2D |
3次元変形(拡大縮小、回転、平行移動) | FTransform |
2次元変形(拡大縮小、回転、平行移動) | FTransform2D |
2次元の剪断 | FShear2D |
自称「スレッドセーフで低ビットの品質の悪い擬似乱数生成器」 実装を見るにスレッドセーフではないし、線形合同法ベースだし、 C++er は <random> を使っておけばよいので存在を忘れても構わない何か。 |
FRandomStream |
暗号鍵用に整数の指数と剰余を保持する template 型 | TEncryptionKey |
この節の表を作っただけで力尽きて来たので、面白い小話などはまた別の機会に書く事にする。さしあたり、 C++er は FMath
に定義される機能で必要十分な限りにおいては FMath
の部品を再実装せず少々の癖はあるが上手く付き合えるよう、どのような機能の関数と型があるのか脳内にインデクシングしておくと良い。
なお、 UE4 の線形幾何ライブラリーの実装レベルは速度最適化の面から言っても、それほど優れた実装にはなっていない。例えば、 Eigen
のように template
が充実していたり、 expression template により評価を遅延していたり、などという工夫はほとんど無く、わりと単純に float
ベースで個々に実装されている。そういうわけで、 "必要十分な限りにおいては" と書いた。それについてもまた本記事の趣旨とは少々ずれるので別の機会があれば書く事にする。
1.10. UE4/C++ における入門的な「コンテナー」ライブラリーの std 互換性
一般的な std 慣れした C++er は UE4 コンテナーのメンバー変数の命名と機能とパラメーターに翻弄される。この節では std に慣れた C++er が UE4/C++ にうっかり翻弄され難くなるよう、予防接種的な視点にも注意しながら UE4 のコンテナー類を整理する。
1.10.1. TArray<T>
と std::deque<T>
/ std::vector<T>
/ std::queue
/ std::stack
所属 | 型 | Header |
---|---|---|
std | vector |
<vector> |
std | deque |
<deque> |
std | stack |
<stack> |
std | queue |
<queue> |
UE4 | TArray |
Runtime/Core/Public/Containers/Array.h |
UE4 | TQueue |
Runtime/Core/Public/Containers/Queue.h |
C++er は std::vector
/ std::stack
/ std::queue
がコンテナーアダプターであり、実装詳細は std::deque
コンテナーである事をよく知っている。また、多くのコンテナー類に対して操作を共通化するため <algorithm>
が用意され、ほとんどの操作はイテレーターを介したレンジで扱われる事もよく把握している。
UE4 にはそれらをひとまとめにしたような "便利" なコンテナーとして "マッチョ" な TArray
が定義されている。
そこで、この項では std::vector
/ std::stack
/ std::queue
と TArray
を対応させ、機能の有無や対応関係がわかりやすいよう整理する。また、 UE4 にはキュー専用に特化した TQueue
も定義されているので "ついで" 程度に含める事にする。
なお、「機能を組み合わせれば実現できる」ものは除外し(それは C++er なら脳内でわかること)、直接的にそのように振る舞う機能がある場合にのみ表に関数名を記載する。
効果 | std::deque |
std::vector |
std::stack |
std::queue |
TArray |
TQueue |
---|---|---|---|---|---|---|
[begin..end) の値群に置き換える |
assign |
assign |
||||
別のコンテナーの値群を追加する | Append operator+= |
|||||
最前に値を直接生成する | emplace_front |
|||||
最後に値を直接生成する | emplace_back |
emplace_back |
emplace |
emplace |
Emplace |
|
最前に値を入れる | push_front |
|||||
最後に値を入れる | push_back |
push_back |
push |
push |
Add AddDefaulted AddUninitialized AddUnique AddZeroed <Push> |
Enqueue |
最前の値を削除する | pop_front |
pop |
Pop |
Pop |
||
最後の値を削除する | pop_back |
pop_back |
pop |
|||
任意の位置へ値を直接生成する | EmplaceAt |
|||||
任意の位置へ値を内挿する | insert |
insert |
Insert InsertDefaulted InsertUninitialized InsertZeroed |
|||
値を全て削除する | clear |
clear |
Empty Reset |
|||
保持する値の数を変更する | resize |
resize |
SetNum SetNumUninitialized SetNumZeroed Init |
|||
保持する値の数を予約する | reserve |
Reserve |
||||
値を範囲で削除する | erase |
erase |
||||
値を値またはインデックスで削除する | Remove RemoveAll RemoveAllSwap RemoveAt RemoveAtSwap RemoveSingle RemoveSingleSwap RemoveSwap |
|||||
保持可能な値の数を実際の保持数に最適化する | shrink_to_fit |
shrink_to_fit |
Shrink |
|||
最前の値を取得する | front |
front |
front |
Peek Dequeue |
||
最後の値を取得する | back |
back |
top |
back |
Last Top |
|
任意の位置の値を範囲チェック付きで取得する | at |
at |
||||
任意の位置の値を取得する | operator[] |
operator[] |
operator[] |
|||
先頭の値のメモリーアドレスを取得 | data |
GetData |
||||
値を保持していない事を判定する | empty |
empty |
empty |
empty |
IsEmpty |
|
値の保持数が正常かアサーション( checkSlow )する | CheckInvariants |
|||||
保持する値の数を取得する | size |
size |
size |
size |
Num |
|
保持する値の総容量を取得する | CountBytes |
|||||
内部バッファーの数を取得する | capacity |
|||||
内部バッファーの空き数を取得する | GetSlack |
|||||
内部バッファーのメモリー容量を取得する | GetAllocatedSize |
|||||
値を保持可能な最大数を取得する | max_size |
max_size |
Max |
|||
最前のイテレーターを取得する | begin |
begin |
CreateIterator |
|||
最後のイテレーターを取得する | end |
end |
||||
最前のconstイテレーターを取得する | cbegin |
cbegin |
CreateConstIterator |
|||
最後のconstイテレーターを取得する | cend |
cend |
||||
最後からの始端のリバースイテレーターを取得する | rbegin |
rbegin |
||||
最後からの終端のリバースイテレーターを取得する | rend |
rend |
||||
最後からの始端のconstリバースイテレーターを取得する | crbegin |
crbegin |
||||
最後からの終端のconstリバースイテレーターを取得する | crend |
crend |
||||
別のコンテナーと値群を挿げ替える | swap |
swap |
swap |
swap |
Swap |
|
別のコンテナーと値群のメモリーを挿げ替える | SwapMemory |
|||||
アロケーターを取得する | get_allocator |
get_allocator |
||||
有効なインデックスか判定する | IsValidIndex |
|||||
有効なレンジか判定する | RangeCheck |
|||||
アドレスがコンテナーの値か判定する | CheckAddress |
|||||
値のインデックスを取得する | IndexOfByKey IndexOfByPredicate |
|||||
要素型のメモリー容量を取得する | GetTypeSize |
|||||
値が含まれるか判定する | Contains ContainsByPredicate |
|||||
最前から値を検索する | std::find |
Find FindByKey FindByPredicate FindItemByClass |
||||
最後から値を検索する | FindLast FindLastByPredicate |
|||||
フィルターしたコンテナーのコピーを取得する | std::copy_if |
FilterByPredicate |
||||
非安定ソートする | std::sort |
Sort |
||||
安定ソートする | std::stable_sort |
StableSort |
||||
シリアライズ結果を取得する | BulkSerialize |
|||||
保持する値群をヒープ構造化する | std::make_heap |
Heapify |
||||
保持する値群がヒープ構造化されているか判定する | std::is_heap |
VerifyHeap |
||||
ヒープ構造を前提に最前の値を削除する | std::pop_heap |
HeapPop HeapPopDiscard |
||||
ヒープ構造を前提に値を追加する | std::push_heap |
HeapPush |
||||
ヒープ構造を前提に任意の位置の値を削除する | HeapRemoveAt |
|||||
ヒープ構造を前提にソートする | std::sort_heap |
HeapSort |
この他に大きな相違として、 UE4 では TArray
と次節で紹介する TMap
、それと TSet
については template
であっても例外的に UE4Editor / Blueprint でも直接的な使用がサポートされている点、 UPROPERTY()
マクロの指定が可能な点がある。これは一般に C++ コードだけでは完結しない UE4 のプロジェクトの "開発" について、また UObject
派生型を要素型とする必要性において、しばしばコンテナーの実装に求められる重要な要件となる。
std 慣れした C++er が注意を要する TArray
を扱う上でのポイントは以下の通り:
deque
|vector
|stack
|queue
|SORT
|HEAP
|FIND
≃TArray
size
=Num
resize
≃SetNum
reserve
=Reserve
empty()
≃Num() > 0
とclear()
≃Empty()
の混乱回避。std::remove
+erase
( erase-remove idiom ) ≃Remove
data
=GetData
TArray
はUPROPERTY()
可能。- std アルゴリズムのレンジは生ポインターでも動作するので
TArray
にも適用はできる。 std::vector
におけるreserve
やcapacity
で扱う内部バッファーをTArray
では "Slack" (スラック)と用語を充てている。
1.10.2. TMap<K,V>
と std::unordered_map<K,V>
所属 | 型 | Header |
---|---|---|
std | unordered_map |
<unordered_map> |
UE4 | TMap |
Runtime/Core/Public/Containers/Array.h |
std の解説一般でもしばしば同じ節で扱われるように unordered_map
にはよく似た unordered_set
があり、 UE4 にもそれらと同じ関係の TMap
と TSet
がある。この記事は網羅的なクラスや API の紹介が趣旨ではないため(&そろそろアドベンカレンダーの期日も近づきすぎている都合もあり…)、冗長を避ける意味でも unordered_map
vs. TMap
のみを取り上げる。
効果 | std::unordered_map |
TMap |
TMap のメンバーの継承元 |
---|---|---|---|
別のコンテナーの値群を追加する | Append operator+= |
TMap |
|
キーと値の組みを直接生成する | emplace |
Emplace |
TMapBase |
キーと値の組みを挿入位置のヒント付きで直接生成する | emplace_hint |
||
キーと値の組みを入れる | insert |
Add |
TMapBase |
キーの値を取得または生成して取得する | operator[] |
FindRef |
TMapBase |
キーの値を取得する | at |
FindChecked operator[] |
TMapBase TMap |
キーの値を取得または生成してポインターを取得する | FindOrAdd |
TMapBase |
|
キーの値のポインターを取得する | Find |
TMapBase |
|
値のキーのポインターを取得する | FindKey |
TMapBase |
|
キーの組みのイテレーターを取得する | find equal_range |
||
キーの組みを削除しつつ値を取得する | FindAndRemoveChecked |
TMap |
|
キーの組みの有無を確認して存在すれば削除しつつ値を取得する | RemoveAndCopyValue |
TMap |
|
キーの組みを削除する | erase |
Remove |
TMapBase |
組みを全て削除する | clear |
Empty Reset |
TMapBase |
内部バッファーの数を予約する | reserve |
Reserve |
TMapBase |
内部バッファーのバケットの最小数を指定してバケット数を調整する | rehash |
||
内部バッファーのバケットの負荷率の最大値を設定または取得する | max_load_factor |
||
内部バッファーのバゲットの負荷率を取得 | load_factor |
||
内部バッファーの末尾の未使用領域を削除する | Shrink |
TMapBase |
|
内部バッファーの未使用領域を削除する | Compact |
TMapBase |
|
内部バッファーの未使用領域を使用領域の順序を保持して削除する | CompactStable |
TMapBase |
|
組みの順序をキーでソートする | KeySort |
TSortableMapBase |
|
組みの順序を値でソートする | ValueSort |
TSortableMapBase |
|
組みへのconstイテレーターを取得する | cbegin |
CreateConstIterator |
TMapBase |
組みの終端へのconstイテレーターを取得する | cend |
||
キーへのconstイテレーターを取得する | CreateConstKeyIterator |
TMapBase |
|
組みへのイテレーターを取得する | begin |
CreateIterator |
TMapBase |
組みの終端へのイテレーターを取得する | end |
||
キーへのイテレーターを取得する | CreateKeyIterator |
TMapBase |
|
キーの配列と数を取得する | GetKeys |
TMapBase |
|
組みの数を取得する | size |
Num |
TMapBase |
内部バッファーの数を取得する | bucket_count |
GetAllocatedSize |
TMapBase |
内部バッファーの最大数を取得する | max_size bucket_size |
||
キーが存在するか判定する | count |
Contains |
TMapBase |
保持する組みが空か判定する | empty |
||
キー群の配列を取得する | GenerateKeyArray |
TMapBase |
|
値群の配列を取得する | GenerateValueArray |
TMapBase |
|
内部バッファーを出力デバイス(ログ的なやつ)へ書き出す | Dump |
TMapBase |
|
シリアライズに要するメモリー容量を取得する | CountBytes |
TMapBase |
|
アロケーターを取得する | get_allocator |
||
要素を挿げ替える | swap |
||
ハッシュ関数オブジェクトを取得する | hash_function |
||
キー比較用オブジェクトを取得する | key_eq |
std::unordered_map
に比べ TMap
ではキー、値それぞれに着目した操作や列挙の実装が充実している。 std 慣れした C++er が留意すべき TMap
のポイントは次の通り:
unordered_map
のoperator[]
は存在しない要素は生成してくれるが、TMap
のoperator[]
は存在しない要素は生成してくれない(実行時エラーとなる)。その用途にはFindRef
を使う。TMap
は KEY, VALUE によるソートが可能。- メンバーの命名 →
TArray
と同様の注意が必要。 UPROPERTY()
可能。- インデックスアクセスも可能な連想配列として振る舞う(もちろん表面上は似てはいるが
std::unordered_map
の一般的な実装とTMap
の実装詳細はまったく異なる)
1.10.3. その他の UE4 コンテナーライブラリー
他の std に対応する UE4 コンテナーは以下の通り:
概要 | std | UE4 |
---|---|---|
ビット列コンテナー | std::vector<bool> |
TBitArray |
単方向リスト | std::forward_list<T> |
TList<T> |
ソート済み連想コンテナー | std::map<K,V> |
TSortedMap<K,V> |
ハッシュ集合 | std::unordered_set<T> |
TSet |
優先度付きキュー | std::priority_queue<T> |
FBinaryHeap<K,I> |
また、 他にも UE4 には std には無いコンテナー類も存在します。そのうちの一部は boost には同種のコンテナーが存在する。
概要 | boost | UE4 |
---|---|---|
既存の生配列を参照してサイズ変更を除く TArray<T> と同等の操作を可能にするビュー |
TArrayView |
|
循環バッファー | boost::circular_buffer<T> |
TCircularBuffer<T> |
ロックフリー循環キュー | boost::lockfree:queue |
TCircularQueue<T> |
ロックフリーポインターリスト | FLockFreePointerListFIFO FLockFreePointerListLIFORoot |
|
疎配列 | Boost.SparseVector |
SparseArray<T> |
バリアント集合 | TUnion<A,B,C,D,E,F> |
何れも前項までに紹介したコンテナー類よろしく std 慣れした C++er の脳を引っ掻き回すような命名規則や引数はおおよそ共通。また、一部には EPIC GAMES 以外が主体的に開発したソースも含まれさらなる混沌感も少々ある。
何れも使い所次第では単に TArray<T>
や TMap<T>
あるいは TSet<T>
、それに何らかの工夫を加えて使うよりも高効率であったり便利であったりはするものの、 UE4Editor / Blueprint からは使用不能。必要が生じたら使える程度に軽く脳にインデクシングしておけば善いでしょう。
(はてなブログの記事あたりの容量制限のため続き §1.11. 以降は次の記事でどうぞ→http://usagi.hatenablog.jp/entry/2017/12/01/ac_ue4_2_p5)