蒼水技術録

蒼水家技術録

蒼水が普段制作とか勉強とかして覚えたことを復習としてまとめてるものです。 それが最適解かどうかはわからないけど、何を目的として始めて、何が必要で、実際何をやって、どうなったか、まで全部過程を残すための技術ブログです。

Blender アドオン編 #2 -アドオン開発勉強記録 第2回-

どうも蒼水です。
前回に引き続き何も機能のないアドオンに実際に何かしらの簡単な機能を一つ追加するところまで行きます。
前回の記事はこちら
atelier-aomi.hatenablog.com

今回の目的

前回作成したアドオンの有効化/無効化のみ行えるアドオンのような何かに、実際に簡単な機能を一つ追加してみることを目的に進めていきます。
メニューからICO球をシーンに追加するアドオンで、実行結果としては以下の画像の様な感じになります。

f:id:Yui_Aomi:20200308164819p:plain
オブジェクト(メッシュ)を追加するアドオンの実行結果

BlenderAPIを利用する

Blenderにおいてアドオンを開発するうえで欠かせないのが公式で用意してくれているAPI【bpyモジュール】の利用です。
これを利用するためにこのモジュールをインポートする必要があります。
インポートは以下のように行います。

import bpy

これでAPIの利用ができるようになります。

今回はbpyモジュールしかインポートしていませんが、とりあえず今はこれだけにとどめておきます。
import方法は他にも書き方がありますがpython自体の話になってきてしまうのでそれに関しては割愛します。
気になる方は”from import” とかでググりましょう。

オペレータクラスの作成

クラス名を決める

Blender上で操作した際に実際に動作する部分を定義していきます。
クラス名には決まりがあり、以下のフォーマットに従います
【〔アドオンの名称〕_〔XX〕_〔任意の名称〕】
また、真ん中のXXの部分に関しては以下のような決まりがあり

文字 内容
OT オペレータ
MT メニュー
PT パネル
UL リスト

■例:SAMPLE_OT_SampleAddon

みたいな感じでクラス名を決めます。

クラス変数を定義する

クラスを作成したら次にクラス変数を以下の4点定義します。

クラス変数 説明
bl_idname str 内部で使用されるID。唯一の文字列。
bl_label str メニューに表示される文字列
bl_description str メニューに表示される説明文
bl_options set 処理の属性
class SAMPLE21_OT_CreateObject(bpy.types.Operator):
    bl_idname = "object.sample21_create_object"
    bl_label = "ICO Sphere"
    bl_description = "Add ICO Sphere."
    bl_options = {'REGISTER' , 'UNDO'}

bl_idnameは他とはかぶらない唯一の文字列である必要があります。
また、文字列は全て小文字である必要があり、以下のフォーマットに沿って決めます。
【〔アドオンのカテゴリ〕.〔任意の文字列〕】
なお、bl_idnameは自由に決めて良く、あくまでも唯一の文字列であれば大丈夫らしい。

メイン処理を行う関数を定義する

上記4つのクラス変数を定義したら、次にメニューなどから実行される関数(execute)をここに追加していきます。

def execute(self, context):
        bpy.ops.mesh.primitive_ico_sphere_add()
        print("Sample : Add ICO Sphere.")
        
        return {'FINISHED'}

オペレータ内で定義する関数の種類はいくつかありますが、一旦今はメイン処理となるexecute関数のみ使用します。
この中に機能を実際に追加していきますが、まずBlenderAPIに含まれている関数を使用します。
使用できる関数は下記URLに列挙されています。今回はICO球を追加しています。
docs.blender.org
引数を指定できるので大きさや位置など指定することもできますが、一旦今回はデフォルトの状態のICO球を追加するだけのアドオンになります。
printは前回もありましたが、実行時コンソールに表示される文字列となります。
戻り値、returnには4種類指定できますが今回はFINISHEDというexecuteの処理が正常に行われたことを示すものを指定します。
逆に、失敗した場合にはCANCELLEDを指定します。
他2種類は今回はいったんスルーします。

メニューを構築する関数を定義する

全項で実際の処理を定義しましたが、このままではどこから実行できるのかが定義されていません。
ので、メニューに実行するためのUIを構築する関数(menu_fn)も定義する必要があります。
そのためには、指定したメニューに登録してやる必要があります。
メニューに関するリファレンスはこのあたり。
docs.blender.org

def menu_fn(self, context):
    self.layout.separator()
    self.layout.operator(SAMPLE21_OT_CreateObject.bl_idname)

メニューUIはメンバ変数であるlayoutを使用します。
separatorではメニューの項目と項目の間に区切る線を入れるためのものです。
operatorではメイン関数であるexecuteを定義した〔クラス名.idname〕を指定します。
これによりメニューへの登録を行うことができます。
実際追加されるとこのようになります。

f:id:Yui_Aomi:20200308165722p:plain
UIに追加されている

上記で作成したクラスをまとめてBlenderに登録する。

