Masalah generasi medan berlian-persegi

11

Saya telah menerapkan algoritma berlian-persegi sesuai dengan artikel ini: http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2

Masalahnya adalah saya mendapatkan tebing curam ini di seluruh peta. Ini terjadi di tepian, saat medan dibagi secara rekursif:

masukkan deskripsi gambar di sini

Inilah sumbernya:

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

}

Parameter: (x1, y1), (x2, y2) - koordinat yang menentukan suatu wilayah pada peta ketinggian (default (0,0) (128.128)). kisaran - pada dasarnya maks. tinggi. (default 32)

Bantuan akan sangat dihargai.

kafka
sumber
Tanpa melihat keras pada kode Anda, sepertinya Anda mungkin memiliki sudut yang salah dalam panggilan yang salah dalam 4 panggilan rekursif di akhir. Peta tampak seperti setiap kotak diputar / dibalik sebelum menghitung set berikutnya, sehingga membagi peta pada tebing aneh. Tepi bawah kotak kanan atas terlihat cocok dengan tepi kanan kotak kiri atas, dan seterusnya.
DampeS8N
Saya tidak yakin apa yang Anda maksud. Pusat sistem koordinat berada di sudut kiri atas, sumbu x menunjuk ke kanan dan y ke bawah. Jadi dalam iterasi pertama (x1 = 0, y1 = 0), (x2 = 128, y2 = 128) dan (x1 + hx = 64, y1 + hy = 64) adalah pusat dari bujur sangkar. Kuadrat demikian dibagi menjadi 4 subsquares: ((0,0) (64,64)), ((64,0) (128,64)), ((0,64) (64,128)) dan ((64, 64) (128.128)). Terlihat bagus untuk saya ...
kafka

Jawaban:

12

Di setiap tingkat pembagian, langkah "kuadrat" bergantung pada hasil "langkah berlian". Tapi itu juga faktor dalam langkah berlian yang diproduksi di sel yang berdekatan, yang tidak Anda perhitungkan. Saya akan menulis ulang fungsi DiamondSquare untuk beralih Breadth-first, bukan depth-first seperti yang Anda miliki saat ini.

Masalah pertama Anda adalah karena Anda menghitung ulang tepi persegi dua kali, itu mengabaikan kontribusi titik pusat yang berdekatan. Misalnya, dalam artikel yang Anda referensi,

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

tetapi kode Anda efektif

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

yaitu faktor di titik tengah saat ini dua kali, bukan titik tengah yang berdekatan. Inilah sebabnya mengapa Anda harus pergi dulu, sehingga Anda memiliki titik tengah sebelumnya dihitung.

Ini kode saya dan hasilnya:.

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

Jimmy
sumber
Ya, saya juga berpikir sejalan dengan pendekatan pertama. Fraktal ini selalu menyebabkan masalah bagi saya. Itu sama dengan kebisingan Perlin dan sistem-L. Kamu luar biasa.
kafka
3

Satu kemungkinan adalah Anda mengambil jalan pintas dengan implementasi Anda yang tidak dimiliki algoritma pada halaman yang ditautkan.

Untuk tahap kuadrat, Anda menghitung ketinggian poin dengan

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

dimana algoritma halaman menunjukkan untuk digunakan jika Anda membungkus peta Anda. Ini memberi kesan bahwa Anda menggunakan nilai tinggi "kuadrat berikutnya" untuk menghitung yang satu ini. Dalam kasus paling sederhana, pertama, titik pusat (dengan tinggi 'e') digunakan pada sisi kiri dan kanan untuk menghitung f.

Namun, algoritma yang Anda referensikan telah Anda gunakan nilai aktual dari kuadrat lain / berlian untuk membantu Anda menghitung nilai ketinggian titik persegi ini. Dalam algoritme mereka, titik level kedua dihitung dengan rumus berikut:

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

Perhatikan kurangnya duplikasi nilai di sana?

Saya pikir Anda mungkin ingin mencoba menggunakan versi non-pembungkus formula yang diberikan, itu akan muncul kembali dengan lebih baik, saya pikir.

F = (A + C + E)/3 + ...
    instead of
F = (A + C + E + E)/4 + ...
fnord
sumber
Terima kasih, itu pengamatan yang bermanfaat. Saya pikir saya belajar lesi saya untuk tidak langsung melompat ke pengkodean, ketika saya melihat persamaannya.
kafka
Anda cukup diterima. Saya sering melakukannya sendiri ... "Lihat, sesuatu yang bisa saya kode. Harus. Kode. Sekarang!"
fnord