ニッチなblender手記

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

loose read about Sverchok documents (Basic)

Basics

プログラムでメッシュやジオメトリを作成したことがある方は、このセクションは読み飛ばしても問題はない。
以下の用語の意味がわからない場合は、各項目の説明を参照。

  • List
  • Index
  • Vector
  • Vertex
  • Edge
  • Polygon
  • Normal
  • Transformation
  • Matrix

上記についてはこのページにて説明していく

Sverchokは、幾何学的実体の生成と修正のために以下の用語を使用する。

上記用語については後述する。

List

視覚的なプログラミング言語として、Sverchokはテキストベースのプログラミング言語、特にPythonから多くの用語を借用している。
Sverchokはジオメトリの保存に List を使用する。 リストに格納されたアイテムは 要素(Elements) と呼ばれます。List の各要素には、一意のシーケンシャルインデックスが割り当てられます。

Sverchokpython内で3Dビジュアライズに必要な処理やデータの運用をしているということ。インストール作業でpythonのライブラリを必須とするのはこのため。

私家版解説

blenderが内部で pythonを使っているので、 Sverchok も オブジェクトの頂点管理に pythonList を用いている。 List で管理するとはどういうことかを下図のようなシンプルな板ポリで説明する。

f:id:r9aArrowhead:20201126102818p:plain

図のコンソール画面にあるような形式でジオメトリを管理している。
Sverchok 特有のというよりは、blender によるアドオン開発や python の 仕様上そうなっているという説明。

Index

インデックスを使用すると、リストの特定の要素を素早く参照することができる。 最初の要素のインデックスは0で、最後の要素のインデックスは総要素数から1を引いた値になる。

ちなみに、一番最後を取りたい場合は -1 を指定すれば取得可能

私家版解説

これも Sverchok の解説というよりは、 pythonList の仕様の説明。

blenderでは オブジェクトの頂点は pythonList を利用して構成していることは先に記した。
ここではその List に保存されている特定の頂点だけを取得するにはどうすればよいのかを解説している。

下図のような感じで、 List のインデックスを指定すれば 特定の頂点の情報のみを取得できるこをことを示している。

f:id:r9aArrowhead:20201126102814p:plain

注意:私家版では分かりやすいように頂点を例にして示しているが、 Sverchok はもっと大きな枠を対象として説明している。 blenderでは オブジェクトやマテリアルなども List で管理されている 点には注意。

3D Geometry

Vector

ベクトル (Vector) は知っておくべき最も基本的な要素となる。
ベクトルは、多数のプロパティ(コンポーネントとも呼ばれる)を持つものとして考える。 例えば家の価格は、20以上の異なるプロパティに応じて計算されている:床面積、近所、年齢、任意のリフォーム、部屋、バスルーム、ガレージ... 要は、家はベクターのデータポイントとして見ることができる。

House_one = Vector((floor_space, neighbourhood, age, renovations, rooms, ...))

# or simply
House_one = (floor_space, neighbourhood, age, renovations, rooms, ...)

3D ジオメトリは、主にX, Y, Z, そしてWの少数のコンポーネントの集中している。 3D空間でモデルを拡大縮小したり移動したりしたことがあれば、それらの3Dポイントの位置をベクター数学で計算したことがあるはず。 3D空間の位置や点の概念は、ベクターがもつ特定の状態を説明するめに特別な名前がついているほど重要な概念となっている。 これについての詳細は後述。

ベクトルとベクトルの計算を理解することは、パラメトリックモデリングとジェネラティブデザインの不可欠な部分であり、最初に抱く印象よりも実際は簡単である。 パラメトリックモデリングやジェネラティブデザインを自分で計算する必要はないが、 Sverchok へ作成したい形となるように適切な入力を与える必要がある。 Sverchok を使う点で良いニュースは、どのようなベクター演算がどのような結果をもたらすかを理解することを、観察を通して学び、対話的に実験することで理解することができる点にある。

