## Seamless fractal terrain using 4D Simplex noise! Let there be land :)

Woot!

After a few (ok, a lot) of missteps I finally got my randomly generated terrain to work! As I mentioned before I’m using a 4D simplex noise generator made  by Gustavson and got pointed in the right way of using it by JTippetts. But the explanations I found were leading me slightly off; I had my mind on tiles and the ranges mentioned were throwing me off.

In the end, I just had to sit down and reset my mind and the solution was easy:

-edit-

just a little explanation here; the xyloop sections define the area which we are taking our noise from and which bound the looping area. To make every map generated random, we shift the noise space by a random amount. For every point we grab from the noise map, we employ a shifter which determines the size of the features. When we have the point (which comes in as a float between -1 and 1) we shift it to be between 0 and 1 and assign a colour to it. Then we put these points into a pixelarray which we write out to our final bitmap, which is saved to disk for retrieval by the tilehandler when needed.

-/edit-

double s;
double t;
int shifter = RNG.nextInt(100000);
double scaler = (RNG.nextInt(150) + 850); //bigger is larger
double scalingfactor = (double)(1.0/scaler);
//m_loop specifies the part of the map to loop (basically sets the resolution of the noise-map, and thus the tile)
double m_loopx0 = 0 + shifter;
double m_loopx1 = (double)((tilewidth * numberOfTilesWidthInt) + shifter);
double m_loopy0 = 0 + shifter;
double m_loopy1 = (double)((tileheight * numberOfTilesHeightInt) + shifter);
double m_dxloop = (double)(m_loopx1-m_loopx0);
double m_dyloop = (double)(m_loopy1-m_loopy0);
noiseTileBitmap = Bitmap.createBitmap(tilewidth, tileheight, Config.ARGB_8888);
int[] noisedpixelsarray = new int[tilewidth * tileheight];

double nx;
double ny;
double nz;
double nw;

for (int i = 0; i<numberOfTilesHeightInt; i++)
{
for (int j = 0; j<numberOfTilesWidthInt; j++)
{
for (int localy = (i * tileheight); localy < ((i+1) * tileheight); localy++)
{
for (int localx = (j * tilewidth); localx < ((j+1) * tilewidth); localx++)
{
s = (double) localx / (double) m_dxloop;
t = (double) localy / (double) m_dyloop;

//Turns out, we don’t need this correction!:

//s = s * (dxmap/m_dxloop);
//t = t * (dymap/m_dyloop);

nx = m_loopx0 + Math.cos(s * 2 * Math.PI)*m_dxloop/(2*Math.PI);
ny = m_loopy0 + Math.cos(t * 2 * Math.PI)*m_dyloop/(2*Math.PI);
nz = m_loopx0 + Math.sin(s * 2 * Math.PI)*m_dxloop/(2*Math.PI);
nw = m_loopy0 + Math.sin(t * 2 * Math.PI)*m_dyloop/(2*Math.PI);
//the scaling factor determines the size of the features of the terrain
noise = SimplexNoise4D.noise(nx* scalingfactor, ny * scalingfactor, nz * scalingfactor, nw * scalingfactor);

noise += SimplexNoise4D.noise(nx * (scalingfactor * 5), ny * (scalingfactor * 5), nz * (scalingfactor * 5), nw * (scalingfactor * 5)) * 0.3;
noise += SimplexNoise4D.noise(nx * (scalingfactor * 30), ny * (scalingfactor * 30), nz * (scalingfactor * 30), nw * (scalingfactor * 30)) * 0.15;

// Adjust range to [0, 1]
noise = ((noise + 1.45) / 2.9);

// Convert noise to colour
alpha = 255;
red = 0;
//green = (int) (128 + (noise*127) + (noise * 64) + (noise * 32));
green = (int) (noise * 255);
blue = 0;

//colouring in the map pixel by pixel (we move this later so we can keep)
if (green > 155) //sea
{
red = 205;
green = 223;
blue = 255;
}
else if (green <= 155 && green > 154) //coast
{
red = 0;
green = 0;
blue = 0;
}
else if (green <= 154) //land
{
/*red = 255;
green = 225;
blue = 205;*/
}
else if (green < 50) //mountaintops
{
red = 255;
green = 225;
blue = 255;
}

// Bounds check colour. The persistence of octaves doesn’t sum to one,
// this will catch any values the fly outside the valid range [0, 255].
//if (red > 255) red = 255;
//else if (red < 0) red = 0;
if (green > 255) green = 255;
else if (green < 0) green = 0;
//if (blue > 255) blue = 255;
//else if (blue < 0) blue = 0;

this.tileColor=Color.argb(alpha, red, green, blue);

noisedpixelsarray[(localx  – (j * tilewidth))+ ((localy – (i*tileheight)) * tilewidth)] = tileColor;
}
}

noiseTileBitmap.setPixels(noisedpixelsarray, 0, tilewidth, 0, 0, tilewidth, tileheight);

_tmpTileCanvas.drawBitmap(noiseTileBitmap, null, dstRect, tmpPaint);
//and draw on h-index-w-index text:
_tmpTileCanvas.drawText(“w” + String.valueOf(j) + “-” + String.valueOf(i), tmpTileBitmap.getWidth() * 0.5f, tmpTileBitmap.getHeight() * 0.5f, penPaint);

saveTile(tmpTileBitmap, j, i);
}
}

And the result? Looky here: This entry was posted in android, art, programming and tagged , , , , . Bookmark the permalink.