MRが楽しい

MRやVRについて学習したことを書き残す

Blender 2.8のPython APIドキュメントを少しずつ読み解く リファレンスAPIの使用法 その4

本日は Blender2.8 の調査枠です。
今回から Blender 2.8 の Python API ドキュメントを少しずつ読みつつ試していきます。

Blender 2.8 Python API Documentation

以下のページを日本語訳しつつ実際に試して記事を進めていきます。
docs.blender.org
docs.blender.org

今日は「ReferenceAPIの使用法」の演算子についてです。
f:id:bluebirdofoz:20190926093203j:plain

演算子

Blenderのほとんどのキーストロークとボタンは bpy.ops を介してPythonで利用可能な演算子を呼び出します

Pythonの同等物を表示するには、マウスをボタンの上に置いてツールチップを表示します。(Python: bpy.ops.render.render()など)
例えば、ツールチップがない場合や行が見つからない場合、このボタンは演算子を使用しておらず、Pythonからアクセスできません。(Python:など)

これをスクリプトで使用する場合、マウスがボタンの上にあるときに[Ctrl+C キー]を押すと、クリップボードにコピーできます。
f:id:bluebirdofoz:20190926093230j:plain

ボタンを右クリックしてOnline Python Referenceを表示することもできます。
これは主に引数とそのデフォルトを表示します。
Pythonで記述された演算子はファイルと行番号を表示するため、ソースコードを確認する場合に役立ちます
f:id:bluebirdofoz:20190926093242j:plain

すべての演算子Pythonから便利に呼び出すことができるわけではありません。
詳細については、using演算子を参照してください。
docs.blender.org

情報ビュー

Blenderは実行した演算子を記録し、Infoスペースに表示します。
これはBlender2.8においては[Scripting]ワークスペースで確認可能です。
f:id:bluebirdofoz:20190926093305j:plain

Blenderにデフォルトで付属しているスクリプト画面を選択して、出力を確認します。
いくつかのアクションを実行して、それらが表示されるのを見ることができます。
例えば、頂点を削除した結果は以下の通りです。
f:id:bluebirdofoz:20190926093315j:plain

すべてのオペレーターが表示用に登録されるわけではありません。
例えば、ビューのズームは繰り返すのにそれほど有用ではないため、出力から除外されます。

実行するすべてのオペレーターを表示するには、「すべてのオペレーターを表示」を参照してください
docs.blender.org

Blender 2.8のPython APIドキュメントを少しずつ読み解く リファレンスAPIの使用法 その3

本日は Blender2.8 の調査枠です。
今回から Blender 2.8 の Python API ドキュメントを少しずつ読みつつ試していきます。

Blender 2.8 Python API Documentation

以下のページを日本語訳しつつ実際に試して記事を進めていきます。
docs.blender.org
docs.blender.org

今日は「ReferenceAPIの使用法」の間接データアクセスです。
f:id:bluebirdofoz:20190925090618j:plain

間接データアクセス

この例では、より複雑なものを調べて、アクティブなスカルプトブラシテクスチャにアクセスする手順を示します。
例えば、Pythonを介してブラシのテクスチャにアクセスして、contrast (コントラスト)を調整する場合を考えてみましょう。

1.デフォルトのシーンで開始し、[3Dビュー]のヘッダーから「スカルプト」モードを有効にします。
f:id:bluebirdofoz:20190925090630j:plain
2.プロパティウィンドウから[テクスチャ]タブを開き、[新規]ボタンで新しいテクスチャを追加します。
f:id:bluebirdofoz:20190925090639j:plain
3.[画像]パネルの[開く]ボタンからテクスチャを読み込みます。
f:id:bluebirdofoz:20190925090648j:plain
4.[色]パネルを展開して、[コントラスト]ボタンを見つけます。
f:id:bluebirdofoz:20190925090659j:plain
5.[コントラスト]ボタンを右クリックし、オンラインPythonリファレンスを選択します。
これは bpy.types.Texture.contrast に移動します。
f:id:bluebirdofoz:20190925090713j:plain
6.contrast がテクスチャのプロパティであることがわかります。
次に、ブラシからテクスチャにアクセスする方法を確認します。
f:id:bluebirdofoz:20190925090723j:plain
7.bpy.types.Texture.contrast のページの下部にある参照を確認してください。
多くの参照が存在する場合があり、適切な参照を見つけるために推測作業が必要になる場合があります。
この場合は Brush.texture です。これでテクスチャにアクセスできることがわかりました。
通常は bpy.data.brushes["BrushName"].texture の名前でアクセスしたくないので、アクティブなブラシにアクセスします。
f:id:bluebirdofoz:20190925090749j:plain
8.次のステップは、 Brush.texture リファレンスを介してブラシにアクセスする場所を確認することです。
この場合、必要なものは bpy.context.brush だけです。
f:id:bluebirdofoz:20190925090732j:plain
※ Blender2.8 では bpy.context.brush がアクセスできないため、bpy.context.tool_settings.sculpt.brush を使用します。

