dskjal
広告
広告

Blender 2.79 のスクリプトを 2.80 にアップデートする

カテゴリ:blender
CC4.0

CC4.0

この記事は 2019 年 08 月 15 日時点でのReference/Release Notes/2.80/Python APIの翻訳だ。

目次

Blender 2.80 における Python API の変更

Blender 2.80 は過去バージョンの Python API と互換性がない。アドオンやスクリプトを 2.80 で実行するにはアップデートが必要になる。

アドオン API

バージョン情報

bl_info ディクショナリの "blender" キーの値は (2, 80, 0) となる。(2, 8, 0) や (2, 79, 0) は例外が投げられる。

# 正しい bl_info
bl_info = {
    "name" : "Addon name",
    "author" : "author",
    "version" : (1, 0),
    "blender" : (2, 80, 0),
    "location" : "",
    "description" : "",
    "warning" : "",
    "wiki_url" : "",
    "tracker_url" : "",
    "category" : ""
}

バージョン情報が間違っている場合、以下の例外が投げられる。

Exception: Add-on 'ADDON_NAME' has not been upgraded to 2.8, ignoring

モジュールの登録

bpy.utils.register_module は不要な管理コストがかかるため削除された。代わりにクラスをタプルまたはリストにして直接登録する。

# クラスの登録コード
classes = (
    FooClass,
    BarClass,
    BazClass,
)

def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)

上記のコードを使い回さなくて済むように、bpy.utils.register_classes_factory が用意されている。

classes = (
    FooClass,
    BarClass,
    BazClass,
)
register, unregister = bpy.utils.register_classes_factory(classes)

大量のクラスがある場合は、Patch to help remove register_module use in 2.8 を使えばクラスのリストを生成できる。

クラスの登録

詳細はPython API, changes to type registration in 2.8(T52599)を参照。

アクセス(bpy.types)

アドオンによって登録されたクラスは bpy.types からアクセスできなくなった。代わりにモジュールをインポートすることで、直接それらにアクセスできるようになった。

ただし [Header, Menu, Operator, Panel, UIList] のサブクラスは bpy.types からアクセスできる。

命名規則

Blender 2.7x ではクラス名の衝突が起こりやすかった。これを防ぐため Blender 2.8x ではクラス名に制約ができた。これらの命名規則は Blender のコードで広く使われているものだ。

その命名規則はわかりにくいが [大文字アルファベット][大文字アルファベット or 数字 or _]_{セパレーター}_[アルファベット or 数字 or _] だ。正規表現で書けば以下のようになる。

[A-Z][A-Z0-9_]*_(HT|MT|OT|PT|UL)_[A-Za-z0-9_]+

セパレーターは以下のようになる。

いくつか有効なクラス名の例をあげる。

この命名規則に従わない場合、起動時(startup:おそらく Blender 起動時とアドオン有効時)に警告が表示される。以下に警告例を示す。

Warning: 'Oscurart Files Tools' doesn't contain '_PT_' with prefix & suffix
Warning: 'Oscurart Overrides' doesn't contain '_PT_' with prefix & suffix
Warning: 'Oscurart Animation Tools' doesn't contain '_PT_' with prefix & suffix

クラスプロパティの登録

bpy.props のプロパティを持つクラスは Python アノテーション(PEP 526)(日本語の解説)を使うように変更された。代入に "=" ではなく ":" を使う。

# 2.7x
class MyOperator(Operator):
    value = IntProperty()

class MyOperator(Operator):

value: IntProperty()

Blender 2.80 以降で 2.7x の記法を使うと以下の警告が出る。

Warning: class Foo "contains a properties which should be an annotation!"

シーンとオブジェクト API

ビューレイヤーとコレクション

2.8x のコレクションは 2.7x のグループと 20 個しかなかったレイヤーとを置き換える。コレクション内のオブジェクトはシーンのコレクション階層にリンクされている場合、エンプティやパーティクルの位置にインスタンス化できたり、シーン内のオブジェクトを管理したりできる。

