1

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

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

并转为 C# 代码。到目前为止,我已经完成了所有变量类型分配,并且代码给出了输出。不幸的是我的输出看起来像这样->在此处输入图像描述

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

这是我的 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;
    }

如果有人愿意,我也可以以 zip 格式上传 Visual Studio 解决方案。

到目前为止,我发现 Noise() 函数有问题,因为它返回 -0,281 的次数最多。它应该返回介于 -1.0 和 1.0 之间的浮点数。我已经尝试过使用其他随机函数,但每次输出都一样。

我希望你们能帮助我,谢谢你的建议。

4

1 回答 1

3

我在代码中发现了两个问题。

首先,您错误地将^符号解释为原始源代码中的幂函数,而它是异或运算。所以线

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

于 2014-06-26T21:25:36.127 回答