これで、ブラシテクスチャのコントラストにアクセスするために必要なネストされたプロパティを形成できるようになりました。

Context -> Brush -> Texture -> Contrast

Pythonコンソールでデータパスを作成できます。

bpy.context.tool_settings.sculpt.brush.texture.contrast

f:id:bluebirdofoz:20190925090811j:plain

または、ブラシに直接アクセスする方法を以下に示します。

bpy.data.brushes["SculptDraw"].texture.contrast

"SculptDraw"の部分は使用中のブラシ名に合わせて変更します。
f:id:bluebirdofoz:20190925090820j:plain

ユーザーツールを作成している場合、通常、ユーザーが選択したものに基づいてツールを操作することを期待するため、bpy.context を使用します。
自動化の場合、ユーザーが現在設定しているビューに関係なく、特定のデータにアクセスして操作できるようにするため、bpy.data を使用する可能性が高くなります。
bluebirdofoz.hatenablog.com

Blender 2.8のPython APIドキュメントを少しずつ読み解く リファレンスAPIの使用法 その2

本日は Blender2.8 の調査枠です。
今回から Blender 2.8 の Python API ドキュメントを少しずつ読みつつ試していきます。

Blender 2.8 Python API Documentation

以下のページを日本語訳しつつ実際に試して記事を進めていきます。
docs.blender.org
docs.blender.org

今日は「ReferenceAPIの使用法」のデータパスのコピーまでです。
f:id:bluebirdofoz:20190924091454j:plain

ネストされたプロパティ

前の例は、コンテキストから直接アクセスできるObjectのlocationプロパティであるため、非常に簡単です。
より複雑な例を次に示します。

# access a render layers samples
bpy.context.scene.render.layers["RenderLayer"].samples
# Blender2.8では以下を使用する
bpy.context.scene.view_layers["View Layer"].samples

# access to the current weight paint brush size
bpy.context.tool_settings.weight_paint.brush.size

# check if the window is fullscreen
bpy.context.window.screen.show_fullscreen

f:id:bluebirdofoz:20190924091503j:plain

ご覧のとおり、ネストされたデータにアクセスしたい場合があります。

プロパティは、データが内部的に(ブレンダーCコードで)格納される方法と一致するように調整されています。
このため、学習には時間がかかります。Blenderでデータがどのように組み合わされるかを理解するのに役立ちます。
これは、スクリプトを記述する際に重要です。

スクリプティングを開始すると、必要なデータにアクセスする方法がわからないという問題に遭遇することがよくあります。
この問題の解決にはいくつかの方法があります。

Pythonコンソールのオートコンプリート(Ctrl + Spaceキー)を使用して、プロパティを検査します。
 これはプロパティの値を簡単に確認して、結果をインタラクティブに割り当てることができるという利点があります。
f:id:bluebirdofoz:20190924091514j:plain
ユーザーインターフェイスからData-Pathをコピーします。
docs.blender.org
・ドキュメントを使用してリファレンスをフォローする。以下で更に説明します。
docs.blender.org

データパスのコピー

Blenderは、Python: ... 以下のツールチップに表示されるプロパティへのPython文字列を計算できます。
これにより、API参照を使用してデータにアクセスする場所を見つける必要がなくなります。

