重複しないエンティティをランダムに配置するにはどうすればよいですか?


11

開発中のゲーム用にランダムに生成された環境を作成しています。で使用OpenGLしてコーディングしていJavaます。

(森を作成するために)私の世界にランダムに木を配置しようとしていますが、モデルを重複させたくありません(2つの木が互いに近すぎて配置されている場合に起こります)。これが私が話していることの写真です:

ここに画像の説明を入力してください

必要に応じてさらに多くのコードを提供できますが、ここに重要なスニペットがあります。オブジェクトをArrayListwithに保存していますList<Entity> entities = new ArrayList<Entity>();。次に、次を使用してそのリストに追加します。

Random random = new Random();
for (int i = 0; i < 500; i++) {
    entities.add(new Entity(tree, new Vector3f(random.nextFloat() * 800 - 400, 
    0, random.nextFloat() * -600), 0, random.nextFloat() * 360, 0, 3, 3, 3);
}

ここで、それぞれEntityは次の構文に従います。

new Entity(modelName, positionVector(x, y, z), rotX, rotY, rotZ, scaleX, scaleY, scaleZ);

rotXx軸に沿った回転scaleX、x方向のスケールなどです。

あなたは私がランダムにこれらの木を配置していていることがわかりますrandom.nextFloat()ためxz位置、および樹木が所望の位置に表示されますので、範囲の境界を示します。ただし、これらの位置を何らかの方法で制御したいので、以前に配置したツリーに近すぎるツリーを配置しようとすると、新しいランダムな位置が再計算されます。各ツリーにEntityはなどの別のフィールドがある可能性があると考えていました。ツリーがtreeTrunkGirth別のツリーの場所との間の距離に配置されている場合treeTrunkGirth、新しい位置が再計算されます。これを達成する方法はありますか?

必要に応じて、コードスニペットと詳細をさらに追加できます。


3
ポアソンディスクサンプリングで十分です。それがこれに最適であるかどうかはわからず、実際に実装/使用したこともありませんが、少なくとも良いスタートのようです。この記事を確認してください:devmag.org.za/2009/05/03/poisson-disk-sampling
Mars

@Mars Wow、そのリンクはとても役に立ちます、ありがとう。私は何ができるか見て、おそらく自分の答えで戻ってきます。
wcarhart

@Pikalekはい、あなたがリンクした質問は重複していると思います。他の質問のように、「星図」の領域としてxz平面を使用するだけですか?
wcarhart

はい、ケースではxz平面を使用します。また、treeTrunkGirth変化する必要がある場合は、定数の代わりにを使用して、ツリーを配置するための最小距離を決定します。
Pikalek

@Pikalek回答にそれらすべてを追加すると、私はそれを最良のものとして選択します。助けてくれてありがとう。
wcarhart 2016

回答:


15

A ポアソンディスクサンプリング分布はあなたが最短距離離れてランダムな点を選択することができるようになります。あなたの状況はこの質問に似ていますが、ツリーは理想的なポイントではないため、距離チェックを次のように変更する必要があります。潜在的な新しいツリーと既存のツリーの間の距離は、それらの半径の合計より小さくなければなりません。

BridsonのアルゴリズムはO(n)の問題を効率的に解決できますが、距離が変化するように微調整するのは少し面倒です。パラメータが低すぎる場合や、地形を事前計算している場合は、ブルートフォースソリューションが役立つこともあります。次のサンプルコードは、すべての潜在的な新しいツリーの配置を、以前に配置されたすべてのツリーに対してチェックすることにより、問題を強制します。

public static class SimpleTree{
    float x;
    float z;
    float r;

    public SimpleTree(Random rng, float xMax, float zMax, float rMin, float rMax){
        x = rng.nextFloat() * xMax;
        z = rng.nextFloat() * zMax;
        r = rng.nextFloat() * (rMax-rMin) + rMin;
    }
}

private static ArrayList<SimpleTree> buildTreeList(float xMax, float zMax, 
        float rMin, float rMax, int maxAttempts, Random rng) {
    ArrayList<SimpleTree> result = new ArrayList<>();

    SimpleTree currentTree = new SimpleTree(rng, xMax, zMax, rMin, rMax);
    result.add(currentTree);

    boolean done = false;
    while(!done){
        int attemptCount = 0;
        boolean placedTree = false;
        Point nextPoint = new Point();
        SimpleTree nextTree = null;
        while(attemptCount < maxAttempts && !placedTree){
            attemptCount++;
            nextTree = new SimpleTree(rng, xMax, zMax, rMin, rMax);
            if(!tooClose(nextTree, result)){
                placedTree = true;
            }
        }
        if(placedTree){
            result.add(nextTree);
        }
        else{
            done = true;
        }
    }

    return result;
}

private static boolean tooClose(SimpleTree tree, ArrayList<SimpleTree> treeList) {
    for(SimpleTree otherTree : treeList) {
        float xDiff = tree.x - otherTree.x;
        float zDiff = tree.z - otherTree.z;

        float dist = (float)Math.sqrt((xDiff * xDiff) + (zDiff * zDiff));
        if(dist < tree.r + otherTree.r){
            return true;
        }
    }        
    return false;
}

以下のパラメーターを使用します。

 maxAttempts = 500;
 width = 300;
 height = 200;
 minSize = 2;
 maxSize = 15;

1秒未満で400〜450本の木をランダムに配置してレンダリングすることができました。次に例を示します。 ここに画像の説明を入力してください


これはポアソンディスクサンプリングを使用していますか?
wcarhart 2016

はい、それを明確にするために編集しました。
Pikalek 2016

math.sqrtのtree.r + other tree.r代わりに、2でmath.powを使用してみてください。sqrt は通常、powよりも遅くなります
Ferrybig

1
@Ferrybig二乗距離の比較はより高速ですが、それがブルートフォースアルゴリズムであり、O(n ^ 2)であるという事実は変わりません。より高速なソリューションが必要な場合は、Bridsonのアルゴリズムを使用してください。また、使用してはMath.pow(x,2)必ずしも任意のより良い/別の使用するよりないx*xとして、ここで議論します
ピカレク2016

1
私は地形に関して同様の問題を抱えており、ある程度の広がりと重複がないことを確認しました。私は実際にバリエーションを作りました、私のバージョンでは、房/ブラシは地形エリア全体にランダムに広がっています。次に、これを投稿する関数を実行して、各アイテムの距離をチェックします。距離が近すぎる場合は、それらを離しました。しかし、これはおそらく地域の他の木に影響を与えます。衝突がなくなるまでこれを繰り返しました。それは遅いですが、ボーナスとして私が得たのは、クリアリング(どこでもカバーされているわけではありません!)や木の密度がより「興味深い」ように見えることなどでした。
ErnieDingo
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.