Генерация карты высот с использованием Perlin Noise возвращает черное растровое изображение

Я делаю генератор карт высот, используя Perlin Noise, как сказано в заголовке.

я использовал псевдокод с этого сайта -> http://freespace.virgin.net/hugo.elias/models/m_perlin.htm

и обратился к коду 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;
    }

Также я мог бы загрузить решение Visual Studio в zip-архиве, если кто-то захочет.

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

Я надеюсь, что вы, ребята, можете мне помочь, и спасибо за любые предложения.


person Ace    schedule 16.04.2013    source источник
comment
Я предполагаю, они имели в виду 0x7fffffff. Тем не менее, почему бы вам не попробовать вместо этого использовать встроенный в C # класс Random?   -  person redtuna    schedule 17.04.2013
comment
Я также пробовал с 0x7fffffff, но результат тот же. как я знаю, все сборки в случайных классах практически на всех языках программирования не являются на 100% случайными при максимальных и минимальных значениях ... значения между минимальным и максимальным значениями генерируются намного чаще, чем значения около минимального и максимального ...   -  person Ace    schedule 17.04.2013
comment
Эйс, это любопытная вещь - вы смогли это проверить? Конечно, никакая детерминированная функция не будет на 100% случайной, но если ваша проблема в том, что ваша псевдослучайная функция не работает, кажется разумным сначала попробовать встроенную, прежде чем писать свою собственную замену.   -  person redtuna    schedule 17.04.2013


Ответы (1)


Я обнаружил две проблемы в коде.

Во-первых, вы неправильно интерпретировали символ ^ как степенную функцию в исходном исходном коде, в то время как это операция 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

person Alexander    schedule 26.06.2014