IDデータブロックからそのプロパティにパスを与えるデータパスをコピーするユーザーインターフェイス機能があります。
機能を確認するため、Subdivision-Surfaceモディファイアのサブディビジョン設定へのパスを取得してみます。

デフォルトのシーンを起動し、Modifiersタブから、Subdivision-Surfaceモディファイアをキューブに追加します。
f:id:bluebirdofoz:20190924091559j:plain

次に、[ビューポート]ボタンの上にマウスを移動します。
ツールチップには bpy.types.SubsurfModifier.levels が表示されます。
オブジェクトからこのプロパティへのパスが必要です。
f:id:bluebirdofoz:20190924091608j:plain

ツールチップのテキストには bpy.data.collection["name"]. コンポーネントが含まれないことに注意してください。
全てのアクセスでコレクションの調査を行わないと想定しているためです。
通常、各 bpy.types.ID インスタンスには名前でアクセスするのではなく、コンテキストを使用します。

PythonコンソールにIDパス bpy.context.active_object を入力します
次に、ボタンを右クリックして[データパスのコピー]を選択し、結果をコンソールに貼り付けます。
f:id:bluebirdofoz:20190924091621j:plain

modifiers["Subdivision"].levels

結果、コンソールには以下のようなテキストが作成されます。

bpy.context.active_object.modifiers["Subdivision"].levels

Enterキーを押すと、現在の値1が取得されます。
f:id:bluebirdofoz:20190924091632j:plain

次に、値を2に変更してみます。

bpy.context.active_object.modifiers["Subdivision"].levels = 2

値の更新は、Subdivision-SurfaceモディファイアのUIで確認できます。
f:id:bluebirdofoz:20190924091641j:plain

bluebirdofoz.hatenablog.com

Blender 2.8のPython APIドキュメントを少しずつ読み解く リファレンスAPIの使用法 その1

本日は Blender2.8 の調査枠です。
Blender 2.8 の Python API ドキュメントを少しずつ読みつつ試していきます。

Blender 2.8 Python API Documentation

以下のページを日本語訳しつつ実際に試して記事を進めていきます。
docs.blender.org
docs.blender.org

今日は「リファレンスAPIの使用法」のシンプルなデータアクセスまでです。
f:id:bluebirdofoz:20190923160814j:plain

リファレンスAPIの使用法

Blenderにはスクリプトを記述するために必要な情報を含む、自動生成されたReferenceAPIを備えた相互リンクデータ型があります。
このドキュメントはリファレンスAPIの使用方法を理解できるように設計されています。

リファレンスAPIスコープ

リファレンスAPIは bpy.types をカバーします。
bpy.types は bpy.context(ユーザコンテキスト) または bpy.data(Blenderデータ) にアクセスする型を保存します。

bmesh や aud などの他のモジュールはBlenderのデータAPIを使用していません。
このため、本ドキュメントはそれらのモジュールには適用されません。

データアクセス

リファレンスAPIを使用する最も一般的なケースは、Blender内のデータにアクセスする方法を見つけることです。
最初にBlenderのIDデータブロックに注意すべきです。何故なら、それらに関連するプロパティがよく見つかるためです。

IDデータ

IDデータブロックはBlenderでトップレベルのデータコンテナとして使用されます。
UIからはそれほど目立ちませんが、開発時にはIDデータブロックについて知る必要があります。

IDデータタイプは以下を含みます。
・シーン
・グループ
・オブジェクト
・メッシュ
・スクリーン
・ワールド
・アーマチュア
・画像
・テクスチャ

完全なリストについては bpy.types.ID を参照して下さい。
docs.blender.org
f:id:bluebirdofoz:20190923160843j:plain

IDデータブロックが共有する特性を以下に示します。

・IDは blend ファイルデータのため、新しい blend ファイルをロードすると、データブロックのセット全体がリロードされます。
・IDは、Pythonの bpy.data.* 以下からアクセスできます。
・各データブロックには .name、インターフェイスに表示される一意の属性があります。
・アニメーションデータは .animation_data に保存されます。
・IDは、blend ファイル間でリンクできる唯一のデータ型です。
・IDはPythonで追加/コピーおよび削除できます。
・IDには、保存時に未使用のIDを解放する独自のガベージコレクションシステムがあります。
・データブロックに外部データへの参照がある場合、これはIDデータブロックです。

