ニッチなblender手記

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

loose read about Sverchok documents (Introduction Unit 02)

Lesson 02 - A Circle

概要

このレッスンでは、以下のノードを利用して円を作成する。

  • List Length
  • List Shift
  • List Zip
  • Formula
  • Lesson 01で既に利用しているノードたち

A Circle

最も手っ取り早い方法は、 blender 標準の circle オブジェクトやカーブを用いる方法がある。
次に簡単な方法は、 Sverchok が標準で提供している Circle Generator ノードを用いること。

ここでは、上記を用いずに正方形メッシュを作成した時と同じように頂点位置の計算や設定を全てノードを使って生成する方法で説明している。

Dynamic Polygons

正方形を作成した時のようにすれば頂点さえ作成できればポリゴンを生成することができる。
しかし、頂点数が増えると頂点の管理やインデックスの把握が困難になるので、複雑な頂点情報は変更が発生した時の修正をある程度自動化しなければならない。

Sverchok では UV Connect ノードというものがそれに該当するが、本チュートリアルではこのノードも未使用ということになっている。

利用しない理由は、基本的なノードの使い方やVisual Programmingでの位置づけを学ぶために頂点やインデックスの生成を自分で構築させるのも本チュートリアルで目指しているとのこと。

Generating an index list for the polygon

自動的に頂点のリストを作成するためには、処理の瞬間に何個の頂点があるのかを知る必要がある。
List Length を使うと、リストがネストしていてもネストの深さに合わせた閲覧ができる。

Add -> List Main -> List Length

ここからは [0,1,2,...n]のようなシーケンス(リスト)を生成していく。Pythonとして書く場合には以下のようなコードになる。

n = 4
range(start=0, end=n, step=1)
>> [0, 1, 2, 3]

まずは Lesson.1 で頂点インデックスを手動で指定していたが、ここを Number Range ノードだけで処理していくようにする。

f:id:r9aArrowhead:20201203142150p:plain f:id:r9aArrowhead:20201203142157p:plain

ここまでのノード画面を見ると、 List Lengthn=4 に相当する出力を作成したことが分かる。
n=4 に該当するノードができたのであれば、次は range(start=0, end=n, step=1) に相当するノードが必要となる。 そのためのノードが Number Range ということになる。

Add -> Numbers -> Number Range

List Length -> Number Range とする。

f:id:r9aArrowhead:20201203142207p:plain

Number Rangestep モードは pythonrange とほぼ同じ名前のソケットがあるので、画面のように range(start=0, end=n, step=1) 対応するような設定をすれば、 [0, 1, 2, 3] という結果が得られた。

ここまでの処理で頂点インデックスを自動生成するところまでは実現できたが、このインデックスをそのまま Viewer Draw へ接続してもポリゴンは生成してくれない。
その理由は、 Number Range の出力結果がblender がポリゴンとして認識できる形となっていないためである。
この問題を修正するために、 Add -> Numbers -> Fomula ノードを追加してデータの形を修正する。

f:id:r9aArrowhead:20201203142214p:plain f:id:r9aArrowhead:20201203142222p:plain f:id:r9aArrowhead:20201203142229p:plain f:id:r9aArrowhead:20201203142236p:plain

Number RangeFomula を経由する前と後のデータの形と、 正方形ポリゴンを出力するために利用している Simple Topology の出力しているデータの形を比較すると、違いが分かりやすい。

ここまでできれば頂点インデックスの形が正方形ポリゴンの出力に使っているものと同じになるので、 Viewer Draw に接続すればポリゴンを生成してくれるようになる。

f:id:r9aArrowhead:20201203142244p:plain

Generating the set of circular verts

ここではあくまで円形のポリゴンを作成することが目的なので、いよいよ頂点データを円形のものへと差し替えていく。
今使っている頂点データは正方形を描画するために Number Range を使って生成したものとなっている。
円形(のように見えるポリゴン)の場合は正方形よりも多くの頂点データが必要となるので、 ノードの先頭にある Number Range の設定を変更して 円形になるように単位円辺りのポリゴンの数を増やせばいい。

f:id:r9aArrowhead:20201203142252p:plain

Forcing an even spread of Vertices

頂点インデックスをノードだけで生成できるようになったので、今度は頂点の数を指定すれば円に必要な頂点もノードだけで計算してくれるようにする。

