Houdiniで植物モデリング(2)　マツバランのモデリング

引き続きThe algorithm of Beautyを読んで植物モデルに関する事物をまとめ、モデリングソフトHoudiniで具体的な実装をします。たまに別文献を参照します（目標）。
# 植物モデルの各名称
ここで植物モデルについて名称を抑えつつ基礎的な部分を確認します。木構造は情報学の分野ではbinary tree（二分木）がおなじみですが、自然界ではbinary treeの他にternary tree(三分木)も存在します。Houdini上では分岐がいくつ増えても扱うことはできますが、今回は二分木に論点を絞り説明します。
<table>
<tr>
<td><img width="300", src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559057/7577f3c3-46c4-4ab8-9ee3-087579b5ee37.png"></td>
</tr>
<th>図1: 木構造の名称1</th>
</table>

まずは図1のような木構造を考えます。nodeは日本語で節を意味し、Houdiniをお使いの方にはおなじみの概念です。
node間の線の部分はセグメント(segment or internode)と言います。そしてセグメントが1つしかつながっていないもののうち、一つだけ地面に近いものをルート(root or base)と呼び、それ以外はapex(terminal)といいます。また、枝分かれ構造をbranchと呼びます。
植物では葉は茎に付随する組織と考えられそれらを合わせてシュート(shoot)と呼びます。シュートの分枝構造は大きく2種類あり、二又分枝と単軸分枝です。
>シュートの分枝(Botany Web 中山 剛 2025/3/31アクセス)
>二又分枝 (dichotoous branching, dichotomy)
>軸の先端の分裂組織が勢力のほぼ等しい２つの軸が別れる分枝様式。叉状分枝ともいう。
>単軸分枝 (monopodial branching)
>主軸 (main axis) があり、その側方に側軸 (lateral axis) がつくられる分枝様式。

つまり図1は二又分枝で図2(下図)は単軸分枝となります。

<table>
<tr>
<td><img width="300", src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559057/2b67f624-e176-4c0f-8ccd-7095efb3e135.png"></td>
</tr>
<th>図2: 木構造の名称2</th>
</table>

単軸分枝の場合、主軸（main axis）と側軸(lateral axis or side axis)に分けられます。このような木構造をaxial treeと呼びます。
主軸はルート(root)から伸びる直線上のセグメントの集合です。側軸はルートではない別のセグメント上のノードから直線上に伸びるセグメントの集合です。側軸の部分には葉腋(axil)(茎と葉の間部分)から側芽(axillary buds)が展開してできます。
このような軸(axis)の集合であり、部分木になっているものをbranchと呼ぶこともあるようです。(図中の*について)

また、一般的にbudに関しては全てが側軸を形成するわけではなく花をつけるものや、休眠するもの、何にもならず消えるものが存在します。

axial treeにおいて軸(axis)についてorderをつけることができます。まず主軸をorder0として側軸については、側軸が展開する前の側芽が存在した軸のorderに1を足したものをそのorderとします。このようにつけたorderが図2に記載されています。branchのorderについては含まれる軸の最小orderになります。
また、apexについては成長点(growth point)にあたり、頂芽(apical bud)とも呼ばれます。頂芽と腋芽を合わせて定芽（definite bud）と呼ばれます。

# ヨー、ピッチ、ロール
L-systemを三次元に適応する場合などで回転方向や回転軸が三種類考えられます。
<table>
<tr>
<td><img width="700", src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559057/16bbaca3-01ef-4fdc-a4b9-000451aef5d8.png"></td>
</tr>
<th>図3: ヨー、ピッチ、ロール</th>
</table>

