【Maya/Python】OpenMaya API2.0 の MAnimMessage のコールバックタイミング解説

この記事は Maya Advent Calendar 2024 シリーズ1 の14日目の記事です。

 

前日は @9boz さんの「Mayaで反対側のfaceを取得したい1」、

翌日は @9boz さんの「UVchoserのはなし」です。

 

今回は OpenMaya API 2.0 の maya.api.OpenMayaAnim のネームスペースにある MAnimMessage クラスのコールバックのタイミングについてまとめていこうと思います。

 

この記事は Maya 2023.3 で検証したものです。

最初に書いておきますが、色々試した結果 1つだけまだ使い所が分かっていない「flushAnimKeyframeEditedCallbacks」というコールバックがあります。

分かり次第追記しますが、もし使い方をご存知の方がいらっしゃれば教えて下さい。

 

 ちなみに過去にコールバック系で

【Maya/Python】OpenMaya API2.0 の MSceneMessage クラス内のコールバックタイミング解説

【Maya/Python】OpenMaya API2.0 の Message 系クラス内のコールバックタイミング解説 1

という記事も書いておりますのでご興味あればご覧下さい。


OpenMayaAnim.MAnimMessage

OpenMayaAnim.MAnimMessage.addAnimCurveEditedCallback()

シーン内でキーを打ったりアニメーションの値を変更してアニメーションカーブに変更があった場合に呼ばれます。
# Sample Code ===================================

import maya.api.OpenMayaAnim as oma2

 

def addAnimCurveEditedCallbackMethod(*args):

    print(args[0]) # 変更のあったアニメーションカーブ (MFnAnimCurve) が MObjectArray で渡されます

 

oma2.MAnimMessage.addAnimCurveEditedCallback(addAnimCurveEditedCallbackMethod)

 

OpenMayaAnim.MAnimMessage.addAnimKeyframeEditCheckCallback()

シーン内でキーを追加した場合(内部的には setKeyframe コマンドが実行された場合)に呼ばれます。
こちらは Check 系のコールバックになっており、必ず return True/False を返す必要があります。
使い方としては、例えば変更のあった MPlug がデータが渡されるので、その内容次第で「このアトリビュートにはキーを打たせたくない」というものだった場合に、False を返すことでその変更が反映されないようにできます。
# Sample Code ===================================

import maya.api.OpenMayaAnim as oma2

 

def addAnimKeyframeEditCheckCallbackMethod(*args):

    print(args[0]) # 変更のあった MPlug (例: pSphere1.translateX) が渡される

    return True

 

oma2.MAnimMessage.addAnimKeyframeEditCheckCallback(addAnimKeyframeEditCheckCallbackMethod)

 

OpenMayaAnim.MAnimMessage.addAnimKeyframeEditedCallback()

シーン内でキーを打ったりアニメーションの値を変更してアニメーションカーブに変更があった場合に呼ばれます。

MObjectArray が渡ってきて、それを for で回して MObject の apiTypeStr を見てみると

 ・キーを追加したり削除したとき kKeyframeDeltaAddRemove
 ・キーの時間や値を変更したとき kKeyframeDeltaMove
 ・Tangent が変わったとき      kKeyframeDeltaTangent
 ・Tangent のウェイト付き/非ウェイト付きを切り替えたとき  kKeyframeDeltaWeighted

などの情報が分かります。

 

しかし!!!! 

なんと、Maya 2023 時点では API 2.0 には MFnKeyframeDelta 系クラスが移植されていないので、この渡された MObjectArray をおそらく何にもできません(方法があれば教えて下さい)

 

ちなみに API 1.0 の方には  MFnKeyframeDelta 系クラスがあり、試してみたところ

例えばキーの追加や削除したときは MFnKeyframeDeltaAddRemove でそのキーの値や時間やインデックスを取得したり、キーの値や時間を変更したときは MFnKeyframeDeltaMove で変更前と変更後の値や時間を取得したりできます。

 

# Sample Code ===================================

import maya.api.OpenMayaAnim as oma2

 

def addAnimKeyframeEditedCallbackMethod(*args):

    print(args[0]) # 変更のあったキーの MFnKeyframeDelta 系が MObjectArray で渡される

 

oma2.MAnimMessage.addAnimKeyframeEditedCallback(addAnimKeyframeEditedCallbackMethod)

 

OpenMayaAnim.MAnimMessage.addDisableImplicitControlCallback()