シンプルなデータアクセス

シンプルなケースから始めます。
オブジェクトのポジションを調整するためのpythonスクリプトが必要だとします。

UIでこの設定を見つけることから始めます

Properties Window -> Object -> Transform -> Location

f:id:bluebirdofoz:20190926094136j:plain

右クリックして[Blender PythonAPI リファレンス]を選択すると、次のリンクが表示されます
docs.blender.org
f:id:bluebirdofoz:20190926093848j:plain

もし[Blender PythonAPI リファレンス]が表示されない場合は以下の手順に沿って表示設定を行います。
bluebirdofoz.hatenablog.com

リファレンスAPIのリンクは多くの場合、ツールヒントよりも多くの情報を提供します。
更に一部のページには使用例が含まれています。
f:id:bluebirdofoz:20190923161036j:plain

この時点で .location を使用する必要があり、3つのfloatの配列であることが分かります。
しかし、スクリプトでこれにアクセスする方法についてはまだ分かりません。

次のステップは、オブジェクトにアクセスする場所を見つけることです。
ページの一番下にある参照(References)セクションに移動します。
オブジェクトには多くの参照があります。
f:id:bluebirdofoz:20190923161046j:plain

モディファイヤ、関数、テクスチャ、および制約など、非常に多くの場所で参照されていることが分かります。
ただし、ユーザーが選択したデータにアクセスする場合、通常は bpy.context 参照を確認するだけです。

今回の場合、bpy.context だけでもかなりの数があります。
ただし、ほとんどはモード固有です。
例えば、ウェイトペイントモードでのみ実行するツールの場合は bpy.context.weight_paint_object を使用するのが適切です。

ユーザーが最後に選択したアイテムにアクセスするには、active メンバーを探します。
Blenderの規則として、ユーザーが選択する単一のアクティブなメンバーにアクセスできます。
active_bone、 active_pose_bone、active_node...などです。
今回のケースでは active_object を使用できます。
f:id:bluebirdofoz:20190923161056j:plain

これで、アクティブなオブジェクトのポジションを見つけるのに十分な情報が得られました。
以下のコードでアクセス可能です。

bpy.context.active_object.location

これをpythonコンソールに入力して、結果を確認できます。
f:id:bluebirdofoz:20190923161110j:plain

参照内のオブジェクトにアクセスするため、他には bpy.types.BlendData.objects を利用できます。
なお bpy.data.objects は参照のリストに含まれていません。
bpy.data は bpy.types.BlendData クラスのインスタンスであるためです。

bpy.data.objects はオブジェクトのコレクションであるため、そのメンバーの1つにアクセスする必要があります。

bpy.data.objects["Cube"].location

f:id:bluebirdofoz:20190923161119j:plain

bluebirdofoz.hatenablog.com

Blender 2.8のPython APIドキュメントを少しずつ読み解く Python APIの概要 その3

本日は Blender2.8 の調査枠です。
Blender 2.8 の Python API ドキュメントを少しずつ読みつつ試していきます。

Blender 2.8 Python API Documentation

以下のページを日本語訳しつつ実際に試しつつ記事を進めていきます。
docs.blender.org
docs.blender.org

今日は「Python APIの概要」の登録に関してです。
f:id:bluebirdofoz:20190922220841j:plain

登録

モジュール登録

起動時にロードされるBlenderモジュールにはregister()関数と、unregister()関数が必要です。
これらは、Blenderがコードから呼び出す唯一の関数です。それ以外は通常のPythonモジュールです。

シンプルなBlender / Pythonモジュールは以下のようになります。

import bpy

class SimpleOperator(bpy.types.Operator):
    """ See example above """

def register():
    bpy.utils.register_class(SimpleOperator)

def unregister():
    bpy.utils.unregister_class(SimpleOperator)

if __name__ == "__main__":
    register()

