ダイヤモンドスクエア地形生成問題


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

回答:


12

各サブディビジョンレベルでは、「正方形」ステップは「ダイヤモンドステップ」の結果に依存します。ただし、隣接セルで生成されるダイヤモンドステップも考慮に入れられますが、これは考慮されていません。現在あるように、DeepSquare関数を書き直して、深さ優先ではなく幅優先で反復処理します。

最初の問題は、正方形のエッジを2回再計算するため、隣接する中心点の寄与を無視することです。たとえば、あなたが参照する記事では、

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

しかし、あなたのコードは効果的に

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

つまり、隣接する中心点ではなく、現在の中心点を2回考慮します。このため、幅優先で前の中心点を計算する必要があります。

これが私のコードと出力です。

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


はい、私は幅優先アプローチの線に沿って考えていました。これらのフラクタルは常に私に問題を引き起こしています。パーリンノイズやLシステムと同じでした。あなたは素晴らしいです。
kafka 2012

3

可能性の1つは、リンクされたページのアルゴリズムにはない、実装のショートカットを取っていることです。

正方形のステージの場合は、ポイントの高さを計算します

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

マップをラップしている場合に、ページのアルゴリズムが使用するように指示します。これにより、「次の正方形」の高さ値を使用してこれを計算しているように見えます。最も単純な最初のケースでは、中心点(高さ「e」)は、fを計算するために左側と右側の両方で使用されます。

ただし、参照するアルゴリズムでは、他の四角形/ひし形の実際の値を使用して、この四角形の点の高さの値を計算できます。彼らのアルゴリズムでは、第2レベルのポイントは次の式で計算されます。

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

そこに値の重複がないことに気づきましたか?

与えられた式のラッピングしないバージョンを使用することを試みたいと思うかもしれません、それらはよりよく再帰するだろうと思います。

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

ありがとう、それは有益な観察でした。方程式を見ると、病変がコーディングに直接ジャンプしないようになったと思います。
kafka 2012

どういたしまして。私自身も多くの時間を費やしています...「見て、私がコーディングできるもの。
2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.