シーンは必ずマスターコレクションをひとつ持つ。これはシーンのコレクション階層の根だ。マスターコレクションはシーンデータで管理されるので、データベース(bpy.data.collections)には現れない。

2.7x ではオブジェクトのレイヤー情報はオブジェクトが持っていた。2.8x ではコレクションにリンクする必要がある。

# 2.7x
C.object.layers[1] = True

# 2.8x
# コレクションをシーンにリンク
col = D.collections.new("Collection 2")
C.scene.collection.children.link(col)

# オブジェクトをコレクションにリンク
col.objects.link(C.object)

2.8x のビューレイヤーは 2.7x のレンダーレイヤーを拡張したものだ。ビューレイヤーはシーン内のオブジェクト・レンダリングするオブジェクト・コレクションの可視をコントロールする。

ビューレイヤーはシーンのコレクション階層を複製する。しかし LayerCollection は特定のコレクションを除外できる。シーンにリンクされているコレクションは全てのビューレイヤーでデフォルトでアクティブになる。

# 2.7x
C.scene.render.layers.active.layers[1] = False

# 2.8x
# アクティブビューレイヤーから "Collection 2" を除外する
C.window.view_layer.layer_collection.children["Collection 2"].exclude = True

2.8x ではアクティブウインドウからアクティブビューレイヤーを取得する。アクティブシーンからは取得できない。

シーンアップデート

# 2.7x
scene = bpy.context.scene
scene.update()

# 2.8x
layer = bpy.context.view_layer
layer.update()

オブジェクトの選択と表示/非表示

2.7x ではオブジェクトの select プロパティを操作することで表示/非表示を操作できた。2.8x ではこれらは削除されており、代わりに get/set メソッドを使うようになった。

obj = bpy.context.object 
# 2.7x
if (not obj.select):
    obj.select = True

# 2.8x
if (not obj.select_get()):
    obj.select_set(True)

詳細はselect_set(state, view_layer=None)を参照。

hide プロパティは hide_viewport に変更された。その方がほかの hide プロパティと一貫性があるためだ。

o = bpy.context.object
# 2.7x
o.hide = True
o.hide_render = True
o.hide_select = True

# 2.8x
o.hide_viewport = True
o.hide_render = True
o.hide_select = True

オブジェクトが可視状態であってもコレクションが不可視である場合には、可視状態のオブジェクトは見えないことに注意する必要がある。

オブジェクトの追加

2.7x ではオブジェクトはシーンにリンクしていた。2.8x ではコレクションにリンクする。ビューレイヤーとコレクションを参照。

scene = bpy.context.scene

# 2.7x
scene.objects.link(o)

# 2.8x
scene.collection.objects.link(o)

オブジェクトは複数のコレクションにリンクできる。しかし実態はひとつなので、複数あるコレクションの内のどれかひとつのオブジェクトが不可視になると、他のコレクション内の該当オブジェクトも不可視になる。これはコレクション自体を不可視にしても同じだ。

注意:2.8x では scene.objects のアクセスは読み出しのみに変更された。scene.objects でシーン内のインスタンス化されたオブジェクトすべてにアクセスできるが、編集はできない。

インスタンス化(Instancing)

Dupli Instances へのアクセス方法は完全に別物になった。Blender 2.7x ではひとつのオブジェクトから生成されたすべてのインスタンスにアクセスできた。

# 2.7x
ob = context.object
ob.dupli_list_create(scene, 'PREVIEW')
for dup in ob.dupli_list:
    pass  # dupli_list が有効な間はあらゆる操作が合法
# ...
ob.dupli_list_clear()  # これより後は dupli objects へのアクセスはエラー(invalid)

