Сглаживание случайных шумов с разными амплитудами - PullRequest
0 голосов
/ 18 ноября 2018

У меня есть функция, которая возвращает ограниченный шум.Например, давайте представим, что входной диапазон равен [-1, 1].С помощью моего метода я могу вернуть ограниченный / находящийся в диапазоне шум (в зависимости от того, какой биом мы на данный момент).

    /// <summary>
    /// Converts the range.
    /// </summary>
    /// <param name="originalStart">The original start.</param>
    /// <param name="originalEnd">The original end.</param>
    /// <param name="newStart">The new start.</param>
    /// <param name="newEnd">The new end.</param>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    public static float ConvertRange(
        float originalStart, float originalEnd, // original range
        float newStart, float newEnd, // desired range
        float value) // value to convert
    {
        float scale = (newEnd - newStart) / (originalEnd - originalStart);
        return (newStart + ((value - originalStart) * scale));
    }

    /// <summary>
    /// Gets the bounded noise.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <param name="meanHeight">Height of the mean.</param>
    /// <param name="amplitude">The amplitude.</param>
    /// <returns></returns>
    // [InRange(-.5f, .5f)] && [InRange(0, 1)]
    public static float GetBoundedNoise(float value, float meanHeight, float amplitude)
    {
        return Mathf.Clamp01(ConvertRange(0, 1, -amplitude, amplitude, ConvertRange(-1, 1, 0, 1, value)) + (meanHeight + .5f));
    }

Установите этот флажок, чтобы понять, что означают высота и амплитуда: https://i.gyazo.com/9dc9cbe949f82d7342d7778e904563de.mp4

Примечание: значение шума задается библиотекой FastNoise.(Вы можете увидеть это на Github )

Проблема в том, что на границе каждого региона есть несоответствие высоты:

Обычный регион:

...

Звуковая область:

...

Черный пиксель равен y = 0, а белый пиксельк у = 1.(Вы можете игнорировать желтые пиксели)

Но, как вы можете видеть, существуют различные биомы с разными амплитудами и средней высотой (Вода, Трава, Трава, DryGrass, Асфальт).

Я пробовалсвертка по Гауссу, но есть проблема: слишком много итераций для CPU (было бы оптимальным для выполнения в GPU).

Почему?Ну, я применяю гауссову свертку для каждого пикселя границы региона (у меня есть оптимизированный метод, чтобы получить это).Представьте, что мы получаем 810 тыс. Баллов.И применять сверточный пиксель foreach имеет 81 итерацию (чтобы получить среднее значение высоты из этой части).Но это только для одного пикселя, теперь мы должны сделать среднее для других 81 пикселя (9x9) или 25 пикселей (5x5) или чего-либо еще.

Есть (в лучшем случае) 1 640 250 000 итераций (чтобы получить очень маленькую сглаженную сетку вокруг границы каждого региона).

Вы можете увидеть мой старый код для этого:

            // Smothing segments

            //var kernel = Kernels.GAUSSIAN_KERNEL_9;

            //int kernelSize = kernel.GetLength(0);

            //if (pol != null && !pol.Segments.IsNullOrEmpty())
            //    foreach (Segment segment in pol.Segments)
            //    {
            //        int d = segment.Distance;

            //        for (int i = 0; i <= d; ++i)
            //        {
            //            Point p = (Vector2)segment.start + segment.Normal * d;

            //            //if (d % kernelSize == 0) // I tried to get less itwrations by checking if the current d modulus from kernelSize was 0. But no luck.
            //            Filters<Color32>.ConvolutionAtPoint(mapWidth, mapHeight, p.x, p.y, target, kernel, 1, pol.Center.x, pol.Center.y, true);
            //        }
            //    }
            //else
            //{
            //    if (pol == null)
            //        ++nullPols;
            //    else if (pol != null && pol.Segments.IsNullOrEmpty())
            //        ++nullSegments;
            //}

++ являются счетчиками отладки, игнорируйте их.

