使用Perlin Noise(基于Tile)生成2d地形

时间:2012-04-19 09:16:58

标签: c++ perlin-noise

我一直在研究perlin噪音的应用程序我正在研究它基本上是一个'二维侧视图'看游戏(模拟)。我不完全理解perlin噪声是如何工作的,但是得到了一般的想法。

我发现这篇文章的代码为Perlin Noise,并决定在此之前给出它,我现在设置世界的方式是每个“块”有16x16块,我刚刚声明如果Y&gt ; = HEIGHT / 2使所有瓷砖'坚固''其他'空气'以便正常工作......但是土地非常平坦,正如您想象的那样。那就是我认为perlin噪音会进来的地方,所以我使用了上面网站上的代码,但我不确定如何将噪音转换成固体/空气砖。

正如你所看到的不是很逼真的地形 enter image description here

我正在寻找下面的地形。应该看起来像山脉和连绵起伏的丘陵)我不担心锋利的边缘(方形) enter image description here

我不知道如何遍历tile数组以将噪音转换为

目前我正在迭代瓷砖阵列(2d),但正如您从第一张图片中看到的那样,它只是随机化瓷砖是否是实心的,它不会产生任何起伏的丘陵或山脉。

for(int Y = 0;Y < HEIGHT;++Y) {
    for(int X = 0;X < WIDTH;++X) {
        Tile Tile;
        if(noise(X,Y) < 0) {
            Tile.Type = BLOCK;
        } else {
            Tile.Type = Air;
        }

        // Then I push the Tile on to a vector

我还应该提到,在这个16x16'块'的右侧,还有另一个块需要与这个块匹配,之后的下一个块也是如此。如果有意义的话,块不应该和以前一样只是让它看起来不是单独的块。

非常感谢任何帮助!谢谢

更新

我已将perlin函数更改为this的函数,并且已实现phresnel建议的内容:

    PerlinNoise *test=new PerlinNoise(0.25, 6);    //0.25 is Persistance 6 is Octaves

        float f,h;
        float seed = 804.343;

        for (int X=0; X!=MAP_WIDTH; ++X) {

            f = test->GetNoise((X * ChunkX) * seed);

            h = f * MAP_HEIGHT + (MAP_HEIGHT / 2);

            for (int y=0; y<h; ++y) {
                Tile tempTile;
                tempTile.Tile = TILE_NONE;
                Tiles[X][y] = tempTile;
            }
            for (int y=h; y<MAP_HEIGHT; ++y) {
                Tile tempTile;
                tempTile.TileID = TILE_BLOCK;
                Tiles[X][y] = tempTile;
            }
        }

这样做后看起来好多了,我X * ChunkX每个噪音好像我没有每个块都是一样的,所以现在它看起来像下面的 enter image description here

正如你所看到的,地形比我以前想要的更多,但仍然看起来不像真正的地形,因为它不是很光滑,有什么我可以做的顺利创建连绵起伏的山丘平原

的整体外观

我在该噪点值下删除了tile的创建,因此更容易看到范围 enter image description here

正如您所看到的那样,它只需要“平滑”,因此它们看起来不像伪随机值。我也想知道为什么左边看到的第一个块具有相同的值。

感谢。

1 个答案:

答案 0 :(得分:4)

你的结果很好,因为你有岛屿,大陆,池塘和海洋。 Perlin噪声可以帮助您生成非随机字符的随机地形。

您基本上将噪声函数的(数学上)无限分辨率降低为仅包含两个不同图块的离散集合,以及块的非常有限的分辨率。鉴于此,您的结果似乎很好。

不同的事情可能会改善您的结果。例如,瓷砖图形之间的lerp:

// Exemplary p-code, fine-tuning required
Color color_at (x, y) {
    Real u = x / width, v = y / height
    Real  f  = min (max(noise(u,v), 0), 1);
    Color c  = water*f + hill*(1-f);
    return c;
}

您可以为任何图块计数推广lerp函数。

锋利边缘的另一种可能性受Voronoi diagrams (1)的启发。您具有与上面相同的功能,但不是内插,而是采用最接近噪声值的图块:

Color color_at (x, y) {
    Real u = x / width, v = y / height
    Real  f  = min (max(noise(u,v), 0), 1);
    if (f<0.5) return water;
    else return hill;
}

这与你的相同,只是你以像素方式进行。同样,这可以概括。

一旦你有一个很好的设置,你可以使用噪音:植物/树木分布,敌人分布,动画(这将是一个噪音功能)等。


编辑您的评论:

连续的1d-terrain:

如果您需要侧视图,如经典的2d-jump并运行,请考虑1d噪声函数,从0迭代到图像宽度,每次停止采样 f 对于噪声函数,将 f 转换为屏幕空间,然后上面的每个像素都将成为天空的一部分,下面的每个像素都将从你的瓷砖中取出:

for (int x=0; x!=width; ++x) {

    // Get noise value:
    f = noise1d (x/width);
    h = f * height + (height/2);  // scale and center at screen-center

    // Select tile:
    Tile *tile;
    if (h < waterLimit) {
        h    = waterLimit;
        tile = waterTile;
    } else {
        tile = terrainTile;
    }

    // Draw vertical line:
    for (int y=0; y<h; ++y)
        setPixel (x, y, skyColor(x,y));
    for (int y=h; y<height; ++y)
        setPixel (x, y, tileColor(x,y, tile));
}

再次,示例性伪代码。

当前设置中的完整2d级别:

噪音功能非常灵活。如果你想要更少的蓝色和更多的绿色,只需降低常数项,即不是if(h < 0) -> blue,而是if(h < -0.25) -> blue


1:我从未尝试过这种方法,因为我正在进行三维地形渲染(picogen.org