はじめに
最近興味のあるSverchok、そしてもともと興味のあったフラクタル。その両方を勉強出来る素晴らしいノードを発見したのでドキュメントを読んでみた。
参照元
機能
xmlで指定されたデザインにしたがって再帰的な3D構造を生成できます。
これらの構造はフラクタルやL-Systemに似ています。
このxmlファイルは変換ルールのセットを定義し、オブジェクトの配置を指示します。単一のルールのセットは多くの場合驚くほど複雑な構造を生成します。
入力とパラメータ
このノードは次のパラメータを持っています
- xml file 必須 これはLsystem設計を指定します。blendファイルのテキストブロックにリンクしていなければいけません。
- r seed Pythonが乱数を生成させる際に初期化する整数。もし複数のルールの選択があるデザインであれば、これを変更するとデザインの見た目を変更します。
- max mats 出力ノードが大量にあるため長い遅延やロックアップを回避するためにこの数を上限値に設定できる
このノードには次の入力があります
- vertices 任意。リング上に結合される頂点のリストでチューブ構造のベースとして用いられます。通常サークルやNgonノードの出力。
- data 任意。xmlファイルは{myvar}形式の記法を使用する事で任意の変数を定義する事が出来る。追加の名前付きデータはそれぞれの変数毎に作成されます。これらの変数はアニメーションを制御できます。
出力
- Vertices、Edges、Faces 頂点が入力されている場合、これらの出力は、xmlファイルで定義された構造を覆うチューブのメッシュを定義します。
- Shapes Matrices xmlファイルで定義された各形状属性に対して、名前付き出力が生成されます。この出力は、構造を定義する行列のリストです。
仕様
XMLファイルはルールのセットから成る、それぞれのルールは命令のリストを持ち、それぞれの命令は変形とルールの呼び出しまたはインスタンスの配置命令を持つ。
※ER風図
システムはスタックによって実装されている。スタックにはアイテムが積まれている。アイテムには次に呼び出すルール、現在のシステムの深さ、そしてシステムの現在の状態から成る
※ER風図
- プロセッサの各反復で最後のアイテムがスタックから除かれ処理される。
- システムの現在の状態はスタックから削除されたアイテムで設定される
- 命令内のいずれのトランスフォームはシステム状態に適用される
- もし命令がルールを呼び出すと、新しいRule、深さを1足したSytem depth、新しいシステム状態を持つアイテムがスタックに積まれる。
- もし命令がインスタンスの配置を行うと、新しいシステム状態を表すマトリックスがその形状のタイプの出力マトリックスリストへ追加される
- プロセッサは次に次の最後のスタックに進む
- max_depth、max_matsについて
- もし現在のルールがmax_depthへ到達、または設計全体のmax_depthへ到達したら、他のアクションを実行せずスタックの最後のアイテムを処理する。
- もしスタックが空、またはマトリックス数の最大まで到達したらプロセッサは停止する
使用例
6スパイラル
<rulesmax_depth="150"> <rulename="entry"> <callcount="3" transforms="rz 120" rule="R1"/> <callcount="3" transforms="rz 120" rule="R2"/> </rule> <rulename="R1"> <calltransforms="tx 2.6 rx 3.14 rz 12 ry 6 sa 0.97" rule="R1"/> <instance transforms="sa 2.6" shape="box"/> </rule> <rulename="R2"> <calltransforms="tx -2.6 rz 12 ry 6 sa 0.97" rule="R2"/> <instancetransforms="sx 2.6" shape="box"/> </rule> </rules>
XMLはルールから成る。少なくともentry と呼ばれる1つのルールが存在している必要がある。これがプロセッサーの開始位置となる。
呼び出しは再帰的である。上記の例ではルール R1 はR1を呼び出す。この再帰はmax_depthに到達するかノードに設定されているmax_matsに到達した時に停止する。max_depthはルールごとに設定でき、属性としても追加できる。例<rule name="R1" max_depth="10">
これらの命令はトランスフォームのセットによって変更できる。もし変換が省略された場合デフォルトの恒等変換となります。
トランスフォームは平行移動、回転、スケーリングがある。例えば tx 1.3
はx方向への 1.3 単位の移動を意味し、rz 6
はz軸の6度回転 sa 0.99
が意味するのはすべての軸を 0.99 のスケーリングを意味する。
変換の完全なリスト: tx ty tz rx ry rz sx sy sz sa
加えて平行移動またはスケールのすべての軸の値は、3つの一連の値で一度に適用出来る。
例: t 1.1 2.2 3.3 s 0.9 0.9 0.7
単一の変換属性を使うのではなく、個別に変換を指定する事もできる。もし count
が省略されたらデフォルトは1となる。例えば <call count="3" transforms="rz 120" rule="R1"/>
はR1を呼び出し120度 z軸を呼び出し毎に適用する。
- インスタンス命令は、プロセッサにその時点でのシステムの状態を定義する出力リストにマトリックスを追加するように支持する
- shape属性で使われる名前はノードの出力ソケットの名前として使われる
- 複数の形状がインスタンス化された場合はそれぞれ独自の出力ソケットができる
複数のルール定義の例
XMLファイルには同じルールで複数定義出来る
例えば
木
<rulesmax_depth="100"> <rulename="entry"> <call rule="spiral"/> </rule> <rulename="spiral" weight="100"> <calltransforms="tz 0.1 rx 1 sa 0.995" rule="spiral"/> <instancetransforms="s 0.1 0.1 0.15" shape="tubey"/> </rule> <rulename="spiral" weight="100"> <calltransforms="tz 0.1 rx 1 ry 4 sa 0.995" rule="spiral"/> <instancetransforms="s 0.1 0.1 0.15" shape="tubey"/> </rule> <rulename="spiral" weight="100"> <calltransforms="tz 0.1 rx 1 rz -4 sa 0.995" rule="spiral"/> <instancetransforms="s 0.1 0.1 0.15" shape="tubey"/> </rule> <rulename="spiral" weight="20"> <calltransforms="rx 15" rule="spiral"/> <calltransforms="rz 180" rule="spiral"/> </rule> </rules>
上記のXMLファイルは spiral
ルールが4つある。それぞれのルールは重み属性がある。このプロセッサーはそれぞれのバージョンの spiral
ルールをランダムな方法で呼び出す。この重み属性は特定のバージョンが呼び出される確率を決定する際に使われる。
最初の3つの定義では spiral
ルールはオブジェクトを配置して下記の様なトランスフォームを命令している。
ルールNo | z移動 | x回転 | y回転 | z回転 | xyzスケーリング |
---|---|---|---|---|---|
1 | 0.1 | 1 | 0.995 | ||
2 | 0.1 | 1 | 4 | 0.995 | |
3 | 0.1 | 1 | -4 | 0.995 |
※ルールNoは便宜上付与
4番目の定義では spiralインスタンスを配置せずにルールを2回呼び出す。これによりツリー構造内にブランチが生成される。
重みを変更するとツリーの分岐が変わる。重みが大きいほどルールはより頻繁に呼び出され枝が増える。
重み属性を省略すると、各バージョンの重みは等しくなる。ノードインタフェースにあるr seed
を変更するとxmlファイルにおいて生成される構造が変更される。この例においては seed = 1 としている。
継承ルールの例
通常 max_depth
ルールに到達すると構造のarm
が終了する。もしルールが後続ルールを定義していると、max_depth
に到達した時にそのルールが呼ばれる。
次の例では y180
が90回連続呼び出され、y軸を180度回転する。y180が終了するとr
が呼び出されy軸またはz軸が180度回転する。
ヌーボーバリエーション
<rulesmax_depth="1000"> <rulename="entry"> <callcount="2" transforms="rz 60" rule="r"/> </rule> <rulename="r"><callrule="y180"/></rule> <rulename="r"><callrule="z180"/></rule> <rulename="y180" max_depth="90" successor="r"> <callrule="dbox"/> <calltransforms="ry -2 tx 0.1 sa 0.996" rule="y180"/> </rule> <rulename="z180" max_depth="90" successor="r"> <callrule="dbox"/> <calltransforms="rz 2 tx 0.1 sa 0.996" rule="z180"/> </rule> <rulename="dbox"> <instancetransforms="s 0.55 2.0 1.25 ry 90 rz 45" shape="box"/> </rule> </rules>
Mesh モード例
行列出力の使用によって各場所に個別のオブジェクトが配置できます。頂点入力とメッシュ出力はかなり少ない数のオブジェクトに「スキン」する。頂点の入力は”Circle”ノードや”NGon”ノードなどによって生成された頂点のリストであるべきです。 ”Onbects In”を使って Scene上にあるCircleタイプのオブジェクトでも可能です。頂点のリストは最後の頂点が最初の頂点に結合されたリングにするように順序付けられている必要があります。リングは平面である必要はありません。
出力は常に1つのメッシュとは限りません。ルールセットが1つのarm
を終了し、別のarm
を開始する為に戻る場合2つのサブパーツは別々のメッシュになります。時にメッシュは意図したとおりにならないことがあります。多くの場合ルールセットを変更することで修正できます。
多くの場合Meshチューブはチューブのようではなくフラットになります。これは通常シーンにある頂点リングを回転させるか、回転トランスフォームをインスタンスコマンドに追加する事で修正できます。
例えば<instance shape="s1"/>
を<instance transforms="ry 90" shape="s1"/>
にする。
その他の場合、メッシュは間違った順序で接続される可能性があります。
例えば次の2つのXMLファイルはMatrix出力がオブジェクトの配置に使われるなら同じように見えますが、メッシュモードで使われたときには異なった結果になります。どちらのxmlルールも同じマトリックスリストを生成しますが異なった順序で生成します。
シダ1
<rulesmax_depth="5000"> <rulename="entry"> <call rule="curl" /> </rule> <rulename="curl" max_depth="80"> <calltransforms="rx 12.5 tz 0.9 s 0.98 0.95 1.0" rule="curl"/> <instanceshape="box"/> <calltransforms="tx 0.1 ty -0.45 ry 40 sa 0.25" rule="curlsmall" /> </rule> <rulename="curlsmall" max_depth="80"> <calltransforms="rx 25 tz 1.2 s 0.9 0.9 1.0" rule="curlsmall"/> <instanceshape="box"/> </rule> </rules>
シダ2
<rulesmax_depth="5000"> <rulename="entry"> <call rule="curl1" /> <call rule="curl2" /> </rule> <rulename="curl1" max_depth="80"> <calltransforms="rx 12.5 tz 0.9 s 0.98 0.95 1.0" rule="curl1"/> <instanceshape="box"/> </rule> <rulename="curl2" max_depth="80"> <calltransforms="rx 12.5 tz 0.9 s 0.95 0.95 1.0" rule="curl2"/> <calltransforms="tx 0.1 ty -0.45 ry 40 sa 0.25" rule="curlsmall" /> </rule> <rulename="curlsmall" max_depth="80"> <calltransforms="rx 25 tz 1.2 s 0.9 0.9 1.0" rule="curlsmall"/> <instanceshape="box"/> </rule> </rules>
これはどちらもmax_mats を5000にして行っています。
定数と変数の例
数値を中括弧のペアで置き換える事によりxmlファイルに定数と変数を含める事ができます
transforms = "tx 0.5 rx 20 sa 0.9"
は
transforms = "tx {x_const} rx 20 sa 0.9"
となる。
定数はxmlの中で次のように定義します。
<constants x_const="0.5" />
1つのエレメント内に複数の定数を定義でき、xmlファイルに置いて必要に応じていくつかの定数エレメントを使うことができます。
もし中括弧で囲まれたフィールド名に定数の値が指定されていない時、名前付き入力ソケットがノードに追加されます。Float、Integerなどの入力ノードはこの入力変数に接続できます。
下記はメッシュモードにおける例です。シダ構造をカールする量をアニメーションする為にカールの角度を変数にしています。また2つの定数を使用しています
シダ3
<rulesmax_depth="2000"> <constantszd="1.5" sxy="0.9" /> <rulename="entry"> <call rule="curl1" /> <call rule="curl2" /> </rule> <rulename="curl1" max_depth="60"> <calltransforms="rx {curl_angle} tz {zd} s {sxy} {sxy} 1.0" rule="curl1"/> <instanceshape="box"/> </rule> <rulename="curl2" max_depth="40"> <calltransforms="rx {curl_angle} tz {zd} s {sxy} {sxy} 1.0" rule="curl2"/> <calltransforms="tx 0.1 ty -0.45 ry 40 sa 0.25" rule="curlsmall" /> </rule> <rulename="curlsmall" max_depth="40"> <calltransforms="rx 2*{curl_angle} tz 2.7 s {sxy} {sxy} 1.0" rule="curlsmall"/> <instanceshape="box"/> </rule> </rules>
このアニメーションにおいて、現在のフレームのインデックス番号 1 から 250 は 16 から 6 へマッピングされ、Generative_artノードのcurcl_angle
に接続しています。これによってアニメーションさせています。
単純な数学もトランスフォーム定義に使用できます。これは上記のcurlsmall
ルール内で使っています。
トランスフォームの rx
回転は常に curl1
と curl2
のルールのrx
回転の2倍です。回転、平行移動、スケールパラメータに単一のトランスフォーム属性文字列を私用する場合は数式を用いる事はできません。より複雑な式を可能にするために核変換を独自の属性に分離する事ができます。
単一のトランスフォーム属性例(数式は使えない)
< call transforms = "tx 1 rz -1 * {v1} ry {v2} " rule = "R1" />
属性ごとに分離している例(数式が使える)
<call tx="1" rz="-1 * {v1}" ry="{v2}" rule="R1"/>
Pythonの math
と random
は Generative Artの名前空間に存在しているため、トランスフォームはこのようにも書けます。
tx="2**0.5"
または
tx="math.sqrt(2)"
References
このノードは Structure Synthに密接に基づいています。
しかしXML設計フォーマットであり、多くのコードは Philip RideoutのLsystemのGithubリポジトリから来ています。