ベイク時に disableImplicitControl(ベイク後にIKハンドルによるIKの制御などを無効にするかどうか)というオプションが有効になっていた場合に、「シミュレーションのベイク処理」を実行し終わったあとに呼ばれます。

 

渡ってきた MDGModifier は ベイク処理を Undo/Redo するためのものだそうです。

 

# Sample Code ===================================

import maya.api.OpenMaya as om2

 

def addDisableImplicitControlCallbackMethod(*args):

    print(args[0]) # ベイクされたキーたちが MPlugArray で渡される

    print(args[1]) # MDGModifier が渡される

 

oma2.MAnimMessage.addDisableImplicitControlCallback(addDisableImplicitControlCallbackMethod)

 

OpenMayaAnim.MAnimMessage.addNodeAnimKeyframeEditedCallback()

addAnimKeyframeEditedCallback と同じようにキーを打ったりアニメーションの値を変更した場合に呼ばれますが、異なる点は監視したいノードをセットする部分です。

特定のノードだけチェックしたい場合に使えます。

ただこちらも addAnimKeyframeEditedCallback と同様に第二引数に渡される MObjectArrayは MFnKeyframeDelta 系のデータとなっております。

 

# Sample Code ===================================

import maya.api.OpenMaya as om2

import maya.api.OpenMayaAnim as oma2

 

def addNodeAnimKeyframeEditedCallbackMethod(*args):

    print(args[0]) # 変更のあったアニメーションカーブ (MFnAnimCurve) が渡される
    print(args[1]) # 変更のあったキーの MFnKeyframeDelta 系が MObjectArray で渡される

 

def getAnimNodes(transNode):
    animNodeList = []
    connectionPlugs = transNode.getConnections()
    for cPlug in connectionPlugs:
        if cPlug.isKeyable == False: # キーが設定できないプラグはパス
            continue
        srcConnect = cPlug.source()
        if srcConnect.node().hasFn(om2.MFn.kAnimCurve):
            animCurve = oma2.MFnAnimCurve(srcConnect.node())
            animNodeList.append(animCurve)
    return animNodeList

 

selList = om2.MGlobal.getActiveSelectionList()

mDagPath = selList.getDagPath(0)
transNode = om2.MFnTransform(mDagPath)
animNodeList = getAnimNodes(transNode)

oma2.MAnimMessage.addNodeAnimKeyframeEditedCallback(animNodeList[0].object(), addNodeAnimKeyframeEditedCallbackMethod) # とりあえず animNodeList の1つ目だけ渡す例

 

OpenMayaAnim.MAnimMessage.addPostBakeResultsCallback()

「シミュレーションのベイク処理」を実行し終わったあとに呼ばれます。

 

# Sample Code ===================================

import maya.api.OpenMayaAnim as oma2

 

def addPostBakeResultsCallbackMethod(*args):

    print(args[0]) # ベイクされたキーたちが MPlugArray で渡される
    print(args[1]) # MDGModifier が渡される

 

oma2.MAnimMessage.addPostBakeResultsCallback(addPostBakeResultsCallbackMethod)

 

OpenMayaAnim.MAnimMessage.addPreBakeResultsCallback()

「シミュレーションのベイク処理」の実行直前に呼ばれます。

 

# Sample Code ===================================

import maya.api.OpenMayaAnim as oma2

 

def addPostBakeResultsCallbackMethod(*args):
    print(args[0]) # ベイクされたキーたちが MPlugArray で渡される
    print(args[1]) # MDGModifier が渡される

oma2.MAnimMessage.addPostBakeResultsCallback(addPostBakeResultsCallbackMethod)

 

OpenMayaAnim.MAnimMessage.flushAnimKeyframeEditedCallbacks()

冒頭でも書きましたが、まだこのコールバックの使い所が分かっていません… 

この関数の説明の Google 翻訳版を載せておきます。

 

アニメーション キーフレーム編集コールバックは、アイドル イベントでのみ発行されるようにキューに入れられます。
特定の時間にコールバックを発行することが必要な場合があります。
このメソッドはこの機能を提供します。
すべてのアニメーション キーフレーム編集コールバックをフラッシュし、その中に含まれるデータを使用してコールバックを発行するように強制します。

 

# Sample Code ===================================

import maya.api.OpenMayaAnim as oma2

 

oma2.MAnimMessage.flushAnimKeyframeEditedCallbacks()