Output algoritma Diamond-Square adalah acak dan berisik


8

Saya telah menerapkan interpretasi kasar dari algoritma Diamond-Square di C + + untuk membuat beberapa medan fraktal semi-realistis, tetapi output hanya tampak seperti nilai acak y pada setiap titik daripada bentuk berbatu yang halus. Saya telah mengubah parameter tetapi merasa seperti melihat kode di luar mungkin membantu saya memahami masalah ini. Berikut adalah contoh hasilnya:

Sebagai bitmap (top-down) dengan variasi ketinggian diturunkan:

Apa yang harus terlihat seperti (ini diambil dari file):

Kode:

//Diamond-square algorithm
HeightMap::HeightMap(float maxY) {
//type = GL_POINTS; 
//type = GL_LINES;
numVertices = RAW_WIDTH*RAW_HEIGHT; //256^2 squares => 257^2 vertices
numIndices = (RAW_WIDTH - 1)*(RAW_HEIGHT - 1) * 6; //each square is 2 triangles (6 indices)
vertices = new Vector3[numVertices];
textureCoords = new Vector2[numVertices];
indices = new GLuint[numIndices];
colours = new Vector4[numVertices];

int cornerA, cornerB, cornerC, cornerD; //Identify corners
cornerA = 0;
cornerB = RAW_WIDTH - 1;
cornerC = RAW_WIDTH*RAW_HEIGHT - RAW_WIDTH;
cornerD = RAW_WIDTH*RAW_HEIGHT - 1;

//Create vertices
for (int x = 0; x < RAW_WIDTH; ++x) {
    for (int z = 0; z < RAW_HEIGHT; ++z) {
        int offset = (x * RAW_WIDTH) + z;
        float y = 0; //Start with vertices set flat
        if (offset == cornerA ||
            offset == cornerB ||
            offset == cornerC ||
            offset == cornerD) {
            vertices[offset] = Vector3(x * HEIGHTMAP_X, maxY/2, z * HEIGHTMAP_Z); //Initialise corners to mid height
            std::cout << "Corners: " << offset << std::endl;
        }

        if (vertices[offset] == Vector3(0, 0, 0)) {
            vertices[offset] = Vector3(x * HEIGHTMAP_X, y * HEIGHTMAP_Y, z * HEIGHTMAP_Z);
        }
        //  textureCoords[offset] = Vector2(x * HEIGHTMAP_TEX_X, z * HEIGHTMAP_TEX_Z);
    }
}

Vector3 tl, tr, bl, br;
tl = vertices[cornerA];
tr = vertices[cornerB];
bl = vertices[cornerC];
br = vertices[cornerD];

float roughness = 1.0f;

Square square = Square(tl, tr, bl, br);
diamondSquare(vertices, numVertices, square, roughness);

//Colour
for (int x = 0; x < RAW_WIDTH; ++x) {
    for (int z = 0; z < RAW_HEIGHT; ++z) {
        int offset = (x*RAW_WIDTH) + z;
        float shade;
        if (vertices[offset].y > 0) {
            shade = 1 - 1.0f / (vertices[offset].y / maxY * 2);
        }
        else {
            shade = 0.1f;
        }
        colours[offset] = Vector4(shade, shade, shade, 1.0f);
        //Colour any vertex that hasn't been passed over red
        if (vertices[offset].y == maxY / 2 + 100) {
            colours[offset] = Vector4(1, 0, 0, 1);
        }
    }
}

//Create indices
numIndices = 0;
for (int x = 0; x < RAW_WIDTH - 1; ++x) {
    for (int z = 0; z < RAW_HEIGHT - 1; ++z) {
        int a = (x*(RAW_WIDTH)) + z;
        int b = ((x + 1)*(RAW_WIDTH)) + z;
        int c = ((x + 1)*(RAW_WIDTH)) + (z + 1);
        int d = (x*(RAW_WIDTH)) + (z + 1);

        indices[numIndices++] = c;
        indices[numIndices++] = b;
        indices[numIndices++] = a;
        indices[numIndices++] = a;
        indices[numIndices++] = d;
        indices[numIndices++] = c;

    }
}
BufferData();

}

void HeightMap::squareStep(Vector3 vertices[], int len, Vector3 tl, Vector3 tr, Vector3 bl, Vector3 br, float mid, float roughness) {
for (int i = 0; i < len; i++) {
    Vector3 top = (tl + tr) / 2;
    Vector3 bot = (bl + br) / 2;
    Vector3 left = (tl + bl) / 2;
    Vector3 right = (tr + br) / 2;
    top.y = 0;
    bot.y = 0;
    left.y = 0;
    right.y = 0;
    if (vertices[i] == top ||
        vertices[i] == bot ||
        vertices[i] == left ||
        vertices[i] == right) {
        float y = rand() % (int)(mid/5);
        y *= roughness;
        vertices[i] = Vector3(vertices[i].x, mid + y, vertices[i].z); //Set Diamond centre points to mid height + rand
        std::cout << "Square: " << vertices[i];
    }
}

}

