所用あって Blender を触ることになったので、防備を兼ねて、作業環境の構築とメッシュ生成までの作業をメモ。
作業環境について
作業環境の構築
Blender のパースペクティブの中には Scripting (スクリプト作成) が存在する (画面上部タブ)。

Scripting タブ内には、オブジェクトエクスプローラー (樹状図)、テキストエディタ、コンソール (Python の REPL) が存在する。
最低限の環境は整っているが、テキストエディタはシンタックスハイライトはあるもののコード補完は存在せず、実際に何か作業するには心もとない。
Python のコード実行は Blender の Scripting タブで行うとして、コードの作成だけは VSCode のような使いやすい環境で行った方がよいだろう。
PIP に fake-bpy-module
というパッケージが存在する (Blender 本体のバージョンに合わせる形でバージョン管理されている)。これは bpy
(Blender Python lib) の型定義を提供しているもので、これを入れておくとエディタ上でコード補完が利くようになる。 venv などを使って分離環境内に入れてもよいが、 import bpy
したときの補完用として割り切ってグローバルインストールしてしまっても問題ないと思われる。

Blender の Python の場所
Blender に含まれる Python はシステムの Python とは異なるものを利用している (Blender は Python を内部に抱えている)。
Blender 内の Python は `{InstallDir}/{Version}/python/bin` に存在する。
また、Blender のインストールディレクトリがそのまま REPL の CWD になっている。コンピューター内にあるファイルを参照したくなった時は (あまり相対パスで参照することはないと思うが) この辺りを頭に入れておくとよい。
Blender の Python について
オブジェクトの生成と階層について
シーンコレクション内に配置するメッシュは、コレクションオブジェクトの中に置くことができる。コレクションオブジェクトは任意の深さにすることができ、ファイルシステムのディレクトリのような構造である。
オブジェクトは形を持たないものであり、実際にレンダリングされるのはオブジェクトに関連付けられたメッシュである。オブジェクトは子を持つことができる。特に、同じコレクション内にあるオブジェクトを親子関係にした場合、 Blender のアウトライナー上でもオブジェクトの親子関係として表示される (異なるコレクションに属するオブジェクトを親子関係にした場合、アウトライナー上では直接的に親子として表示されない)。
import bpy
root_collection = bpy.context.scene.collection
# 孤立したコレクションを作成し、
parent_collection = bpy.data.collections.new("ParentCollection")
# ルートコレクションにリンクする
root_collection.children.link(parent_collection)
# コレクションは複数階層にできる
child_collection = bpy.data.collections.new("ChildCollection")
parent_collection.children.link(child_collection)
# メッシュの頂点と面を定義する
mesh = bpy.data.meshes.new("CubeMesh")
parent_mesh = mesh.from_pydata(
# 頂点座標 (8頂点)
[(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0), (0, 0, 1), (1, 0, 1), (1, 1, 1), (0, 1, 1)],
# 辺を成す頂点の順番
[],
# 面を成す頂点の順番 (面に向かって反時計回りに) (6面)
[(0, 1, 2, 3), (4, 5, 6, 7), (0, 1, 5, 4), (1, 2, 6, 5), (2, 3, 7, 6), (7, 4, 0, 3)]
)
mesh.update()
# 孤立したオブジェクトを作成し、メッシュと関連付ける
parent_object = bpy.data.objects.new("ParentObject", mesh)
# オブジェクトをコレクションにリンクする
child_collection.objects.link(parent_object)
# 別のオブジェクトも同様に作成する
child_object = bpy.data.objects.new("ChildObject", mesh)
# オブジェクトの相対位置を設定
child_object.location = (2, 0, 0)
# オブジェクトをコレクションにリンクする (この時点ではオブジェクトは親子関係ではない)
child_collection.objects.link(child_object)
# オブジェクト同士の親子関係を設定する
child_object.parent = parent_object
上記のコードを実行すると、親子関係を持った以下のメッシュが生成される。

面の向きについて
Blender のメッシュの面は両側から見ることができるが、設定によって適切な方向からでないと面が見えないようにできる。エクスポートするときに困ることになるため、片面からしか見えないように設定しておくとよい。