Elmas kare arazi oluşturma sorunu


11

Bu makaleye göre elmas kare bir algoritma uyguladım: http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2

Sorun şu ki, bu dik uçurumları harita üzerinde buluyorum. Arazi tekrar tekrar alt bölümlere ayrıldığında kenarlarda olur:

resim açıklamasını buraya girin

İşte kaynak:

void DiamondSquare(unsigned x1,unsigned y1,unsigned x2,unsigned y2,float range)
    {      
    int c1 = (int)x2 - (int)x1;
    int c2 = (int)y2 - (int)y1;
    unsigned hx = (x2 - x1)/2;
    unsigned hy = (y2 - y1)/2;
    if((c1 <= 1) || (c2 <= 1))
            return;

// Diamond stage
float a = m_heightmap[x1][y1];
float b = m_heightmap[x2][y1];
float c = m_heightmap[x1][y2];
float d = m_heightmap[x2][y2];
float e = (a+b+c+d) / 4 + GetRnd() * range;

m_heightmap[x1 + hx][y1 + hy] = e;

// Square stage
float f = (a + c + e + e) / 4 + GetRnd() * range;
m_heightmap[x1][y1+hy] = f;
float g = (a + b + e + e) / 4 + GetRnd() * range;
m_heightmap[x1+hx][y1] = g;
float h = (b + d + e + e) / 4 + GetRnd() * range;
m_heightmap[x2][y1+hy] = h;
float i = (c + d + e + e) / 4 + GetRnd() * range;
m_heightmap[x1+hx][y2] = i;

DiamondSquare(x1, y1, x1+hx, y1+hy, range / 2.0);   // Upper left
DiamondSquare(x1+hx, y1, x2, y1+hy, range / 2.0);   // Upper right
DiamondSquare(x1, y1+hy, x1+hx, y2, range / 2.0);   // Lower left
DiamondSquare(x1+hx, y1+hy, x2, y2, range / 2.0);       // Lower right

}

Parametreler: (x1, y1), (x2, y2) - yükseklik haritasındaki bir bölgeyi tanımlayan koordinatlar (varsayılan (0,0) (128,128)). aralık - temelde maks. yükseklik. (varsayılan 32)

Yardım çok takdir edilecektir.


Kodunuza sert bakmadan, muhtemelen sonunda 4 özyinelemeli çağrıda yanlış aramalarda yanlış köşelere sahip gibi görünüyorsunuz. Harita, bir sonraki set hesaplanmadan önce her kare döndürülmüş / çevrilmiş gibi görünür, böylece haritayı garip uçurumlarda alt bölümlere ayırır. Sağ üst karenin alt kenarı, sol üst karenin sağ kenarıyla eşleşiyor gibi görünüyor, vb.
DampeS8N

Neyi kastettiğinden emin değilim. Koordinat sisteminin merkezi sol üst köşede, x ekseni sağa ve y'yi gösteriyor. Yani ilk yinelemede (x1 = 0, y1 = 0), (x2 = 128, y2 = 128) ve (x1 + hx = 64, y1 + hy = 64) karenin merkezidir. Böylece kare 4 alt kareye bölünür: ((0,0) (64,64)), ((64,0) (128,64)), ((0,64) (64,128)) ve ((64, 64) (128.128)). Bana iyi görünüyor ...
Kafka

Yanıtlar:


12

Her alt bölüm düzeyinde, "kare" adım "elmas adım" ın sonuçlarına dayanır. Ama aynı zamanda, hesaba katmadığınız bitişik hücrede üretilen elmas adımını da etkiler. DiamondSquare işlevini, halihazırda sahip olduğunuz derinlik önce değil, önce Genişliği tekrarlamak için yeniden yazardım.

İlk sorununuz, kare kenarları iki kez yeniden hesapladığınız için, bitişik merkez noktanın katkısını yok sayar. Örneğin, referans verdiğiniz makalede,