L-system上で上記のようにセグメント（$F$）がつながっている場合を考えます。回転軸の一つとしては元となるセグメントの延長となる軸で、Headingの頭文字をとり$H$とします。またこの軸を中心に回転することはロール(roll)といいます。
また図3中のLはLeftを指し、この軸での回転をピッチ(pitch)といいます。同様に$U$はupを指し、この軸での回転をヨー（yaw）といいます。
この三軸$H,L,U$は初期の三軸の取り方とそこからの回転角により求められます。図3中の右上のように初期の軸をとします（$H,L,U$はHoudini上のx,y,z軸と対応する）。
そこから元となるセグメント軸はy軸中心で$\alpha$度回転し、z軸中心で$\beta$度回転したものであるとします。
このとき3次元の回転行列を用い、次のように書けます。
```math
H\ = \ \begin{pmatrix}1 \\ 0 \\ 0\end{pmatrix} \begin{pmatrix}\cos\alpha &  0 & -\sin\alpha\\ 
0 & 1 & 0 \\ \sin\alpha & 0 & \cos\alpha \end{pmatrix}
\begin{pmatrix}\cos\beta & \sin\beta & 0 \\ -\sin\beta & \cos\beta & 0 \\ 0 & 0 & 1\end{pmatrix}
```
```math
L\ = \ \begin{pmatrix}0 \\ 1 \\ 0\end{pmatrix} \begin{pmatrix}\cos\alpha &  0 & -\sin\alpha\\ 
0 & 1 & 0 \\ \sin\alpha & 0 & \cos\alpha \end{pmatrix}
\begin{pmatrix}\cos\beta & \sin\beta & 0 \\ -\sin\beta & \cos\beta & 0 \\ 0 & 0 & 1\end{pmatrix}
```
```math
U\ = \ \begin{pmatrix}0 \\ 0 \\ 1\end{pmatrix} \begin{pmatrix}\cos\alpha &  0 & -\sin\alpha\\ 
0 & 1 & 0 \\ \sin\alpha & 0 & \cos\alpha \end{pmatrix}
\begin{pmatrix}\cos\beta & \sin\beta & 0 \\ -\sin\beta & \cos\beta & 0 \\ 0 & 0 & 1\end{pmatrix}
```
また、新たなセグメントの延長となる3軸$H',L',U'$は元のセグメントから$\theta$ヨーし、$\phi$ピッチし、$\psi$ロールしたものとします。このとき、以下を満たします。
```math
(H'\,,L'\,,U')\ = (H\,,L\,,U)
\begin{pmatrix}1 & 0 & 0 \\ 0 & \cos\theta & -\sin\theta \\ 0 & \sin\theta & \cos\theta\end{pmatrix} 
\begin{pmatrix}\cos\phi &  0 & -\sin\phi\\ 0 & 1 & 0 \\ \sin\phi & 0 & \cos\phi \end{pmatrix}
\begin{pmatrix}\cos\psi & \sin\psi & 0 \\ -\sin\psi & \cos\psi & 0 \\ 0 & 0 & 1\end{pmatrix}
```
Turtle-interpretionでヨー、ピッチ、ロールを使うコマンドは以下です。

<table>
<caption>turtle-interpretationの法則</caption>
<thead>
<tr>
    <th>記号</th><th>意味</th>
</tr>
<tr>
    <th>+</th><th>決められた角、反時計回りにヨー</th>
</tr>
<tr>
    <th>-</th><th>決められた角、時計回りにヨー</th>
</tr>
<tr>
    <th>&</th><th>決められた角、時計回りにピッチ（ピッチダウン）</th>
</tr>
<tr>
    <th>^</th><th>決められた角、反時計回りにピッチ（ピッチアップ）</th>
</tr>
<tr>
    <th>\\(\\\)</th><th>決められた角、反時計回りにロール</th>
</tr>
<tr>
    <th>/</th><th>決められた角、時計回りにロール</th>
</tr>
</table>

# context-sensitiveを使ったIL-system
DOL-system((1)の記事を参照)ではcontext-free(文脈自由)の形式文法を採用していました。以下では、context-sensitive（文脈依存）の形式文法を採用しL-systemを拡張します。
## 1L-system
生成規則で置き換えるアルファベット(ターゲット)の左側か右側のアルファベットを指定します。
例 : 
```math
b<a\\\to d
```
```math
b>c\\\to d
```
```math
F(1)\\<F(0)\\\to F(1)
```
このように$<,>$の口の空いている側がターゲットとなり、置き換えられます。例の3つ目のように変数を駆使し。物質の伝播のように用いることも可能です。
## 2L-system
$<,>$を両方使うパターンです。
例 : 
```math
a<b>c\\\to d
```
```math
A<F(1,s)>F(0,u)\\\to F(0,s)
```
より一般的には、ターゲットの前方に$k$個のアルファベット、後方に$m$個のアルファベットを指定した$(k,m)$**system**または**IL-system**と呼ばれるL-systemを考えています。

# マツバランのモデリング
今回はマツバランという植物のモデリングに挑戦します。マツバランはwikipediaの二又分枝の例として挙げられています。
>マツバラン wikipedia（2025/03/27　アクセス）
>茎だけで葉も根ももたない。胞子体の地上部には茎しかなく、よく育ったものは30cmほどになる。茎は半ばから上の部分で何度か２又に分枝する。分枝した細い枝は稜があり、あちこちに小さな突起が出ている。枝はややくねりながら上を向き、株によっては先端が同じ方向になびいたようになっているものもある。その姿から、別名をホウキランとも言う。先端部の分岐した枝の側面のあちこちに粒のような胞子のうをつける。胞子のう（実際には胞子のう群）は3つに分かれており、熟すと黄色くなる。

今回はHoudini(19.5)L-system SOPのデフォルトの生成規則を少し補足し、モデリングしていきます。また完成した動画はこの章の完成動画をご覧ください。

