ニッチなblender手記

世の中には自分に似た人が3人いるとされています。その人達へと情報共有するために主にblenderの記事を書いていきます。

loose read about Sverchok documents (Introduction Unit 03)

Lesson 03 - A Grid

ここではグリッド状の平面オブジェクトを作成していくことで、パラメトリックデザインと動的トポロジーの概念を学習する。

グリッドは、一般的な幾何学的プリミティブであり、x軸とy軸で細分化された平面と考えることができる。

あるいは小さな板ポリを格子状に並べたオブジェクト

Sverchok の平面ジェネレータはグリッドを作成し、関連する辺とポリゴンを含む。
ここでは、 Sverchok に標準で用意されている Plane ノードを使うのではなく、ノードツリーを作成してグリッドを作成する。 これがどのように動作するかを理解すれば、要点を理解したことになり、より複雑なオブジェクトへの応用ができる。 パラメトリックデザインと動的トポロジーの重要な概念をいくつか取り上げます。

元記事

Introduction to modular components - Lesson 03 - A Grid

What do we know about Grids?

ここからは下図のようにx軸とy軸が細分化された平面を作成していく。

参照画像

Where to start?

ここからはビューポート上に図示しながらの解説が進んでいく。

レッスンとしてグリッドが選ばれたのは、グリッドが以下のような単純なプロパティしかもたないためである。

  • X Side Length
  • Y Side Length
  • X num subdivs
  • Y num subdivs

上記のプロパティに関しては表示する手段があるらしいが、ここではその手段は記載されずに図でのみ解説されている。

参照画像

Decide which variables you want to expose

作成しようとしているグリッドの内、以下のプロパティから作成していく。

  • Side X total length
  • Side Y total length
  • Number Vertices on side X
  • Number Vertices on side Y

Think in Whole numbers (integers, ints) if you can

グリッドを作成するために、形状を数学的に単純化して取り組んでいく。
下図は座標を説明するためにXY軸上に描かれたグリッドである。
今回はXY平面上にグリッドを作成するのでZ軸は無視できるが、完全性のためにZ軸も含んでいる。

参照画像

上図で 4 * 3 頂点を選んだ理由は、それがグリッドを解説する上での最小の形の一つであり、任意の次元のグリッドに変換するためには微調整するだけいいから。
3 * 3や4 * 4を選ばない理由は、xとyに異なる頂点数を使用することでX軸が4でY軸が3であることの関係を見出しやすいから。

上図の4 * 3 グリッドの各頂点の第一成分のシーケンスを考える。

[0,1,2,3,0,1,2,3,0,1,2,3]

続いて第二成分のシーケンス。

[0,0,0,0,1,1,1,1,2,2,2,2]

これらは Sverchok では簡単にノードで生成できる。

Lesson 01 や Lesson 02 で実際にやった、 Number Range などの組み合わせによる頂点の生成のこと。

Using modulo and integer division to get grid coordinates

ここでは、周期的な関数 (periodic functions) や段階的な増加 (stepwise increases、インクリメント) の話をするときに常に関わってくる2つの数学的な概念(操作)を取り上げる。

  • modulo, or the symbol %
  • integer division, or the symbol //

module および integer division 共に Sverchok には標準機能として Scala Math ノードの設定として搭載されている

Operands

Lesson 01 と 02 で Scalar Matth ノード利用したが、Scalar Matth ノード にはオペランドと呼ばれる多くの操作がある。ここでは、それらを用いて頂点の構成要素を得ていく。

operand Symbol Behaviour
Modulo (mod) % i % 4 returns the division remainder of i / 4 , rounded down to the nearest whole number
Integer Division // i // 4 returns the result of i / 4 , rounded down to the nearest whole number.

1つ目は剰余算を計算するためのオペランド、 下は除算した結果を整数値に丸めるためのオペランド

これらのオペランドを用いると、下記のような計算をすればそれぞれ第一成分と第二成分のシーケンスと同じ結果になる:

  • i % 4 to turn [0,1,2,3,4,5,6,7,8,9,10,11] into [0,1,2,3,0,1,2,3,0,1,2,3]
  • i // 4 to turn [0,1,2,3,4,5,6,7,8,9,10,11] into [0,0,0,0,1,1,1,1,2,2,2,2]

