想象你拿到一本传了五代的家族谱。第一页只写着一位祖先的名字,家规也只有一句话:“每人生育三子,次子向左扎根,幼子向右扎根。”当你把五代人的关系图一笔一笔画在纸上,你惊讶地发现——家族的开枝散叶,竟然长成了一棵枝繁叶茂的大树。这就是 L-System(林氏系统)的核心直觉:计算机不直接“画”植物,而是像记家谱一样,用极简的“家规”(产生式规则)反复生成记录(字符串),再请一位“画师”(海龟绘图)把记录一笔一笔描成图形。1968 年,生物学家 Aristid Lindenmayer 受细胞分裂启发发明了这套形式文法,如今它已成为游戏程序化内容生成(PCG)的顶梁柱,也被广泛用于 AI 驱动游戏玩法中动态生态的构建。这篇教程会从这条“家规”讲起,带你逐步理解它的原理、绘图方式、如何塑造千姿百态的植被、如何让成千上万棵树流畅渲染,最终看透一片虚拟森林是怎样从一行字符里长出来的。

岗位关联

对 AI 从业者与游戏开发者而言,掌握 L-System 意味着能用“规则驱动内容”的思维替代“手工堆内容”,这是程序化内容生成、AI 驱动玩法与大规模虚拟世界构建的一项核心底层能力。

目录
  1. 可视化演示
  2. 基本概念原理:一条家规,代代相传
  3. 海龟绘图解释:请一位画师照谱作画
  4. 植被类型构建:改改家规,换换树种
  5. 随机化与多样性:同一家族,千姿百态
  6. 性能优化策略:让千万棵树的森林不卡
  7. 游戏与AI应用:从字符到活着的生态
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示L-System植被生成三大核心:字符串重写规则(公理F经产生式F→F[+F]F[-F]F迭代5^n指数增长)、Turtle Graphics绘图(F前进/+−转向25°/[]栈分支递归绘制分形树)、随机L-System(3条概率规则各33%生成形态各异植被),三模式切换理解程序化植被生成全流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

'+C1+'

基本概念原理:一条家规,代代相传

假设你是家族的记谱人,祖谱第一页写着始祖的名字 F,旁边钉着一块家规木牌:“凡 F 者,成年后生育三子,长子继续顶门立户,次子向左开枝,幼子向右散叶。”你严格照办,第一代家谱变成 F[+F]F[-F]F;第二代再把这段文字逐字“过堂”——每个 F 都按家规重新写一遍,方括号是旁支的记号。如此往复,家谱文本越来越长,可规则从未变过。

L-System 正是把“记家谱”翻译成了数学:它是一套形式文法,由字母表、公理和产生式组成。公理(Axiom)就是始祖 F;产生式(Production Rule)就是家规 F → F[+F]F[-F]F;每一代把字符串中每个字符按产生式替换,生成下一代字符串,这个过程叫字符串重写。重写三代的家谱长这样:

第 2 代字符串已长达 47 个字符,里面藏着一个秘密:任意截取一段带方括号的子串,它都是整棵树的“缩小版家谱”。把这个过程写成数学表达式:

你看,家谱还是那本家谱,家规还是那块木牌,可传了五代之后,纸上已经密密麻麻布满分支。L-System 的“魔力”就在这种极简规则与反复迭代的组合——它不靠复杂逻辑,而是靠代际累积制造复杂。下一节,我们要请一位画师,把这份家谱真正画成一棵树。