И Convolution at Point делает следующее:

     private static void ConvolutionAtPointFunc(int width, int height, T[] source, params object[] parameters)
    {
        float[][] kernel = (float[][])parameters[0];
        int kernelSize = kernel.Length;
        int iteration = (int)parameters[1];

        int _x = (int)parameters[2];
        int _y = (int)parameters[3];
        int xOffset = (int)parameters[4];
        int yOffset = (int)parameters[5];
        bool withGrid = (bool)parameters[6];

        for (int ite = 0; ite < iteration; ++ite)
        {
            Color c = new Color(0f, 0f, 0f, 0f);

            for (int y = 0; y < kernelSize; ++y)
            {
                int ky = y - kernelSize / 2;
                for (int x = 0; x < kernelSize; ++x)
                {
                    int kx = x - kernelSize / 2;

                    try
                    {
                        if (!withGrid)
                        {
                            c += ((Color)(dynamic)source[F.P(_x + kx + xOffset, _y + ky + yOffset, width, height)]) * kernel[x][y];
                            ++FiltersDebug.convolutionIterations;
                        }
                        else
                        {
                            for (int i = 0; i < 81; ++i)
                            {
                                int __x = i % 9,
                                    __y = i / 9;

                                c += ((Color)(dynamic)source[F.P(_x + __x + kx + xOffset, _y + __y + ky + yOffset, width, height)]) * kernel[x][y];
                                ++FiltersDebug.convolutionIterations;
                            }

                            source[F.P(_x + kx + xOffset, _y + ky + yOffset, width, height)] = (dynamic)c;
                        }
                    }
                    catch
                    {
                        ++FiltersDebug.outOfBoundsExceptionsIn;
                    }
                }
            }

            if (!withGrid)
                try
                {
                    source[F.P(_x + xOffset, _y + yOffset, width, height)] = (dynamic)c;
                }
                catch
                {
                    ++FiltersDebug.outOfBoundsExceptions;
                }
        }
    }

Как видите, очень неоптимизировано.Код из этого: http://wiki.unity3d.com/index.php/TextureFilter

Я не могу представить другого способа сделать этот подход.Лучшее, что я мог себе представить, это нарисовать перпендикулярную линию (перпендикулярно текущему сегменту (у меня есть утилита, чтобы получить ребра многоугольника (сегмент образован начальной точкой и конечной точкой, где начало сегмента = текущее).край и конец сегмента = предыдущий край))) (со средним шумом для каждой точки линии).Но есть и проблема:

...

Между сегментами с тупой проекцией есть промежуток (отмечен желтым).И перекрывающийся градиент шума на сегментах с четкой проекцией.

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

Примерно так:

...

Я также видел реализацию Cuberite (http://cuberite.xoft.cz/docs/Generator.html#heightgen):

Но я неЯ не могу понять эту часть, и если я смогу что-то извлечь из этого:

Если мы возьмем область 9x9 биомов, центрированную вокруг запрашиваемого столбца, сгенерируем высоту для каждого из биомов в ней, суммируем их иразделив на 81 (количество суммированных биомов), мы будем эффективно делать 9-кратное скользящее среднее по рельефу, и все границы внезапно станут плавными. На следующем рисунке показана ситуация из предыдущего абзаца после применения процесса усреднения.

Примечание. Я уже создал искаженную функцию вороного для получения текущего биома в точке местности (следуя этому руководству, но я не до конца понимаю, что делать, потому что не понимаюэтот подход, и я не вижу ни одного кода относительно этого текста).

Но я не знаю, с чего начать и как решить проблему с оптимизированнымАлгоритм.Кроме того, я не знаю, что исследовать.Поэтому у меня возникла проблема, поэтому любая помощь приветствуется.

1 Ответ

0 голосов
/ 29 ноября 2018

Я думаю, что это не лучший способ сделать это.

Но для всех, кто посещает этот вопрос, вам следует посетить Часть 2: Сглаживание шумов с разными амплитудами (Часть 2)

Есть очень хороший ответ.

...