Question

I'm trying to implement procedural generation in my game. I want to really grasp and understand all of the algorithms nessecary rather than simply copying/pasting existing code. In order to do this I've attempted to implement 1D midpoint displacement on my own. I've used the information here to write and guide my code. Below is my completed code, it doesn't throw an error but that results don't appear correct.

srand(time(NULL));

const int lineLength = 65;
float range = 1.0;
float displacedLine[lineLength];

for (int i = 0; i < lineLength; i++)
{
    displacedLine[i] = 0.0;
}

for (int p = 0; p < 100; p++)
{
    int segments = 1;
    for (int i = 0; i < (lineLength / pow(2, 2)); i++)
    {
        int segs = segments;
        for (int j = 0; j < segs; j++)
        {
            int x = floor(lineLength / segs);
            int start = (j * x) + 1;
            int end = start + x;
            if (i == 0)
            {
                end--;
            }
            float lo = -range;
            float hi = +range;
            float change = lo + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / (hi - lo)));

            int center = ((end - start) / 2) + start;
            displacedLine[center - 1] += change;
            segments++;
        }
        range /= 2;
    }
}

Where exactly have I made mistakes and how might I correct them?

I'm getting results like this:

My Results

But I was expecting results like this:

Expected Results

Était-ce utile?

La solution

The answer is very simple and by the way I'm impressed you managed to debug all the potential off-by-one errors in your code. The following line is wrong:

displacedLine[center - 1] += change;

You correctly compute the center index and change amount but you missed that the change should be applied to the midpoint in terms of height. That is:

displacedLine[center - 1] = (displacedLine[start] + displacedLine[end]) / 2;
displacedLine[center - 1] += change;

I'm sure you get the idea.

Autres conseils

The problem seems to be that you are changing only the midpoint of each line segment, rather than changing the rest of the line segment in proportion to its distance from each end to the midpoint. The following code appears to give you something more like what you're looking for:

#include <iostream>
#include <cstdlib>
#include <math.h>
#include <algorithm>

using namespace std;

void displaceMidPt (float dline[], int len, float disp) {
    int midPt = len/2;
    float fmidPt = float(midPt);
    for (int i = 1; i <= midPt; i++) {
        float ptDisp = disp * float(i)/fmidPt;
        dline[i] += ptDisp;
        dline[len-i] += ptDisp;
    }
}

void displace (float displacedLine[], int lineLength, float range) {
    for (int p = 0; p < 100; p++) {
        int segs = pow(p, 2);
        for (int j = 0; j < segs; j++) {
            float lo = -range;
            float hi = +range;
            float change = lo + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / (hi - lo)));
            int start = int(float(j)/float(segs)*float(lineLength));
            int end = int(float(j+1)/float(segs)*float(lineLength));
            displaceMidPt (displacedLine+start,end-start,change);
            }
        range /= 2;
    }
}

void plot1D (float x[], int len, int ht = 10) {
    float minX = *min_element(x,x+len);
    float maxX = *max_element(x,x+len);
    int xi[len];
    for (int i = 0; i < len; i++) {
        xi[i] = int(ht*(x[i] - minX)/(maxX - minX) + 0.5);
    }
    char s[len+1];
    s[len] = '\0';
    for (int j = ht; j >= 0; j--) {
        for (int i = 0; i < len; i++) {
            if (xi[i] == j) {
                s[i] = '*';
            } else {
                s[i] = ' ';
            }
        }
        cout << s << endl;
    }
}

int main () {
    srand(time(NULL));

    const int lineLength = 65;
    float range = 1.0;
    float displacedLine[lineLength];

    for (int i = 0; i < lineLength; i++) {
        displacedLine[i] = 0.0;
    }

    displace (displacedLine,lineLength,range);
    plot1D (displacedLine,lineLength);
    return 0;
}

When run this way, it produces the following result:

$ c++ -lm displace.cpp
$ ./a
                                  *
                              *       *
                                 * ***
                             * *       *             *
                         * **            ****       * **
      * ***  ****  *   *                *    **         *
     * *   **    ** ***   *     *                * *
   **                                          **        *
  *                     *                         *       ***
**                                                            ***
                                                             *
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top