MayaScripts_AddAnimatedAttrToAnimLayer : アニメーションレイヤーへのAttr追加補助
AnimationLayerを利用する際、アニメートされているAttributeだけをAnimationLayerに追加したいと思ったことはありますか?
AnimationLayerに対してノードを追加する際、いつも対象のノードを選択した状態でAnimationLayerEditor上のLayerを右クリックして表示されるコンテキストメニューから「選択したオブジェクトの追加」を実行しているのですが、この機能だとアニメート可能な全てのTransformAttributeとVisiblityがLayerに追加されてしまい・・・後にAnimationLayerをマージする際にLayerに追加された全てのAttributeがベイクされてしまいます。マージ時にスマートベイク等を利用すれば結果は変わりますが、AnimationLayerの利用目的にもよりますが、基本的にはベースのアニメーションに対して加算的にLayerを使いたいことの方が多いように思います。よって、そもそもアニメートされていないAttributeがLayerに追加される必要はないことが殆どではないでしょうか。
任意のAttributeだけをAnimationLayerに追加するには、チャンネルボックス上でAttributeを選択し、右クリックすると、コンテキストメニューに「選択したレイヤに追加」とありますので、これを実行すると良いのですが・・・対象のAnimationLayerを選択して、Attributeを選択して・・・と少々面倒に感じます。
なので、自動化するスクリプトを作りました。
AddAnimatedAttrToAnimLayer
# encoding:utf-8 import pymel.core as pm VERSION = "0.2" print ("\n-*- import {0}.{1} -*-".format(__name__,VERSION)) # 選択しているレイヤーがなかった場合の挙動 WITH_CREATE_NEWLAYER = True# 新規レイヤーの作成を行う PRIORITY_CREATE_LAYER = False# 新規レイヤーの作成を優先する PRIORITY_EXIST_LAYER = True# 既存レイヤーを優先する SKIP_BASE_LAYER = True# Baseレイヤーを対象から除外する ANIM_LAYER = ["animLayer"]# 対象とするAnimLayerノード TARGET_NODE_TYPES = ["animCurve","animBlendNodeBase"]# Animatedと判断する接続ノードの種類 def __listAnimatableAttrsFromNode (target_nodes): """任意のノードから、AnimatableなAttrを返す""" # type:(list[pm.PyNode]) -> list[pm.general.Attribute] animatable_attrs = list() for n in target_nodes: animatable_attrs.extend(n.listAnimatable()) return animatable_attrs def __popAnimatedAttrs (target_attributes): """Attrのリストから、TARGET_NODE_TYPESに接続されているAttrだけを抽出""" # type:(list[pm.general.Attribute]) -> list[pm.general.Attribute] animated_attrs = list() for a in target_attributes: if a.connections(t = TARGET_NODE_TYPES, d = False): animated_attrs.append(a) print ("Animated attributes = {0}".format(animated_attrs)) return animated_attrs def __listAllExistAnimLayers (): """存在するAnimLayerを全て返す""" # type:() -> list[pm.nodetypes.AnimLayer] return [pm.nodetypes.AnimLayer(n) for n in pm.ls(type = ANIM_LAYER)] def __getSelectedAnimLayersFromEditor (): """AnimLayerEditorで選択されているAnimLayerを返す""" # type:() -> list[pm.nodetypes.AnimLayer] selected_animlayers = list() base_layer = pm.animLayer(q = True, r = True) for al in __listAllExistAnimLayers(): if SKIP_BASE_LAYER and al == base_layer : continue if pm.animLayer(al, q = True, sel = True): selected_animlayers.append(al) print ("Selected AnimLayers = {0}".format(selected_animlayers)) return selected_animlayers def __addAttrToAnimLayers (target_attrs, target_animlayers): """任意のAttrを任意のAnimLayerに追加する""" # type:(list[pm.general.Attribute],list[pm.nodetypes.AnimLayer]) -> None for al in target_animlayers: pm.animLayer(al, e = True, at = target_attrs) print ("Add Attrs:\n{0} \n\tto {1}".format([a.name() for a in target_attrs],target_animlayers)) def __createNewAnimLayer (name = "NewAnimLayer"): """新規AnimLayerを作成する(または同名のAnimLayerを返す)""" # type:(str) -> list[pm.nodetypes.AnimLayer] animLayer = None isAlreadyExist = pm.animLayer(name, q = True, ex = True) if isAlreadyExist and PRIORITY_CREATE_LAYER: animLayer = pm.animLayer(name + "_new")# 必ず新規Layerを作成 elif not isAlreadyExist: animLayer = pm.animLayer(name)# 新規Layerを作成 else: animLayer = pm.nodetypes.AnimLayer(name)# 既存の同名Layerを取得 print ("Create or ExistAnimLayer = {0}".format(animLayer)) return [animLayer] def __findAnimLayerWithAttrs (target_attrs): """任意のAttrがIncludeされているAnimLayerを返す""" # type:(list[pm.general.Attribute]) -> list[pm.nodetypes.AnimLayer] found_animLayers = list() for al in __listAllExistAnimLayers(): if al == pm.animLayer(q = True, r = True):continue layered_attrs = al.getAttributes() for a in target_attrs: if a in layered_attrs and al not in found_animLayers: found_animLayers.append(al) return found_animLayers def __getValidAnimLayers(target_attrs): """有効なAnimLayerを返す""" # type:(list[pm.general.Attribute]) -> list[pm.nodetype.AnimLayer] animLayers = __getSelectedAnimLayersFromEditor() if animLayers: return animLayers if PRIORITY_EXIST_LAYER: animLayers = __findAnimLayerWithAttrs(target_attrs) if not animLayers and WITH_CREATE_NEWLAYER: animLayers = __createNewAnimLayer() return animLayers def __addAnimatedAttrToLayer (target_nodes): """選択しているノードのAnimatedなAttrをAnimLayerへ追加する""" # type:(list[pm.PyNode]) -> None animatable_attrs = __listAnimatableAttrsFromNode(target_nodes) target_attrs = __popAnimatedAttrs(animatable_attrs) if not target_attrs : return target_animLayers = __getValidAnimLayers(target_attrs) if not target_animLayers : return __addAttrToAnimLayers(target_attrs, target_animLayers) def main (): __addAnimatedAttrToLayer(pm.selected())
実行するには下記を参照。
import AddAnimatedAttrToAnimLayer
AddAnimatedAttrToAnimLayer.main()
実行すると、選択しているAnimationLayerに対して、シーン上で選択中のノードのアニメートされているAttributeだけが追加されます。 選択しているAnimationLayerがない場合は、新規でAnimationLayerを生成し、そのLayerを対象とします。
余談
ずっと疑問なんですけど、Mayaコマンドの「animLayer」の引数のひとつに「bestLayer」というものがありますけど、何をもってベストとするのか、イマイチ理解できていません。 公式のコマンドに「ベスト」という単語が使われているのも珍しくないっすか?そうでもない? しかし、ベストて・・・なんかのコマーシャル以外で聞かない単語ですよね。
もうひとつ疑問。 AnimationLayerEditorの各Layer名の右横にある、緑とか赤色のドットインジケーター。
それぞれ、なにを意味しているかは理解できているつもりなんですが、このインジケーターの正式名称て何? 公式のリファレンスには「アクティブなキーイング フィードバック」とか書いてあるけど、ではこれをコマンドから参照するには、なんという名前なの?って話。