これらの関数は通常、スクリプトで実行され、メニュー項目が追加される場合があります。
また、独自のツールのデータを設定する内部目的で使用することもできます。
しかし新しいブレンドファイルがロードされたときにはスクリプトが再実行されないため注意してください。

登録/登録解除の呼び出しが使用できるため、Blenderの実行中にアドオンを切り替えてスクリプトを再ロードすることができます。
登録呼び出しがスクリプトの本文に配置された場合、登録時にインポートが呼び出されます。
つまり、モジュールのインポートとそのクラスのBlenderへのロードが同時に行われます。

これは、スクリプトが別のモジュールからクラスをインポートするときに問題になります。
どのクラスがいつロードされるかを管理するのが難しくなります。

一例の最後の2行はテスト用です。

if __name__ == "__main__":
    register()

これにより、スクリプトテキストエディターで直接実行して、変更をテストできます。
このregister()呼び出しは、スクリプトがモジュールとしてインポートされた場合、実行されません。
f:id:bluebirdofoz:20190922220923j:plain

クラス登録

クラスをBlenderに登録すると、クラス定義がBlenderにロードされ、既存の機能とともに使用できるようになります。
このクラスがロードされると、クラスの元の名前ではなく bl_idname を使用して bpy.types からアクセスできます。

クラスをロードするとき、以下のチェックを実行します。
・すべての必要なプロパティと関数が見つかること
・プロパティが正しい型を持っていること
・関数が正しい数の引数を持っていること

クラス定義に問題がある場合は、登録時に発生します。以下に例を示します。

def execute(self, context, spam) のような関数の引数を使用すると、以下の例外が発生します

ValueError: expected Operator, SimpleOperator class "execute" function to have 2 args, found 3

f:id:bluebirdofoz:20190922220944j:plain

bl_idname = 1 を使用すると以下の例外が発生します。

TypeError: validating class error: Operator.bl_idname expected a string type, not int

f:id:bluebirdofoz:20190922221007j:plain

複数クラス

※ Blender2.8では本章で紹介する register_module は削除されている。
  代わりに bpy.utils.register_classes_factory を利用する。
wiki.blender.org

クラスをBlenderにロードする方法は、単純なケースでは bpy.utils.register_class を呼び出すだけで十分です。
しかし、クラスが多い場合やパッケージサブモジュールに独自のクラスがある場合は、全てを登録するのは面倒です。

より便利なロード/アンロードのために、以下の関数が存在します。
・bpy.utils.register_module(モジュール)
・bpy.utils.unregister_module(モジュール)

独自の演算子、パネルメニューなどの多くを定義するスクリプトは、次のように記述するだけです。

def register():
    bpy.utils.register_module(__name__)

def unregister():
    bpy.utils.unregister_module(__name__)

内部的にBlenderは、登録可能なタイプのサブクラスを収集ます。
それらが定義されているモジュール毎にサブクラスを保存します。
モジュール名を bpy.utils.register_module に渡すことで、このモジュールとそのサブモジュールによって作成されたすべてのクラスを登録できます。

クラス間の依存関係

Blenderをカスタマイズする場合、独自の設定をグループ化する必要がある場合があります。
他のスクリプトと共存する必要があるためです。
これらのプロパティクラスをグループ化するには、グループ内のグループまたはグループ内のコレクションに対して、登録/登録解除の順序に気を付ける必要があります。

カスタムプロパティグループは、それ自体が登録が必要なクラスです。
カスタムエンジンのマテリアル設定を保存する例を以下に示します。

# Create new property
# bpy.data.materials[0].my_custom_props.my_float
import bpy

class MyMaterialProps(bpy.types.PropertyGroup):
    my_float = bpy.props.FloatProperty()

def register():
    bpy.utils.register_class(MyMaterialProps)
    bpy.types.Material.my_custom_props = bpy.props.PointerProperty(type=MyMaterialProps)

def unregister():
    del bpy.types.Material.my_custom_props
    bpy.utils.unregister_class(MyMaterialProps)

if __name__ == "__main__":
    register()

f:id:bluebirdofoz:20190922221052j:plain

クラスは、プロパティで使用する前に登録する必要があります。登録しないと、エラーが発生します。

