はじめに
blenderをpythonで操作してみたくて試してみた。
どちらも軽く入門サイト見たぐらいのレベル。
やってみた内容、嵌ったことなど記載。
ちなみに、C言語ならわかるので言語の基礎的な知識はある状態(変数に型があるとか、forで繰り返すとか)
環境
blender:2.92.0
python:3.7.7
目的
- Cubeオブジェクトを何個か追加
- 選択して動かしてみる
結果
何じゃこりゃー!! 簡単だと思ってたらはまりまくった。。
そもそもpythonの理解が足りてない。。
少しずつ学習してなんとか達成。
実施内容
前準備
blender の python 実行できるよう準備
- blenderアプリ立ち上げてScriptingタブに移動
そして、以下のpythonコード実行
前回情報クリア
前回の選択結果が残っていると毎回動き変わるので最初に初期化
選択クリア
bpy.ops.object.select_all(action='DESELECT')
Cube 追加
キューブ3個追加(Z座標マイナス、0、プラス)
x = -1
z = -1
for i in range(3):
bpy.ops.mesh.primitive_cube_add(size = 0.5, location=(x,0,z))
x = x + 1
z = z + 1
Z座標0より下にあるCube選択
for obj in bpy.data.objects:
if obj.location[2] < 0:
obj.select_set(True)
選択したCube上に移動
bpy.ops.transform.translate(value=(0,0,+5))
はまった内容 [python]
試行錯誤中に詰まった内容を記載
通常の代入とfor文の代入の違いがわからない
>>> # case1
>>> obj = bpy.data.objects
>>> print(obj)
<bpy_collection[4], BlendDataObjects>
>>> #case2
>>> for obj in bpy.data.objects:
... print(obj)
<bpy_struct, Object("Camera") ...
<bpy_struct, Object("Cube") ...
<bpy_struct, Object("Light") ...
for文で格納される変数と
代入で格納される変数の中身がなんか違う。
でも、何が違うかわからない・・・。
[理解した内容]
代入は代入元の型で格納(丸ごと格納)
for文は代入元の型の中身が格納(1個ずつ格納)
>>> words = ['a', 'i', 'u']
>>> print (words)
['a', 'i', 'u']
→ 文字列のリストが格納
>>> for w in words:
... print(w)
a
i
u
→ 文字列が格納
なるほど。そりゃそうか。
forの特性上、リストの中身が入らないと困るのか。
for文の動きがイメージできない
サンプルで以下のようなコードを見たが、どう動くか不明。
name_list = [obj.name for obj in bpy.context.selected_objects]
これ何? forの前に何かあるけどこれなんで動くの?
以下に説明あり
https://docs.python.org/ja/3.7/tutorial/datastructures.html
5.1.3. リストの内包表記
[自分の学習結果]
for文
- for文は
__iter__メソッドを持つものであれば型関係なく繰り返すだけ - 終端(StopIteration)か返ってきたら終了
リスト型
- 生成するには以下の方法がある
リスト表現:list_a = [1,2,3]
リスト内包表現: list_a = [x * 2 for x in range(5)]
※ if文やforの入れ子も可能
[まとめ]
-
リストを簡単に作成する方法としてfor文が使えるよというだけ(for文のルールとは関係ない)
-
詳しく知りたい場合はリストの説明を確認
(for文の説明ページには出てこないので注意)
はまった内容 [blender]
select_set(True)って何のAPI?
>>> type(bpy.data.objects['Cube'])
<class 'bpy_types.Object'>
ってあるから、このクラスの関数かと思い
APIマニュアルでbpy_types.Objectを検索したがヒット数0件。
bpy.types.Objectで検索したら出てきた。
マニュアルが対応してないだけ?
とりあえず探す方法わかったので様子見。
追加したCubeってどこに登録された?
Cube追加できたけど、内部で何が起きてる?
内部のデータ構造はどうなってる?
追加できたけど内部が全然イメージできない。調べてみる。
[自分の理解]
Blenderのデータ構造は大きく分けて3段階(CameraやLightは今は使わないので保留)
シーン(Scene Collection)
-> シーン(Collection)
-> オブジェクト(Cube.001)
-> メッシュ(Cube.002)
以下の図参照

メッシュを削除するとオブジェクトも消えた。
オブジェクト削除してもコレクションは消えない。
シーン(Collection)削除してもオブジェクト消えない。
最上位のシーン(Scene Collection)は削除できない
シーン:
グループや箱みたいなもの。
なので中身が無くてもよい。でも絶対1個は必要なのでマスター(Scene Collection)が存在。これは消せない。
オブジェクト/メッシュ:
物体を示すもの。
どちらかが欠けても存在できないのでどちらも重要(セットで存在。片方だけ削除は不可。)
ただし優先度が高いのはメッシュ。
登録するときはメッシュが先にないとオブジェクト登録できない。
(物体はまず実在しその後に名前がつけられるイメージ。
実態ないと描画できないしいろいろ困るからかな。)
使用するAPIのイメージがわかない
# Cube作成
bpy.ops.mesh.primitive_cube_add(size = 0.5, location=(0,0,0))
# 選択
bpy.data.objects['Cube'].select_set(True)
# 移動(編集)
bpy.ops.transform.translate(value=(0,0,+5))
使用するAPIに統一感がない。
イメージ的には bpy.data 関連のAPIを使うイメージだが選択以外は使わない?
bpy.data関連のAPIでも同様のことができた。
# 登録(※Layout画面には表示されない)
me = bpy.data.meshes.new("sampleCube")
ob = bpy.data.objects.new("sampleCube", me)
bpy.data.collections["Collection"].objects.link(ob)
# 移動
bpy.data.objects['sampleCube'].location = [0, 0, -5]
登録のやり方はは何種類かあり、
bpy.ops系はこれらを簡略化してくれていると理解。
Cube登録できたが、画面に表示されない(Modeling画面で移動や回転などはできる)
たぶんまだ設定が足りないのだろう。
ここまで細かい設定まだしないので様子見。
ちなみに、bpy.ops系で操作すると遅いとの情報も見かけたのでできればdata系で操作していきたい。
2021/07/01追加
以下で表示されるようになった。メッシュの中身が無いから画面に表示されない模様。
bm = bmesh.new()
bmesh.ops.create_cube(bm)
me = bpy.data.meshes.new('sampleCube')
bm.to_mesh(me)
bm.free()
ob = bpy.data.objects.new("sampleCube", me)
bpy.data.collections["Collection"].objects.link(ob)
※bmesh.ops.create_cube()の代用方法はまだ不明
はまった内容 [VSCode]
VSCodeだと移動ができないことあり
VSCode上で以下をコーディング
Cube追加
Cube選択
Cube移動
まとめて記載して実行するも移動だけ動かないい。
Cube追加のコード消して再実行すると移動してくれる。なぜ?
blenderのScriptタブで直接書いて実行すると動くのでコードの問題ではなく、アプリ間の問題の模様。
→ 原因不明。
コンソールに「Info: Deleted 0 object(s)」とあるので削除自体は実行している。
対象の選択がうまくできいないのか、消すデータがまだ準備できてないのか。。
個別で実行すると動くため準備がまだの方だと思うが、Sleep入れても代わらない。。
今の知識だとわからないのでしばらく放置する。
削除もできないことあり
Cube追加
Cube選択
Cube削除(bpy.ops.object.delete)
こちらも理由不明。
以下の方法で削除できたがこれが正しい手順化は不明。
for col in bpy.data.collections:
for item in col.objects:
col.objects.unlink(item)
bpy.data.objects.remove(item)
blenderのScriptタブでしばらく学習することにしたので様子見。

コメント