今は Number Range を使って頂点の数がどれだけ必要かを考えてから円を作っている状態。

そのためには、 一番最初に作成した Number RangeStep で指定している数値を計算で算出する必要がある。
頂点の数に合わせた円周上の頂点の間隔を計算するには、以下のような式となる。

step_distance = 2.0 / n # n は円を表現するために利用する頂点の数

まずは step_distance = 2.0 / n の式を表現するノードを追加する。

Add -> Numbers -> Scalar Math

f:id:r9aArrowhead:20201203142300p:plain f:id:r9aArrowhead:20201203142308p:plain

次に、利用する頂点の数を表現するノードを追加する。

'Add -> Numbers -> A Number'

f:id:r9aArrowhead:20201203142315p:plain

後は n を表現する Numberstep_disance を算出するための Scalar Math を接続すれば計算は完了。
Scalar MathNumber Range -> Step へとつなげば、直接ステップ数を指定しないで円を表現できるようになる。

f:id:r9aArrowhead:20201203142322p:plain

円はできたが、元々表示していた円よりも頂点の数が多いという現象が発生している。
これは Number Range で設定している StopStep へ接続した 計算結果によるもの。
Step = 0.1 となっている状態なので Start (=0.0) から Stop (=2.0) まで 0.1刻みで数値を生成している 状態となっている。

接続する前は Step = 2.0 だった

ただし、単純に Stop = 1.0 にして出力される値の数を半減させると下図のようになる。

f:id:r9aArrowhead:20201203142330p:plain

この解決方法として、 Sverchok のドキュメントでは tau (タウ) による計算へと切り替えていた。

f:id:r9aArrowhead:20201203142339p:plain f:id:r9aArrowhead:20201203142346p:plain

別解。

f:id:r9aArrowhead:20201203142353p:plain

Polygon was easy, what about Edges?

ここまでで円形のポリゴンを作成してきたが、ここからは円形のエッジを作成していく。

円形の頂点を用いてエッジを生成する場合、エッジの生成に必要な頂点インデックスの指定方法は以下のようになる。

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

# n個の頂点を用いた円形のエッジを生成するために必要なインデックスはこんな感じ
[[0,1],[1,2],...,[n-1,n],[n,0]]

# 上記のリストを n 個の頂点が収まったリストだけで頂点インデックスを生成する場合は、for文を使えばよい
n = 5
for i in range(n):
    print(i, (i+1) % n)

>>> 0 1
>>> 1 2
>>> 2 3
>>> 3 4
>>> 4 0

# 頂点インデックスを sverchok がエッジの組み合わせと認識できるような形へ整形する必要がある
n = 5
edges = [[i, (i+1) % n] for i in range(n)]
print(edges)

>>> [[0, 1], [1, 2], [2, 3], [3, 4], [4, 0]]

# 上の頂点インデックスの組み合わせを見ると、基本的に 元の配列と中身が1つズレている配列の組み合わせということが分かる
# そのため、pythonのzipメソッドを用いれば、for文を簡略化できる

indices                = [0, 1, 2, 3, 4]
indices_shifted_by_one = [1, 2, 3, 4, 0] # indicesの中身を1つずらした

for a, b in zip(indices, indices_shifted_by_one):
    print([a, b])

>>> [0, 1]
>>> [1, 2]
>>> [2, 3]
>>> [3, 4]
>>> [4, 0]

pythonを知らなければ上の式は意味不明に見えるが、 for a, b in zip(indices, indices_shifted_by_one): の部分を Sverchook で表現しようということになる。

難しいこと言っているように見えるが、今回のケースに限っては Sverchok にそのまんまのノードがあるためそれらを利用する。
利用するのは以下の2つのノード。

add -> List Struct -> List Shift

add -> List Main -> List Zip

f:id:r9aArrowhead:20201203142401p:plain f:id:r9aArrowhead:20201203142408p:plain f:id:r9aArrowhead:20201203142415p:plain f:id:r9aArrowhead:20201203142423p:plain f:id:r9aArrowhead:20201203142431p:plain f:id:r9aArrowhead:20201203142440p:plain f:id:r9aArrowhead:20201203142449p:plain f:id:r9aArrowhead:20201203142455p:plain

参考

Sverchok - Lesson 02 - A Circle