ValueError: bpy_struct "Material" registration error: my_custom_props could not register
# Create new property group with a sub property
# bpy.data.materials[0].my_custom_props.sub_group.my_float
import bpy

class MyMaterialSubProps(bpy.types.PropertyGroup):
    my_float = bpy.props.FloatProperty()

class MyMaterialGroupProps(bpy.types.PropertyGroup):
    sub_group = bpy.props.PointerProperty(type=MyMaterialSubProps)

def register():
    bpy.utils.register_class(MyMaterialSubProps)
    bpy.utils.register_class(MyMaterialGroupProps)
    bpy.types.Material.my_custom_props = bpy.props.PointerProperty(type=MyMaterialGroupProps)

def unregister():
    del bpy.types.Material.my_custom_props
    bpy.utils.unregister_class(MyMaterialGroupProps)
    bpy.utils.unregister_class(MyMaterialSubProps)

if __name__ == "__main__":
    register()

最も低いクラスを最初に登録する必要があります。登録解除はその逆です。
f:id:bluebirdofoz:20190922221121j:plain

クラスの操作

プロパティは、Blenderの実行中に追加および削除できます。
通常、登録または登録解除で行いますが、特別な場合には、スクリプトの実行中にタイプを変更すると便利な場合があります。

以下に例を示します。

# add a new property to an existing type
bpy.types.Object.my_float = bpy.props.FloatProperty()
# remove
del bpy.types.Object.my_float

f:id:bluebirdofoz:20190922221736j:plain

自分で定義したPropertyGroupサブクラスに対しても同様に機能します。

class MyPropGroup(bpy.types.PropertyGroup):
    pass
MyPropGroup.my_float = bpy.props.FloatProperty()

これは以下と同等です

class MyPropGroup(bpy.types.PropertyGroup):
    my_float = bpy.props.FloatProperty()
動的な定義済みクラス(高度)

レンダーマンシェーダー定義など、データの指定子がBlenderにない場合があります。
それらをタイプとして定義し、その場で削除することが役立つ場合があります。

for i in range(10):
    idname = "object.operator_%d" % i

    def func(self, context):
        print("Hello World", self.bl_idname)
        return {'FINISHED'}

    opclass = type("DynOp%d" % i,
                   (bpy.types.Operator, ),
                   {"bl_idname": idname, "bl_label": "Test", "execute": func},
                   )
    bpy.utils.register_class(opclass)

type() はクラスを定義するために呼び出されています。
これはPythonでクラスを作成するための代替構文であり、クラスを動的に構築するのに適しています。

以下に演算子を呼び出す例を示します。

>>> bpy.ops.object.operator_1()
Hello World OBJECT_OT_operator_1
{'FINISHED'}
>>> bpy.ops.object.operator_2()
Hello World OBJECT_OT_operator_2
{'FINISHED'}

f:id:bluebirdofoz:20190922221807j:plain

Blender 2.8のPython APIドキュメントを少しずつ読み解く Python APIの概要 その2

本日は Blender2.8 の調査枠です。
Blender 2.8 の Python API ドキュメントを少しずつ読みつつ試していきます。

Blender 2.8 Python API Documentation

以下のページを日本語訳しつつ実際に試しつつ記事を進めていきます。
docs.blender.org
docs.blender.org

今日は「Python APIの概要」のクラスを介した統合までです。
f:id:bluebirdofoz:20190921205042j:plain

クラスを介した統合

テキストエディターでPythonスクリプトを実行する方法は、テストを行うのに役立ちます。
しかし、Blenderを拡張して他の組み込み機能のようにツールにアクセスできるようにする必要があります。

Blender Python APIにより、以下との統合が可能です。
・bpy.types.Panel
・bpy.types.Menu
・bpy.types.Operator
・bpy.types.PropertyGroup
・bpy.types.KeyingSet
・bpy.types.RenderEngine

これは意図的に制限されています。
現在、メッシュモディファイヤ、オブジェクトタイプ、シェーダノードなどのより高度な機能を使用するには、C/C ++ を使用する必要があります。