## L-system SOPの初期値
L-system SOPをNode Network上に置いたとき、デフォルトで設定されているL-systemについて考えてみます。
以下がそのL-systemです。
```
Premise : FFFA
Rule1 : A=!"[B]////[B]////B
Rule2 : B=&FFFA
```
まず"や!についてですが、これらはセグメントの長さやセグメントをチューブ化したときの半径を決められた値で乗算します（L-systemのトポロジー的な構造には干渉しません）。
ここで言う決められた値はL-system SOP内のValue>Step Size ScaleやTube>Thickness Scaleで変更できます。この値は通常1以下（デフォルトでは両者ともに0.9）で、セグメントの長さやチューブの半径は指数関数的に減少することが分かります。
AはAxisの略称として使われ、BはAのlateral axisを指しています。
/の回転角を$\theta$、&の回転角を$\phi$とします（HoudiniではどちらもValue>Angleの値を参照します）。Rule1によればlateral axisは$4\theta$おきに配置されることが分かり、それぞれ$\phi$ピッチダウンします。

<table>
<tr>
<td><img width="400", src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559057/7f9c19f4-bbae-436b-903e-53acc0e351c4.png"></td>
</tr>
<th>図4: L-system SOPの初期値</th>
</table>

## 生成規則の変更
以上の生成規則をマツバラン用に変更していきます。まずは、マツバランは二又分枝なのでRule1を変更します。
```
Rule1 : A=!"/[B]\\\\[B]
```
ここではロールの回転角をデフォルトの参照値であるAngleを変更し60°としています。/で時計回りに60°ロールし、\4つで反時計回りに120°ロールします（Houdiniでは\\2つで一つのコマンド）。これにより新たに生成する2軸は対象に配置されます。
Rule2に関しては、段階に分けて変更していきます。
```
Rule2 : B=&(15)F/T(-20)F/F/A
```
まずはマツバランの形状ではピッチダウンの角度が60°ですと大きすぎるので、&コマンドに変数を追加し15°とします。
続いてマツバランは枝のくねる特徴があるので、FとFの間に/（ロール）を入れチューブ化したときにくねる効果を得るようしています。
最後にTというコマンドですが、これは重力による屈性(tropism)ベクトルを適用するとしています。正の値を変数に入れると重力方向に、負の値を変数に入れると、重力とは反対の方向に曲がる効果があります。今回は適切な負の変数を採用し、重力とは反対方向に曲げる効果を働きます。

さらにマツバランには茎にとげがあり、先端付近に胞子のうをつける特徴があります。HoudiniにはJ,K,Mのタートルコマンドで外部の入力をL-system上で使用できます。
今回はJに胞子のう、Kにとげを簡単にモデリングしたものをいれ、Rule2をさらに変更します。
```
Rule2 : B=&(15)F[&(10)F(0.03)X(0)J]/T(-20)F[&(20)K]/F[F(0.03)X(0)J]/A
```
胞子のうは先端付近にしか存在しないので、ある程度時間がたつと消失するようにします。
```
Rule3 : X(s)>J = X(s+0.5)
Rule4 : X(t)<J:t=1.5 = a
```
このL-systemでは、2回おきに成長が発生するので0.5ずつXの変数を増加させています。そして、変数が1.5となるとJがa(消失)へと変わります。まとめると以下です。
```
Rule1 : A=!"/[B]\\\\[B]
Rule2 : B=&(15)F[&(10)F(0.03)X(0)J]/T(-20)F[&(20)K]/F[F(0.03)X(0)J]/A
Rule3 : X(s)>J = X(s+0.5)
Rule4 : X(t)<J:t=1.5 = a
```
## 完成動画
さらにPoint Jitterノードでポイントの位置を少し動かし、アトリビュートgenに対して色付けしたものが下記の動画となります（フォローよろしくお願いします）。

https://x.com/hou_saji/status/1906595624440811815

<table>
<tr>
<td><img width="400", src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559057/1e6490b0-5a8d-4b64-b2d0-8d3f0ef30ef3.png"></td>
</tr>
<th>図5: ワークフロー</th>
</table>



### 最後に
最後までのお読みいただきありがとうございました。次回はつる植物のようなよじのぼる植物を主題として取り上げていく予定です。

# 参照
Przemyslaw Prusinkiewicz・Aristed Lindenmayer著 The algorithmic beauty of plants(2004)　Ch1~3
https://algorithmicbotany.org/papers/#abop
Houdini 日本語版wiki
https://www.sidefx.com/ja/docs/houdini/nodes/sop/lsystem.html#%E3%82%A8%E3%83%83%E3%82%B7-%E3%81%AE%E6%9B%B8%E3%81%8D%E6%8F%9B%E3%81%88,%E3%82%A8%E3%83%83%E3%82%B8%E3%81%AE%E6%9B%B8%E3%81%8D%E6%8F%9B%E3%81%88
シュート Botany Web 中山 剛著
https://www.biol.tsukuba.ac.jp/~algae/BotanyWEB/shoot.html
マツバラン wikipedia
https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%84%E3%83%90%E3%83%A9%E3%83%B3