使用L系统以程序方式生成城市


10

我目前正在制作一款专注于程序生成内容的应用。到目前为止,我已经使用单纯形噪声成功实现了地形和地图形状的程序生成。我对它的外观感到非常满意。现在,我正在尝试为城市做同样的事情。我只需要生成街道和建筑物的2D布局即可。我研究了它,似乎大多数人都建议使用L系统。但是我似乎无法将他们的头缠住。我得到了概念,但没有将实现转化为代码。是否有人提供用于程序生成城市的L系统的代码示例,或有关处理城市的其他方法的建议?




我执行类似操作的一种方法是创建代表交叉点的节点网格,然后随机连接相邻节点。形成迷宫般的布局,但街道并不都连通,因此实际上无法导航。
user137 2014年

关于生成城市的L系统的普遍不满之处是Parish和Müller的论文:《城市程序建模》。我还找到了一个很好的实现示例。这是一个很好的起点,但是根据您的确切要求,您可能必须更改一些内容。
安德斯·林德尔

Answers:


20

我所知*,L系统是一组类似语法的替换规则,您可以递归应用这些规则以获得有趣的“有机”结果。

植物是经常使用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)

因此,在第一代,我们才刚刚开始:

o
|

在第2代中,我们遵循每个规则,并根据规则替换现有部分。我们将“球”替换为“两棍和球”:

o   o
 \ /
  |

第三代:

o o   o o
 \|   |/
   \ /
    |

很快,我们将有一棵漂亮的(cr脚的)大树!

要在代码中执行此操作,您可以递归执行此操作(即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-Systems的许多用途都通过细分来执行“增长”步骤-也就是说,随着“增长”,零件不断变小,而更大的零件就被分割了。否则,您正在成长的系统可能会开始在自身之上重叠。您会在我的棒棒糖树示例中看到,我神奇地通过更改新分支的形状来确保两个分支不会在中间重叠。让我们使用细分来制作城市示例:

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

(取决于密度,环中心可能没有空间,请参见九龙)。

一旦完成了块,就需要生成建筑物。他们有点棘手,需要两次通过。它们是部分相互依赖的:生成器不应在下一个建筑物侧壁的前面创建窗口。

为了增加生命,您可能希望通过地形或经济地图等环境来影响这一代:道路(旧金山除外)倾向于绕过大山丘,而不是直行,并且房屋类型繁多受他们所在城市部分的影响。

玩得开心。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.