MRが楽しい

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

Blender3.0で利用可能なpythonスクリプトを作る その89(ハンドラーを使って状態の変化を検知する)

本日は Blender の技術調査枠です。
Blender3.0で利用可能なpythonスクリプトを作ります。

ハンドラーを使って状態の変化を検知する

BlenderPython API では Application Handlers を使ってプロジェクトの様々な状態変化を検知して処理を実行することができます。
docs.blender.org

以下、参照ページの日本語訳です。

基本的なハンドラーの例

以下は Handler を追加する最も簡単な例を示しています。

import bpy

def my_handler(scene):
    print("Frame Change", scene.frame_current)
bpy.app.handlers.frame_change_pre.append(my_handler)

永続ハンドラーの例

デフォルトでは新しいプロジェクトをロードするとき、ハンドラーが解放されます。
プロジェクト間でハンドラーを実行し続けたい場合(ハンドラーがアドオンの一部である場合など)は bpy.app.handlers.persistent デコレータを使用する必要があります。

import bpy
from bpy.app.handlers import persistent

@persistent
def load_handler(dummy):
    print("Load Handler:", bpy.data.filepath)
bpy.app.handlers.load_post.append(load_handler)

データの変更に関する注意

ハンドラー呼び出しからのデータの変更は慎重に行う必要があります。
例えばレンダリング中の frame_change_pre, frame_change_post ハンドラーはビューポートとは異なるスレッドから呼び出されています。
このときハンドラーでビューポートからアクセスされるデータを変更した場合、Blenderがクラッシュする可能性があります。
このような場合はレンダリングを開始する前に、インターフェイスをロックします。
(Render → Lock Interface または bpy.types.RenderSettings.use_lock_interface)

以下は、ハンドラーから変更するメッシュの例です。

def frame_change_pre(scene):
    # A triangle that shifts in the z direction
    zshift = scene.frame_current * 0.1
    vertices = [(-1, -1, zshift), (1, -1, zshift), (0, 1, zshift)]
    triangles = [(0, 1, 2)]

    object = bpy.data.objects["The Object"]
    object.data.clear_geometry()
    object.data.from_pydata(vertices, [], triangles)

サンプルコード

今回は以下の Depsgraph の変化を検知する Handlers を使ってモードの切り替えを検知してみます。
docs.blender.org
docs.blender.org

・Script_handler_viewmodet.py

# bpyインポート
import bpy
# @persistent参照のため
from bpy.app.handlers import persistent

# @persistentを指定することで起動中は永続的にハンドラーが登録される
# (https://docs.blender.org/api/current/bpy.app.handlers.html#persistent-handler-example)
@persistent
def handler_check_viewmode(scene):
    # 現在のモードが「編集モード(EDIT_MESH)」かチェックする
    result = check_viewmode('EDIT_MESH')
    # 結果をコンソールに表示する
    print("Is EditMode : " + str(result))

# 現在のモードが指定のモードかチェックする
def check_viewmode(arg_checktype:str) -> bool:
    """現在のモードが指定のモードかチェックする

    Keyword Arguments:
        arg_checktype {str} -- 比較するモード名

    Returns:
        str -- 現在のモード
    """

    # 現在のモードをチェックする
    # (https://docs.blender.org/api/current/bpy.context.html#bpy.context.mode)
    modetype = bpy.context.mode

    return (arg_checktype == modetype)

# ハンドラの登録例
# (https://docs.blender.org/api/current/bpy.app.handlers.html#bpy.app.handlers.depsgraph_update_post)
# Depsgraph の変化を検出する
# (https://docs.blender.org/api/current/bpy.types.Depsgraph.html)
bpy.app.handlers.depsgraph_update_post.append(handler_check_viewmode)

f:id:bluebirdofoz:20211221231847j:plain

以下の通り、モードの切り替え操作を行った時に depsgraph_update_post ハンドラーによって関数が実行されます。
f:id:bluebirdofoz:20211221231855j:plain