Usando L-Systems para gerar cidades proceduralmente

10

Atualmente, estou criando um aplicativo que se concentra muito no conteúdo gerado processualmente. Até agora, implementei com sucesso a geração processual do terreno e a forma de um mapa usando ruído simplex. Estou realmente satisfeito com a aparência. Agora estou tentando fazer o mesmo pelas cidades. Eu só preciso gerar um layout 2D das ruas e edifícios. Eu olhei para ele e parece que a maioria das pessoas sugere o uso de L-Systems. No entanto, eu não consigo envolver minha cabeça em torno deles. Eu entendo o conceito, mas não a implementação no código. Alguém tem algum exemplo de código do L-Systems para cidades geradas processualmente ou sugestões de outras maneiras de lidar com as cidades?

pasawaya
fonte
+1 Viva para L-Systems !
Luser droog
Uma maneira de fazer algo semelhante foi criar uma grade de nós representando interseções e conectar aleatoriamente nós adjacentes. Cria um layout semelhante ao labirinto, mas as ruas não estão todas conectadas, portanto, não é possível navegá-lo.
user137
A autoridade comumente citada para os sistemas L geradores das cidades é o artigo de Parish e Müller: Modelagem Procedimental de Cidades . Eu também encontrei um excelente exemplo de implementação . É um bom lugar para começar, mas, dependendo da sua exigência exata, talvez você precise alterar algumas coisas.
Anders Ryndel

Respostas:

20

Os sistemas L , pelo que sei *, são um conjunto de regras de substituição semelhantes a gramáticas que você pode aplicar recursivamente para obter resultados "orgânicos" interessantes.

As plantas são onde os L-Systems são freqüentemente usados, pois mostram muito crescimento recursivo (ou seja, o ramo se divide em mais ramos). Para um exemplo simples, mostrarei uma árvore "pirulito" gerada usando um sistema 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)

Então, na geração 1, nós apenas começamos:

o
|

Na geração 2, seguimos cada uma das regras e substituímos as partes existentes de acordo com as regras. Substituímos as "bolas" por "dois bastões e bolas":

o   o
 \ /
  |

Geração 3:

o o   o o
 \|   |/
   \ /
    |

Em breve teremos uma linda árvore (de baixa qualidade)!

Para fazer isso no código, você pode fazer isso recursivamente (por exemplo, DFS), aplicando continuamente as regras nas mesmas partes até chegar a um fim arbitrário ou fazer isso de forma iterativa (por exemplo, BFS), como fizemos neste exemplo , executando uma regra "passar" em todos os elementos e repetindo várias etapas. Isso é:

Recursivamente:

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')

Iterativamente:

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

Muitos usos do L-Systems executam a etapa "crescer" usando a subdivisão - ou seja, as partes ficam cada vez menores à medida que são "crescidas", as partes maiores são divididas. Caso contrário, seu sistema crescente poderá começar a se sobrepor. Você verá no meu exemplo de árvore de pirulito, que eu garanti magicamente que os dois galhos não se sobrepõem ao meio, alterando a forma dos novos galhos. Vamos fazer o exemplo da cidade usando a subdivisão:

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)

Isso fará sentido em um minuto.

Geração 1:

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

Um único bloco vertical chato. (OV significa vertical.)

Geração 2: substituímos o bloco vertical por blocos horizontais por uma estrada vertical no meio

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

OR significa estrada! Dividi a divisão aleatoriamente, não queremos peças regulares chatas no PCG.

Geração 3: substituímos os blocos horizontais por blocos verticais separados por estradas horizontais. As estradas existentes ficam; não há regras para eles.

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

Observe como as estradas se conectam, o que é bom. Repita isso várias vezes e você terminará com algo assim (descaradamente rasgado uma resposta relacionada ):

insira a descrição da imagem aqui

Observe que há muitos detalhes que não cobri e que esse resultado parece "obviamente" gerado - as cidades reais parecem um pouco diferentes. É isso que torna o PCG divertido / difícil. Existem inúmeras coisas que você pode fazer para ajustar e melhorar seus resultados, mas, como não está relacionado ao L-Systems, deixarei esta resposta aqui; espero que isso ajude você a começar.

* - Não estudei formalmente o L-Systems, embora tenha encontrado tipos específicos como gramáticas e vegetação de PCG; corrija-me se eu tiver alguma definição ou conceito errado

congusbongus
fonte
1

resposta @congusbongus é excelente, deixe-me adicionar algumas coisas.

Os blocos precisam ser divididos em áreas de construção de acordo com todas as estradas que os cercam. Quando você tem estrada por toda parte, o padrão geral é um anel. Veja este link por exemplo: http://oldurbanist.blogspot.fr/2012/01/city-blocks-spaces-in-between.html

(Dependendo da densidade, pode não haver espaço no centro do anel, consulte kowloon).

Depois de ter feito os blocos, você precisa gerar os edifícios. Eles são um pouco complicados e exigem uma geração de duas passagens. Eles são parcialmente interdependentes: seu gerador não deve criar uma janela em frente à próxima parede lateral do edifício.

E para adicionar vida a isso, você pode influenciar a geração em ambientes como o terreno ou um mapa econômico: Estradas (exceto em San Francisco) tendem a percorrer grandes colinas, em vez de seguir em frente e os tipos de casas são fortemente influenciados pela parte da cidade em que estão.

diverta-se.

Lionel Barret
fonte