S0=ω,Sn+1=R(Sn),r(c)={F[+F]F[−F]F,c=Fc,c≠FS_0 = \omega,\qquad S_{n+1} = R(S_n),\qquad r(c)=\begin{cases} F[+F]F[-F]F, & c=F \\ c, & c \neq F \end{cases}
这个公式描述了一代代“家谱”如何被重写:先定始祖,再按家规逐个替换字符,最后拼出下一代。
  1. 设定初始公理$\omega$ 是重写前的始祖字符串,通常设为单个符号 F,代表种子。
    S0=ω=FS_0 = \omega = F
  2. 逐字符遍历对第 n 代字符串 $S_n$ 中的每个字符 $c$ 独立应用产生式 $r(c)$。
    c∈Snc \in S_n
  3. 套用产生式遇到 F 就替换成一整段分支结构,其他字符(方括号、加减号)原样保留。
    r(F)=F[+F]F[−F]F,r(c)=c (c≠F)r(F) = F[+F]F[-F]F,\quad r(c) = c\ (c \neq F)
  4. 拼接出下一代所有替换结果按原顺序拼接,得到新一代字符串。
    Sn+1=R(Sn)S_{n+1} = R(S_n)
text3 行
第 0 代:F第 1 代:F[+F]F[-F]F第 2 代:F[+F]F[-F]F[+F[+F]F[-F]F]F[+F]F[-F]F[-F[+F]F[-F]F]F[+F]F[-F]F

海龟绘图解释:请一位画师照谱作画

家谱记录得再详细,也只是文字。要让旁人心领神会,得请画师照着文字作画。这位画师笔法极其机械:听到“走一步”就落笔画固定长度,听到“左拐”就原地转一个角度;最特别的是,听到“[“就在桌上压一张便签,记下当前笔尖的位置和朝向;听到”]”就翻出最近一张便签,把笔挪回那里继续画。

这位“画师”在计算机图形学里有个可爱的名字:海龟绘图(Turtle Graphics),来自 1980 年代的 Logo 语言。L-System 生成的符号串本身没有形状,海龟解释器负责把符号翻译成几何操作——F 前进并画线,+ 左转、− 右转,[ ] 压栈与弹栈。于是同一串字符,换个初始位置和朝向,就能画出任意角度的树。海龟每一步的状态可以压缩为三元组 $(x, y, \theta)$:位置和朝向。前进一单位长度 $l$ 时:

画师照本宣科,却画出了真正的“树”,因为字符串里的方括号天然对应“枝条回到主干”。更妙的是,每个枝条上的图案都是整棵树的缩小版——这种自相似性正是分形的精髓。海龟画师看不见整片森林,但它一笔一画,森林就自己浮现了。

x′=x+lcos⁡θ,y′=y+lsin⁡θ,θ′=θ+δx' = x + l\cos\theta,\qquad y' = y + l\sin\theta,\qquad \theta' = \theta + \delta
这是海龟画师的“脚步公式”:它在平面上走一步,横纵坐标分别按角度投影位移,同时更新朝向。
  1. 横坐标前进海龟沿当前朝向 θ 走一步,横坐标等于原横坐标加上步长 l 在 x 轴上的投影。
    x′=x+lcos⁡θx' = x + l\cos\theta
  2. 纵坐标前进同理,纵坐标增加 y 轴投影,θ 从水平向右方向起算。
    y′=y+lsin⁡θy' = y + l\sin\theta
  3. 转向更新遇到 + 时角度加上转角 δ,遇到 − 时减去转角 δ,实现左右分支。
    θ′=θ+δ\theta' = \theta + \delta
  4. 方括号入栈出栈[ 把当前三元组压入栈,] 弹出最近一组恢复海龟状态,完成枝条回退。
    push(x,y,θ)⟷(x,y,θ)=pop()\text{push}(x,y,\theta) \quad \longleftrightarrow \quad (x,y,\theta) = \text{pop}()

植被类型构建:改改家规,换换树种

同样是记家谱,不同家族的家规天差地别:有的家族开枝散叶极密,有的只留独苗;有的分支角度大、长得张扬,有的收敛紧窄。想生成松树、灌木还是路边野草?改一改“家规”即可——L-System 的魅力就在此处,植物形态完全由产生式与参数决定。

工程上构建植被类型,就是设计三件事:公理选什么初始结构、产生式长什么样、以及两个关键参数——每次重写步长如何收缩(长度衰减率 $\delta$)和分支转角 δθ。例如针叶树常用层叠收敛的规则,灌木让次级分支极其密集,草本植物迭代深度很低。其中,长度衰减率是塑造树冠的关键。若初始步长为 $l_0$,每深入一代步长乘以 $\delta$($0<\delta<1$),则第 n 代的步长为:

调参像给家规“画刻度”:角度决定树冠是张扬还是内敛,衰减率决定枝条是疏朗还是逼仄。你把家规改一改,同一只海龟画出的就是另一棵树种。到这一步,你已经能从字符串里“读”出树木的形状了。

ln=l0⋅δnl_n = l_0 \cdot \delta^{n}
这条公式说明树枝越分越细:每一代长度都按固定比例收缩,深度越大,枝条越短越密。
  1. 定义基础步长$l_0$ 是树干第一段的长度,由画布或网格尺寸决定,必须是正数。
    l0>0l_0 > 0
  2. 每代收缩比例$\delta$ 是子代步长与父代步长的比值,也叫长度衰减率,典型值 0.5~0.7。
    δ∈(0,1)\delta \in (0, 1)
  3. 指数累积效应经过 n 代之后,步长被连乘 n 次,这就是指数衰减。
    δn=δ×δ×⋯×δ⏟n\delta^{n} = \underbrace{\delta \times \delta \times \cdots \times \delta}_{n}
  4. 代入数值直觉取 $\delta = 0.65$、$n = 4$,第 4 代枝条长度约为基础步长的 18%,细如发丝。
    l4=l0⋅0.654≈0.18 l0l_4 = l_0 \cdot 0.65^4 \approx 0.18\,l_0

随机化与多样性:同一家族,千姿百态

同一个家族的堂兄弟,高矮胖瘦各不相同。自然界没有两片相同的叶子,可纯手工让每棵树都不同又累死人。解决之道是给家规加上“抽签”:同一情形下,按概率从几条家规里挑一条执行——这就是随机 L-System(Stochastic L-System)。

随机产生式为每种可能替换指定权重,权重越大越常被选中。设某符号有 $m$ 条候选规则,权重为 $w_1, w_2, \dots, w_m$,则第 $i$ 条被选中的概率是:

除规则级随机外,更轻量的手段是参数扰动:给转角、步长加少量噪声(如 ±5°、±8%),也能让同一棵树长出高低错落的枝条。工程上还会用多个随机种子批量生成“一母同胞”的树木族群,粗筛后入库。家规没变,抽签却让每张家族照都独一无二。随机化不是失控,而是受控的“同族不同形”——这一手在 PCG 里叫受控多样性,是植被看起来自然的关键秘诀。

pi=wi∑j=1mwjp_i = \dfrac{w_i}{\displaystyle\sum_{j=1}^{m} w_j}
这条公式就是“加权抽签”:每一条候选家规的偏好权重除以所有候选权重之和,得到各自被抽中的概率。
  1. 候选规则权重$w_i$ 是第 i 条产生式的权重,权重越大被抽中机会越高。
    wi≥0w_i \ge 0
  2. 权重总和$\sum_{j=1}^{m}w_j$ 把所有候选规则权重相加,作为归一化的分母。
    Wtotal=∑j=1mwjW_{\text{total}} = \sum_{j=1}^{m}w_j
  3. 计算选中概率归一化后 $p_i$ 表示每条候选规则被选中的概率,所有概率之和恒为 1。
    pi=wiWtotalp_i = \dfrac{w_i}{W_{\text{total}}}
  4. 固定随机源用带随机种子 s 的伪随机数发生器抽签,保证同一种子永远长出同一棵树。
    choice∼RNG(s),P(rulei)=pi\text{choice} \sim \text{RNG}(s), \quad P(\text{rule}_i) = p_i

性能优化策略:让千万棵树的森林不卡

一个村子记家谱很容易,可要记一整个王国、几百万个家族的家谱呢?如果每棵树的每条枝条都细细画来,再好的画师也画不完。游戏引擎面对的就是这个“王国”:一片森林几十万棵树,GPU 每一帧能画的三角形却有限。

指数爆炸是 L-System 的第一敌人。若产生式把每个 F 替换成 b 个 F(如 F→F[+F]F[-F]F 中 b=3),迭代 n 代后字符串中 F 的数量为:

实战中对抗指数爆炸有四板斧:其一,几何实例化(Instancing),一棵树的网格只上传一次,GPU 复用绘制成千上万棵,把同模板的树木合并成少量绘制批次;其二,细节层次(LOD),远处用只画主干骨架的低模甚至公告板,近处才上高模;其三,预计算缓存,树干拓扑离线烘焙,运行时只做位置摆布与动态叶片摆动;其四,视锥剔除(Frustum Culling),相机看不到的树一个像素都不画。组合使用后,几十万棵树的场景依旧流畅。画师再勤快,也不如聪明的排版:家谱图分远近,远处的家族只画名字不画肖像。优化不是偷懒,而是把绘画预算花在玩家看得见的地方——这跟真实世界的生态视觉规律如出一辙。

T(n)=c⋅bnT(n) = c \cdot b^{n}
这条公式揭示了“家谱越写越长”的数学本质:每多记一代,分支数量按底数 b 指数膨胀。
  1. 单符号展开数$b$ 是每个 F 产生的后代 F 数量,本例 F→F[+F]F[-F]F 中为 3。
    b=3b = 3
  2. 初始数量$c$ 是公理中 F 的个数,通常为 1,代表始祖。
    c=∣S0∣F=1c = |S_0|_F = 1
  3. 指数增长每迭代一代数量乘 b,n 代后为 $b^n$,这就是字符串长度的膨胀规律。
    T(n)=c⋅bnT(n) = c \cdot b^{n}
  4. 数量估算深度 6 时约 729 条线段,深度 12 时超过 53 万条,必须限制深度或简化规则。
    T(6)=729,T(12)=531441T(6) = 729, \quad T(12) = 531441

游戏与AI应用:从字符到活着的生态

当一份家谱传遍整个虚拟世界,它就不再是纸上的图案,而是活生生的生态。塞尔达式的旷野之息、艾尔登法环式的王国,那些远山如绿浪的树海,背后往往都是 L-System 在批量“续写家谱”。

在 AI 驱动游戏玩法中,L-System 常与规则引擎、生态仿真结合:植被不再是静态美术资源,而是一个可生长的系统。玩家的行为(砍伐、播种、火焚)会改变局部参数,触发新的重写。例如砍倒一棵树后,残桩按“再生家规”重新长枝;季节系统改变转角权重,让树木冬天落叶、春天抽芽。落地的工程链路通常是:离线阶段用海龟解释器把 L-System 烘焙成网格与 LOD 资产,按种子入库;运行时按生态密度图放置,密度由海拔、湿度、光照等噪声场驱动。一个区域树的数量估算为:

从一行字符到一片森林,L-System 用“记家谱”这种最朴素的方式,完成了虚拟世界的绿化工程。它提醒我们:复杂的世界不一定需要复杂的代码,只需要简单的规则,加上足够多的迭代和想象力。

N=⌊ρ⋅A⌋N = \lfloor \rho \cdot A \rfloor
这条公式用于“植树造林”的预算控制:用单位面积密度乘以区域面积,再向下取整得到精确棵数。
  1. 树木密度$\rho$ 表示单位面积内允许放置的树木数量,取决于生态类型与性能预算。
    ρ>0\rho > 0
  2. 区域面积$A$ 是待填充植被的多边形区域面积,由生态图(湿度、海拔、光照)决定。
    A=∬Ddx dyA = \iint_D \mathrm{d}x\,\mathrm{d}y
  3. 向下取整$\lfloor \cdot \rfloor$ 保证树木数量为整数,避免出现半棵树。
    N=⌊ρ⋅A⌋N = \lfloor \rho \cdot A \rfloor
  4. 流式加载修正运行时只对玩家周围区域实例化网格,远处退化为贴图,实际绘制量远小于 N。
    Ndraw=min⁡(N, ⌊ρ⋅Avisible⌋)N_{\text{draw}} = \min(N,\ \lfloor \rho \cdot A_{\text{visible}} \rfloor)

AI 应用场景

开放世界植被自动铺种

阶段:程序化内容生成(PCG)· 资产生产

解决的问题:传统方式中美术手动种树,一片 1km² 森林需要数周工时,且重复感强、难以覆盖大世界任意角落。L-System 把“种树”变成“写规则”:一条家规 + 一组参数即可批量产出树木资产。

具体案例:某开放世界项目用 L-System 预烘焙 50 种植物模板,结合噪声分布图自动铺景——树木位置由湿度、海拔、光照驱动,玩家跑图时远处山峦的“树海”全部来自几十条字符串规则,而非手工摆放。

AI驱动生态仿真

阶段:AI 驱动玩法 · 动态世界

解决的问题:静态植被不会回应玩家,世界缺乏“活着”的感觉。L-System 让植被作为“活体”参与游戏循环:砍伐、季节、光照都会改写局部规则,生态随之演变。

具体案例:生存类游戏中玩家砍伐树木后,系统按 L-System 规则从残桩重新长出枝条;季节参数改变转角权重,冬季树木收缩枝条、夏季重新展开;AI 动物寻路逻辑读取植被密度图决定栖息地范围,形成植物—动物—玩家的闭环生态。

美术概念快速预演

阶段:内容生成辅助设计

解决的问题:植物外形手绘迭代慢,一棵概念树可能要改好几轮。用 L-System 脚本批量跑几十组参数,几秒钟输出不同树形的草图,让美术先“盲选”再精修。

具体案例:技术策划用 Python 脚本把 20 组公理/转角/衰减率参数批量生成 SVG 剪影图,美术从中挑选 3 个方向深入建模,概念阶段从一周缩短到半天。

Python 演示

python96 行
#!/usr/bin/env python3# -*- coding: utf-8 -*-"""L-System 植被生成器: 用一条家规长出植物轮廓, 导出 SVG 矢量图""" import mathimport random AXIOM = "F"RULES = {"F": "F[+F]F[-F]F"}STOCHASTIC = {"F": ["F[+F]F[-F]F", "F[+F]F", "F[-F]F"]}WEIGHTS = {"F": [0.6, 0.2, 0.2]}ANGLE = math.radians(25.7)BASE_STEP = 12.0DECAY = 0.62SEED = 42  def build_string(axiom, rules, depth):    """把公理反复重写 depth 代, 返回最终符号串"""    s = axiom    for _ in range(depth):        s = "".join(rules.get(ch, ch) for ch in s)    return s  def build_string_stochastic(axiom, depth, rand):    """随机 L-System: 每次按权重选择一条产生式"""    s = axiom    for _ in range(depth):        out = []        for ch in s:            if ch in STOCHASTIC:                choices = STOCHASTIC[ch]                out.append(rand.choices(choices, weights=WEIGHTS[ch])[0])            else:                out.append(ch)        s = "".join(out)    return s  def interpret(s, step, angle, start, heading):    """把符号串翻译成线段列表"""    x, y = start    theta = math.radians(heading)    stack = []    segs = []    for ch in s:        if ch == "F":            nx = x + step * math.cos(theta)            ny = y + step * math.sin(theta)            segs.append((x, y, nx, ny))            x, y = nx, ny        elif ch == "+":            theta += angle        elif ch == "-":            theta -= angle        elif ch == "[":            stack.append((x, y, theta))        elif ch == "]":            x, y, theta = stack.pop()    return segs  def to_svg(segments, path):    """把线段写出为 SVG 文件"""    lines = []    for x1, y1, x2, y2 in segments:        lines.append(            '<line x1="%.1f" y1="%.1f" x2="%.1f" y2="%.1f" '            'stroke="#10B981" stroke-width="2"/>' % (x1, y1, x2, y2)        )    svg = ('<svg xmlns="http://www.w3.org/2000/svg" '           'viewBox="-320 -320 640 640">\n'           + "\n".join(lines) + "\n</svg>\n")    with open(path, "w", encoding="utf-8") as f:        f.write(svg)    print("已输出 %d 条线段到 %s" % (len(segments), path))  def main():    depth = 4    step = BASE_STEP * (DECAY ** depth)    start = (0, -280)     det_str = build_string(AXIOM, RULES, depth)    det_segs = interpret(det_str, step, ANGLE, start, 90.0)    to_svg(det_segs, "plant_det.svg")     rand = random.Random(SEED)    sto_str = build_string_stochastic(AXIOM, depth, rand)    sto_segs = interpret(sto_str, step, ANGLE, start, 90.0)    to_svg(sto_segs, "plant_sto.svg")  if __name__ == "__main__":    main()
目的:用约 80 行 Python 实现确定性 L-System 与随机 L-System,将符号串解释为线段并导出两张 SVG 植物图,完整走通“规则 → 重写 → 绘图”全流程。
  1. s = "".join(rules.get(ch, ch) for ch in s)字符串重写的核心循环:每个字符查“家规”,没有规则的原样保留。
  2. out.append(rand.choices(choices, weights=WEIGHTS[ch])[0])按权重随机挑选一条产生式,实现受控多样性。
  3. stack.append((x, y, theta))海龟遇到 [ 时把当前位置、朝向压入栈,记住分支起点。
  4. x, y, theta = stack.pop()遇到 ] 弹栈回到分支起点,海龟继续画主干。
  5. nx = x + step * math.cos(theta)沿当前朝向计算下一笔的横坐标,对应海龟前进公式。
  6. step = BASE_STEP * (DECAY ** depth)用长度衰减率计算第 depth 代的枝长,枝条越分越细。
  7. rand = random.Random(SEED)固定随机种子,确保同一参数永远长出同一棵树,方便复现调试。

常见误区

误区我一开始以为 L-System 是个“画树算法”,只要喂一张草稿图,它就能自动输出一棵 3D 树模型,所以看到满屏的字符串示例时完全懵了。

正解L-System 只管“生成记录”,不管“画图”。它是一套字符串重写文法——公理加产生式反复迭代,产出的是符号串。至于串长成什么样,完全取决于你用哪种解释器:海龟绘图把它画成植物,换成道路解释器就生成城市路网,换成音频解释器就生成节奏。就像家谱本身只是文字记录,画成族谱树还是家谱表格,由画师决定。

为何常见:几乎所有教程都用植物配图讲解,视觉先入为主,让学习者把“示例”当成了“本质”。

误区把迭代深度调到 12,树肯定更茂盛、更逼真,反正机器算得快,为什么不呢?

正解深度每加 1,指令数按 b 倍膨胀(b≥2)。深度 12 时一个 F 可能变成 53 万个,性能直接崩溃;而且枝条过于细密,视觉上反而变成一团乱麻。工程上深度 4~6 就能获得满意效果,剩余真实感靠随机扰动、叶片网格和材质来补。正如家族谱系记到第 12 代,纸张密密麻麻反而没人看得懂。

为何常见:直觉上“更多细节 = 更好”,忽略了指数增长的代价与视觉密度的边际效应。

误区既然要让每棵树都不一样,那就把角度、长度全部随机化,越乱越自然!

正解无约束随机只会得到一堆乱七八糟的“丑树”。受控多样性才是正解:规则层面的随机用权重采样,参数层面的扰动控制在 ±5°~±10% 以内,并用固定随机种子保证同一场景可复现。恰如同一家族的人共享五官轮廓,只在细节上各有不同,这才叫“同族不同形”。

为何常见:把“自然”误等同于“无序”,忽略了自然产物背后的遗传约束。

误区转角参数随手填个值就行,反正最后画出来都是树,差别不大。

正解转角直接决定树冠的几何形态:25°~30° 左右形成匀称的扇形树冠;超过 60° 时枝条过度内折,互相重叠遮挡;接近 0° 则几乎看不出分支。真实感来自小数参数的精确调校,而不是碰运气。改一次转角,等于给整棵树的“骨骼”重新塑形。

为何常见:从字符串看不出转角影响,参数又藏在代码深处,容易被系统性忽略。

误区生成植被只有 L-System 这一种方法,学会它就能通吃所有植物场景。

正解实际项目中 L-System 擅长“有明确结构感”的植物(树木、灌木),但草地常用噪点散布,藤蔓常用粒子约束生长,树干细节可用手工模型拼接。工程上常按植物类型混用多种 PCG 方法与美术资产,L-System 只是工具箱里最趁手的一把。

为何常见:单一教程体系容易造成“锤子钉子”思维,让人低估了真实管线里的混合策略。

面试题

Q1. L-System 本质上是一种什么方法?

单选题 · easy

  • A.字符串重写的形式文法← 正确答案
  • B.图像滤波的卷积算子
  • C.三维网格重建算法
  • D.蒙特卡洛采样方法

答案:A。L-System 是形式文法,核心是公理加产生式反复重写字符串,与卷积、网格重建、蒙特卡洛都无关。就像家谱的核心是记录与繁衍规则,而不是画画的笔法。

Q2. 在 L-System 中,“公理”(Axiom)指的是什么?

单选题 · easy

  • A.竖直的树干粗细数值
  • B.初始的字符串结构← 正确答案
  • C.分支的弯曲角度大小
  • D.最终渲染分辨率高低

答案:B。公理是重写的起点,即始祖字符串,例如单个 F。树干粗细、转角、分辨率都是后续解释或渲染阶段的参数,不属于公理定义。

Q3. 符号 “[“ 与 ”]” 在海龟绘图中的功能是?

单选题 · mid

  • A.放大与缩小绘制步长
  • B.保存与恢复海龟状态← 正确答案
  • C.加速与减速动画播放
  • D.切换前景与背景颜色

答案:B。[ 把海龟的 (x, y, θ) 压入状态栈,] 弹栈恢复,以此实现分支回退。就像画师压一张便签记住笔尖位置,画完旁支再回到主干继续画。

Q4. 规则 F → F[+F]F[-F]F 每迭代一代,F 的数量变为?

单选题 · mid

  • A.原来的 2 倍
  • B.原来的 3 倍← 正确答案
  • C.原来的 4 倍
  • D.保持不变

答案:B。产生式中一个 F 被替换为含三个 F 的结构,因此每代数量乘以 3,对应指数增长公式 T(n) = c·3ⁿ。

Q5. 随机 L-System 选择产生式时,通常依据什么?

单选题 · mid

  • A.画布空间的哈希散列
  • B.字符串的字典序排列
  • C.规则权重的归一化概率← 正确答案
  • D.GPU 顶点缓冲区的空闲

答案:C。随机产生式按权重归一化采样,权重越大被选中概率越高。这是受控随机的标准做法,与哈希、字典序、顶点缓冲无关。

Q6. 转角参数设置过大会导致植物?

单选题 · mid

  • A.分支过于重叠显得杂乱← 正确答案
  • B.树干无限向上持续生长
  • C.叶片全部变成圆润球形
  • D.花朵尺寸变得越来越大

答案:A。转角过大使分支过度内折,枝条互相重叠遮挡,视觉杂乱。它不影响树干生长方向、叶片形状或花朵尺寸,这些由其他参数决定。

Q7. 大面积森林渲染中降低 GPU 压力的核心策略是?

单选题 · mid

  • A.采用LOD与几何实例化← 正确答案
  • B.提高树木贴图分辨率
  • C.增加迭代深度达十二代
  • D.关闭垂直同步功能开关

答案:A。LOD 按距离降面数,几何实例化复用网格、合并批次,两者组合可成数量级降低绘制开销。提高分辨率反而更耗性能,增加深度会指数爆炸。

Q8. 以下哪些手段可以增加植被多样性?

多选题 · mid

  • A.为产生式设置多种权重← 正确答案
  • B.让角度长度加入噪声← 正确答案
  • C.固定唯一的转角参数
  • D.使用种子控制随机源← 正确答案

答案:ABD。多权重产生式、参数噪声、多随机种子都能让“同族不同形”;固定唯一转角只会让所有树长得一模一样,与多样性目标相反。

Q9. 关于迭代深度 n,下列说法正确的有?

多选题 · hard

  • A.深度增加时指令数指数膨胀← 正确答案
  • B.深度越大运行性能就越好
  • C.深度过小导致结构太简单← 正确答案
  • D.深度过大反而视觉杂乱难控← 正确答案

答案:ACD。指令数按 bⁿ 指数膨胀,深度越大性能越差而非越好;深度过小结构单薄,深度过大则细密杂乱,工程上需取折中。

Q10. 在开放世界游戏中落地 L-System 植被,通常的做法包括?

多选题 · hard

  • A.离线烘焙植被几何数据← 正确答案
  • B.流式加载玩家附近植被← 正确答案
  • C.每帧全量重写一遍规则
  • D.结合生态仿真动态生长← 正确答案

答案:ABD。工程链路是离线烘焙网格资产、按需流式加载、结合生态仿真做动态生长。每帧全量重写规则在性能上不可行,因为字符串会指数膨胀。