Python統合の場合、Blenderはすべてのタイプに共通のメソッドを定義します。
これはBlenderとのインターフェース用に事前定義されている親クラスによって指定された、変数と関数を含むBlenderクラスのPythonサブクラスを作成することで機能します。

例を以下に示します。

import bpy
class SimpleOperator(bpy.types.Operator):
    bl_idname = "object.simple_operator"
    bl_label = "Tool Name"

    def execute(self, context):
        print("Hello World")
        return {'FINISHED'}

bpy.utils.register_class(SimpleOperator)

f:id:bluebirdofoz:20190921205055j:plain

最初に、bpy.types のメンバーをサブクラス化していることに注目してください
これはBlenderと統合して使用できるすべてのクラスに共通するため、登録時にPanelではなくOperatorであると分かります。

クラスプロパティは bl_ プレフィックスで始まります。
これはBlenderのプロパティと自分で追加したプロパティを区別するために使用される規則です。

次に、演算子インスタンスと現在のコンテキストを取得する execute 関数があります。
関数には共通の接頭辞は使用されません。

最後にregister関数が呼び出されます。
これによりクラスが取得され、Blenderにロードされます。
詳しくは Class Registration を参照してください。
・Class Registration
 https://docs.blender.org/api/blender2.8/info_overview.html#class-registration

継承に関して、Blenderは使用されるクラス継承の種類を制限しません。
登録チェックは親クラスで定義された属性と関数を使用します。

以下に例を示します。

import bpy
class BaseOperator:
    def execute(self, context):
        print("Hello World BaseClass")
        return {'FINISHED'}

class SimpleOperator(bpy.types.Operator, BaseOperator):
    bl_idname = "object.simple_operator"
    bl_label = "Tool Name"

bpy.utils.register_class(SimpleOperator)

これらのクラスは__init__(self)関数を定義しないことに注意してください。

__init__()および__del__()が定義されている場合は呼び出されますが、クラスインスタンスの有効期間は実行中のみです。
例えば、パネルには再描画ごとに新しいインスタンスとなります。
このため、パネルインスタンスに変数を格納する理由はほとんどありません。
代わりに、永続変数はBlenders ATAに保存して、Blenderの再起動時に状態を復元できるようにする必要があります。

Modal演算子は例外であり、Blenderの実行時にインスタンス変数を保持します。
演算子テンプレートを参照してください。

クラスがBlenderに登録されると、クラスのインスタンス化と関数の呼び出しはBlenderに任されます。
ほとんどのPython APIで分かるように、スクリプトからこれらのクラスをインスタンス化することはできません。

演算子を実行するには、API を介してそれらを呼び出すことができます。

import bpy
bpy.ops.object.simple_operator()

f:id:bluebirdofoz:20190921205107j:plain

UIクラスには、描画するコンテキスト、ボタンウィンドウ、ファイルヘッダー、ツールバーなどが与えられます。
その領域が表示されるときに描画されるため、Pythonスクリプトから直接呼び出されることはありません。
bluebirdofoz.hatenablog.com

Blender 2.8のPython APIドキュメントを少しずつ読み解く Python APIの概要 その1

本日は Blender2.8 の調査枠です。
今回から Blender 2.8 の Python API ドキュメントを少しずつ読みつつ試していきます。

Blender 2.8 Python API Documentation

以下のページを日本語訳しつつ実際に試して記事を進めていきます。
docs.blender.org
docs.blender.org

今日は「Python APIの概要」のアドオンまでです。
f:id:bluebirdofoz:20190920184811j:plain

Python APIの概要

このドキュメントの目的は、PythonBlenderがどのように連携するかを説明することです。
不明な機能がある場合は、APIリファレンスとサンプルスクリプトを参照してください。

BlenderでのPython

BlenderにはPythonインタープリターが組み込まれています。
これはBlenderの起動時に読み込まれ、Blenderの実行中もアクティブなままです。
このインタープリターはスクリプトを実行してUIを描画し、Blenderの内部ツールのいくつかにも使用されます。

