2013-04-16 16 views
0

Я создаю генератор высоты с использованием шума Perlin, как говорится в названии.Генерация высот с использованием Perlin Noise возвращает черное растровое изображение

я использовал псевдокод с этого сайта ->

и повернулся, чтобы C# код. до сих пор я выполнил все назначения типа переменной, и код дает результат. к сожалению, мой результат выглядит следующим образом:>enter image description here

как вы можете видеть, правый и нижний края имеют небольшой градиент от черного до белого, но все остальное черное.

вот мой C# источник ->

private void button1_Click(object sender, EventArgs e) { 
     persistence = float.Parse(textBox4.Text); 
     NumberOfOctaves = Int32.Parse(textBox5.Text); 

     int width = Int32.Parse(textBox1.Text); 
     int height = Int32.Parse(textBox2.Text); 
     float zoom = float.Parse(textBox3.Text); 

     generate(width, height, zoom); 
    } 

    public float Noise(int x, int y) { 
     long n = x + (y * 57); 
     n = (long)Math.Pow((n << 13), n); 
     return (float)(1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff)/1073741824.0); 
    } 

    public float SmoothNoise(float x, float y) { 
     float corners = (Noise((int) (x-1), (int) (y-1)) + Noise((int) (x+1), (int) (y-1)) + Noise((int) (x-1), (int) (y+1)) + Noise((int) (x+1), (int) (y+1)))/16; 
     float sides = (Noise((int) (x-1), (int) y) + Noise((int) (x+1), (int) y) + Noise((int) x, (int) (y-1)) + Noise((int) x, (int) (y+1)))/8 ; 
     float center = Noise((int)x, (int)y)/4; 
     return corners + sides + center; 
    } 

    public float CosineInterpolate(float a, float b, float x) { 
     double ft = x * 3.1415927; 
     double f = (1 - Math.Cos(ft)) * 0.5; 

     return (float)((a * (1 - f)) + (b * f)); 
    } 

    public float InterpolatedNoise(float x, float y) { 
     // MessageBox.Show(x.ToString()); 
     int intX = (int)x; 
     float fractX = x - intX; 

     int intY = (int) y; 
     float fractY = y - intY; 

     float v1 = SmoothNoise(intX,  intY); 
     float v2 = SmoothNoise(intX + 1, intY); 
     float v3 = SmoothNoise(intX,  intY + 1); 
     float v4 = SmoothNoise(intX + 1, intY + 1); 

     float i1 = CosineInterpolate(v1 , v2 , fractX); 
     float i2 = CosineInterpolate(v3 , v4 , fractX); 

     // MessageBox.Show(intX + "\n" + intY + "\n" + fractX + "\n" + fractY + "\n" + v1 + "\n" + v2 + "\n" + v3 + "\n" + v4 + "\n" + i1 + "\n" + i2 + "\n" + CosineInterpolate(i1, i2, fractY)); 

     return CosineInterpolate(i1 , i2 , fractY); 
    } 

    public float PerlinNoise2D(float x, float y) { 
     float total = 0; 
     float p = persistence; 
     int n = NumberOfOctaves; 

     for(int i = 0; i < n; i++) { 
      int frequency = (int)Math.Pow(2, i); 
      // MessageBox.Show(Math.Pow(2, i).ToString()); 
      float amplitude = (int)Math.Pow(p, i); 
      total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude; 
     } 
     return total; 
    } 

    private void generate(int sizeX, int sizeY, float zoom) { 
     int zoomX = (int)(sizeX * zoom); 
     int zoomY = (int)(sizeY * zoom); 

     float max = int.MinValue; 
     float min = int.MaxValue; 

     float[,] nmap = new float[zoomX,zoomY]; 

     Bitmap heightMap = new Bitmap(zoomX,zoomY); 

     for (int x=0; x<zoomX; x++) { 
      for (int y=0; y<zoomY; y++) { 
       // MessageBox.Show(PerlinNoise2D(x/zoom, y/zoom).ToString()); 

       nmap[x,y] = PerlinNoise2D(x/zoom,y/zoom); 
       max = (max < nmap[x,y]) ? nmap[x,y] : max; 
       min = (min > nmap[x,y]) ? nmap[x,y] : min; 
      } 
     } 

     max = max-min; 

     for (int x=0; x<zoomX;x++) { 
      for (int y=0; y<zoomY;y++) { 
       int calc = (int) ((nmap[x,y] - min)/max); 
       heightMap.SetPixel(x,y,Color.FromArgb(calc,calc,calc)); 
      } 
     } 

     pictureBox1.Image = heightMap; 
    } 

также я мог загрузить визуальное решение студии в почтовый индекс, если кто-то хочет, чтобы.

До сих пор я узнал, что что-то не так с функцией Noise(), потому что оно возвращает -0,281 ... больше всего времени. он должен возвращать числа с плавающей запятой между -1.0 и 1.0. Я пробовал его с другими случайными функциями, но каждый раз выводит вывод.

Надеюсь, вы, ребята, можете мне помочь, и thx для аннуальных предложений.

+0

Я предполагаю, что они имели в виду 0x7fffffff. Тем не менее, почему бы вам не попробовать использовать встроенный случайный класс C#? – redtuna

+0

Я также пробовал его с помощью 0x7fffffff, но результат тот же. как я знаю, все сборки в случайных классах почти в каждом программируемом языке не на 100% случайны при значениях max & min ... Значения между min & max генерируют гораздо больше, чем значения, близкие к min & max ... – Ace

+0

Туз, это любопытная вещь - вы смогли ее проверить? Разумеется, никакая детерминированная функция не будет на 100% случайной, но если ваша проблема в том, что ваша псевдослучайная функция нарушена, кажется разумным сначала попробовать встроенный, прежде чем писать свою собственную замену. – redtuna

ответ

2

Я нашел две проблемы в коде.

Во-первых, вы неправильно интерпретировали символ ^ как функцию питания в исходном коде, хотя это операция xor. Так линия

n = (long)Math.Pow((n << 13), n); 

Должно быть

n = (long)((n << 13)^n); 

Во-вторых, при создании цвета пикселя от значения шума, ваш шум в диапазоне 0..1, а значение цвета должно быть в диапазоне 0..255, поэтому линия

int calc = (int) ((nmap[x,y] - min)/max); 

Должно быть

int calc = (int) (((nmap[x,y] - min)/max) * 255); 

Полный рабочий (консольный) образец здесь: http://ideone.com/RGVf8J