菱形方形地形生成问题


11

根据本文,我已经实现了菱形平方算法: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)-定义高度图上区域的坐标(默认为(0,0)(128,128))。范围-基本上最大 高度。(默认为32)

帮助将不胜感激。


不用仔细看代码,看起来在最后的4个递归调用中,您可能在错误的调用中遇到了错误的角落。该地图看起来像每个正方形在计算下一组之前都已旋转/翻转,因此将地图细分为奇特的悬崖。右上角正方形的底部边缘看起来像它与左上角正方形的右边缘匹配,依此类推。
DampeS8N 2012年

我不确定你是什么意思。坐标系的中心在左上角,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 2012年

Answers:


12

在每个细分级别中,“正方形”步骤取决于“钻石步骤”的结果。但这也影响了相邻单元中产生的菱形台阶,您无需考虑。我将重写DiamondSquare函数以迭代广度优先,而不是像当前那样深度优先。

您的第一个问题是,由于您两次重新计算了正方形边缘,因此它忽略了相邻中心点的影响。例如,在您引用的文章中,

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

但是你的代码有效地做到了

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

也就是说,它是当前中心点的两倍,而不是相邻中心点。这就是为什么需要广度优先的原因,这样才能计算出先前的中心点。

这是我的代码和输出:

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


是的,我也在考虑广度优先方法。这些分形总是给我带来麻烦。Perlin噪声和L系统也是如此。你真棒。
卡夫卡2012年

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 + ...

谢谢,这是一个有益的观察。我认为当我看到方程式时,我学会了避免直接跳入编码。
卡夫卡2012年

你太客气了。我自己也花了很多时间……“看,我可以编码。必须。现在。”
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.