3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【UE4】Sobolの森 (Random Sobol Cell 2D/3Dについて)

Last updated at Posted at 2020-04-03

random forest と呼ばれる決定木の話ではありません。ご注意を。

前回に引き続き、株式会社ヒストリアさん主催の第13回UE4ぷちコン応募後のあれこれなど。
やったこと、やれなかったこと、誤魔化したところなどの整理と備忘録として。

(もしよろしければ、私の作品の動画も見てくださいませ)

Random Sobol Cell 関数

image.png

Random Sobol Cell は、UE4.17で追加された機能で、リリースノートの「新規:Sobol ブループリントとマテリアルノード」の画像を見ると何やら良さげな匂いがするのに、使い方が良く分からない。

使用例は Epic Games Japan のおかずさんの Slide Share の49~52ページ目、くらいしか見当たらない。皆さん、あまり使っていないのかしら?

というわけで、私が分かった範囲でメモを残しておく。

どうやらこういうものらしい

20200403_1115.gif

※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 で森を作っている。

20200403_1130.png

これも上記のボックス内にCylinderを生やす例と同様、ボックスの中に Sobol Random Cell 2D で木を生やす仕組みを持たせたアクタを、レベル中にたくさん配置してある。
ちなみに、なぜ Foliage を使っていないのかというと、Foliage だとレベルエディットが面倒くさいからである。この道狭いな、とか思ったときに、木のカタマリをザバっと動かしたいからである。

私の使い方:

  • アクタで作る森: コリジョンとセットのものや、キャラクタがインタラクションしそうなもの。
  • Foliageで作る森: キャラクタがインタラクションしないようなもの。遠景など。大地に生えている草なら近景でも Foliage で良かろう。

使い方(備忘録)

何回使ってもややこしくて、試行錯誤の時間が長くなってしまうので、備忘録として。

  • Sobol Random Cell 2D を使いたい範囲を NumCellsX * NumCellsY 個のセルに分けたとする。
  • 一つのセルの中には NumTreeInCell 個の木を生やしたいとする。
Blueprintで書くと大きくなってしまうので、C++ダミーコード。
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 ノードと見比べてみていただきたい。

image.png

    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 の返り値にセルのサイズを掛ければよい。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?