So I'm making a map generator that makes random islands. It uses Perlin Noise at the heart of the generator and then a method using circles with gradients to make the islands.
The circle method creates a number of circles in the centerish of the map with a gradient from a colour starting at 64 down to 0. The issue is that this method is creating a un-natrual look at parts of the map with circular edges. When the perlin noise is generated for a pixel it will get that pixel on the gradient map and then mutliply it by the blue value.
So if the perlin noise gives a one on pixel 1, 5 and the blue value on the gradient map is 54 it will output a noise value of 54. If the perlin noise on pixel 130, 560 is 0.5 and the gradient colour value is 64 then the noise value of 32.
Here is what I am getting:
There is two key points to the code, the perlin bit:
noise = NoiseGenerator.Noise(x, y);
double gradColour = getGradColour(x, y).B;
double addedNoise = noise * gradColour;
double gradNoise = addedNoise;// - gradColour;
And then the gradient map generator:
public static void DrawGrad(float X, float Y, float R, Color C1, Color C2)
{
Graphics g = Graphics.FromImage(imgGrad);
GraphicsPath path = new GraphicsPath();
path.AddEllipse(X, Y, R, R);
PathGradientBrush pathGrBrush = new PathGradientBrush(path);
pathGrBrush.CenterColor = C1;
Color[] colours = { C2 };
pathGrBrush.SurroundColors = colours;
g.FillEllipse(pathGrBrush, X, Y, R, R);
//g.FillEllipse(Brushes.Red, X, Y, R, R);
g.Flush();
}
int amount = rnd.Next(25, 30);
for (int i = 0; i < amount / 4; i++)
{
float X = rnd.Next(-800, 1748);
float Y = rnd.Next(-800, 1748);
float R = rnd.Next(1000, 1200);
DrawGrad(X, Y, R, Color.FromArgb(255, 0, 0, rnd.Next(15, 20)), Color.FromArgb(0, 0, 0, 0));
}
for (int i = 0; i < amount; i++)
{
double positionDiv = 1.98;
double X1 = rnd.Next(0, 450) / positionDiv;
double Y1 = rnd.Next(0, 450) / positionDiv;
double R1 = rnd.Next(300, 650) / 4;
float R = (float)R1;
float X = (float)X1;
float Y = (float)Y1;
while (X + R > 1004)
{
X = 924 - R;
}
while (Y + R > 1004)
{
Y = 924 - R;
}
if(X < 30)
{
X = 30;
}
if(Y < 30)
{
Y = 30;
}
DrawGrad(X, Y, R, Color.FromArgb(255, 0, 0, rnd.Next(40, 64)), Color.FromArgb(0, 0, 0, rnd.Next(13, 17)));
}
I was just wondering if anyone else knows any other methods in C# that could create an island using perlin noise? Any advice would be greatly appreciated.
As I mentioned in the comment diamond and square is much easier with good enough results. So the algorithm:
configure generation properties
Here you need to have set of parameters like min,max elevation, sea level, elevation ranges for vegetation, sand/rock/dirt, etc, slope parameters etc.
create terrain height map I call it
zed[][]
For this you need slightly modified Diamond&Square algorithm. The problem is this algorithm produces "inland" like terrain.
To adjust it so it produces island like terrains you need to initialize it with lowest possible elevation in corners. Also you need to ignore the first diamond step and initialize the mid point with some random value instead (not average of corners). And last after each square iteration correct the border points to the minimal (underwater) elevation (or some random value near it).
To achieve the good output I use approximately range
<-2^15 , 2^16>
while generation. After this I find min and max elevation in the generated terrain and rescale to configured elevation ranges.Do not forget that Diamond and square need map of resolution
(2^n)+1
!!!create surface map I call it
typ[][]
When terrain map is finished you can add elevation based features like these in ascending order:
Then add parameters based on slope of terrain
Then you can add additional things like (based on some rules):
I do it in C++ like this:
The output with current settings is like this:
[Notes]
This approach usually produce only single big hill on the island. (Inland is generated OK) If you want more of them you can create more terrain maps and average them together.
I do following instead: I set the middle point to max height and ignore first diamond pass. After the first square pass I set the middle point back to some random value. This adds the possibility of more central hills then just one. Using this approach and adding lighting (ambient + normal shading) to preview and slight tweaking of pixel size (
35m
) I got this result:On rare occasion this can generate inland like map (if the central area is too small. To handle it you can scan corners for watter. if there is land generate again or add some bias for central points randomness in first pass.
You can play with the code for example add rivers:
if it is on edge of map or set to sea/water type stop otherwise loop #3
If you want more then one rivers then do not forget to use some temp type for already done rivers so the algorithm can work properly. You can also increase the river volume with distance from start... Here is the result:
After this you should also equalize the formed lakes water level.