4

ダイヤモンド スクエア アルゴリズムを使用して、ランダムな地形を生成しています。これらの大きな円錐形が地形から突き出ているか、地形に突き出ていることを除いて、うまく機能します。問題は、時々、ポイントが高すぎたり低すぎたりすることです。

これが問題の写真です
スクリーンショット

そして、滑らかさを非常に高く設定すると、よりよく見えるようになります
スクリーンショットのクローズアップ

そして、ここに私のコードがあります -

private void CreateHeights()
    {
        if (cbUseLand.Checked == false) 
            return;
        int
            Size = Convert.ToInt32(System.Math.Pow(2, int.Parse(tbDetail.Text)) + 1),
            SideLength = Size - 1,
            d = 1025 / (Size - 1),
            HalfSide;
        Heights = new Point3D[Size, Size];
        float
            r = float.Parse(tbHeight.Text),
            Roughness = float.Parse(RoughnessBox.Text);

        //seeding all the points
        for (int x = 0; x < Size; x++)
            for (int y = 0; y < Size; y++)
                Heights[x, y] = Make3DPoint(x * d, 740, y * d);

        while (SideLength >= 2)
        {
            HalfSide = SideLength / 2;

            for (int x = 0; x < Size - 1; x = x + SideLength)
            {
                for (int y = 0; y < Size - 1; y = y + SideLength)
                {
                    Heights[x + HalfSide, y + HalfSide].y =
                      (Heights[x, y].y +
                      Heights[x + SideLength, y].y +
                      Heights[x, y + SideLength].y +
                      Heights[x + SideLength, y + SideLength].y) / 4 - r + ((float)(random.NextDouble() * r) * 2);
                }
            }

            for (int x = 0; x < Size - 1; x = x + SideLength)
            {
                for (int y = 0; y < Size - 1; y = y + SideLength)
                {
                    if (y != 0)
                        Heights[x + HalfSide, y].y = (Heights[x, y].y + Heights[x + SideLength, y].y + Heights[x + HalfSide, y + HalfSide].y + Heights[x + HalfSide, y - HalfSide].y) / 4 - r + ((float)(random.NextDouble() * r) * 2); 
                    if (x != 0)
                        Heights[x, y + HalfSide].y = (Heights[x, y].y + Heights[x, y + SideLength].y + Heights[x + HalfSide, y + HalfSide].y + Heights[x - HalfSide, y + HalfSide].y) / 4 - r + ((float)(random.NextDouble() * r) * 2);
                }
            }
            SideLength = SideLength / 2;
            r = r / Roughness;
        }
    }
4

4 に答える 4

6

Gavin SP Miller は SIGGRAPH '86 で、Fournier、Fussel & Carpenter の元のアルゴリズムに根本的な欠陥があったことについて講演しました。したがって、ダイヤモンド スクエア アルゴリズムの単純な実装では、これは正常な結果です。平滑化には、各 Diamond-Square 複合ステップをポストするか、すべての Diamond-Square 反復の後処理として (またはその両方)、個別のアプローチが必要になります。ミラーはこれに対処しました。重み付けとボックスまたはガウス フィルタリングは 1 つのオプションです。最初の 4 点だけでなく、最初の配列をシードする (つまり、ダイアモンド スクエアの最初の数ステップの結果セットを、手動または組み込みのインテリジェンスを使用して複製しますが、代わりにバイアスのない値を提供します)。ダイアモンドスクエアを使用して詳細を増やす前に、配列に与える初期情報が多いほど、結果は良くなります。

その理由は、Square ステップの実行方法にあるようです。ダイアモンド ステップでは、正方形の 4 つの角の平均をとって、その正方形の中心を生成しました。次に、後続の Square ステップで、直交して隣接する 4 つの隣接要素の平均をとります。そのうちの 1 つは、作成したばかりの正方形の中心点です。. 問題が見えますか?これらの元の角の高さの値は、それ自体の影響と作成した中間点の両方を通じて寄与しているため、後続のダイヤモンド スクエアの反復に大きく寄与しています。これにより、尖塔 (押し出しと侵入) が発生します。これは、局所的に派生したポイントが初期のポイントに強く向かう傾向があるためです...そして (通常は 3 つの) 他のポイントも同様であるため、反復すると、これらのポイントの周りに「円形」の影響が作成されます。 Diamond-Square を使用してより深い深度まで。したがって、この種の「エイリアシング」の問題は、配列の初期状態が十分に指定されていない場合にのみ発生します。実際、発生するアーティファクトは、最初に 4 つのポイントのみを使用したことによる直接的な幾何学的結果と見なすことができます。

次のいずれかを実行できます。

  • ローカル フィルタリングを行います -- 一般に高価です。
  • 初期配列をより徹底的にプレシードします -- ある程度の知性が必要です。
  • 与えられた初期点のセットからあまりにも多くのステップを滑らかにしないでください。これは、初期配列をシードしても適用されます。それはすべて、独自の最大変位パラメーターと組み合わせた相対的な深さの問題です。
于 2012-10-17T12:44:51.153 に答える
0

各反復における変位rのサイズは、現在の長方形のサイズに比例するはずです。この背後にあるロジックは、フラクタル サーフェスはスケール不変であるため、任意の四角形の高さの変化はその四角形のサイズに比例する必要があるということです。

コードでは、高さの変化は r に比例するため、現在のグリッド サイズに比例するように維持する必要があります。つまり、ループの前に r にラフネスを掛け、各反復で r を 2 で割ります。

だから、代わりに

r = r / Roughness;

あなたは書くべきです

r = r / 2;
于 2011-09-26T02:06:22.380 に答える
0

上記のアルゴリズムの実際の欠陥は、概念化と実装のエラーです。アルゴリズムとしてのダイヤモンド スクエアにはアーティファクトがありますが、これは範囲ベースのアーティファクトです。したがって、一部のピクセルの技術的な最大値は、他の一部のピクセルよりも高くなります。ランダム性によって直接値が与えられるピクセルもあれば、菱形および二乗中点補間プロセスによって値を取得するピクセルもあります。

ここでのエラーは、ゼロから始めたことです。そして、値を現在の値に繰り返し追加しました。これにより、二乗されたダイヤモンドの範囲がゼロから始まり、上方に拡張されます。実際にはゼロから始まり、ランダム性に応じて上下する必要があります。したがって、トップレンジのことは問題になりません。しかし、これに気づかず、ゼロから始めてそこから変動するのではなく、すべてを値に追加するように単純に実装すると、隠されたアーティファクトが明らかになります。

Miller の指摘は正しかったが、一般的にその欠陥はノイズの中に隠されている。この実装は、それらの問題を示しています。それは正常ではありません。そして、いくつかの異なる方法で修正できます。これが、このアルゴリズムを拡張してすべてのメモリ制限とサイズ制限を取り除き、それを無限かつ決定論的にした1後でも、コアのアイデアから離れた理由の 1 つです (3D への拡張と GPU 向けの最適化の問題)。も役割を果たした.2

ダイヤモンド二乗アーティファクト

于 2016-05-05T01:34:13.183 に答える