MRが楽しい

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

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

本日は 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:20200124091005j:plain

データの削除

削除したデータは、後で変更したりアクセスしたりしないでください。
これには以下のものが含まれます。
オブジェクト、シーン、コレクション、ボーン、カーブ、レンダーレイヤー、タイムラインマーカー、モディファイアなどです。

remove() 呼び出しは間違いを防ぐために、解放したデータを無効にします。
次の例はこの仕組みを示しています。

mesh = bpy.data.meshes.new(name="MyMesh")
# normally the script would use the mesh here...
bpy.data.meshes.remove(mesh)
print(mesh.name)  # <- give an exception rather than crashing:

# ReferenceError: StructRNA of type Mesh has been removed

f:id:bluebirdofoz:20200124091026j:plain

ただし、これは削除される変数へのアクセスに限定されます。
このため、次の例はクラッシュします。

mesh = bpy.data.meshes.new(name="MyMesh")
vertices = mesh.vertices
bpy.data.meshes.remove(mesh)
print(vertices)  # <- this may crash

f:id:bluebirdofoz:20200124091103j:plain

不幸なケース

これまでの全ての予想されるケースに加えて、内部実装の詳細のために問題となるケースがあります。

・Object.hide_viewport、Object.hide_selectおよびObject.hide_render
これらのブール値のいずれかを設定すると、コレクションキャッシュの再構築がトリガーされるため、Collection.all_objectsの反復が中断されます。

import bpy

for obj in bpy.context.scene.collection.all_objects:
    print(obj) # クラッシュしない

for obj in bpy.context.scene.collection.all_objects:
    obj.hide_viewport = True
    print(obj) # クラッシュの可能性あり

f:id:bluebirdofoz:20200124091115j:plain

sys.exit

一部の Python モジュールは、エラーが発生したときに sys.exit() を呼び出します。
sys.exit() は処理をすぐに終了するため、Blender がクラッシュしているように見えるため、注意が必要です。

引数が無効な場合、argparse モジュールはエラーを出力して終了します。

これを解決する方法は sys.exit = None を設定し、Python コードのどの行が終了しているかを確認することです。
もちろん、sys.exit を独自の関数に置き換えることもできますが、この方法で Python を操作するのは推奨されません。