ปัญหาการสร้างภูมิประเทศแบบสี่เหลี่ยมจัตุรัส


11

ฉันใช้อัลกอริทึม Diamond-Square ตามบทความนี้: http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2

ปัญหาคือฉันได้หน้าผาที่สูงชันเหล่านี้ไปทั่วแผนที่ มันเกิดขึ้นที่ขอบเมื่อภูมิประเทศถูกแบ่งย่อยซ้ำแล้วซ้ำอีก:

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือแหล่งที่มา:

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

}

พารามิเตอร์: (x1, y1), (x2, y2) - พิกัดที่กำหนดพื้นที่บน heightmap (ค่าเริ่มต้น (0,0) (128,128)) ช่วง - สูงสุดโดยทั่วไป ความสูง (ค่าเริ่มต้น 32)

ความช่วยเหลือจะได้รับการชื่นชมอย่างมาก


ดูเหมือนว่าคุณอาจมีมุมที่ผิดในการโทรที่ไม่ถูกต้องในการโทรซ้ำ 4 ครั้งที่สิ้นสุด แผนที่ดูเหมือนว่าแต่ละตารางจะถูกหมุน / พลิกก่อนที่จะคำนวณชุดถัดไปดังนั้นการแบ่งแผนที่ย่อยบนหน้าผาแปลก ขอบด้านล่างของตารางด้านบนขวาดูเหมือนจะตรงกับขอบด้านขวาของตารางด้านบนซ้ายและอื่น ๆ
DampeS8N

ฉันไม่แน่ใจว่าคุณหมายถึงอะไร ศูนย์กลางของระบบพิกัดอยู่ที่มุมบนซ้ายแกน x ชี้ไปทางขวาและ y ลง ดังนั้นในการวนซ้ำครั้งแรก (x1 = 0, y1 = 0), (x2 = 128, y2 = 128) และ (x1 + hx = 64, y1 + hy = 64) เป็นศูนย์กลางของจัตุรัส สแควร์ถูกแบ่งออกเป็น 4 ส่วนย่อย: ((0,0) (64,64)), ((64,0) (128,64)), ((0,64) (64,128)) และ ((64, 64) (128,128)) ดูดีสำหรับฉัน ...
kafka

คำตอบ:


12

ในแต่ละระดับส่วนย่อยขั้นตอน "สแควร์" ขึ้นอยู่กับผลลัพธ์ของ "ขั้นตอนเพชร" แต่มันก็เป็นปัจจัยในขั้นตอนของเพชรที่ผลิตในเซลล์ที่อยู่ติดกันซึ่งคุณไม่ได้คำนึงถึง ฉันจะเขียนฟังก์ชั่น DiamondSquare ใหม่เพื่อย้ำความกว้างก่อน - แทนที่ความลึกก่อนตามที่คุณมีอยู่ในปัจจุบัน

ปัญหาแรกของคุณคือเนื่องจากคุณคำนวณขอบสี่เหลี่ยมซ้ำสองครั้งมันจะไม่สนใจจุดศูนย์กลางที่อยู่ติดกัน ตัวอย่างเช่นในบทความที่คุณอ้างอิง

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

แต่รหัสของคุณจะมีประสิทธิภาพ

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

นั่นคือปัจจัยในจุดศูนย์กลางปัจจุบันสองครั้งไม่ใช่จุดศูนย์กลาง adjecent นี่คือสาเหตุที่คุณต้องกว้างก่อนเพื่อให้คุณคำนวณจุดกึ่งกลางก่อนหน้านี้

นี่คือรหัสของฉันและผลลัพธ์:

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


ใช่ฉันยังคิดตามแนวทางที่กว้างเป็นอันดับแรก fractals เหล่านี้มักจะทำให้ฉันมีปัญหา มันเป็นแบบเดียวกันกับเสียง Perlin และระบบ L คุณเจ๋งมาก.
kafka

3

มีความเป็นไปได้อย่างหนึ่งคือคุณกำลังใช้ช็อตคัทกับการติดตั้งที่อัลกอริทึมในหน้าที่เชื่อมโยงของคุณไม่มี

สำหรับสแควร์สเตจคุณกำลังคำนวณความสูงของคะแนนด้วย

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

อัลกอริทึมของหน้าระบุว่าจะใช้หากคุณกำลังตัดแผนที่ของคุณ สิ่งนี้จะให้ลักษณะที่คุณใช้ในการคำนวณค่าความสูงของ "สี่เหลี่ยมถัดไป" ในกรณีที่ง่ายที่สุดกรณีแรกจะใช้จุดศูนย์กลาง (พร้อมความสูง 'e') ทั้งด้านซ้ายและด้านขวาเพื่อคำนวณ f

อย่างไรก็ตามอัลกอริทึมที่คุณอ้างอิงใช้ค่าจริงของสี่เหลี่ยม / เพชรอื่น ๆ เพื่อช่วยคุณคำนวณค่าความสูงของจุดสแควร์นี้ ในอัลกอริทึมของพวกเขาจุดระดับที่สองจะคำนวณด้วยสูตรต่อไปนี้:

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

สังเกตเห็นการขาดการทำซ้ำของค่าในนั้นหรือไม่

ฉันคิดว่าคุณอาจต้องการที่จะลองใช้สูตรที่ไม่ได้ห่อมาให้พวกนั้นจะดีขึ้นฉันคิดว่า

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

ขอบคุณนั่นเป็นข้อสังเกตที่เป็นประโยชน์ ฉันคิดว่าฉันเรียนรู้ว่าบาดแผลของฉันไม่ควรกระโดดไปที่รหัสโดยตรงเมื่อฉันเห็นสมการ
kafka

ยินดีต้อนรับคุณค่อนข้าง ฉันทำด้วยตัวเองเป็นจำนวนมากเช่นกัน ... "ดูสิสิ่งที่ฉันสามารถเขียนโปรแกรมได้ต้องได้รหัสตอนนี้!"
ฟอร์ด
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.