ベクトルを操作するための様々な方法については、後のパートで説明する。
Sverchok を使ってクールなことをしたいのであれば、時間をかけてベクターベースの数学を理解することに時間を費やす必要がある。

私家版説明

まず、 Sverchokパラメトリックモデリングを旨とするアドオンであるため、大前提として自分が望むデザインを作成したい場合は数学的知識を必要とする。

これが示すところは、数学はよくわからないけど Sverchokパラメトリックモデリングをしたいと考えることは諦めろということ。

それを理解した上で、 Vector を解説。
Vector という要素がいきなりでているが、実はこの項目自身はもっと大雑把な説明でとなっている。

実はここは一言でいうなら python の 変数の説明である。プログラムでいう変数とは何かが分かっている場合はここの説明はむしろ分かりにくいし、数学方面からすればサンプルコードで混乱を招く・・・

ここでいうベクターというのは、数学におけるベクトルとは少しニュアンスが違う。
数学のベクトルというと大体の人が想起するのはが [x=1, y=2] あるいは [x=2, y=4, z=6]のような数値の組み合わせになる。

ここで説明しているベクトルは 色んな種類の要素がいっぱい詰まった箱を Vector と呼ぶ ぐらいのニュアンス。

pythonにはそもそも 数学でいう ベクトル を扱える専用機能はない

House_one = Vector((floor_space, neighbourhood, age, renovations, rooms, ...))

# or simply
House_one = (floor_space, neighbourhood, age, renovations, rooms, ...)

上記のような例を示してくれているが、要素を見れば家の何を示しているのかいまいち見えてこないのが分かる。
家の敷地面積でもなければ、住所でもない、それどころか、floor_space と neighbourhood といった性質が異なる要素をまとめて放り込んでいる。

要は下図のように、ある一つの概念には色んな要素が含まれていることを説明したいのだろう。

f:id:r9aArrowhead:20201126102830p:plain

そして後述で、 3DCGでパラメトリックモデリングをしていく上で特定のオブジェクトを構成するのに必要な要素の説明をしていく文章となっている。

Vertex

頂点は、X,Y,Zの位置を表す3つまたは4つの値で記述された3次元空間内の点。
オプションで設定可能な4番目の値は通常は影響力や重みを表す頂点の特性を表すことができ、Wとして表現する。

最大で(X, Y, Z, W)の 4 つの次元を利用するということ

簡単なPythonの例を見てみると、これが明らかになる。
次のようにすると、3つの頂点を表現することができる。
この場合、各頂点は3つの要素を持っていることとなる。

# 各々が全く関連性を持たない、3つの頂点を表現

v0 = (1.0, 1.0, 0.0) #頂点0 (X=1.0, Y=1.0, Z=0.0)
v1 = (0.5, 0.6, 1.0) #頂点1 (X=0.5, Y=0.6, Z=1.0)
v2 = (0.0, 1.0, 0.0) #頂点2 (X=0.0, Y=1.0, Z=0.0)

オプション指定可能な W に関しては記載されていない。

Blenderのメッシュオブジェクトは、リストに格納された幾何学的なデータを含んでいる。
PythonSverchok では、空のリストは [ ] として表現する。
頂点もリストに格納され、3つの頂点を持つリストは次のようになります。

# blender では一つのメッシュオブジェクトが複数の頂点を持っている場合、下のように配列 (List) として表現する
# この場合は三角ポリゴンを表現する 3 つの頂点を持つことになる
vertices = [
    (1.0, 1.0, 0.0), #頂点0 (X=1.0, Y=1.0, Z=0.0)
    (0.5, 0.6, 1.0), #頂点1 (X=0.5, Y=0.6, Z=1.0)
    (0.0, 1.0, 0.0) #頂点2 (X=0.0, Y=1.0, Z=0.0)
]

私家版説明

cgの頂点情報をプログラム視点で見た場合の解説。

