MRが楽しい

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

Blender 2.8のPython APIドキュメントを少しずつ読み解く 落とし穴 その6

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

Blender 2.8 Python API Documentation

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

今日は「落とし穴」の「データ名」です。
f:id:bluebirdofoz:20200116094236j:plain

データ名

命名の制限

よくある間違いは、新しく作成されたデータに要求した名前が与えられていると想定してしまうことです。
これにより、データ(通常はインポートされる)を追加して後で名前で参照するとき、バグが発生する可能性があります。

bpy.data.meshes.new(name=meshid)

# normally some code, function calls...
bpy.data.meshes[meshid]

f:id:bluebirdofoz:20200116094248j:plain

または名前を直接割り当てた場合です。

obj.name = objname

# normally some code, function calls...
obj = bpy.data.meshes[objname]

f:id:bluebirdofoz:20200116094258j:plain

データ名は以下のケースで割り当てられた値と一致しない場合があります。
・最大長を超える場合
・既に使用されている場合
・空の文字列の場合

オブジェクトは名前で参照しないことをお勧めします。
一度作成すると、List、Dictionary、クラスなどにデータを保存できます。
同じデータを名前で検索し続ける必要はほとんどありません。

名前参照を使用する必要がある場合、インポートされたアセットの名前と新しく作成されたデータの間のマッピングを維持するため、辞書を使用するのが最善です。
この方法ではブレンドファイルから既存のデータを参照するリスクはありません。

# typically declared in the main body of the function.
mesh_name_mapping = {}

mesh = bpy.data.meshes.new(name=meshid)
mesh_name_mapping[meshid] = mesh

# normally some code, or function calls...

# use own dictionary rather than bpy.data
mesh = mesh_name_mapping[meshid]

f:id:bluebirdofoz:20200116094308j:plain

ライブラリ衝突

Blenderは bpy.types.ID.name でデータ名を一意に保ちます。
複数のオブジェクト、メッシュ、シーンなどに同じ名前を付けることはできません。

ただし、別のブレンドファイルからライブラリデータにリンクすると名前の競合が発生する可能性があります。
このため、名前でデータを参照しないようにしてください。

ブレンダーでさえこれを正しく処理しない場合があります。
(たとえばモディファイアオブジェクトを選択する場合、同じ名前のオブジェクトを複数選択することはできません)

ローカルデータとライブラリデータのどちらかを選択する必要がある場合、これを許可する機能が bpy.data メンバーにあります。

# typical name lookup, could be local or library.
obj = bpy.data.objects["my_obj"]

# library object name look up using a pair
# where the second argument is the library path matching bpy.types.Library.filepath
obj = bpy.data.objects["my_obj", "//my_lib.blend"]

# local object name look up using a pair
# where the second argument excludes library data from being returned.
obj = bpy.data.objects["my_obj", None]

# both the examples above also works for 'get'
obj = bpy.data.objects.get(("my_obj", None))

bluebirdofoz.hatenablog.com