如何为类似Minecraft的引擎生成漂浮的陆地块?


19

我正在XNA中创建类似于Minecraft的引擎。我想要做的是创建类似于此视频中所示的浮岛:

http://www.youtube.com/watch?v=gqHVOEPQK5g&feature=related

我将如何使用世界生成器复制它?我必须使用一些Perlin噪声算法吗?我不知道这将如何帮助我取得这样的土地质量。

这是我正在使用的perlin噪声发生器的代码:

    private double[,] noiseValues;
    private float amplitude = 1;    // Max amplitude of the function
    private int frequency = 1;      // Frequency of the function

    /// <summary>
    /// Constructor
    /// </summary>
    /// 
    public PerlinNoise(int freq, float _amp)
    {
        Random rand = new Random(System.Environment.TickCount);
        noiseValues = new double[freq, freq];
        amplitude = _amp;
        frequency = freq;

        // Generate our noise values
        for (int i = 0; i < freq; i++)
        {
            for (int k = 0; k < freq; k++)
            {
                noiseValues[i, k] = rand.NextDouble();
            }
        }
    }

    /// <summary>
    /// Get the interpolated point from the noise graph using cosine interpolation
    /// </summary>
    /// <returns></returns>
    public double getInterpolatedPoint(int _xa, int _xb, int _ya, int _yb, double x, double y)
    {
        double i1 = interpolate(
            noiseValues[_xa % Frequency, _ya % frequency],
            noiseValues[_xb % Frequency, _ya % frequency]
            , x);

        double i2 = interpolate(
            noiseValues[_xa % Frequency, _yb % frequency],
            noiseValues[_xb % Frequency, _yb % frequency]
            , x);

        return interpolate(i1, i2, y);
    }

    public static double[,] SumNoiseFunctions(int width, int height, List<PerlinNoise> noiseFunctions)
    {
        double[,] summedValues = new double[width, height];

        // Sum each of the noise functions
        for (int i = 0; i < noiseFunctions.Count; i++)
        {
            double x_step = (float)width / (float)noiseFunctions[i].Frequency;
            double y_step = (float)height / (float)noiseFunctions[i].Frequency;

            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    int a = (int)(x / x_step);
                    int b = a + 1;
                    int c = (int)(y / y_step);
                    int d = c + 1;

                    double intpl_val = noiseFunctions[i].getInterpolatedPoint(a, b, c, d, (x / x_step) - a, (y / y_step) - c);
                    summedValues[x, y] += intpl_val * noiseFunctions[i].Amplitude;
                }
            }
        }
        return summedValues;
    }

    /// <summary>
    /// Get the interpolated point from the noise graph using cosine interpolation
    /// </summary>
    /// <returns></returns>
    private double interpolate(double a, double b, double x)
    {
        double ft = x * Math.PI;
        double f = (1 - Math.Cos(ft)) * .5;

        // Returns a Y value between 0 and 1
        return a * (1 - f) + b * f;
    }

    public float Amplitude { get { return amplitude; } }
    public int Frequency { get { return frequency; } }

但问题是代码的编写者使用以下代码来产生噪声,至少我不太理解。

    private Block[, ,] GenerateLandmass()
    {
        Block[, ,] blocks = new Block[300, 400, 300];

        List<PerlinNoise> perlins = new List<PerlinNoise>();
        perlins.Add(new PerlinNoise(36, 29));
        perlins.Add(new PerlinNoise(4, 33));

        double[,] noisemap = PerlinNoise.SumNoiseFunctions(300, 300, perlins); 

        int centrey = 400 / 2;

        for (short x = 0; x < blocks.GetLength(0); x++)
        {
            for (short y = 0; y < blocks.GetLength(1); y++)
            {
                for (short z = 0; z < blocks.GetLength(2); z++)
                {
                    blocks[x, y, z] = new Block(BlockType.none);
                }
            }
        }

        for (short x = 0; x < blocks.GetLength(0); x++)
        {
            for (short z = 0; z < blocks.GetLength(2); z++)
            {
                blocks[x, centrey - (int)noisemap[x, z], z].BlockType = BlockType.stone; 
            }
        }

        //blocks = GrowLandmass(blocks);

        return blocks;
    }

这是我正在使用的网站:http : //lotsacode.wordpress.com/2010/02/24/perlin-noise-in-c/

我正在尝试以Martin Sojka所指定的方式实现perlin噪声。

