random forest と呼ばれる決定木の話ではありません。ご注意を。
前回に引き続き、株式会社ヒストリアさん主催の第13回UE4ぷちコン応募後のあれこれなど。
やったこと、やれなかったこと、誤魔化したところなどの整理と備忘録として。
(もしよろしければ、私の作品の動画も見てくださいませ)
Random Sobol Cell 関数
Random Sobol Cell
は、UE4.17で追加された機能で、リリースノートの「新規:Sobol ブループリントとマテリアルノード」の画像を見ると何やら良さげな匂いがするのに、使い方が良く分からない。
使用例は Epic Games Japan のおかずさんの Slide Share の49~52ページ目、くらいしか見当たらない。皆さん、あまり使っていないのかしら?
というわけで、私が分かった範囲でメモを残しておく。
どうやらこういうものらしい
※3Dでやると混乱しそうだったので、2Dでやってます。
【左側】普通の乱数でボックス内にCylinderを16本生成する。
【右側】ボックス内を2×4マス(=Cell)に分けて、Sobol Random Cell 2D
でCylinderをそれぞれのマスに2本ずつ生成する。つまり、2 × 4 × 2 = 16 本のCylinderが生成されている。
つまり、普通の乱数ではどこかに偏ってしまいがち(左側)だが、あらかじめマス(=Cell)に切って Sobol を使えば、それなりに均一に、それなりにランダムにばら撒ける(右側)、ということのようだ。
UE4.17のリリースノートに掲載されている画像のように、森などを作るときに便利だとわかる。
実際、UE4ぷちコン#13に応募した私の作品でも、Sobol Random Cell 2D
で森を作っている。
これも上記のボックス内にCylinderを生やす例と同様、ボックスの中に Sobol Random Cell 2D
で木を生やす仕組みを持たせたアクタを、レベル中にたくさん配置してある。
ちなみに、なぜ Foliage を使っていないのかというと、Foliage だとレベルエディットが面倒くさいからである。この道狭いな、とか思ったときに、木のカタマリをザバっと動かしたいからである。
私の使い方:
- アクタで作る森: コリジョンとセットのものや、キャラクタがインタラクションしそうなもの。
- Foliageで作る森: キャラクタがインタラクションしないようなもの。遠景など。大地に生えている草なら近景でも Foliage で良かろう。
使い方(備忘録)
何回使ってもややこしくて、試行錯誤の時間が長くなってしまうので、備忘録として。
- Sobol Random Cell 2D を使いたい範囲を
NumCellsX * NumCellsY
個のセルに分けたとする。 - 一つのセルの中には NumTreeInCell 個の木を生やしたいとする。
void DoSobol(int NumCellsX, int NumCellsY, int NumTreeInCell)
{
const int NumCellsTotal = NumCellsX * NumCellsY;
const FVector2D RandomSeed(RandomFloat(), RandomFloat()); // (0, 0)~(1, 1)の範囲
// Y方向のセルの個数分のループ
for (int IndexY = 0; IndexY < NumCellsY; ++IndexY)
{
// X方向のセルの個数分のループ
for (int IndexX = 0; IndexX < NumCellsX; ++IndexX)
{
const FVector2D Cell((float)IndexX, (float)IndexY);
// 1つのセルに生やす木の数のループ
for (int IndexTreeInCell = 0; IndexTreeInCell < NumTreeInCell; ++IndexTreeInCell)
{
const FVector2D SobolValue = RandomSobolCell2D( // Sobol 本体
IndexTreeInCell, // int Index
NumCellsTotal, // int NumCells
Cell, // FVector2D Cell
RandomSeed); // FVector2D Seed
AddInstancedStaticMeshTree(SobolValue); // 木を生やす何らかの関数
}
}
}
}
コメントで Sobol 本体と書いたところは、Random Sobol Cell 2D
の Blueprint ノードと見比べてみていただきたい。
const FVector2D SobolValue = RandomSobolCell2D( // Sobol 本体
IndexTreeInCell, // int Index
NumCellsTotal, // int NumCells
Cell, // FVector2D Cell
RandomSeed); // FVector2D Seed
さて、ここで一安心したいところだが、Random Sobol Cell 2D/3D
の返り値も多少癖がある。
気分的には、0~1の範囲で返してもらいたいところだが、実際は平気で1.0を超えてくる。
初めて使ったときには、使い方が間違ったのかと思った。だが大丈夫。
- (0, 0)番目のセルに入っている木の場合: (0.0, 0.0)~(1.0, 1.0) の返り値
- (0, 1)番目のセルに入っている木の場合: (0.0, 1.0)~(1.0, 2.0) の返り値
- 中略
- (2, 4)番目のセルに入っている木の場合: (2.0, 4.0)~(3.0, 5.0) の返り値
という値が返ってくる。
なので、実際の座標に直したいときは、
const FVector2D CellSize(BoxSize.X / NumCellsX, BoxSize.Y / NumCellsY);
const FVector2D TreeLocation2D = SobolValue * CellSize;
と、Sobol の返り値にセルのサイズを掛ければよい。