P = (J + G + K + E)/4 + RAND(d)

ama kodunuz etkili bir şekilde

P = (J + G + J + E)/4 + RAND(d)

yani akımdaki faktörler merkez noktasını iki kez etkiler, iyi merkez noktasını değil. Bu yüzden önce genişliğe gitmeniz gerekir, böylece önceki merkez noktalarınız hesaplanır.

İşte benim kod ve çıktı:.

void DiamondSquare(unsigned x1, unsigned y1, unsigned x2, unsigned y2, float range, unsigned level) {
    if (level < 1) return;

    // diamonds
    for (unsigned i = x1 + level; i < x2; i += level)
        for (unsigned j = y1 + level; j < y2; j += level) {
            float a = m_heightmap[i - level][j - level];
            float b = m_heightmap[i][j - level];
            float c = m_heightmap[i - level][j];
            float d = m_heightmap[i][j];
            float e = m_heightmap[i - level / 2][j - level / 2] = (a + b + c + d) / 4 + GetRnd() * range;
        }

    // squares
    for (unsigned i = x1 + 2 * level; i < x2; i += level)
        for (unsigned j = y1 + 2 * level; j < y2; j += level) {
            float a = m_heightmap[i - level][j - level];
            float b = m_heightmap[i][j - level];
            float c = m_heightmap[i - level][j];
            float d = m_heightmap[i][j];
            float e = m_heightmap[i - level / 2][j - level / 2];

            float f = m_heightmap[i - level][j - level / 2] = (a + c + e + m_heightmap[i - 3 * level / 2][j - level / 2]) / 4 + GetRnd() * range;
            float g = m_heightmap[i - level / 2][j - level] = (a + b + e + m_heightmap[i - level / 2][j - 3 * level / 2]) / 4 + GetRnd() * range;
        }

    DiamondSquare(x1, y1, x2, y2, range / 2, level / 2);
}

http://i.imgur.com/laBhN.png


Evet, aynı zamanda ilk genişlik yaklaşımı üzerinde de düşünüyordum. Bu fraktallar bana her zaman sorun çıkarıyor. Perlin gürültüsü ve L sistemleri için de aynıydı. Harikasın.
kafka

3

Bir olasılık, uygulamanızla bağlantılı sayfanızdaki algoritmanın yapmadığı bir kısayol almanızdır.

Kare aşama için, noktaların yüksekliğini

float f = (a + c + e + e) / 4 + GetRnd() * range;
m_heightmap[x1][y1+hy] = f;

haritanızı kaydırıyorsanız sayfanın algoritmasının kullanacağını gösterir. Bu, "sonraki kare üzerinden" yükseklik değerini kullandığınız görünümü verir. En basit, ilk durumda, f noktası hesaplamak için hem sol hem de sağ tarafta merkezi nokta ('e' yüksekliği ile) kullanılır.

Ancak, başvuruda bulunduğunuz algoritma, bu kare noktanın yüksekliğinin değerini hesaplamanıza yardımcı olması için diğer karelerin / elmasların gerçek değerlerini kullanmanıza yardımcı olur. Algoritmalarında, ikinci seviye noktası aşağıdaki formülle hesaplanır:

N = (K + A + J + F)/4 + RAND(d)

Orada bir değerin çoğaltılmamasına dikkat edin?

Sanırım verilen formüllerin ambalajsız versiyonlarını kullanmaya çalışmak isteyebilirsin, bunlar daha iyi geriletir, sanırım.

F = (A + C + E)/3 + ...
    instead of
F = (A + C + E + E)/4 + ...

Teşekkürler, bu yararlı bir gözlemdi. Denklemleri gördüğümde lezyonumu doğrudan kodlamaya atlamamayı öğrendim.
kafka

Hiç önemli değil. Kendim de çok zaman yapıyorum ... "Bak, kodlayabileceğim bir şey. Zorunlu. Kod. Şimdi!"
fnord
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.