Blender 2.8x では depsgraph context の内部でのみインスタンスにアクセスできる。なのでインスタンスを作成する必要はなく、ループを使ってアクセスするだけだ。ただし depsgraph を取得する必要がある。

depsgraph = context.depsgraph
for dup in depsgraph.object_instances:
    pass  # dup を使って何かする。ただし参照を取得してはならない!

警告:取得した dupli のあらゆる参照(ID を含む)を保存してはならない。ループの外だけでなく、ループの次のアイテムへの持越しもよくない。そのデータは実行時に生成され、ループの次のアイテムを処理するさいに無効になる。さらに ID RNA ポインタは評価された(生成された)ものを参照するため、何らかの値(行列やベクトルなど)を保存する場合は、その値を複製する必要がある。

もうひとつの大きな違いがある。Blender 2.7x ではオブジェクトに dupli が紐づけられていたが、Blender 2.8x では current depsgraph に大量のインスタンスが格納されるようになった。大量のインスタンスの中に 'リアル' オブジェクトも含まれる。

# 2.8x
depsgraph = context.depsgraph
for dup in depsgraph.object_instances:
    if dup.is_instance:  # リアル dupli インスタンス(実行時に生成されたオブジェクト)
        obj = dup.instance_object.original
        parent = dup.parent.original
        mat = dup.matrix_world.copy()
    else:  # 普通のオブジェクト
        obj = dup.object.original
    # obj, parent, mat を使って何かする。これらの値はローカルコピーもしくはオリジナルデータブロックだ。

アクティブなオブジェクトの dupli のタプルが欲しい場合は、以下のようにする。

depsgraph = context.evaluated_depsgraph_get()
for ob_inst in depsgraph.object_instances:
    if ob_inst.parent and ob_inst.parent.original == context.object:
       # ob_inst にアクセスする.

depsgraph は今のところ Context または ViewLayer から取得できる。しかし 'render' depsgraph を取得する方法がまだない。depsgraph の API はいまだに実装途中だ。

マルチオブジェクトモード

Blender 2.80 では複数のオブジェクトをエディットモードやポーズモードで同時に編集できるようになった。なのでオペレーターはアクティブなモードですべてのオブジェクトが更新しなければならない。

アクティブなモードを取得するには context.mode を使う。このモードでオブジェクトにアクセスするには以下の context プロパティが使える。

ベースとコンテクストオーバーライド

scene.object_bases が削除されたので、Python API から ObjectBase にアクセスできなくなった。なのでコンテクストをオーバーライドするさいに、いくつかのオペレーターのために以下のベースを設定する必要がなくなった。

メッシュ API

メッシュテッセレーション

テッセレートされた面を取得する古い機能は API から削除された。それは n ゴンをサポートする前の、三角面と四角面しか扱えなかった時代の名残だ。

代わりに mesh polygons を使う。メッシュのテッセレートを必要とするエクスポーターやレンダラーは loop triangles が代わりに使える。

# 2.7x
mesh.calc_tessface()
for face in mesh.tessfaces:
    for vert_index in face.vertices:
        print(mesh.vertices[vert_index].co)

# 2.8x
mesh.calc_loop_triangles()
for tri in mesh.loop_triangles:
    for vert_index in tri.vertices:
        print(mesh.vertices[vert_index].co)

Loop triangles はメッシュの三角分割のみをサポートしている。四角面が必要な場合は、同じポリゴンの連続した loop triangles を四角面として解釈できる。

UV と頂点色も loop triangles を介してアクセスするようになった。

# 2.7x
for uv_layer in mesh.tessface_uv_textures:
    for face in mesh.tessfaces:
        face_uvs = uv_layer.data[face.index]
        for uv in face_uvs:
            print(uv)

# 2.8x
for uv_layer in mesh.uv_layers:
    for tri in mesh.loop_triangles:
        for loop_index in tri.loops:
            print(uv_layer.data[loop_index].uv)

BMesh

Operator Enumerators and Flags