数値に対して moduloint.division を利用した時の結果テーブルは下記の通り

number range (n) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
n % 4 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2
n // 4 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3
n % 6 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2
n // 6 0 0 0 0 0 0 1 1 1 1 1 1 2 2 2

下図は上のテーブルに繰り返しやシーケンスの流れが分かりやすいようにマーカーをつけたものとなっている。

参照画像

このレッスンでは Sverchok によるビジュアルプログラミンを学ぶことが目的となっている。
上記の数学的な処理や概念といった角度から、基礎的な数学的な知識や概念をコード化していくことになる。

グリッドの頂点を計算するために %// を使用する2つのコード (python) を後述する。このコードは、必要な頂点の数(12 = 4 * 3)に基づいて、頂点のxとyの成分を生成するアルゴリズムになっている。
どちらも結果は変わらない。

あえて比較するのであれば、 python を利用する以上は連想配列で処理する後者の方が処理速度は速くなる

# the for-loop version:

num_verts_x = 4
num_verts_y = 3
j = num_verts_x * num_verts_y      # the * symbol means multiplication

final_list = []
for i in range(j):                 # passes: 0 1 2 3 4 5 6 7 8 9 10 11
   x = i % 4                       #  makes: 0 1 2 3 0 1 2 3 0 1 2 3
   y = i // 4                      #  makes: 0 0 0 0 1 1 1 1 2 2 2 2
   final_list.append((x, y, 0))
# the list comprehension version:

num_verts_x = 4
num_verts_y = 3
j = num_verts_x * num_verts_y      # the * symbol means multiplication

