Diamond-Squareアルゴリズムの出力はランダムでノイズが多い


8

C ++でダイヤモンドスクエアアルゴリズムの大まかな解釈を実装して、半現実的なフラクタル地形を作成しましたが、出力は滑らかな岩の形状ではなく、各ポイントでランダムなy値のように見えます。パラメータを変更しましたが、コードの外観を見て問題を理解するのに役立つかもしれません。次に出力の例を示します。

高さの変化を下げたビットマップ(トップダウン)として:

それどのように見えるべきか(これはファイルからロードされます):

コード:

//Diamond-square algorithm
HeightMap::HeightMap(float maxY) {
//type = GL_POINTS; 
//type = GL_LINES;
numVertices = RAW_WIDTH*RAW_HEIGHT; //256^2 squares => 257^2 vertices
numIndices = (RAW_WIDTH - 1)*(RAW_HEIGHT - 1) * 6; //each square is 2 triangles (6 indices)
vertices = new Vector3[numVertices];
textureCoords = new Vector2[numVertices];
indices = new GLuint[numIndices];
colours = new Vector4[numVertices];

int cornerA, cornerB, cornerC, cornerD; //Identify corners
cornerA = 0;
cornerB = RAW_WIDTH - 1;
cornerC = RAW_WIDTH*RAW_HEIGHT - RAW_WIDTH;
cornerD = RAW_WIDTH*RAW_HEIGHT - 1;

//Create vertices
for (int x = 0; x < RAW_WIDTH; ++x) {
    for (int z = 0; z < RAW_HEIGHT; ++z) {
        int offset = (x * RAW_WIDTH) + z;
        float y = 0; //Start with vertices set flat
        if (offset == cornerA ||
            offset == cornerB ||
            offset == cornerC ||
            offset == cornerD) {
            vertices[offset] = Vector3(x * HEIGHTMAP_X, maxY/2, z * HEIGHTMAP_Z); //Initialise corners to mid height
            std::cout << "Corners: " << offset << std::endl;
        }

        if (vertices[offset] == Vector3(0, 0, 0)) {
            vertices[offset] = Vector3(x * HEIGHTMAP_X, y * HEIGHTMAP_Y, z * HEIGHTMAP_Z);
        }
        //  textureCoords[offset] = Vector2(x * HEIGHTMAP_TEX_X, z * HEIGHTMAP_TEX_Z);
    }
}

Vector3 tl, tr, bl, br;
tl = vertices[cornerA];
tr = vertices[cornerB];
bl = vertices[cornerC];
br = vertices[cornerD];

float roughness = 1.0f;

Square square = Square(tl, tr, bl, br);
diamondSquare(vertices, numVertices, square, roughness);

//Colour
for (int x = 0; x < RAW_WIDTH; ++x) {
    for (int z = 0; z < RAW_HEIGHT; ++z) {
        int offset = (x*RAW_WIDTH) + z;
        float shade;
        if (vertices[offset].y > 0) {
            shade = 1 - 1.0f / (vertices[offset].y / maxY * 2);
        }
        else {
            shade = 0.1f;
        }
        colours[offset] = Vector4(shade, shade, shade, 1.0f);
        //Colour any vertex that hasn't been passed over red
        if (vertices[offset].y == maxY / 2 + 100) {
            colours[offset] = Vector4(1, 0, 0, 1);
        }
    }
}

//Create indices
numIndices = 0;
for (int x = 0; x < RAW_WIDTH - 1; ++x) {
    for (int z = 0; z < RAW_HEIGHT - 1; ++z) {
        int a = (x*(RAW_WIDTH)) + z;
        int b = ((x + 1)*(RAW_WIDTH)) + z;
        int c = ((x + 1)*(RAW_WIDTH)) + (z + 1);
        int d = (x*(RAW_WIDTH)) + (z + 1);

        indices[numIndices++] = c;
        indices[numIndices++] = b;
        indices[numIndices++] = a;
        indices[numIndices++] = a;
        indices[numIndices++] = d;
        indices[numIndices++] = c;

    }
}
BufferData();

}

void HeightMap::squareStep(Vector3 vertices[], int len, Vector3 tl, Vector3 tr, Vector3 bl, Vector3 br, float mid, float roughness) {
for (int i = 0; i < len; i++) {
    Vector3 top = (tl + tr) / 2;
    Vector3 bot = (bl + br) / 2;
    Vector3 left = (tl + bl) / 2;
    Vector3 right = (tr + br) / 2;
    top.y = 0;
    bot.y = 0;
    left.y = 0;
    right.y = 0;
    if (vertices[i] == top ||
        vertices[i] == bot ||
        vertices[i] == left ||
        vertices[i] == right) {
        float y = rand() % (int)(mid/5);
        y *= roughness;
        vertices[i] = Vector3(vertices[i].x, mid + y, vertices[i].z); //Set Diamond centre points to mid height + rand
        std::cout << "Square: " << vertices[i];
    }
}

}