float HeightMap::diamondStep(Vector3 vertices[], int len, Vector3 tl, Vector3 tr, Vector3 bl, Vector3 br, float roughness) {
float avg;
float y;
    for (int i = 0; i < len; i++) {
        Vector3 corners = (tl + tr + bl + br) / 4;
        avg = corners.y;
        y = rand() % (int)(avg/5);
        y *= roughness;
        corners.y = 0;
        if (vertices[i] == corners) {
            vertices[i] = Vector3(vertices[i].x, avg + y, vertices[i].z);         //Set Square centre point to avg height of corners + rand
            std::cout << "Diamond: " << vertices[i];
        }
    }
return avg + y;

}

void HeightMap::diamondSquare(Vector3 vertices[], int numVertices, Square s, float roughness) {
Vector3 tl = s.tl;
Vector3 tr = s.tr;
Vector3 bl = s.bl;
Vector3 br = s.br;
float mid = diamondStep(vertices, numVertices, tl, tr, bl, br, roughness);
squareStep(vertices, numVertices, tl, tr, bl, br, mid, roughness);
roughness *= 0.75f;
if (s.width > 2 * HEIGHTMAP_X) {
    std::vector<Square> squares = s.split();
    for (int i = 0; i < 4; i++) {
        diamondSquare(vertices, numVertices, squares[i], roughness);
    }
}

}


1
Dalam metode diamondSquare, Langkah-berlian dan Langkah-persegi tampaknya beroperasi di sudut yang sama. Tetapi sebenarnya Anda harus melakukan langkah-persegi empat kali, sekali untuk masing-masing sub-kotak yang dihasilkan oleh langkah-berlian sebelumnya. Dan kemudian langkah-persegi harus melakukan hal yang sama dan melakukan empat langkah berlian. Tetapi ada cukup banyak hal lain yang berbau dalam kode itu, seperti for-loop di diamondStep yang membuang dan menulis ulang nilai kembali fungsi di setiap iterasi.
Philipp

4
Ketika saya mengimplementasikan DS untuk pertama kalinya, saya memastikan untuk membuat proses interaktif sehingga saya bisa melihat dengan tepat apa yang terjadi pada setiap langkah, dimulai dengan empat sudut seluruh ruang dan bekerja melalui setiap iterasi berikutnya. Ubah data, modifikasi simpul sesuai, bilas, ulangi. Saya sarankan Anda melakukan ini, karena algoritma rekursif bisa sulit untuk dilacak.
Insinyur

Bagaimana Anda memutuskan untuk mengurangi ukuran langkah roughness *= 0.75f;?
Roflo

Saya perlu mengoreksi komentar saya sebelumnya: Anda hanya harus melakukan satu langkah berlian untuk setiap langkah persegi, bukan empat . Tetapi Anda masih harus melakukan empat langkah persegi setelah setiap langkah berlian. Saya berharap implementasi yang tepat untuk memiliki panggilan diamondStep squareStep dan kemudian squareStep panggilan diamondStep sampai kedalaman iterasi yang diinginkan tercapai.
Philipp

Jawaban:


1

Saya pikir biasanya Anda akan memasukkan ketinggian titik tengah di langkah persegi (dan melakukan langkah berlian pertama. Yang) akan sedikit mempengaruhi bagaimana runcing kelihatannya membuatnya menjadi lereng yang lebih bertahap. Apakah Anda mencobanya dengan offset acak berkurang?

Tampaknya juga selama ketinggian positif, tidak ada peluang untuk tinggi offset menjadi negatif sehingga semakin tinggi poin, semakin tinggi offset membuatnya semakin runcing.

Saya membuat program yang cukup sederhana dengan algoritihm ini memberikan hasil yang oke dan alih-alih mendasarkan offset acak dari rata-rata ketinggian, saya membuatnya dipengaruhi oleh gridwidth saat ini.


-3

Untuk Memperbaiki keacakan ketinggian, Anda dapat menerapkan Perlin Noise .

Yang menghasilkan ketinggian berdasarkan ketinggian adjecent dan dengan demikian Anda mendapatkan hasil yang sangat halus.

Berikut adalah beberapa Implementasi pada C ++


2
Ini bukan jawaban untuk pertanyaan
Bálint

1
Selamat datang di gamedev.SE. Harap dicatat bahwa ini adalah komunitas tanya jawab. Kami hanya menjawab pertanyaan saat ditulis. Pertanyaan ini secara eksplisit menanyakan tentang masalah dengan penerapan algoritma berlian-persegi. "Gunakan algoritma yang sama sekali berbeda" bukanlah jawaban yang baik untuk pertanyaan seperti itu.
Philipp

1
Algoritma Diamond Square dan Perlin Noise adalah dua algoritma yang berbeda untuk menghasilkan noise yang koheren. Anda tidak akan menggunakan yang satu untuk membuat yang lain.
MichaelHouse
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.