スターマップを生成しようとしています。
私の試みは:
- マップの幅と高さがあります。
- 幅と高さの領域全体にランダムにポイント(星)を配置します。
単純なアプローチですが、ランダムに星を互いに非常に近くに配置するという問題があります。
この問題を解決するための1つの方法は、最小距離を設定することです。星を生成するときに、新しい星から生成されたすべての星までの距離を比較し、最小距離を下回る場合は新しい星を生成しますが、それは効率的です。任意のヒント?
スターマップを生成しようとしています。
私の試みは:
単純なアプローチですが、ランダムに星を互いに非常に近くに配置するという問題があります。
この問題を解決するための1つの方法は、最小距離を設定することです。星を生成するときに、新しい星から生成されたすべての星までの距離を比較し、最小距離を下回る場合は新しい星を生成しますが、それは効率的です。任意のヒント?
回答:
A ポアソンディスクサンプリング分布を使用すると、最小の距離離れてランダムな点を選択するために、&ができますBridsonのアルゴリズムは十分な速さをリアルタイムであなたの星の数があまりにも巨大な取得していない提供のために-効率的にO(n)の中に問題を解決することができます。
Bridsonのアルゴリズムは、出力領域を最小許容距離を基準にしたサイズのセルのグリッドに分割し、各セルに1つのポイントしか表示されないようにします。次に、新しいポイントを追加することを検討する場合、ポイントのリスト全体ではなく、隣接するセルのディスク形状のコレクションをチェックするだけで済みます。たとえば、次の画像について考えてみます。
候補の青いドットが既存のドットに近すぎるかどうかを確認する場合、既存のすべてのドットに対してチェックする必要はありません。代わりに、隣接するセルのドットに検索を制限できます(これはルックアップテーブルを使用してすばやく見つけることができます)。Mike Bostockには、進行中のアルゴリズムを示す素晴らしいアニメーションがあります。
標準の実装では、ポイント間の固定された最小距離のみが考慮されます。Herman Tullekenのポアソンディスクサンプリング記事(ソースコードを含む)は、画像のさまざまな部分で最小距離を変化させるための適応について説明しています。基本的にはディザリングアルゴリズムのようです。記事の雲に示されているようにパーリンノイズ/シンプレックスノイズを使用すると、より自然に見える星図が得られる場合があります。たとえば、左側の画像を使用して右側を生成しました。
これを行うには、候補点を検討するときに、最初に入力画像の値を確認します。これにより、0から1までの値が得られます。次に、これを点間の望ましい最小および最大距離にスケーリングします。この場合、5ピクセルと20ピクセルを選択しました。したがって、暗い領域に点を配置すると、私の星は互いに5ピクセル近くになり、明るい領域に星を配置すると、最大20ピクセル離れることがあります。
出力ポイントが均一な最小距離を使用していないため、ブリドソンの高速化は可変距離サンプリングでは正確に機能しないことに注意してください。ただし、出力グリッドを使用して検索を減らすことができます。グリッドを小さくすると、ルックアップテーブルが大きくなりメモリが増える代わりに、最近傍の検索が速くなります。
非常に素朴だが単純な解決策の1つは、常に「最小」距離をジャンプし、その上にランダムな量を追加することです。これは、星がバディバディになることは決してないことを意味し、少なくとも多少の偏差が発生します。
例えば
for (int x = 0; x < MAX_WIDTH; x+= MIN_SEPERATION_X)
{
x += generateRandom();
for (int y = 0; y < MAX_HEIGHT; y+= MIN_SEPERATION_Y)
{
y += generateRandom();
if (x < MAX_WIDTH && y < MAX_HEIGHT)
{
image[x + y * width] = STAR;
}
}
}
(お好みの乱数生成機能を挿入)
プレイスペースのXYZサイズがわかっている場合は、そのスペースでランダムなスポットを選択できます
次に、SphereCastを実行して、近すぎるものがないかどうかを確認します。
//pseudo code
SpawnStar(){
Vector3 spot = new vector3(random(0,world size),random(0,world size,random(0,world size)
while(true){
SphereCast(spot, radius)
if(hit something){
spot = get new random spot
}else{
SpawnStar();
brake;
}
}
}
これの問題は、それはおそらくリアルタイムではあまり良くないということですが、事前に生成されたものでは問題なく、かなり高速です。