float HeightMap::diamondStep(Vector3 vertices[], int len, Vector3 tl, Vector3 tr, Vector3 bl, Vector3 br, float roughness) {
float avg;
float y;
    for (int i = 0; i < len; i++) {
        Vector3 corners = (tl + tr + bl + br) / 4;
        avg = corners.y;
        y = rand() % (int)(avg/5);
        y *= roughness;
        corners.y = 0;
        if (vertices[i] == corners) {
            vertices[i] = Vector3(vertices[i].x, avg + y, vertices[i].z);         //Set Square centre point to avg height of corners + rand
            std::cout << "Diamond: " << vertices[i];
        }
    }
return avg + y;

}

void HeightMap::diamondSquare(Vector3 vertices[], int numVertices, Square s, float roughness) {
Vector3 tl = s.tl;
Vector3 tr = s.tr;
Vector3 bl = s.bl;
Vector3 br = s.br;
float mid = diamondStep(vertices, numVertices, tl, tr, bl, br, roughness);
squareStep(vertices, numVertices, tl, tr, bl, br, mid, roughness);
roughness *= 0.75f;
if (s.width > 2 * HEIGHTMAP_X) {
    std::vector<Square> squares = s.split();
    for (int i = 0; i < 4; i++) {
        diamondSquare(vertices, numVertices, squares[i], roughness);
    }
}

}


1
diamondSquareメソッドでは、diamond-Stepとsquare-Stepが同じコーナーで動作するように見えます。しかし、実際には、正方形のステップを4回実行することになっています。前のダイヤモンドステップによって生成された各サブ正方形に対して1回ずつです。そして、正方形のステップは同じことを行い、4つのダイヤモンドステップを実行する必要があります。しかし、そのコードには他にも多くの臭いがあります。たとえば、diamondStepのforループのように、反復ごとに関数の戻り値を破棄して書き換えます。
フィリップ

4
初めてDSを実装したときは、プロセス全体をインタラクティブにして、スペース全体の4つのコーナーから始まり、その後の反復ごとに作業を進めて、各ステップで何が起こっているかを正確に確認できるようにしました。データを変更し、それに応じて頂点を変更し、すすぎ、繰り返します。再帰的なアルゴリズムは追跡しないと追跡が難しいため、これを行うことをお勧めします。
エンジニア

どのようにしてステップサイズを小さくすることにしましたroughness *= 0.75f;か?
Roflo

以前のコメントを訂正する必要があります。正方形のステップごとに4 つではなく、1つのダイヤモンドステップを実行することになっています。しかし、ダイヤモンドステップごとに、4つの四角ステップを実行する必要があります。適切な実装ではdiamondStepがsquareStepを呼び出し、次にsquareStepがdiamondStepを呼び出して、目的の反復深度に到達することが期待されます。
フィリップ

回答:


1

私は通常、正方形のステップに中間点の高さを含めます(そして最初にダイヤモンドのステップを実行します)。ランダムオフセットを減らして試してみましたか?

また、高さが正である限り、高さのオフセットが負になる可能性はないため、ポイントが高いほど、オフセットが高くなり、尖っています。

私はこのアルゴリズムを使用してかなり単純なプログラムを作成しました。ランダムなオフセットを高さの平均から外す代わりに、現在のグリッド幅の影響を受けました。


-3

高さのランダム性を修正するには、Perlin Noiseを実装できます。

隣接する高さに基づいて高さが生成されるため、非常にスムーズな結果が得られます。

これは C ++での実装です


2
これは、質問への答えではありません
バリント

1
gamedev.SEへようこそ。これは質疑応答コミュニティであることに注意してください。書かれた質問にのみ答えます。この質問は、ダイヤモンド二乗アルゴリズムの実装に関する問題について明確に尋ねています。「完全に異なるアルゴリズムを使用する」はそのような質問に対する良い答えではありません。
フィリップ

1
Diamond SquareアルゴリズムとPerlin Noiseは、コヒーレントノイズを生成するための2つの異なるアルゴリズムです。一方を使用して他方を作成することはありません。
MichaelHouse
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.