2016-04-27 26 views
1

Ich habe eine grobe Interpretation der Diamond-Square-Algorithmus in C++, um einige semi-realistische fraktale Gelände zu erstellen, aber die Ausgabe scheint nur wie ein zufälliger y-Wert bei jeder Punkt eher als glatte felsige Formen. Ich habe die Parameter geändert, aber ich habe das Gefühl, dass ein Blick auf den Code von außen dazu beitragen könnte, das Problem zu verstehen. Hier sind Beispiele für die Ausgabe:C++ - Diamond-Square-Algorithmus Ausgabe ist zufällig und laut

ich diese bekam:

Example

Und sollte wie folgt aussehen:

What it *should* look like (this is loaded from a file)

Der Code:

//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); 
    } 
} 

}

+2

was meinst du mit "grobe Interpretation"? Vielleicht ist Ihr Beispiel eine grobe Interpretation dessen, wie es aussehen soll. – user463035818

+0

Zu faul, um durch Ihren Code zu gehen, also nur Hinweise: 1. Rekursion ist wirklich schwierig, da Überlappungen und Kantenübergänge Unregelmäßigkeiten einfacher/schneller/besser Iteration stattdessen verwenden Sie meine [Iterative Diamond & Square in C++] (http: // stackoverflow.com/a/36258843/2521214) 2. Es sieht so aus, als ob Sie die Zufälligkeit nicht anpassen (die Magnitude sollte mit der Rekursionsebene geliebäugelt werden) oder nicht die durchschnittliche Position als Basis (Mittelpunktverschiebung), aber das ist nur der visuelle Eindruck, den Sie überprüfen müssen (könnte auch falsche Rekursion sein). Siehe auch [Inselgenerator] (http://stackoverflow.com/a/36647622/2521214) – Spektre

Antwort

0

Ihr Mittelpunkt Berechnungen falsch aussehen. Der Algorithmus sollte den Mittelpunkt dieses Quadrats oder Diamanten als den Durchschnitt der vier Eckpunkte plus einen zufälligen Wert festlegen. Aber in Ihrem Code sehe ich:

y = rand() % (int)(avg/5);

Diese im Grunde sagt, setzen Sie y auf eine Zufallszahl zwischen null & ein Fünftel des Durchschnitts der Ecken. Stattdessen würde ich erwarten, so etwas zu sehen:

// get a random float in the range 0 to 1 
float r = (float)(rand())/(float)(RAND_MAX); 
// scale r to be in the range -magnitude to magnitude 
r = (r * 2 * magnitude) - magnitude; 
// add the scaled random value to the average of the corners 
y = avg + r; 

Hinweis: es ist möglich, dass dieser Ansatz, den Sie gibt y-Werte von weniger als Null ist. Wenn das ein Problem ist, normalisieren Sie die Daten, indem Sie den niedrigsten Wert & finden, der diesen Betrag von jedem y subtrahiert.