Blender 2.7x では BMesh の operator enumerators/flags は整数で指定していた。Blender 2.8x では文字列で指定する。

# 2.7x
bmesh.ops.mirror(bm, geom=verts, axis=1)

bmesh.ops.mirror(bm, geom=verts, axis='Y')

Skin Root Vertices の設定

API を使って Mesh skin vertex roots (スキンモディフィアの「ルートをマーク」)を設定できるようになった。

l = bm.verts.layers.skin.verify()
v = bm.verts[0]
v[l].use_root = True

それぞれの独立したメッシュ(mesh island)はルートをひとつしか持つべきではない。これは自動でチェックされないのでスクリプト側で処理する必要がある。

Preference API

ユーザー設定(User Preference)はプリファレンス(Preference)に改名された。Python API もそれに合わせて変更されている。

# 2.7x
bpy.context.user_preferences

# 2.8x
bpy.context.preferences

残りのパラメータはBlender 2.80: Preferences API を参照。

ユーザーインターフェイス API

ツールバー

ツールバーはアクティブツールのみ配置するように変更された。ツールバーにツールを配置していたアドオンをアップデートする方法はいくつかある:

ボタンとパネル

シングルカラムレイアウト

ほとんどの Blender のユーザーインターフェイスはシングルカラムレイアウトを使うように変更された。シングルカラムレイアウトを使うには以下のようにする。

def draw(self, context):
    layout = self.layout
    layout.use_property_split = True # シングルカラムレイアウトを有効にする

    view = context.scene.view_settings

    layout.prop(view, "view_transform")
    layout.prop(view, "look")

サブパネル

パネルはサブパネルを持てるようになった。サブパネルはコンテンツをまとめたり、あまり使わない機能や高度な機能を隠したりするのに使える。親パネルを参照する 'bl_parent_id' を追加することでサブパネルを作成できる。

# 親パネル
class RENDER_PT_color_management(RenderButtonsPanel, Panel):
    bl_label = "Color Management"
    ...

# サブパネル
class RENDER_PT_color_maangement_curves(RenderButtonsPanel, Panel):
    bl_label = "Use Curves"
    bl_parent_id = "RENDER_PT_color_management"
    ...

アイコン

アイコンは変更点が多すぎる。変更リストはIconsを参照。

描画 API

OpenGL Core Profile

Blender 2.80 では OpenGL core profile を使う。これは Eevee やビューポートのレンダリングに必要な機能をすべて含んでいる。しかしこの OpenGL バージョンは、immediate モードや固定機能パイプラインといったよく使われる機能が削除されている。そのため簡単な描画機能のために多くの API 呼び出しが必要になる。

低レイヤーの bgl モジュールを直接使うのではなく、gpu モジュールの使用を推奨する。gpu モジュールは将来 Vulkan が採用されたときでも変更されにくい、抽象度の高い API を提供している。

gpu モジュールで提供されていないより低レイヤーの機能が必要な場合は、Getting Started の OpenGL core profile を移植する方法を参照。

GPU モジュール

GPU モジュールを使うにあたりバッチとシェーダオブジェクトとを理解することが重要だ。バッチは描画の単位だ。たいていはマテリアルひとつあたりバッチがひとつ必要になる。シェーダはジオメトリの描画方法をきめる。GLSL でシェーダを描くこともできるし、gpu モジュールのユーティリティシェーダを使うこともできる。

詳細やサンプルは GPU Shader Module (gpu) を参照

タイマー API

ユースケース:

詳細は Application Timers (bpy.app.timers) を参照。

アニメーション&リグ API

PoseBone.bone の振る舞いの修正

PoseBone.bone プロパティは正しく id_data の結果を Armature ID にセットするようになった。以前はアーマチュアオブジェクトへのポインタを保持しているだけだった(1c106e18)。

# 2.7x
>>> bpy.data.objects[0].pose.bones[0].bone
bpy.data.objects['Armature'].pose.bones["Bone"].bone