Blenderの組み込みインタープリターはPython環境を提供します。
このため、Pythonスクリプトの基本的なチュートリアルコードはBlenderインタープリターで実行できます。
Blenderは bpy や mathutils などのPythonモジュールを提供します。
これらのPythonモジュールをスクリプトでインポートすると、Blenderのデータやクラス、関数にアクセスできます。
Blenderデータを扱うスクリプトは、動作するモジュールをインポートする必要があります。

簡単な例を以下に示します。"Cube"という名前のオブジェクトの頂点を移動します。

import bpy
bpy.data.objects["Cube"].data.vertices[0].co.x += 1.0

これにより、Blenderの内部データが直接変更されます。
インタラクティブコンソールでこれを実行すると、[3Dビュー]の表示が更新されます。
f:id:bluebirdofoz:20190920185126j:plain

デフォルト環境

独自のスクリプトを開発する場合、BlenderPython環境をどのように設定するかの理解が役立ちます。
Blenderの多くのPythonスクリプトBlenderにバンドルされており、スクリプト作成者が利用するものと同じAPIを使用しています。
このため、リファレンスとして使用できます。
スクリプトの一般的な使用法には以下の例が挙げられます。
ユーザーインターフェイス
・インポート/エクスポート
・シーン操作
・自動化
・独自のツールセットの定義とカスタマイズ

Blenderは起動時に scripts/startup ディレクトリ配下のPythonモジュールを探してインポートします。
このディレクトリの正確な場所は、インストール環境によって異なります。
ディレクトリレイアウトのドキュメントを参照して下さい。
Blender’s Directory Layout
 https://docs.blender.org/manual/en/dev/advanced/blender_directory_layout.html#blender-directory-layout

例:Windowsの場合
 LOCAL: .\2.81\
 USER:  %USERPROFILE%\AppData\Roaming\Blender Foundation\Blender\2.81\
 SYSTEM:%USERPROFILE%\AppData\Roaming\Blender Foundation\Blender\2.81\
スクリプトの読み込み

スクリプトを直接実行することとスクリプトをモジュールとしてインポートすることの違いに注意して下さい。

スクリプトを直接実行してBlenderを拡張することは、スクリプトの実行が終了した後も、スクリプトが定義したクラスがBlender内で利用可能なままであることを意味します。
この方法でスクリプトを使用すると、スクリプトをモジュールとしてインポートする場合と比較して、クラスへの将来のアクセス(クラスの登録解除など)が難しくなります。

このため、クラスを登録することでBlenderを拡張するスクリプトを直接実行することは避けることが望ましいです。

Blenderで直接スクリプトを実行する方法をいくつか紹介します。

テキストエディタにコードを読み込み、[スクリプトの実行]をクリックします。
インタラクティブコンソールにコードを入力または貼り付けます。
Blenderを使用して、コマンドラインからPythonファイルを実行します。例を以下に示します。

blender --python /home/me/my_script.py

f:id:bluebirdofoz:20190920185611j:plain

次にモジュールとして実行する方法を紹介します。

・テキストウィンドウまたは対話型コンソールから import some_module コマンドを利用する。
スクリプトを scripts/startup のいずれかのディレクトリにコピーすると、起動時に自動的にインポートされます。
・アドオンとして定義し、アドオンを有効にするとPythonモジュールとして読み込まれます。
・テキストファイルとして開き、[登録]オプションにチェックを入れると、ブレンドファイルを開いたときに読み込まれます。
f:id:bluebirdofoz:20190920185622j:plain
f:id:bluebirdofoz:20190920185633j:plain

アドオン

Blenderの機能の一部は、オプションで保持するのが最適です。
起動時に読み込まれるスクリプトと共に、独自のディレクトリ scripts/addons に保持されるアドオンがあります。
これらはユーザー設定から選択された場合のみ起動時に読み込まれます。

アドオンとビルトインPythonモジュールの唯一の違いは、アドオンに bl_info 変数が含まれている必要があることです。
bl_info 変数は名前、作成者、カテゴリ、URLなどのメタデータを読み取るためにBlenderが使用する変数です。

User Preferencesアドオンリストは、bl_info 変数を使用して各アドオンに関する情報を表示します。

bl_info の詳細については、アドオンページをご覧ください。
wiki.blender.org
wiki.blender.org

bluebirdofoz.hatenablog.com