使用Perlin Noise生成高度图会返回黑色位图

时间:2013-04-16 22:58:58

标签: c# .net generator perlin-noise heightmap

正如标题所示,我正在使用Perlin Noise制作高度图生成器。

我使用过这个网站的伪代码 - > http://freespace.virgin.net/hugo.elias/models/m_perlin.htm

并转入C#代码。到目前为止,我已完成所有变量类型赋值,代码给出了输出。不幸的是我的输出看起来像这样 - > enter image description here

如你所见,右边和下边有从黑到白的轻微渐变,但其他一切都是黑色的。

这是我的c#source - >

    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之间的浮点数。 我已尝试使用其他随机函数,但输出每次都相同。

我希望你们可以帮助我,以及他们提出的建议。

1 个答案:

答案 0 :(得分: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