Lシステムを使用して手続き的に都市を生成する


10

私は現在、手続き的に生成されたコンテンツに重点を置いたアプリを作成しています。これまでのところ、シンプレックスノイズを使用して、地形の手順による生成とマップの形状の実装に成功しています。私はそれがどのように見えるかに本当に満足しています。今、私は都市にも同じことをしようとしています。通りと建物の2Dレイアウトを生成するだけです。私はそれを調査しました、そして、ほとんどの人がL-Systemsを使うことを提案するようです。しかし、私はそれらの周りに頭を包むようには見えません。コンセプトはわかりますが、コードへの実装はわかりません。誰かが手続き的に生成された都市のためのLシステムのコード例、または都市を処理する他の方法に関する提案を持っていますか?




私が同様のことをした方法は、交差点を表すノードのグリッドを作成してから、隣接するノードをランダムに接続することでした。迷路のようなレイアウトになりますが、通りはすべてつながっていないため、実際にナビゲートすることはできません。
user137 14年

都市を生成するLシステムの一般的に引用されるアソーリティーは、ParishとMullerの論文:Procedural Modeling of Citiesです。また、実装の優れた例も見つかりました。始めるのに良い場所ですが、実際の要件によっては、いくつか変更する必要があるかもしれません。
アンダースリンデル2017

回答:


20

L-Systemsは、私が言えること*から、一連の文法のような置換規則であり、再帰的に適用して興味深い「有機的な」結果を得ることができます。

植物は、L-システムが頻繁に使用される場所です。植物は、多くの再帰的な成長を示します(つまり、枝がより多くの枝に分かれる)。簡単な例として、L-Systemを使用して生成された「lollipop」ツリーを示します。

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
|

第2世代では、各ルールに従い、既存のパーツをルールに従って置き換えます。「balls」を「two-sticks-and-balls」に置き換えます。

o   o
 \ /
  |

第3世代:

o o   o o
 \|   |/
   \ /
    |

間もなく、かなり(くだらない)大きな木ができます!

コードでこれを行うには、これを再帰的に(つまり、DFS)行い、同じ部分に規則を適用して、任意の終わりに到達するか、この例で行ったように、これを繰り返し(つまり、BFS)できます。 、すべての要素に対して1つのルール「パス」を実行し、いくつかのステップを繰り返します。あれは:

再帰的に:

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-Systemsの多くの使用法は、サブディビジョンを使用して「成長」ステップを実行します。つまり、「成長」すると、パーツは小さくなり続け、大きなパーツは分割されます。そうしないと、成長しているシステムがそれ自体の上に重なる可能性があります。私のロリポップツリーの例を見るとわかるように、新しいブランチの形状を変更することで、2つのブランチが中央で重ならないように魔法のように確認しています。サブディビジョンを使用して都市の例を見てみましょう:

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とは無関係であるため、ここではこの答えを残しておきます。これがあなたが始めるのに役立つことを願っています。

*-文法やPCG植生のような特定のタイプに遭遇したものの、L-システムを正式に研究していません。定義や概念が間違っている場合は修正してください


1

@congusbongusの回答はすばらしいので、いくつか補足させてください。

ブロックは、それらに隣接するすべての道路に従って建物エリアに分割する必要があります。あなたがすべての道を持っているとき、全体的なパターンはリングです。たとえば、このリンクを参照してください:http : //oldurbanist.blogspot.fr/2012/01/city-blocks-spaces-in-between.html

(密度によっては、リングの中心にスペースがない場合があります。九龍を参照してください)。

ブロックを作成したら、建物を生成する必要があります。それらは少しトリッキーで、2パス生成が必要です。それらは部分的に相互依存しています。ジェネレーターは、次の建物の側壁の前にあるウィンドウを作成しないでください。

これに生命を加えるには、地形や経済地図などの環境で世代に影響を与えることができます。道路(サンフランシスコを除く)は、直進するのではなく、大きな丘を回る傾向があり、家の種類は非常に多いです彼らがいる都市の一部の影響を受けています。

楽しんで。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.