Використання L-систем для процедурного генерування міст


10

В даний час я створюю додаток, який багато уваги приділяє процедурно створеному вмісту. Поки я успішно реалізував процедурну генерацію місцевості та форму карти, використовуючи симплексний шум. Я дуже задоволений тим, як це виглядає. Зараз я намагаюся зробити те саме для міст. Мені просто потрібно генерувати двовимірне планування вулиць та будівель. Я вивчив це, і, здається, більшість людей пропонують використовувати L-Systems. Однак я, здається, не можу обернути їх головою. Я отримую концепцію, але не реалізацію в коді. Чи є у когось приклади коду L-Systems для процедурно створених міст або пропозиції щодо інших способів управління містами?



+1 Ура для L-Systems !
luser droog

Способом, який я зробив щось подібне, було створити сітку вузлів, що представляють перехрестя, а потім випадковим чином з'єднати сусідні вузли. Створює лабіринтний макет, але вулиці не всі пов’язані, тому фактично переміщатися по ньому неможливо.
user137

Часто цитується прихильність для генеруючих міст L-систем - це робота Парафія та Мюллера: Процедурне моделювання міст . Я також знайшов відмінний приклад реалізації . Це гарне місце для початку, але залежно від вашої точної вимоги, можливо, доведеться щось змінити.
Андерс Рендел

Відповіді:


20

З того, що я можу сказати *, L-Systems - це набір граматичних правил заміни, які ви можете застосовувати рекурсивно, щоб отримати цікаві, "органічні" результати.

Заводи часто використовують L-системи, оскільки вони демонструють багато рекурсивного зростання (тобто гілка розпадається на більше гілок). Для простого прикладу я покажу дерево "льодяник", сформоване за допомогою системи L:

variables : | o              (these are the things that will grow)
start  : o
         |                   (this is what we start with)
rules  : (o  o   o)         (these are the substitution rules that we apply
               \ /            one step at a time)

Отже, у поколінні 1 ми тільки починаємо:

o
|

У другому поколінні ми дотримуємось кожного з правил і підміняємо існуючі частини відповідно до правил. Заміняємо "кульки" на "дві палички і кульки":

o   o
 \ /
  |

Покоління 3:

o o   o o
 \|   |/
   \ /
    |

Незабаром у нас буде гарне (хитре) велике дерево!

Для цього в коді ви можете робити це рекурсивно (тобто DFS), постійно застосовуючи правила до одних і тих же частин, поки не досягнете якогось довільного кінця, або ви можете це робити ітеративно (тобто BFS), як ми це робили в цьому прикладі , виконуючи одне правило «пройти» на всі елементи і повторити ряд кроків. Це є:

Рекурсивно:

tree = start
grow(tree, start)

func grow(tree, part)
    if this part of the tree is big enough
        stop
    if part is 'o'
        replace part with 'o\/o'
        grow(tree, the left 'o')
        grow(tree, the right 'o')

Ітеративно:

tree = start
for a number of iterations
    for each part in tree
        if part is 'o':
            replace with 'o\/o'

Багато використання L-систем виконують крок "зростання", використовуючи підрозділ - тобто деталі зменшуються, оскільки вони "вирощуються", більші частини просто поділяються. Інакше ваша зростаюча система може почати перекриватися поверх себе. Ви побачите на прикладі мого льодяника, я магічно переконався, що дві гілки не перетинаються посередині, змінюючи форму нових гілок. Зробимо приклад міста за допомогою підрозділу:

variables: block_vertical block_horizontal road_vertical road_horizontal
start: block_vertical
rules: (block_vertical  block_horizontal road_vertical block_horizontal)
       (block_horizontal  block_vertical road_horizontal block_vertical)

Це матиме сенс через хвилину.

Покоління 1:

+--------------------+
|                    |
|                    |
|                    |
|        V           |
|                    |
|                    |
|                    |
+--------------------+

Єдиний, нудний вертикальний блок. (V означає вертикаль.)

Покоління 2: вертикальний блок замінюємо горизонтальними блоками вертикальною дорогою посередині

+--------------------+
|       r            |
|       r            |
|       r            |
|   H   r      H     |
|       r            |
|       r            |
|       r            |
+--------------------+

R означає дорогу! Я випадковим чином розподілив розкол, ми не хочемо нудних регулярних деталей в PCG.

Покоління 3: горизонтальні блоки замінюємо вертикальними блоками, розділеними на горизонтальні дороги. Залишилися існуючі дороги; для них немає правил.

+--------------------+
|   V   r            |
|       r            |
|rrrrrrrr            |
|       r      V     |
|   V   r            |
|       rrrrrrrrrrrrr|
|       r      V     |
+--------------------+

Зауважте, як дороги з'єднуються між собою, що приємно. Повторіть це достатньо разів, і у вас вийде щось подібне (нахабно зірвавши відповідну відповідь ):

введіть тут опис зображення

Зауважте, що є багато деталей, які я не висвітлював, і що цей результат виглядає "очевидно" породженим - реальні міста виглядають дещо інакше. Ось що робить PCG весело / важко. Є нескінченні речі, які ви можете зробити для налаштування та покращення своїх результатів, але будучи не пов'язаними з L-Systems, я залишу цю відповідь тут; сподіваюся, що це допоможе вам почати роботу.

* - Я формально не вивчав L-системи, хоча зіткнувся з конкретними типами, такими як граматика та PCG-рослинність; будь ласка, виправте мене, якщо я визнаю неправильні визначення чи поняття


1

@congusbongus відповідь відмінна, дозвольте додати кілька речей.

Блоки потрібно розділити на будівельні ділянки відповідно до всіх доріг, які їх межують. Коли у вас є дорога навколо, загальний малюнок - це кільце. Перегляньте, наприклад, посилання: http://oldurbanist.blogspot.fr/2012/01/city-blocks-spaces-in-between.html

(Залежно від густини, у центрі кільця може бути місце, див. Колун).

Після того як ви зробите блоки, вам потрібно створити будівлі. Вони трохи хитрі і вимагають генерації двох проходів. Вони частково взаємозалежні: ваш генератор не повинен створювати вікно, яке знаходиться перед сусідньою бічною стіною будівлі.

І щоб додати життя цьому, ви, можливо, захочете вплинути на покоління з оточенням, таким як місцевість або економічна карта: дороги (крім Сан-Франциско) мають тенденцію обходити великі пагорби, а не прямувати, а типи будинків сильно під впливом частини міста, в якому вони перебувають.

весело провести час.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.