広告
広告

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

カテゴリ:blender
cc4.0

この記事は 2018 年 10 月 04 日時点でのProcess/Addons/Guidelines/UpdatingScriptsの翻訳だ。

目次

Blender 2.7x のスクリプトのアップデート

このページは 2.7x のスクリプトを 2.8x で実行するために必要な変更を列挙する。

注意:現在の Blender 2.8 の Python API は開発中であり変更される可能性がある。スクリプトのアップデートは 2.8 Beta(予定では2018 年 10 月末)まで待った方がよい。

文法・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] のみに制限された。一般的にスクリプトは、モジュールをインポートすることで定義したクラスにアクセスするので、この変更はほとんどのスクリプトに影響はないはずだ。

命名規則

Blender 2.7x ではクラス名の衝突が起こりやすかった。これを防ぐため Blender 2.8x では命名規則を強制する(これらの命名規則は Blender のコードで広く使われているものだ)。この命名規則はクラスの bl_idname に適用される。クラス内で bl_idname を定義しない場合はクラス名にも適用される。

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

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

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

  • Header -> _HT_
  • Menu -> _MT_
  • Operator -> _OT_
  • Panel -> _PT_
  • UIList -> _UL_

いくつか有効な bl_idname の例をあげる。

  • OBJECT_OT_fancy_tool
  • SOME_HEADER_HT_my_header
  • PANEL123_PT_myPanel

この命名規則に従わない場合、起動時(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()
# 2.8x
class MyOperator(Operator):
    value: IntProperty()

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

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

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

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

# 2.7x
context.scene.frame_set(10, 0.25)
noise.noise(position, noise.types.BLENDER)
# 2.8x
context.scene.frame_set(10, subframe=0.25)
noise.noise(position, noise_basis='BLENDER')

行列の乗算

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

  • Vector * Vector
  • Quaternion * Vector
  • Matrix * Vector
  • Vector * Matrix
  • Matrix * Matrix

"*" 演算子は要素ごとの乗算に割り当てられる予定だ。

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

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

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

データへのアクセス

シーンレイヤー

TODO.(原文ママ)

オブジェクト選択

TODO.(原文ママ)

Dupli Instances(プロパティパネルのオブジェクトタブにある複製)

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 インスタンス(おそらく実行時に生成された dupli オブジェクト)
        obj = dup.instance_object.original
        parent = dup.parent.original
        mat = dup.matrix_world.copy()
    else:  # 普通のオブジェクト
        obj = dup.object.original
    # obj, parent, mat を使って何かする。これらの値はローカルコピーもしくはオリジナルデータブロックだ。

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

(dup for dup in context.depsgraph.object_instances if dup.parent and dup.parent.original == context.object)

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

IO アドオン補助

座標系(Orientation)

既定のカスタム座標系(orientation)をもつ基底クラスを作るために orientatioin_helper_factory 型のジェネレーターが使われていた。しかし axis helpers として使われていた共通のプロパティは削除されている。代わりにより 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
# 2.8x
from bpy_extras.io_utils import (
        ImportHelper,
        orientation_helper,
        )

@orientation_helper(axis_forward='-Z', axis_up='Y')
class ImportFBX(bpy.types.Operator, ImportHelper):
    pass

ノードシェーダ/ノードマテリアル

Blender 2.7x ではノードシェーダ(Cycles マテリアル)はインポートしかできなかった(cycles_shader_compat モジュールでその機能が提供されていた)。Blender 2.8 ではノードシェーダしか存在しないので、bpy_extras モジュールの node_shader_utils に新しいラッパーが追加された。Blender 2.7x とは以下の違いがある。

  • インポートとエクスポートとをサポートし、値の読み書きが簡単で、複雑なノードを隠すことができる
  • 大量のシンプルなシェーダの組み合わせでなく、プリンシプルシェーダを基本とする
  • 今のところプリンシプルシェーダのみを使う。前のシステムでサポートされていた displacement のような機能は未実装である
  • クランプのような値の変換は行わない(それは FBX でのみ必要なので)。変換や変形は個々のアドオンが行う
  • 以下のような機能を実現するためにアクセサを積極的に使う
    • 書き込みチェック(エクスポート時にシェーダを書き換えてしまうのを防ぐ)
    • 最初にアクセスしたときに、ノードやリンクを同時にすべて作成しない。これは最終的に使われていないノードが発生するのを防ぐ

ここにコード例を書くには余白が狭すぎる。比較的シンプルな使用例として Blender 2.8x の OBJ のインポートエクスポートアドオンを参照するといい。

ここは翻訳が怪しいので原文も載せる。シェーダとしてエクスポートできるノードは制限されている。プリンシプルシェーダと基本的な画像テクスチャの設定と以外は無視される。無視されたソケットの場所はデフォルト値がエクスポートされる。(Note that especially in the export case, user is expected to feature a rather specific, limited kind of node tree as shaders to be exported. Anything besides basic Principled BSDF shader usage, with basic image-based texturing, will be ignored, leading to some kind of default values being exported instead.)

この画像フリーの OBJ 猫モデルをインポートしたときに生成されたノードマテリアルだ。

モジュールの変更

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)
# 2.8x
bmesh.ops.mirror(bm, geom=verts, axis='Y')

ノイズ

Noise and Metric Enumerators

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

# 2.7x
noise.noise(position, noise_basis=noise.types.BLENDER)
# 2.8x
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'

Blender 2.8 の新しい Python API の機能

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)はルートをひとつしか持つべきではない。これは自動でチェックされないのでスクリプト側で処理する必要がある。

関連記事

Blender 2.8 API Changes

Blender 記事の目次


広告
広告