简体   繁体   English

随着无限 map 的增长,如何连续产生 Perlin 噪声?

[英]how to continuously generate Perlin noise as an infinite map grows?

EDIT: I ended up using the FastNoise library found here: https://github.com/Auburns/FastNoise It has everything under the sun which someone might need to generate many different kinds of noise.编辑:我最终使用了这里找到的 FastNoise 库: https://github.com/Auburns/FastNoise它拥有阳光下的一切,有人可能需要产生许多不同种类的噪音。 As the title might suggest its also quite fast!正如标题所暗示的那样,它也很快!

I'm creating a 2D infinitely, procedural generated world.我正在创建一个 2D 无限的程序生成世界。 I load and unload chunks from disc as the player moves.当播放器移动时,我从光盘加载和卸载块。 I'm using a cellular automata function to define how local tiles within each chunk are designed but I need noise (Perlin in this case) to define what biome type each chunk will be as new ones are created.我正在使用元胞自动机 function 来定义如何设计每个块中的本地图块,但我需要噪声(在本例中为 Perlin)来定义每个块在创建新块时将是什么生物群落类型。 I understand how I would translate decimals between 0 and 1 to represent this, my only issue is that the tutorial I followed on creating Perlin noise requires that you pass it a predefined 2d array and returns a noise array of the same size.我了解如何转换 0 和 1 之间的小数来表示这一点,我唯一的问题是我遵循的关于创建 Perlin 噪声的教程要求您将一个预定义的二维数组传递给它并返回一个相同大小的噪声数组。 Because my world grows dynamically I'm a bit confused on how I would use a fixed sized array to designate new chunk types.因为我的世界是动态增长的,所以我对如何使用固定大小的数组来指定新的块类型有点困惑。

Other answers I've seen don't cover exactly how to handle the infinite part of noise generation.我见过的其他答案并未准确涵盖如何处理噪声生成的无限部分。 My best guess is that I need to somehow generate or expand the noise with each newly created chunk although how I do this stumps me.我最好的猜测是,我需要以某种方式生成或扩展每个新创建的块的噪音,尽管我是如何做到这一点的。

Here is some code I translated to C# from here: http://devmag.org.za/2009/04/25/perlin-noise/这是我从这里翻译成 C# 的一些代码: http://devmag.org.za/2009/04/25/perlin-noise/

admittedly some of the math here I don't fully understand yet, especially the bitwise function!诚然,这里的一些数学我还不完全理解,尤其是按位函数!

public class PerlinNoiseGenerator
    {
        public int OctaveCount { get; set; }
        public float Persistence { get; set; }


        public PerlinNoiseGenerator(int octaveCount, float persistence)
        {
            this.OctaveCount = octaveCount;
            this.Persistence = persistence;
        }

        public float[,] GenerateWhiteNoise(int width, int height)
        {
            float[,] noiseFieldToReturn = new float[width, height];
            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    noiseFieldToReturn[i, j] = (float)Game1.Utility.RGenerator.NextDouble() % 1;
                }
            }
            return noiseFieldToReturn;
        }

        public float[,] SmoothNoiseField(float[,] whiteNoise, int octave)
        {
            int width = whiteNoise.GetLength(0);
            int height = whiteNoise.GetLength(1);
            float[,] smoothField = new float[width, height];

            int samplePeriod = 1 << octave;

            float sampleFrequency = 1.0f / samplePeriod;

            for(int i =0; i < width; i++)
            {
                int samplei0 = (i / samplePeriod) * samplePeriod;
                int samplei1 = (samplei0 + samplePeriod) % width;

                float horizontalBlend = (i - samplei0) * sampleFrequency;
                for(int j =0; j < height; j++)
                {
                    int samplej0 = (j/samplePeriod) * samplePeriod;
                    int samplej1 = (samplej0 + samplePeriod) % height;
                    float verticalBlend = (j - samplej0) * sampleFrequency;

                    float top = LinearInterpolate(whiteNoise[samplei0, samplej0],
                        whiteNoise[samplei1, samplej0], horizontalBlend);

                    float bottom = LinearInterpolate(whiteNoise[samplei0, samplej1],
                        whiteNoise[samplei1, samplej1], horizontalBlend);

                    smoothField[i, j] = LinearInterpolate(top, bottom, verticalBlend);
                }
            }

            return smoothField;
        }

        public float[,] GeneratePerlinNoise(float[,] baseNoise, int octaveCount)
        {
            int width = baseNoise.GetLength(0);
            int height = baseNoise.GetLength(1);

            float[][,] smoothNoise = new float[octaveCount][,];

            float persistance = .5f;

            for(int i =0; i < octaveCount;i++)
            {
                smoothNoise[i] = SmoothNoiseField(baseNoise, i);
            }
            float[,] perlinNoise = new float[width, height];
            float amplitude = 1f;
            float totalAmplitude = 0.0f;

            for(int octave = octaveCount - 1; octave > 0; octave-- )
            {
                amplitude *= persistance;
                totalAmplitude += amplitude;

                for(int i =0; i < width;i++)
                {
                    for(int j =0; j < height; j++)
                    {
                        perlinNoise[i, j] += smoothNoise[octave][i, j] * amplitude;
                    }
                }
            }

            for(int i =0; i < width; i++)
            {
                for(int j =0; j < height; j++)
                {
                    perlinNoise[i, j] /= totalAmplitude;
                }
            }
            return perlinNoise;
        }

        public float LinearInterpolate(float a, float b, float alpha)
        {
            return a * (1 - alpha) + alpha * b;
        }
    } 

This code should compile and produces a FIXED size array of noise此代码应编译并生成固定大小的噪声数组

The main thing you want to make sure is that the starting random noise is pseudo random, so you always have a "fixed random value" for a coordinate.您要确保的主要内容是起始随机噪声是伪随机的,因此您始终具有坐标的“固定随机值”。

It might be that you'd have to rewrite your random noise generator, using the coordinates as input.可能您必须使用坐标作为输入来重写您的随机噪声生成器。 I imagine your maps have a random seed number, so you could use this post as a starting point, adding 1 factor: A pseudo-random number generator based on 2 inputs我想你的地图有一个随机种子数,所以你可以使用这篇文章作为起点,添加 1 个因素: 基于 2 个输入的伪随机数生成器

For a bit of inspiration for your map making, I wrote this article a while back: https://steemit.com/map/@beeheap/create-a-fantasy-grid-map-in-excel对于您制作 map 的一些灵感,我不久前写了这篇文章: https://steemit.com/map/@beeheap/create-a-fantasy-grid-map-in-excel

Added after your comment: the only function you'd need to change is the GenerateWhiteNoise one.在您发表评论后添加:您需要更改的唯一 function 是 GenerateWhiteNoise 之一。 I don't speak C#, but this is the general idea:我不会说 C#,但这是大意:

GenerateWhiteNoise(int x_start_coord, int y_start_coord, int random_seed) {
    int default_x_width = 100;
    int default_y_heigth = 50;
    float[,] noiseFieldToReturn = new float[width, height];

    for (in x = x_start_coord; i < default_x_width + x_start_coord; x++)
    {
        for (in y = y_start_coord; i < default_y_width + y_start_coord; y++)
        {
            noiseFieldToReturn[i, j] = (float)pseudo_rnd_value(x, y, random_seed);
        }
    }
    return noiseFieldToReturn;
}

That should give you the pseudo random values you need to build your map tiles, the only thing you need is the coordinate of the player (x and y).这应该为您提供构建 map 瓷砖所需的伪随机值,您唯一需要的是玩家的坐标(x 和 y)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM