Как я могу добавить коэффициенты масштабирования к моему генератору шума "perlin"? - PullRequest
1 голос
/ 16 марта 2011

У меня есть генератор шума Perlin, который я пытаюсь использовать для создания прокручиваемой местности.

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

Я не хочу просто генерировать большую карту;это быстро станет непомерно большим.

Я не знаю, что делать;все очевидные решения потерпели неудачу, так или иначе.

    /// <summary>
    /// Generates a new perlin map.
    /// </summary>
    /// <param name="xStart">The left coordinate (using 0, 0 as top-left and +, + as down and to the right).</param>
    /// <param name="yStart">The top coordinate (using 0, 0 as top-left and +, + as down and to the right).</param>
    /// <param name="width">The width of the map.</param>
    /// <param name="length">The length of the map.</param>
    /// <param name="persistance">If set, values lower than 1 make the map less noisey; values greater than 1 make the map more noisy.</param>
    /// <param name="fromShift">Low values here provide for a broader "base".</param>
    /// <param name="toShift">High values here provide for more speckled "highlights".</param>
    /// <param name="interpolate">If set to false, the algorithm will not smooth values.</param>
    public double[,] Generate(
        int xStart, int yStart,
        int width, int length,
        double? persistance,
        uint fromShift, uint toShift,
        bool interpolate = true,
    )
    {
        _noiseMap = new double[width, length];
        _workingMap = new double[width + 6, length + 6];
        _smoothedNoise = new double[width + 6, length + 6];
        int ifromShift = -(int)(toShift),
            itoShift = -(int)(fromShift);
        int idiv = 1 + (itoShift - ifromShift);
        double ddiv = 0;
        double amplitude = 0.0;
        if (persistance.HasValue)
            for (int i = ifromShift; i <= itoShift; ++i)
                ddiv += Math.Pow(persistance.Value, i);

        for (int i = ifromShift; i <= itoShift; ++i)
        {
            _frequency = Math.Pow(2, i);
            if (persistance.HasValue) amplitude = Math.Pow(persistance.Value, i);
            int useWidth = (int)(width * _frequency) + 1,
                useLength = (int)(length * _frequency) + 1;
            int useXStart = (int)(xStart * _frequency),
                useYStart = (int)(yStart * _frequency);
            double frequencyXStart = xStart * _frequency - useXStart,
                frequencyYStart = yStart * _frequency - useYStart;

            for (int y = 0; y < useLength + 5; ++y)
                for (int x = 0; x < useWidth + 5; ++x)
                {
                    int genX = ((int)(useXStart) + (int)((x) + 0.5));
                    int genY = ((int)(useYStart) + (int)((y) + 0.5));
                    _workingMap[x, y] = GenerateNoise(genX, genY);
                }

            if (interpolate)
            {
                for (int y = 1; y < length + 4; ++y)
                    for (int x = 1; x < width + 4; ++x)
                    {
                        _smoothedNoise[x, y] = SmoothedNoise(x, y);
                    }

                if (persistance.HasValue)
                    for (int y = 0; y < length; ++y)
                        for (int x = 0; x < width; ++x)
                        {
                            _noiseMap[x, y] += InterpolatedNoise((x * _frequency) + 2 + frequencyXStart, (y * _frequency) + 2 + frequencyYStart) * amplitude;
                            // _noiseMap[x, y] += _workingMap[x, y] * amplitude;
                        }
                else
                    for (int y = 0; y < length; ++y)
                        for (int x = 0; x < width; ++x)
                        {
                            _noiseMap[x, y] += InterpolatedNoise((x * _frequency) + 2 + frequencyXStart, (y * _frequency) + 2 + frequencyYStart) / idiv;
                            // _noiseMap[x, y] += _workingMap[x, y] / idiv;
                        }
            }
            else
                if (persistance.HasValue)
                    for (int y = 0; y < length; ++y)
                        for (int x = 0; x < width; ++x)
                        {
                            _noiseMap[x, y] +=
                                _workingMap[(int)((x * _frequency) + 2 + frequencyXStart), (int)((y * _frequency) + 2 + frequencyYStart)] * amplitude;
                        }
                else
                    for (int y = 0; y < length; ++y)
                        for (int x = 0; x < width; ++x)
                        {
                            _noiseMap[x, y] +=
                                _workingMap[(int)((x * _frequency) + 2 + frequencyXStart), (int)((y * _frequency) + 2 + frequencyYStart)] / idiv;
                        }
        }

        if (persistance.HasValue)
            for (int y = 0; y < length; ++y)
                for (int x = 0; x < width; ++x)
                {
                    _noiseMap[x, y] = _noiseMap[x, y] / ddiv;
                }

        return _noiseMap;
    }

Спасибо.

Ответы [ 2 ]

0 голосов
/ 05 марта 2014

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

0 голосов
/ 16 марта 2011

Просто чтобы прояснить ситуацию (чтобы проверить мое понимание вашей проблемы).

Вы генерируете карту A со стороной размера X. Эта карта окружена еще девятью картами B1 ... B9, каждая ссторона размера X. Теперь вам нужны карты C1 ... C2, которые будут окружать карты B1 ... B9 снаружи.Каждая из этих карт будет иметь сторону размера 3X, но с только X ^ 2 точками данных (каждая точка данных будет иметь размер 3x3).

Верно?

Вы пытались просто интерполировать данные с помощью алгоритма ближайшего соседа?Когда любой код запрашивает данные из координаты X, просто округлите координату до кратного трех и используйте его.Я думаю, что это должно работать.

Другим вариантом может быть использование алгоритма смещения средней точки , за исключением того, что вы бы разбили плитку на три части вместо двух в каждом рекурсивном шаге.Это позволит вам остановить один раунд раньше, что даст вам результат, который вы ищете: Карта высот с точками данных, сгенерированными только в точках пересечения сетки 3х3.Без необходимости касаться остальных точек.

...