final_list = [(i % 4, i // 4, 0) for i in range(j)]

上記2つのコードは、どちらも同じ結果を出力する。

[(0, 0, 0), (1, 0, 0), (2, 0, 0), (3, 0, 0),
 (0, 1, 0), (1, 1, 0), (2, 1, 0), (3, 1, 0),
 (0, 2, 0), (1, 2, 0), (2, 2, 0), (3, 2, 0)]

これら頂点は、最終的に下図のような形となる。

参照画像

ビジュアルプログラミングはタイピングが少ないことを除けば、従来のプログラミングと非常に似ている。 ノードをクリックしてドラッグして情報の流れを作っても、テキストエディタでコードを書いても、アルゴリズムは同じとなる。

Making vertices

下図を用いれば、グリッド状に配置する頂点を生成することができる。

  • Vector In
  • Sclar Math (3x) notice I minimized the Multiplication Node.
  • A Number (2x)
  • Number Range (int)

y=3 に x=4 を掛け合わせて 12 となり、これが頂点の数となる。
Number Range ノードへ接続した頂点の数が [0,1...11] の範囲を決定している。

参照画像

ノードを用いたパラメトリックな構成ができたので、X と Y の頂点を設定しているノードの値を変えるとグリッドの結果が変わることも確認できるようになっている。

補足として、全てのノードの計算結果も表示した内容が下図となる。

f:id:r9aArrowhead:20201209145007p:plain

Making Polygons

ここまででグリッド状のメッシュを作成するために必要な頂点グループを作成することが可能となった。
ここからは作成した頂点グループを利用してポリゴンを作成していく。

どこからポリゴンを作成するかについては色々あると思うが、ここでは例として頂点インデックスの若い順にポリゴンを作成していくようになっている。詳細は本家の図を参照。

参照画像

ポリゴンを作成していくに辺り、いくつかの注意点が存在する。
上図の例にあるような頂点グループの場合、単純に4つの頂点をグループ化してポリゴンを作成していくというやり方は採用できない。

そうした地続きを前提としたポリゴンの生成をした場合、下図のように意図していないポリゴンが頂点インデックス [3,7,8,4] で作成されてしまう。

参照画像

上図のようなことにならないよう、ポリゴンを作成するために利用する頂点インデックスの組み合わせは下記の通り。

#    |A   B   C   D|
#    ---------------
0  = [0,  4,  5,  1]
1  = [1,  5,  6,  2]
2  = [2,  6,  7,  3]
#  = [3,  7,  8,  4] .. not a valid polygon for x=4, y=3 ここがあるとさっきのような意図しないポリゴンが発生する
3  = [4,  8,  9,  5]
4  = [5,  9,  10, 6]
5  = [6,  10, 11, 7]

組み合わせがわかれば、後はこれをマジックナンバーを用いずに作成するために数式へと置き換える必要がある。

今回のケースにおける観点は以下の通り。

  • BはAより4つ多い
  • CはBより1つ多い
  • DはAより1つ多い

A(第一成分)を基準にすると上記のような規則性を見出すことができた。後はこれをノードやプログラムで式として表現していけばいい。

Aに該当する頂点インデックスを与えると、ポリゴンの作成に必要なB, C, Dの頂点インデックスを計算する式

まずは blenderpython を用いずに数式として表現する。

A = A
B = (A + 4) # BはAより4つ多い
C = (A + 4 + 1) # CはBより1つ多い
D = (A + 1) DはAより1つ多い

# 4の部分は固定なので、固定値は別の変数にできそう

A = A
B = (A + offset)
C = (A + offset + 1)
D = (A + 1)

まずは上記パターンをプログラムとして表現する。

[A, (A + offset), (A + offset + 1), (A + 1)]

ここまででポリゴンを貼るための式は大体できたが、試作した式だけでは例の連続していない頂点インデックスの間でポリゴンが張られてしまう問題を回避できていない。

[3,7,8,4] の頂点インデックスを参照してしまう問題のこと

この問題は今回に限った話ではなく、4 * 4 などの一直線に頂点が並んでいないグリッドでれば必ず発生する。

#    |A   B   C   D|
#    ---------------
0  = [0,  4,  5,  1]   # row 1  column 1
1  = [1,  5,  6,  2]   # row 1  column 2
2  = [2,  6,  7,  3]   # row 1  column 3
#  = [3,  7,  8,  4] .. not a valid polygon for x=4, y=4
3  = [4,  8,  9,  5]   # row 2  column 1
4  = [5,  9,  10, 6]   # row 2  column 2
5  = [6,  10, 11, 7]   # row 2  column 3
#  = [7,  11, 12, 8] .. not a valid polygon for x=4, y=4
6  = [8,  12, 13, 9]   # row 3  column 1
7  = [9,  13, 14, 10]  # row 3  column 2
8  = [10, 14, 15, 11]  # row 3  column 3

A polygon Algorithm

ノードでくみ上げるとこうなるということが図示されているだけで、具体的な構築方法は記載なし。

参照画像

参照画像

私家版 A polygon Algorithm 補足

ハンズオンできなかったので、勝手に解析した手順。

f:id:r9aArrowhead:20201209145020p:plain

ここでのレッスンではグリッド状のポリゴンを作成することが目的になっているが、基本的には以下の手順でくみ上げていく。

  • 作成するグリッド状ポリゴンの頂点を作成(これはこのページで記載されているので割愛)
  • 作成した頂点から作成する面の列数と行数を計算する
  • ポリゴンを貼るための頂点インデックスの組み合わせを作成する
  • 表示する

ポリゴンの列数と行数を計算する

頂点グループは既に 3 * 4 のグリッド状に作成しているが、面のグループはまだ作成されていない。
グリッドの行列の数も改めて生成しておく必要がある。

f:id:r9aArrowhead:20201209145029p:plain f:id:r9aArrowhead:20201209145038p:plain

作成する面の列数と行数を計算する

f:id:r9aArrowhead:20201209145046p:plain f:id:r9aArrowhead:20201209145055p:plain f:id:r9aArrowhead:20201209145104p:plain

頂点インデックスの組み合わせを作成する

f:id:r9aArrowhead:20201209145113p:plain f:id:r9aArrowhead:20201209145121p:plain f:id:r9aArrowhead:20201209145127p:plain f:id:r9aArrowhead:20201209145134p:plain f:id:r9aArrowhead:20201209145143p:plain

表示する

f:id:r9aArrowhead:20201209145151p:plain