Vấn đề tạo địa hình kim cương vuông


11

Tôi đã triển khai thuật toán hình vuông kim cương theo bài viết này: http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2

Vấn đề là tôi có được những vách đá dựng đứng trên khắp bản đồ. Nó xảy ra ở các cạnh, khi địa hình được phân chia đệ quy:

nhập mô tả hình ảnh ở đây

Đây là nguồn:

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

}

Các tham số: (x1, y1), (x2, y2) - tọa độ xác định một vùng trên sơ đồ chiều cao (mặc định (0,0) (128,128)). phạm vi - về cơ bản tối đa. Chiều cao. (mặc định 32)

Trợ giúp sẽ được đánh giá cao.


Nếu không nhìn kỹ vào mã của bạn, có vẻ như bạn có thể có các góc sai trong các cuộc gọi sai trong 4 cuộc gọi đệ quy ở cuối. Bản đồ trông giống như mỗi hình vuông được xoay / lật trước khi tính toán bộ tiếp theo, do đó phân chia bản đồ trên các vách đá lạ. Cạnh dưới của hình vuông trên cùng bên phải trông giống như cạnh bên phải của hình vuông trên cùng bên trái, v.v.
DampeS8N

Tôi không chắc ý của bạn là gì. Tâm của hệ tọa độ nằm ở góc trên cùng bên trái, trục x hướng về bên phải và y xuống. Vì vậy, trong lần lặp đầu tiên (x1 = 0, y1 = 0), (x2 = 128, y2 = 128) và (x1 + hx = 64, y1 + hy = 64) là tâm của hình vuông. Do đó, hình vuông được chia thành 4 phần con: ((0,0) (64,64)), ((64,0) (128,64)), ((0,64) (64,128)) và ((64, 64) (128.128)). Có vẻ tốt với tôi ...
kafka

Câu trả lời:


11

Trong mỗi cấp độ phân khu, bước "vuông" phụ thuộc vào kết quả của "bước kim cương". Nhưng nó cũng là yếu tố trong bước kim cương được sản xuất trong ô liền kề mà bạn không tính đến. Tôi sẽ viết lại hàm DiamondSapes để lặp lại Breadth-first, thay vì sâu trước như bạn hiện có.

Vấn đề đầu tiên của bạn là vì bạn tính lại các cạnh vuông hai lần, nó bỏ qua sự đóng góp của điểm trung tâm liền kề. Ví dụ, trong bài viết bạn tham khảo,

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

nhưng mã của bạn có hiệu quả

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

tức là các yếu tố trong trung tâm hiện tại hai lần, không phải là trung tâm phụ. Đây là lý do tại sao bạn cần đi đầu tiên, để bạn có các điểm trung tâm trước đó được tính toán.

Đây là mã của tôi và đầu ra :.

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


Vâng, tôi cũng đã suy nghĩ theo hướng tiếp cận đầu tiên. Những mảnh nhỏ này luôn gây ra cho tôi những vấn đề. Điều này cũng tương tự với tiếng ồn Perlin và hệ thống L. Bạn thật tuyệt vời.
kafka

3

Một khả năng là bạn đang thực hiện một lối tắt với việc triển khai mà thuật toán trên trang được liên kết của bạn không có.

Đối với giai đoạn hình vuông, bạn đang tính chiều cao của các điểm với

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

mà thuật toán của trang chỉ ra để sử dụng nếu bạn đang bọc bản đồ của mình. Điều này mang lại vẻ ngoài mà bạn đang sử dụng giá trị chiều cao của "hình vuông tiếp theo" để tính toán giá trị này. Trong trường hợp đơn giản, đầu tiên, điểm trung tâm (có chiều cao 'e') được sử dụng ở cả bên trái và bên phải để tính f.

Tuy nhiên, thuật toán bạn tham chiếu có bạn sử dụng các giá trị thực tế của các hình vuông / hình thoi khác để giúp bạn tính giá trị chiều cao của điểm vuông này. Trong thuật toán của họ, điểm cấp hai được tính theo công thức sau:

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

Lưu ý sự thiếu trùng lặp của một giá trị trong đó?

Tôi nghĩ rằng bạn có thể muốn thử sử dụng các phiên bản không gói của các công thức được đưa ra, những thứ đó sẽ tái diễn tốt hơn, tôi nghĩ vậy.

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

Cảm ơn, đó là một quan sát hữu ích. Tôi nghĩ rằng tôi đã học được tổn thương của mình khi không nhảy trực tiếp vào mã hóa, khi tôi thấy các phương trình.
kafka

Bạn được chào đón. Tôi cũng tự mình làm rất nhiều thời gian ... "Hãy nhìn xem, thứ gì đó tôi có thể viết mã. Phải. Mã. Ngay bây giờ!"
fnord ngày
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.