# 2.8x
>>> bpy.data.objects[0].pose.bones[0].bone
bpy.data.armatures['Armature'].bones["Bone"]

この結果として object.pose.[...].bone.driver_add() は object.animation_data ではなく object.data.animation_data にドライバーを設定するようになった。

ボーン行列ユーティリティ

ボーンとポーズボーンとに、ボーンロールと Bendy ボーンの形状との計算を補助するメソッドが追加された(a58f0eea

ボーンにポーズ座標への変換行列を計算するメソッドが追加された(48a3f97b

キーフレームユーティリティ

anim_data.nla_tweak_strip_time_to_scene() で NLA ストリップとシーン時間(scene time)とを変換できる(27d097e9)。

object.keyframe_inser() で使えるフラグが追加された(ebc44aae)。

fcurve.is_empty プロパティが追加された。これを使うと、キーフレームや有用なモディフィアがないためにアニメーションに影響がないカーブを簡単に検出できる(b05038fe)。現在はそのようなカーブはアニメーションを評価するコードによって無視される。なので不要なカーブのクリーンアップは複雑な編集を行うオペレーターが終了するまで延期できる。そのオペレーターが現在のフレームを変更したりカーブの再評価を引き起こしたとしても特別な処理は不要だ。

そのほか

hook.vertex_indices, hook.vertex_indices_set() で、フックモディフィアのバインドされている頂点インデックス配列に直接アクセスできるようになった。(3f788eac

object.shape_key_clear() でオブジェクトのすべてのシェイプキーを削除できるようになった。(c7ec6bb7

from rna_prop_ui import rna_idprop_ui_create で、既定値・値制限・ UI 設定を一度に設定できるカスタムプロパティを作成できるようになった。(40dd9156

ヘルパーモジュール

シェーダーノードのインポート/エクスポート

Blender レンダーが削除されたのですべてのマテリアルはノードベースになった。しかし外部ファイルのシェーダは大抵、固定されたパラメータを持っているだけだ。そのようなシェーダのインポート/エクスポートを補助するため bpy_extras.node_shader_utils が追加された。これは cycles_shader_compat の置き換えだ。

2.7x とは以下の点で違っている:

コード例:

import bpy

from bpy_extras.node_shader_utils import PrincipledBSDFWrapper
from bpy_extras.image_utils import load_image

# Import
mat = bpy.data.materials.new(name="Material")
mat.use_nodes = True
principled = PrincipledBSDFWrapper(mat, is_readonly=False)
principled.base_color = (0.8, 0.8, 0.5)
principled.specular_texture.image = load_image("/path/to/image.png")

# Export
principled = PrincipledBSDFWrapper(mat, is_readonly=True)
base_color = principled.base_color
specular_texture = principled.specular_texture
if specular_texture and specular_texture.image:
    specular_texture_filepath = principled.specular_texture.image.filepath

比較的シンプルな使用例として Blender 2.8x の OBJ のインポートエクスポートアドオンを参照するといい。この画像フリーの OBJ 猫モデルをインポートしたときに生成されたノードマテリアルだ。

ノイズ

Noise and Metric Enumerators

Blender 2.7x では Enumerator はモジュールレベルの定数だった。Blender 2.8x では文字列になる。

# 2.7x
noise.noise(position, noise_basis=noise.types.BLENDER)

noise.noise(position, noise_basis='BLENDER')

ノイズ型名

ノイズ型名は以下の文字列に変更された。

2.7x2.8x
noise.types.BLENDER'BLENDER'
noise.types.STDPERLIN'PERLIN_ORIGINAL'
noise.types.NEWPERLIN'PERLIN_NEW'
noise.types.VORONOI_F1'VORONOI_F1'
noise.types.VORONOI_F2'VORONOI_F2'
noise.types.VORONOI_F3'VORONOI_F3'
noise.types.VORONOI_F4'VORONOI_F4'
noise.types.VORONOI_F2F1'VORONOI_F2F1'
noise.types.VORONOI_CRACKLE'VORONOI_CRACKLE'
noise.types.CELLNOISE'CELLNOISE'

座標系(Orientation)

既定のカスタム座標系(orientation)をもつ基底クラスを作る orientatioin_helper_factory は削除された。代わりにより Python 風な orientation_helper デコレーターが追加されている。

# 2.7x
from bpy_extras.io_utils import (
        ImportHelper,
        orientation_helper_factory,
        )

IOFBXOrientationHelper = orientation_helper_factory("IOFBXOrientationHelper", axis_forward='-Z', axis_up='Y')

class ImportFBX(bpy.types.Operator, ImportHelper, IOFBXOrientationHelper):
    pass

from bpy_extras.io_utils import (

ImportHelper,

orientation_helper,

)

@orientation_helper(axis_forward='-Z', axis_up='Y')

class ImportFBX(bpy.types.Operator, ImportHelper):

pass

削除されたモジュール

extensions_framework モジュールは削除された。

リネーム

いくつかの用語はユーザーインターフェイス上で変更された。

キーワード強制引数(Keyword Only Arguments)

キーワード引数はキーワードが必要となり、引数の位置から推測させることができなくなった。

# 2.7x
context.scene.frame_set(10, 0.25)
noise.noise(position, noise.types.BLENDER)

context.scene.frame_set(10, subframe=0.25)

noise.noise(position, noise_basis='BLENDER')

行列の乗算

行列の乗算には "*" が使われていたが、Blender 2.8x からは "@" を使う(PEP 465)。これは以下の組み合わせに適用される。

"*" 演算子はアダマール積(要素ごとの乗算)に割り当てられる予定だ。

# 2.7x
mat = Matrix()
vec = Vector()
result = mat * vec

mat = Matrix()

vec = Vector()

result = mat @ vec

Blender 2.80 以降で 2.7x の記法を使うと以下の警告が出る。

TypeError: Element-wise multiplication: not supported between 'xxx' and 'yyy' types

テキストのインポート

モジュールとして Blender テキストデータをインポートする能力は削除された(dc8dd24351)。モジュールとしてテキストデータブロックを取得したければ as_module() が使える。

my_module = bpy.data.text["my_module"].as_module()

オペレーターアップデート

select_by_layer は削除され view3d.viewnumpad(view3d.view_axid, view3d.view_camera) に置き換えられた。

プロパティアップデート

SpaceView3D.viewport_shader は SpaceView3D.shading.type に置き換えられた。

そのほかの変更

percentage キーワードは factor に改名された。

# 2.7x
box.split(percentage=0.6, align=False)

# 2.8x
box.split(factor=0.6, align=False)

アクティブオブジェクトの設定は view_layer から行う

# 2.7x
bpy.context.scene.objects.active = bpy.data.objects['Cube']

# 2.8x
bpy.context.view_layer.objects.active = bpy.data.objects['Cube']

Blender のバージョンの比較

文字列としてバージョンを取得

bpy.app.version_string

バージョンの比較(2.80 より古いバージョンの検出)

if (2, 80, 0) > bpy.app.version: 
    print("This version is older than 2.80.")

オブジェクトの選択とアクティブ化

o = 何らかのオブジェクトの取得
bpy.context.view_layer.objects.active = o
o.select_set(True)
bpy.context.view_layer.update()

# ループでオブジェクトを取得する場合前回のオブジェクトの選択を解除
old_object.select_set(False)

Process/Addons/Guidelines/UpdatingScripts

Blender 2.8 API Changes

Blender 2.8x / Python, Proposed Changes

2.80 Cheat Sheet for updating add-ons

Blender 2.81: Python API

関連記事

Blender 記事の目次


広告
広告

カテゴリ