前項までオペレータクラスの作成が完了しましたが、まだこのままではアドオンとして利用できません。
最後にアドオンとして利用できるようにregister/unregisterでBlenderに登録してやる必要があります。
前回の記事では単に文字をコンソールに表示させただけですが、今回はこの作成したオペレータクラスを登録してやらねばいけません。
作成したクラスは以下のように一旦まとめておきます。

classes = [
    SAMPLE21_OT_CreateObject,
]

今回はひとつだけしかクラスがないので1つだけですが、複数クラスを扱う場合はそれらを全てclassesにまとめておきます。

次にregister/unregisterの処理。

def register():
    for c in classes:
        bpy.utils.register_class(c)
    bpy.types.VIEW3D_MT_mesh_add.append(menu_fn)
    print("サンプル: ICO球を生成するアドオンが有効化されました。")

def unregister():
    bpy.types.VIEW3D_MT_mesh_add.remove(menu_fn)
    for c in classes:
        bpy.utils.unregister_class(c)
    print("サンプル: ICO球を生成するアドオンが無効化されました。")

まず、作成したクラスはbpy.utils.register/unregister_classに渡してやることでクラスをBlenderに登録してくれます。
変数cにクラスを格納し、それを一個一個登録していく、という部分になります。登録の解除も同様。
1点注意することは順番の問題で、
登録時にはクラスの登録→メニューへの追加
削除時にはメニューから削除→クラスの削除
の順で記述する必要がある。

次にbpy.types.VIEW3D_MT_mesh_add.append/removeという部分。
VIEW3D_MT_xxxというのは3Dビューの上部メニューにあるこれらのこと。

f:id:Yui_Aomi:20200308171312p:plain
3DVIEW_MT_xxx

ここにappend(追加)/remove(削除)するよ!っていうのがこの部分。
なお、今回はオブジェクトの追加なので追加であるmesh_addを指定している。
他にも【オブジェクト】や【選択】などにも追加することができる。

詳細は後述するが、リファレンスを開かずともどの関数が使われているのかは実は下画像の様にBlender上で確認することができる。
f:id:Yui_Aomi:20200308171800p:plain

コード全体

import bpy

bl_info = {
    "name": "サンプル:ICO球を生成するアドオン",
    "author": "Yui_Aomi",
    "version": (3, 0),
    "blender": (2, 80, 0),
    "location": "3D view Port > Add > Mash",
    "description": "ICO球を生成するサンプルアドオン",
    "warning": "",
    "support": "TESTING",
    "wiki_url": "",
    "tracker_url": "",
    "category": "Object"
}

class SAMPLE21_OT_CreateObject(bpy.types.Operator):
    bl_idname = "object.sample21_create_object"
    bl_label = "ICO Sphere"
    bl_description = "Add ICO Sphere."
    bl_options = {'REGISTER' , 'UNDO'}
    
    def execute(self, context):
        bpy.ops.mesh.primitive_ico_sphere_add()
        print("Sample : Add ICO Sphere.")
        
        return {'FINISHED'}

def menu_fn(self, context):
    self.layout.separator()
    self.layout.operator(SAMPLE21_OT_CreateObject.bl_idname)
    
classes = [
    SAMPLE21_OT_CreateObject,
]
    

def register():
    for c in classes:
        bpy.utils.register_class(c)
    bpy.types.VIEW3D_MT_mesh_add.append(menu_fn)
    print("ICO球を生成するアドオンが有効化されました。")

def unregister():
    bpy.types.VIEW3D_MT_mesh_add.remove(menu_fn)
    for c in classes:
        bpy.utils.unregister_class(c)
    print("ICO球を生成するアドオンが無効化されました。")

if __name__ == "__main__":
    register()

おまけ:Blenderで使われている関数をBlender上で確認する。

今回リファレンスも貼って確認してきたが、量が膨大故探すのが大変である。
ので、必要な機能が欲しい場合2種類確認方法がある。
1:対象箇所にマウスオーバーすると表示されるものを確認する
こちらはメニュー上での操作などを確認しやすい。
f:id:Yui_Aomi:20200308172729p:plain

2:コンソールを確認する
こちらは実際呼ばれているクラス/関数などが確認できる。
下画像で言えば今回作成したアドオンが呼ばれていることが確認できる。
f:id:Yui_Aomi:20200308174010p:plain
bpy.ops.mesh.primitive_ico_sphere_add(enter_editmode=False, location=(0,0,0,))
bpy.ops.object.sample21_create_object()
これがその部分にあたる。

bpy.ops.object.editmode_toggle()
はオブジェクトモードと編集モードの切り替え時に呼ばれている。

このようにBlender上でどの機能がどのタイミングでどの関数を呼んでいるのか、くらいはBlender上で確認することができます。

まとめ

オペレータクラス作ってメニュー関数作って1個1個登録してやると機能追加ができるらしい。
Blender上でいろいろ確認できるのとてもたすかる。ありがたや...。

次回は今回作成したオペレータクラスを複数作成し、機能の拡張と登録をやっていこうと思います。

前回
atelier-aomi.hatenablog.com

次回
atelier-aomi.hatenablog.com