blender&python奮闘1_オブジェクト追加して操作してみる

はじめに

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タブでしばらく学習することにしたので様子見。

コメント

タイトルとURLをコピーしました