HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Is there a way to optimise my Perlin noise?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
perlinwayoptimisenoisethere

Problem

I just started using Perlin noise a few days ago, and the results look quite good. But it takes over 3 seconds to calculate and draw a 1024x1024 bitmap of said noise. I use an array of 1024x1024 to store int32s ranging from -1 to 1.

Please note that the variable tileSize equals 1024 / resolutieX. This is in case I want to use a lower resolution Perlin noise.

```
private void button1_Click(object sender, EventArgs e)
{
sw.Start();
LibNoise.Perlin perlinMap = new LibNoise.Perlin();
perlinMap.Lacunarity = lacunarity + 0.01d;
perlinMap.NoiseQuality = LibNoise.NoiseQuality.High;
perlinMap.OctaveCount = octaveCount;
perlinMap.Persistence = persistence;
perlinMap.Frequency = frequency;
perlinMap.Seed = 1024;

if (radioButton1.Checked)
perlinMap.NoiseQuality = LibNoise.NoiseQuality.Low;
else if (radioButton2.Checked)
perlinMap.NoiseQuality = LibNoise.NoiseQuality.Standard;
else if (radioButton3.Checked)
perlinMap.NoiseQuality = LibNoise.NoiseQuality.High;

double sample = trackBar6.Value * 10;

double[,] perlinArray = new double[resolutieX, resolutieY];
for (int x = 0; x < resolutieX; x++)
{
for (int y = 0; y < resolutieY; y++)
{
perlinArray[x, y] = perlinMap.GetValue(x / sample, y / sample, 1d);
}
}
draw(perlinArray);
textBox12.Text = sw.ElapsedMilliseconds.ToString() + "ms";
sw.Reset();
}

public void draw(double[,] array)
{
Bitmap afbeelding = new Bitmap(1024, 1024);
Color color;
int tileSize = 1024 / resolutieY;
for (int y = 1; y < resolutieY; y++)
{
for (int x = 1; x < resolutieX; x++)
{
if (array[x, y] <= -0.2)
color = Color.DarkBlue;
if (array[x, y] <= 0)
color = Color.DarkBlue;

Solution

Your check

if (array[x, y] <= -0.2)
    color = Color.DarkBlue;


serves no purpose, if your number is indeed lessthan or equal -.2 then it will also hit the next check if it is lessthan or equal to 0.

A prettier way to write if-else blocks like yours would have been to use the ternary operator...

color = array[x, y] <= 0.0  ? Color.DarkBlue       :
        array[x, y] <= 0.1  ? Color.Blue           :
        array[x, y] <= 0.2  ? Color.Beige          :
        array[x, y] <= 0.22 ? Color.LightGreen     :
        array[x, y] <= 0.40 ? Color.Green          :
        array[x, y] <= 0.75 ? Color.DarkGreen      :
        array[x, y] <= 0.8  ? Color.LightSlateGray :
        array[x, y] <= 0.9  ? Color.Gray           :
        array[x, y] <= 1.0  ? Color.DarkSlateGray  :
                              Color.DarkSlateGray  ;


Your method draw is a public method, and should be PascalCase not camelCase

Your worst case scenario for the if-else chain is that you have to hit every single one of those IFs.
If you structured those in binary search design, ie. start from the middle and eliminate half of the spectrum at a time and work your way out, worst case scenario is that you have to hit half of your IFs. The code for this may look ugly, but it would help.

The most inefficient thing about your code though, and the reason it is taking so long to process is most likely your quadruple nested for-loop

for (int y = 1; y < resolutieY; y++)
{
    for (int x = 1; x < resolutieX; x++)
    {
        //color calculations

        for (int i = 0; i < tileSize; i++)
        {
            for (int j = 0; j < tileSize; j++)
            {
                afbeelding.SetPixel(((x - 1) * tileSize) + i, ((y - 1) * tileSize) + j, color);
            }
        }
    }
}


I would recommend instead, to create the 2d array of colors in that first double for-loop, then, loop over that Color[,] and set the pixels.

If possible, instead just create a max resolution version of your image, and rely on the PictureBox's ability to scale the image for you.

Code Snippets

if (array[x, y] <= -0.2)
    color = Color.DarkBlue;
color = array[x, y] <= 0.0  ? Color.DarkBlue       :
        array[x, y] <= 0.1  ? Color.Blue           :
        array[x, y] <= 0.2  ? Color.Beige          :
        array[x, y] <= 0.22 ? Color.LightGreen     :
        array[x, y] <= 0.40 ? Color.Green          :
        array[x, y] <= 0.75 ? Color.DarkGreen      :
        array[x, y] <= 0.8  ? Color.LightSlateGray :
        array[x, y] <= 0.9  ? Color.Gray           :
        array[x, y] <= 1.0  ? Color.DarkSlateGray  :
                              Color.DarkSlateGray  ;
for (int y = 1; y < resolutieY; y++)
{
    for (int x = 1; x < resolutieX; x++)
    {
        //color calculations

        for (int i = 0; i < tileSize; i++)
        {
            for (int j = 0; j < tileSize; j++)
            {
                afbeelding.SetPixel(((x - 1) * tileSize) + i, ((y - 1) * tileSize) + j, color);
            }
        }
    }
}

Context

StackExchange Code Review Q#54065, answer score: 6

Revisions (0)

No revisions yet.