Реализация алгоритма Diamond-Square

Программирование на Юнити.

Реализация алгоритма Diamond-Square

Сообщение ArXen42 24 янв 2015, 22:20

Думаю многие слышали об этом алгоритме процедурной генерации чего либо, в моем случае карты высот. Никак не получается его реализовать, руководствовался этой статьей. Но получается как всегда:
bandicam 2015-01-24 21-50-36-037.jpg

Картинка, конечно, интересная, но абсолютно не в тему. Это уже моя третья попытка реализации этого алгоритма, до этого получались шумные картинки с черными полосами вокруг квадратов, замучился уже. Вот код:
Синтаксис:
Используется csharp
public class Heighmap_class
{
    public static int size = 2048;
    public static float[,] heighmap = new float[size, size];
    public static float roughness = 1.5f;

    public static void Square(int lx, int ly, int rx, int ry)
    {
        int l = (rx - lx) / 2;

        float a = heighmap[lx, ly];              //  B--------C
        float b = heighmap[lx, ry];              //  |        |
        float c = heighmap[rx, ry];              //  |   ce   |
        float d = heighmap[rx, ly];              //  |        |
                                                 //  A--------D
        int cex = lx + l;
        int cey = ly + l;

        heighmap[cex, cey] = (a + b + c + d) / 4 + Random.Range(-l * 2 * roughness / size, l * 2 * roughness / size);
    }
    public static void Diamond(int tgx, int tgy, int l)
    {
        float a, b, c, d;

        if (tgy - l > 0)
            a = heighmap[tgx, tgy - l];                        //      C--------
        else                                                   //      |        |
            a = heighmap[tgx, size - l];                       // B---t g----D  |
                                                               //      |        |
                                                               //      A--------
        if (tgx - l > 0)                                      
            b = heighmap[tgx - l, tgy];                      
        else
            b = heighmap[size - l, tgy];


        if (tgy + l < size - 1)
            c = heighmap[tgx, tgy + l];                      
        else
            c = heighmap[tgx, l];


        if (tgx + l < size - 1)
            d = heighmap[tgx + l, tgy];
        else
            d = heighmap[l, tgy];

        heighmap[tgx, tgy] = (a + b + c + d) / 4 + Random.Range(-l * 2 * roughness / size, l * 2 * roughness / size);
    }                                                        

    public static void DiamondSquare(int lx, int ly, int rx, int ry)
    {
        int l = (rx - lx) / 2;

        if (l > 0)
        {
            Square(lx, ly, rx, ry);

            Diamond(lx, ly + l, l);
            Diamond(rx, ry - l, l);
            Diamond(rx - l, ry, l);
            Diamond(lx + l, ly, l);

            int cex = lx + l;
            int cey = ly + l;

            DiamondSquare(lx, ly, cex, cey);
            DiamondSquare(lx, ly + l, lx + l, ry);
            DiamondSquare(cex, cey, rx, ry);
            DiamondSquare(lx + l, ly, cex, cey);
        }
    }

    public static void Generate()
    {
        heighmap[0, 0] = Random.Range(0.2f, 1.0f);
        heighmap[size - 1, 0] = Random.Range(0.2f, 1.0f);
        heighmap[size - 1, size - 1] = Random.Range(0.2f, 1.0f);
        heighmap[0, size - 1] = Random.Range(0.2f, 1.0f);

        DiamondSquare(0, 0, size - 1, size - 1);
    }
}


Попытаюсь объяснить.
Метод Square на вход получает два угла, левый нижний и правый верхний и считает центральную точку заданного таким образом квадрата.
Diamond принимает на вход только координаты точки, которую надо посчитать (т.е. середины квадрата из предыдущего шага) и половинную сторону этого квадрата, считает координаты четырех точек справа, слева, сверху и снизу от принятой точки и также, как и в Square, усредняет их и прибавляет случайное число, пропорциональное стороне. Если любая из координат этих четырех точек выходит за границы карты, то он берет значение точки, лежащей с другой стороны, т.е. как бы сворачивает плоскость.
Метод DiamondSquare комбинирует эти два метода, принимая те же параметры, что и Square. Сначала он вызывает Square для входного квадрата, потом Diamond для всех четырех середин своих сторон, а потом рекурсивно вызывает сам себя для четырех под-квадратов до тех пор, пока не посчитает все пиксели.

Проверял перепроверял, ошибок в координатах сторон не нашел. Теперь уж и не знаю, что может быть не так. Подозрение падало на неправильные координаты смещения при выходе их за ноль в Diamond, но сколько я их не менял, ничего не поменялось. Может в генераторе случайных чисел проблема? Подозрительно, что так много точек просто ноль. Или все - таки надо точки в другом порядке считать?
У вас нет доступа для просмотра вложений в этом сообщении.
Последний раз редактировалось ArXen42 24 янв 2015, 22:25, всего редактировалось 1 раз.
Разрабатываю пошаговую космическую RPG в стиле Космических Рейнджеров - Stardust.
ArXen42
UNIт
 
Сообщения: 127
Зарегистрирован: 12 сен 2014, 17:34
Откуда: Санкт-Петербург
Skype: georgy10003
  • Сайт

Re: Реализация алгоритма Diamond-Square

Сообщение ArXen42 24 янв 2015, 22:23

Чуть не забыл. Вывожу так:
Синтаксис:
Используется csharp
public class Renderer_script : MonoBehaviour
{
    public Texture2D tex;
    public static Color[] coloredHeighmap = new Color[Heighmap_class.size * Heighmap_class.size];

    void Awake()
    {
        Heighmap_class.Generate();
        tex.Resize(Heighmap_class.size, Heighmap_class.size);
        tex.Apply();

        int counter = 0;
        for (int x = 0; x < Heighmap_class.size; x++)
            for (int y = 0; y < Heighmap_class.size; y++)
            {
                coloredHeighmap[counter].r = Heighmap_class.heighmap[x, y];
                coloredHeighmap[counter].g = Heighmap_class.heighmap[x, y];
                coloredHeighmap[counter].b = Heighmap_class.heighmap[x, y];

                counter++;
            }

        tex.SetPixels(coloredHeighmap);
        tex.Apply();
    }
}
 


Создал readable текстуру, повесил на UI Image, вроде все правильно.
Разрабатываю пошаговую космическую RPG в стиле Космических Рейнджеров - Stardust.
ArXen42
UNIт
 
Сообщения: 127
Зарегистрирован: 12 сен 2014, 17:34
Откуда: Санкт-Петербург
Skype: georgy10003
  • Сайт

Re: Реализация алгоритма Diamond-Square

Сообщение ArXen42 26 янв 2015, 01:00

Заработало! Сначала нашел опечатку в одну букву в координате, потом переделал все в итеративный метод, чтобы корректно считалось по слоям и вот, наконец, рабочая картинка!
Изображение
Всем спасибо, вопрос решен.
Разрабатываю пошаговую космическую RPG в стиле Космических Рейнджеров - Stardust.
ArXen42
UNIт
 
Сообщения: 127
Зарегистрирован: 12 сен 2014, 17:34
Откуда: Санкт-Петербург
Skype: georgy10003
  • Сайт


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 9