算法创作实战03 - 用 MaxMSP 实现 L-system

算法创作实战01 - 巴纳姆效应之随机星座实验

算法创作实战02 - 用 MaxMSP 生成随机颜色

好久不见~

前面两篇算法创作的实战,都是相对容易的小程序。今天我们一起来挑战用 Max/MSP (更准确说,是用 jitter) 来「种」植物。

名称:L-system

主要使用的对象:jit.linden, jit.turtle, jit.matrix, jit.str.fromsymbol, jit.iter, jit.lcd, jit.pwindow

难度系数:★★★★☆

什么是 L-system?

生成式艺术和算法创作07-向自然致敬的 L-system 中,已经对 L-system 做了详细的介绍。L-system 是 Aristid Lindenmayer 提出的有关生长发展中的细胞交互作用的数学模型,被广泛应用于植物生长过程的研究和建模,也常用于模拟各种生物体的形态。

L-system 是一系列不同形式的语法规则,它的自然递归规则产生自相似性,也能用于生成自相似的分形,例如迭代函数系统。它一般可以这样定义:

1
2
3
4
5
6
7
8
9
G ={V,S,ω,P},

V: 变量符号集合

S: 常量符号集合

ω: 初始状态串(i.e. seed or axiom)

P: 生成式规则(production)

接下来,我们动手来实现它。

开始的正确姿势

如何在 Max/MSP 实现 L-system?

最开始面对这个问题,会觉得茫然无措:该从哪里开始?

回答与软件相关的工程问题,最好答案永远是——搜索。

而搜索的第一站,不是 Google,应该是官方文档。在经历了长时间漫无头绪的搜索,各种成功不成功的尝试后,00 再次获得了一个多么痛的领悟——永远先搜索软件文档。搜索结果已经清楚明白地列出跟 L-system 有关的对象了!

然后我们来仔细读一下文档里面的说明吧。

jit.linden

打开 jit.linden 的帮助文档,例子如下:

一阵头晕目眩后冷静下来,试着运行程序。然而并不知道它在做什么……

只好静下心来一点一点看。

首先是找出核心对象。核心对象 jit.linden 前面连接的是一个矩阵,接收了 tolinden 的消息(unlock patch 后才看到 s tolinden 的内容);后面连接的是同一个矩阵。将矩阵可视化出来时需要变成 1 维 1 平面的矩阵。但是这个可视化方式非常不直观,需要另外寻找方法。(所以搜索结果列出了 jit.turtle 是不是……)

例子右边是规则相关的部分。在生成式艺术和算法创作07-向自然致敬的 L-system 中我们已经知道,生成式规则(production) 是决定 L-system 生成结果的关键。那么,这里 production 后面的一串 * F * +[F+]* G * -[GF-]F - F -- 是什么意思呢?下面给出的注释是:

list of symbols in the format:
left_context strict_predecessor right_context successor

if a symbol matching the strict_predecessors is found in the matrix it is replaced with the sucessor string if the left and right context is met. the wildcard character (‘*’ by default) means no left or right context.

还是一知半解的感觉,这时候需要打开顶部 p moreinfo 子 patch。里面解释了 production 规则是如何设定的。

L-systems work on an interpreted grammar model wherein a syntax is defined for replacing individual elements of the incoming string with a replacement string.

L-systems get larger through successive productions. the size of the Jitter matrix used by the object determines the maximum length of the string, so a large matrix is advisable, even if the axiom (starting string) is very small.

大意是,随着迭代,矩阵会变得越来越大,建议设定一个较大尺寸的矩阵。

‘production F +F[F]’ tells jit.linden to take every ‘F’ found in the input matrix and replace it with the string ‘+F[F]’. So the first four generations of an L-system with an axiom of ‘F’ would look like this:

1
2
3
4
F
+F[F]
++F[F][+F[F]]
+++F[F][+F[F]][++F[F][+F[F]]]

production 接着的第一个 F 是初始值,或者叫做 axiom(公理),第二个 是 axiom 替代自己的规则。

More complex models can be created by adding multiple productions, or by introducing context matching into the L-system grammar.

例如:production G F * +F 意思是只有在 F 前面是一个 G 的时候,才将 F 替换为 +F

又如:production G F * +F * G * G- 包含两个规则,一个是上面提到的 GF 替换 为 G+F; 另一个是 G 替换为 G-

jit.linden 最多可以定义 50 个规则。

the jit.turtle object interprets L-systems as turtle graphics, so that characters such as ‘F’, ‘+’, and ‘-‘ acquire special meaning. you could easily use jit.iter to access the Lindenmayer string in Max.

这一段也剧透了很多重要信息,包括用 jit.iter 获取字符串和用 jit.turtle 显示 L-system 生成的图形。

jit.turtle

然后再来看看 jit.turtle 怎么画图。

jit.turtle 前面是设定各种参数,例如步进值、旋转角度、起始点等,然后接收 jtr 传来的 production 规则,尤其要理解 F、+、- 的含义。jit.turtle 后面接的是一个 jit.lcd ,将规则显示出来。

生成 L-system

下面开始动手尝试了。好消息是,不必从零开始,从 jit.linden 帮助里面 copy 主要的部分,就可以快速建立起程序的框架。

首先是用规则生成矩阵的部分。又可以分为矩阵、公理和规则三部分:

  1. 矩阵部分:jit.linden 前面是一个初始化矩阵,r generate 接收每一步的生成指令;jit.linden 后面是一步生成后存储的矩阵,在下面用 jit.cellblockjit.pwindow 显示存储的值和存储占用情况
  2. 公理:用 jit.str.fromsymbol 接收 axiom 字母并转换成 ASCII 编码,同时指定矩阵的大小,如 1000
  3. 规则:将包含 axiom、production、turtle 参数的规则写入一个 message 中,然后用 r linden 接收并传入 jit.linden

接下来将矩阵中存储的规则用 jit.turtle 画出来。

这里的关键是用 jit.iter 将矩阵中每个值依次传到 jit.turtle ,并且接收 r turtle 中关于角度、大小等设置值,然后传给 jit.lcd 绘制:

Let’s Play!

接下来终于进入寻找有趣 production 的游戏环节了~

可以自己试验,也可以从网上搜刮一些已经写好的规则。一个完整的规则可以写到一个 message 里面,打包传给 jit.linden:

下面进入愉快的玩耍时间~

种草:

1
* A * F * F * F-[[A]+A]+F[+FA]

种(歪的)树:

1
* X * C0F-[C2[X]+C3X]+C1F[C3+FX]-X * F * FF

种粮食:

1
* A * G * G * GFX[+G][-G] * X * X[-FFF][+FFF]FX

大城市的“地铁图”:

1
* F * +F[--F+F]

Ref



友情提示:独自折腾 Max 易患上癔症……不妨入群互助

👇👇👇

kidult00 wechat
扫码关注 00 的公众号
如果文章帮您节省时间或者解答疑问,不妨打个赏 :)