6

我一直在研究我正在开发的应用程序的柏林噪声,它基本上是一个“二维侧视图”外观游戏(模拟)。我不完全了解柏林噪声的工作原理,但大致了解。

我发现这篇带有代码Perlin Noise的文章并决定在之前给出它,我目前设置世界生成的方式是每个“块”都有 16x16 块,我刚刚声明如果 Y >= HEIGHT / 2 全部瓷砖“实心”或“空气”,所以这很有效..但土地很平坦,正如你想象的那样。那就是我认为柏林噪声会出现的地方,所以我使用了在上述网站上找到的代码,但我不确定如何将噪声转换为固体/空气瓷砖。

如您所见,地形不是很逼真 在此处输入图像描述

我更喜欢下面的地形。应该看起来像山脉和连绵起伏的丘陵)我不担心锋利的边缘(正方形) 在此处输入图像描述

我不确定如何遍历 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 函数更改为这个函数,并且我已经实现了 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对每个噪音都好像我没有每个块都是一样的,所以现在看起来像下面 在此处输入图像描述

正如你所看到的,地形比以前更像我想要的,但看起来仍然不像真实的地形,因为它不是很平滑,我能做些什么来平滑它的整体外观以创建连绵起伏的山丘平原

我删除了在该噪声值下创建图块,以便更容易看到范围 在此处输入图像描述

如您所见,它看起来不错,只需将这些值“平滑”掉,以免它们看起来像伪随机值。我也想知道为什么左边看到的第一个块在整个过程中具有相同的值。

谢谢。

4

1 回答 1

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 图 (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 噪声函数)等。


编辑您的评论:

连续的一维地形:

如果您需要像经典的 2d-jump 和运行中那样的侧视图,请考虑 1d-noise 函数,从 0 迭代到 image-width,在每个停止处获取噪声函数的样本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:我从未尝试过这种方法,因为我喜欢 3d 地形渲染 ( picogen.org )

于 2012-04-19T09:59:42.550 回答