как непрерывно генерировать шум Перлина по мере роста бесконечной карты?

РЕДАКТИРОВАТЬ: В итоге я использовал библиотеку FastNoise, найденную здесь: https://github.com/Auburns/FastNoise В нем есть все под солнцем, что может понадобиться кому-то для создания различных шумов. Судя по названию, это тоже довольно быстро!

Я создаю двумерный бесконечно процедурно сгенерированный мир. Я загружаю и выгружаю куски с диска по мере движения игрока. Я использую функцию клеточного автомата, чтобы определить, как создаются локальные плитки в каждом фрагменте, но мне нужен шум (в данном случае Perlin), чтобы определить, к какому типу биома будет относиться каждый фрагмент при создании новых. Я понимаю, как я бы перевел десятичные дроби между 0 и 1, чтобы представить это, моя единственная проблема заключается в том, что в учебнике, которому я следовал по созданию шума Перлина, требуется, чтобы вы передали ему предопределенный 2-мерный массив и вернули массив шума того же размера. Поскольку мой мир динамично растет, я немного запутался в том, как использовать массив фиксированного размера для обозначения новых типов блоков.

Другие ответы, которые я видел, не охватывают точно, как справиться с бесконечной частью генерации шума. Мое лучшее предположение состоит в том, что мне нужно каким-то образом генерировать или расширять шум с каждым вновь созданным фрагментом, хотя то, как я это делаю, меня озадачивает.

Вот код, который я перевел отсюда на C #: http://devmag.org.za/2009/04/25/perlin-noise/

по общему признанию, часть математики здесь я еще не совсем понимаю, особенно поразрядная функция!

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;
        }
    } 

Этот код должен компилироваться и генерировать массив шума ФИКСИРОВАННОГО размера.


person propellerhat23    schedule 04.10.2019    source источник
comment
Вероятно, вы ищете что-то вроде: forum.unity.com/threads/ Все сводится к использованию perlinNoise[i, j] and width, height. У меня нет времени помогать тебе больше, чем это.   -  person Christophe Roussy    schedule 07.10.2019


Ответы (1)


Главное, что вы хотите убедиться, это то, что начальный случайный шум является псевдослучайным, поэтому у вас всегда есть «фиксированное случайное значение» для координаты.

Возможно, вам придется переписать генератор случайного шума, используя координаты в качестве входных данных. Я полагаю, что ваши карты имеют случайное начальное число, поэтому вы можете использовать этот пост в качестве отправной точки, добавив 1 коэффициент: Генератор псевдослучайных чисел на основе 2-х входов

Чтобы немного вдохновить вас на создание карты, я недавно написал эту статью: https://steemit.com/map/@beeheap/create-a-fantasy-grid-map-in-excel

Добавлено после вашего комментария: единственная функция, которую вам нужно изменить, - это GenerateWhiteNoise. Я не говорю на 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;
}

Это должно дать вам псевдослучайные значения, необходимые для построения фрагментов карты, единственное, что вам нужно, это координаты игрока (x и y).

person Koen Rijnsent    schedule 15.10.2019
comment
Спасибо за ответ. Ваша карта Excel очень крутая. Однако я не совсем уверен, как интерпретировать вопрос, который вы связали. Я понимаю, что мне нужно использовать координаты в качестве входных данных, но я не уверен, как бы я это сделал, не ссылаясь каким-либо образом на установленный 2D-массив (например, у вас в вашем). - person propellerhat23; 16.10.2019
comment
Обновил мой ответ с помощью некоторого макета кода, это помогает? - person Koen Rijnsent; 17.10.2019