独立した頂点と、1つのメッシュオブジェクトを表現する頂点では Sverchok (= python) での扱い方が違うことを説明している。

なお、ここでは (X, Y, Z, W) があると説明しているにも関わらず W に関する説明はない。
W座標は通常の頂点情報を表現する場合は利用することがないため、ここでは解説していないのだろう。

f:id:r9aArrowhead:20201126102835p:plain

Edges

エッジは2つの頂点間の結合を形成する。
エッジはメッシュオブジェクトに関連付けられたリストにも格納する。
例えば、次の例では、空のリストにエッジを格納していることを表現している。

# 一切のエッジ情報がないメッシュオブジェクトを表現
# このオブジェクトしかビューポート上にない場合は、オブジェクトがないか、頂点しか表示されていないオブジェクトとなる
edges = []

エッジを宣言したい場合は、インデックスでエッジを形成する頂点を参照する。
以下は3つの辺を作成した例。

# 3 つの頂点(頂点0, 頂点1, 頂点2)を用いてエッジを宣言
# 注意点として、それぞれの頂点の座標 (X, Y, Z) は別のところに格納されている
# このコードだけでは 頂点0 - 2 の座標までは分からない
edges = [[0, 1], [1, 2], [2, 0]]

ここでは、リストの中のリストを使ってエッジを分離している。この方法をネスティングと呼ぶ。

私家版説明

ここは Edge が頂点同士をつなげることによってプログラム上で表現されていることを説明している。

最後の ネスティング については vertex の項の説明を引きずっているため分かりにくいが、作者的には下のようになっているんだよと説明したいのだと思う。

# 上のコードを頂点とか絡めて定義すると、以下のようになる
vertices = [
    (1.0, 1.0, 0.0), #頂点0 (X=1.0, Y=1.0, Z=0.0)
    (0.5, 0.6, 1.0), #頂点1 (X=0.5, Y=0.6, Z=1.0)
    (0.0, 1.0, 0.0) #頂点2 (X=0.0, Y=1.0, Z=0.0)
]

# 頂点0から頂点1、頂点1から頂点2、頂点2から頂点0の3つのエッジを宣言
edges = [
    [vertices [0], vertices [1]],
    [vertices [1], vertices [2]],
    [vertices [2], vertices [0]]
]

f:id:r9aArrowhead:20201126102809p:plain

プログラミング界では ネスト構造 といわれる、配列の中に配列が入れ子になっている状態のこと。

Polygons

ポリゴンはエッジと同じ規則で作成されている。 主な違いは、ポリゴンには少なくとも3つのユニークな頂点が含まれていること。
ここでは、3 つまたは 4 つの頂点から作られたポリゴンのみを扱います。

一般的に 3 つの頂点は三角ポリゴン (Tris) 、4 つの頂点なら四角ポリゴン (Quads) と呼ばれる

頂点の総数が6個、最後の頂点のインデックスが5となる頂点群から3つの頂点で構成される多角形を2つを表現するには、下記のようになる。

polygons = [[0, 1, 2], [3, 4, 5]]

Blenderモデリングしていると一つのオブジェクトにTrisとQuadsが混ざるが、Sverchokのジオメトリではそれぞれに別々のリストを作成して、最後にそれらを結合した方が便利になると思う。

最初のSverchokの例のために私たちを設定する例は、次のpyhonのコードです。

# this code can be run from Blender Text Editor and it will generate a Cube.

import bpy

# define vertecies (total : 8 verts, indeies 0 - 7)
verts = [
    ( 1.0, 1.0,-1.0),
    ( 1.0,-1.0,-1.0),
    (-1.0,-1.0,-1.0),
    (-1.0, 1.0,-1.0),
    ( 1.0, 1.0, 1.0),
    ( 1.0,-1.0, 1.0),
    (-1.0,-1.0, 1.0),
    (-1.0, 1.0, 1.0)
]

edges = []  # empty list for now.