好的,这就是我到目前为止所得到的:

在此处输入图片说明

Answers:


21

对于基准区域,制作两个2D连续噪声场(Perlin,Simplex,Wavelet,或它们的组合-随便您如何使用),其中一个通常为低频。低振幅部分为平台的上限,另一部分同时具有高频,高振幅部分和低频,高振幅,为平台的下限。如果下限高于上限,则不包括任何陆地体素(或您的游戏将用来表示地形的任何物体)。最终结果大致如下所示:


但这是二维的吗?
Darestium

但我还是很喜欢:)
Darestium

4
2D / 3D-同一件事
Gavin Williams

好吧,明天尝试实施它的恶意尝试...祝我好运;)
Darestium 2011年

@Darestium:这是一个2D示例,可轻松实现可视化。相同的方法适用于任意数量(代数)大于1的维。
马丁·索伊卡

15

这样的东西够了吗?

在此处输入图片说明

如果是这样,请查看本文。引用最相关的部分:

为了获得更多有趣的噪声,可以将多个八度的单工噪声相加在一起。[...]由于我想得到一种大致呈球形的浮石,因此需要将噪声乘以其距中心的距离。我也希望岩石的顶部比底部更平坦,因此第二个乘数是y方向上的梯度。将它们组合在一起并拉伸y以获得噪声,同时压缩x和za位,我们得到的东西就像一块浮石。[...]挖掘洞穴时会稍微抵消一些噪声,这也使它更加有趣。

  • 因此,基本上,您将从以单形或perlin 噪声(或多个噪声加在一起的八度音)生成的数据集开始。
  • 然后通过使其更球形(通过将噪声乘以其距中心的距离),将其成形为更接近浮动陆地的形状。
  • 并通过使其在顶部附近更平整来创建地面(通过将其乘以垂直渐变,即从顶部的低值开始,然后向底部变高)。
  • 将这三个结合起来,并通过沿X / Y / Z轴缩放噪声来调整形状(本文建议在Y轴上拉伸,在X和Z轴上压缩)。
  • 额外的噪音可能会被用来挖掘洞穴

是的,我想这样的事情绝对是我想要的。问题是我对Perlin噪声的经验很少,所以我只能生成真正的基本山脉,并且对如何添加“多个八度的杂音”一无所知。对于Perlin噪声生成,我正在使用代码我下了stackoverflow.com/questions/4753055/…并将其移植到C#。我将在原始帖子中添加我的版本...您是否愿意举一个例子说明我将如何实现这一目标?代码?
Darestium

2
这就是为什么我链接这篇文章。它对所有步骤进行了解释,最后给出了源代码。您应该尝试研究。
David Gouveia

4
  1. 使用现有的3D网格,确定您想要岛顶的高度。通过在平面上分散点,然后在这些点上放置立方体,在该2D平面(称为XY平面)中创建一组岛。使用内聚力将它们拉成团紧密靠近。填满任何孔,您就会有一组岛顶。
  2. 使用CA-类似的方法来向下生长岛屿。(a)从绘制初始点的Z层开始,针对当前Z层中的每个单元格,确定给定XY平面中的邻居数从0到8向下扩展到下一个较低层的机会(包括对角线邻居),例如,为每个邻居分配10%的机会,最高为80%的机会。对起始平面中的每个像元进行计算。(b)然后根据这个机会随机化,如果您在百分比范围内,则向下扩展。漂洗,重复步骤2(转到下一个级别,确定每个体素的邻居,向下扩展该体素),直到不再发生扩展。由于采用近邻法,您的向下延伸应形成圆锥形,因为朝向该岛XY中心的那些体素通常会具有更多邻域。

步骤2的伪代码:

int planeNeighbours[x][y]; //stores how many neighbours each voxel in this plane has

for each z level (starting at level where you plotted your points)
    for each x, y voxel in z level
        for each neighbour space bordering this voxel
            if neighbour exists
                ++planeNeighbours[x][y];
    for each x, y voxel in z level
        chance = random(0,8); //depends on your RNG implementation
        if chance < planeNeighbours[x][y]
            worldGrid[x][y][z+1] = new cube

一旦完成孤岛的生成,就可以选择在空间中上下移动它们,以使它们处于不同的高度。


好的,我对您的方法有所了解,似乎是在向外而不是向内扩展地形。我将发布代码...
Darestium
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.