Çakışmayan varlıkları rastgele nasıl yerleştirebilirim?


11

Geliştirdiğim bir oyun için rastgele oluşturulmuş bir ortam oluşturuyorum. OpenGLKullanıyorum ve kod yazıyorum Java.

(Orman oluşturmak için) dünyama rastgele ağaçlar yerleştirmeye çalışıyorum, ancak modellerin üst üste gelmesini istemiyorum (iki ağaç birbirine çok yakın yerleştirildiğinde gerçekleşir). İşte bahsettiğim şeyin bir resmi:

resim açıklamasını buraya girin

Gerekirse daha fazla kod sağlayabilirim, ancak burada temel snippet'ler var. Ben nesneleri bir ArrayListile saklıyorum List<Entity> entities = new ArrayList<Entity>();. Daha sonra kullanarak bu listeye ekliyorum:

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);
}

burada her biri Entityaşağıdaki sözdizimini takip eder:

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

rotXx ekseni boyunca dönüş ve x scaleXyönündeki ölçek vb.

Bu ağaçları random.nextFloat(), xve zkonumları için rastgele yerleştirdiğimi ve aralığı sınırlandırdığımı görebilirsiniz, böylece ağaçlar istenen konumda görünecektir. Ancak, bir şekilde bu pozisyonları kontrol etmek istiyorum, böylece daha önce yerleştirilmiş bir ağaca çok yakın bir ağaç yerleştirmeye çalışırsa, yeni bir rastgele pozisyonu yeniden hesaplar. Her ağacın Entitybaşka bir alana sahip olabileceğini düşünüyordum treeTrunkGirthve eğer bir ağaç başka bir ağacın konumu ile konumu arasındaki mesafeye yerleştirilirse, treeTrunkGirthyeni bir pozisyonu yeniden hesaplar. Bunu başarmanın bir yolu var mı?

Gerektiğinde daha fazla kod parçacığı ve ayrıntı eklemek için mutluyum.


3
Poisson disk örnekleme işi yapmalıdır. Bunun için en iyisi olup olmadığını ve asla gerçekten uygulanıp kullanılmadığını bilmiyorum, ama en azından iyi bir başlangıç ​​gibi görünüyor. Bu makaleye göz atın: devmag.org.za/2009/05/03/poisson-disk-sampling
Mars

@Mars Wow, bu bağlantı çok faydalı, teşekkürler. Ne yapabileceğimi göreceğim ve belki kendi cevabımla geri döneceğim.
wcarhart

@Pikalek Evet, bağladığınız sorunun kopya olduğunu düşünüyorum. Sadece kullanmak misiniz xz-düzlemi diğer Söz konusu gibi "yıldız haritası" için alan olarak?
wcarhart

Evet, davanızda xz düzlemini kullanın . Ayrıca, treeTrunkGirthdeğişmeleri gerektiğinde ağaç yerleştirmek için minimum mesafeyi belirlemek için sabit yerine kullanın .
Pikalek

@Pikalek Tüm bunları bir cevaba eklerseniz, en iyisini seçeceğim. Yardım için teşekkürler.
wcarhart

Yanıtlar:


15

Bir Poisson-Diskte örnekleme dağılımı sen ayrı rasgele noktaları minimum mesafe seçmenizi sağlayacak. Durumunuz bu soruya benzer , ancak ağaçlarınız idealleştirilmiş noktalar olmadığından mesafe kontrolünü şu şekilde değiştirmeniz gerekir: potansiyel yeni bir ağaç ile mevcut bir ağaç arasındaki mesafe, yarıçaplarının toplamından daha az olmalıdır .

Bridson algoritması O (n) 'deki problemi etkili bir şekilde çözebilir, ancak değişken mesafeler için ince ayar yapmak biraz zor olabilir. Parametreleriniz düşükse ve / veya arazinizi önceden hesaplıyorsanız, kaba kuvvet çözümü de size hizmet edebilir. İşte tüm potansiyel yeni ağaç yerleşimlerini önceden yerleştirilmiş tüm ağaçlara karşı kontrol ederek kaba kuvvete uğratan bazı örnek kodlar:

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;
}

Aşağıdaki parametrelerle:

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

Bir saniyenin altında 400-450 ağaç arasına rastgele yerleştirip render edebildim. İşte bir örnek: resim açıklamasını buraya girin


Poisson disk örneklemesi kullanıyor mu?
wcarhart

Evet, bunu açıkça belirtmek için düzenledim.
Pikalek

Math.sqrt tree.r + other tree.ryerine math.pow kullanmaya çalışın , sqrt genellikle
pow'den

1
@Ferrybig Kareli mesafelerin karşılaştırılması daha hızlıdır, ancak bu bir kaba kuvvet algoritması olduğu ve hala O (n ^ 2) olacağı gerçeğini değiştirmez. Daha hızlı bir çözüm gerekiyorsa, Bridson algoritmasını kullanın. Ayrıca, Math.pow(x,2)kullanım burada tartışıldığıx*x gibi kullanmaktan daha iyi / farklı değildir .
Pikalek

1
Arazi ile benzer bir sorun yaşadım ve bazı iyi yayılma ve örtüşme yok. Aslında bir varyasyon yaptım, versiyonumda tress / fırça rastgele arazi alanına yayıldı. Daha sonra her öğenin birbirine karşı mesafelerini kontrol etmek için bu işlevi gönderirim, çok yakın oldukları yerde onları ittim. Ancak bu muhtemelen bölgedeki diğer ağaçlara da etki edecektir. Çarpışma olmayana kadar bunu tekrarladım. daha yavaş ama aynı zamanda bir bonus olarak vardı ne gibi açıklıklar (her yerde kapalı!) ve ağaç yoğunluğu daha "ilginç" gibi şeyler vardı.
ErnieDingo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.