# define Quads
# faces member in tuple must set verts index number. this is not python traditional rule only blender.
faces = [
    (0, 1, 2, 3),
    (4, 7, 6, 5),
    (0, 4, 5, 1),
    (1, 5, 6, 2),
    (2, 6, 7, 3),
    (4, 0, 3, 7)
]

mesh_data = bpy.data.meshes.new("cube_mesh_data")
mesh_data.from_pydata(verts, edges, faces)
mesh_data.update()

cube_object = bpy.data.objects.new("Cube_Object", mesh_data)

scene = bpy.context.scene
scene.objects.link(cube_object)
cube_object.select = True

上のコードからジオメトリだけを抽出すれば、残るのは以下のようなコードとなる。

v0 = (1.0, 1.0, -1.0)
v1 = (1.0, -1.0, -1.0)
v2 = (-1.0, -1.0, -1.0)
v3 = (-1.0, 1.0, -1.0)
v4 = (1.0, 1.0, 1.0)
v5 = (1.0, -1.0, 1.0)
v6 = (-1.0, -1.0, 1.0)
v7 = (-1.0, 1.0, 1.0)

vertices = [v0, v1, v2, v3, v4, v5, v6, v7]

polygons = [
    (vertices[0], vertices[1],vertices[2], vertices[3]),
    (vertices[4], vertices[7], vertices[6], vertices[5]),
    (vertices[0], vertices[4], vertices[5], vertices[1]),
    (vertices[1], vertices[5], vertices[6], vertices[2]),
    (vertices[2], vertices[6], vertices[7], vertices[3]),
    (vertices[4], vertices[0], vertices[3], vertices[7])
]

私家版解説

ここでは エッジでの説明の時と同じように、頂点データを使った ポリゴンの表現方法を解説している。

.8x以降はオブジェクトの管理方法が違うのでここで説明されているコードは実はpython 2.7xまでしか通用しない。

vlender 2.8x以降でドキュメントと同じ結果を得たい場合は、以下のコードで実行する必要がある

# this code can be run from Blender Text Editor and it will generate a Cube.

import bpy

# define vertecies (total : 8 verts, indeies 0 - 7)
verts = [
    ( 1.0, 1.0,-1.0),
    ( 1.0,-1.0,-1.0),
    (-1.0,-1.0,-1.0),
    (-1.0, 1.0,-1.0),
    ( 1.0, 1.0, 1.0),
    ( 1.0,-1.0, 1.0),
    (-1.0,-1.0, 1.0),
    (-1.0, 1.0, 1.0)
]

edges = []  # empty list for now.

# define Quads
# faces member in tuple must set verts index number. this is not python traditional rule only blender.
faces = [
    (0, 1, 2, 3),
    (4, 7, 6, 5),
    (0, 4, 5, 1),
    (1, 5, 6, 2),
    (2, 6, 7, 3),
    (4, 0, 3, 7)
]

mesh_data = bpy.data.meshes.new("cube_mesh_data")
mesh_data.from_pydata(verts, edges, faces)
mesh_data.update()

cube_object = bpy.data.objects.new("Cube_Object", mesh_data)

# after blender 2.8x, objects.link must use with bpy.context.collection
# scene = bpy.context.scene
# scene.objects.link(cube_object)
# cube_object.select = True
bpy.context.collection.objects.link(cube_object)
bpy.data.objects['Cube_Object'].select_set(True)

f:id:r9aArrowhead:20201126102824p:plain

Side Effect of Defining Polygons

頂点の連鎖がポリゴンを定義し、各ポリゴンはその境界を構成する辺 (Edge) を持っている。
ポリゴンが 4 つの頂点を持つ場合、同時に4つの辺(または辺)を持つことになる。

参考サイト

Sverchok - Basics

Dive into python - List

Dive into python JP - リスト

忘却まとめ - 【Python入門 01】コピペで覚えるぱいそん【Blender】