MayaScripts_StaticAnimationRemover:フラットなキーフレームの削除
アニメーションを制作する上で、皆さんが気にしていることはなんでしょうか?
ポージング?タイミング?テンポの良さ?カメラワーク?キャラクター性?
私は、ゴミのようなキーフレームがないかどうか を気にしています。
こういうやつですよ。
キャプチャーデータの編集とか、外部リグに出したり戻したりを繰り返しながら編集するアニメーションに多く存在します。
キーフレーム自体がフルベイクされているのは全く問題ないのですけど、値の変動が一切ないアトリビュートにキーフレームが入っているのが許せません。
単純に不要なアニメーションカーブノードがシーンに含まれていることになりますし、思わぬ不具合に繋がる可能性もあるので、いつも見つけ次第削除しています。
とは言っても、いちいち全てに対応するのも 面倒 なので、これを作成しました。
StaticAnimationRemover
選択ノードのアニメーションのキーフレームに値の変動が見つからなければ、そのアニメーションをゴミとして削除します。
コード
# encoding:utf-8 import pymel.core as pm VERSION = "1.1" print ("-*- import {0}.{1} -*-".format(__name__,VERSION)) SAFEMODE = True ROUND_NUM = 5 def __getAnimatedAttrs (target_node): """任意のノードにて、AnimCurveに接続されたAttrを返す""" # type:(pm.PyNode) -> list[pm.general.Attribute] animatable_attrs = target_node.listAnimatable() return [a for a in animatable_attrs if a.connections(t = "animCurve", d = False)] def __isStaticKeyframe (keyframe_values): """与えられたキーフレーム値が最初の値から変化しないか""" # type:(list[float]) -> bool firstframe_value = round(keyframe_values[0], ROUND_NUM) return len([v for v in keyframe_values if firstframe_value != round(v, ROUND_NUM)]) == 0 def __isStaticAnim (target_attr): """与えられたAttrのKeyframeが最初の値から変化しないか""" # type:(pm.general.Attribute) -> bool animCurve = target_attr.connections(t = "animCurve") keyframe_values = pm.keyframe(animCurve, q = True, vc = True) return __isStaticKeyframe(keyframe_values) def __getStaticAnimAttrs (target_node): """任意のノードからAnimateされていないAttrを取得""" # type:(pm.PyNode) -> list[pm.general.Attribute] return [a for a in __getAnimatedAttrs(target_node) if __isStaticAnim(a)] def __showConfirmDialog (target_attrs, deleteAll): """削除対象Attrを表示するDialogを出す""" # type:(list[pm.general.Attribute], bool) -> bool if not SAFEMODE : return True msg = "\n".join([str(a.name()) for a in target_attrs]) y_string = "Delete" if deleteAll else "Clear" dialog = pm.confirmDialog(t = "{0}StaticAnim".format(y_string), m = msg, b = [y_string,"Cancel"]) return dialog == y_string def __getTimerange (): """現在のTimerangeを返す""" # type:() -> list[float] return [ pm.playbackOptions(q = True, min = True) + 1, pm.playbackOptions(q = True, max = True) - 1, ] def __deleteAnim (target_attrs, deleteAll): """対象AttrのAnimを削除する""" # type:(list[pm.general.Attribute], bool) -> bool if not target_attrs : return False if not __showConfirmDialog(target_attrs, deleteAll) : return False if deleteAll: pm.cutKey(target_attrs) return True pm.cutKey(target_attrs, t = __getTimerange()) return True def __getAllStaticAnimAttr (target_nodes): """任意のノードからAnimateされていないAttrを全て取得""" # type:(list[pm.PyNode]) -> list[pm.general.Attribute] static_attrs = list() for n in target_nodes: static_attrs.extend(__getStaticAnimAttrs(n)) return static_attrs def main (): selection = pm.selected() isDeleteAll = pm.getModifiers() == 8# Alt押しながらで全削除 result = __deleteAnim(__getAllStaticAnimAttr(selection), isDeleteAll) pm.headsUpMessage("-*- Remove Static Animations {0}. -*-".format("Done" if result else "Canceled"))
また面倒ごとが一個減った。
■ インストール
上記のコードを適当な名前でPythonファイルとして保存して、
C:\Users\ユーザー名\Documents\maya\scripts
に配置してください。
そして、以下のコードで実行します。
import StaticAnimationRemover
StaticAnimationRemover.main()
■ 使い方
- ゴミを清掃したいノードを全て選択した状態で実行してください。
- 削除対象のアトリビュート名がダイアログで表示されます。
- Enterを押すと削除完了です。
ちなみにソースコード内の定数:「SAFEMODE」を「False」にするとダイアログは表示されなくなります。
また、「Altキー」を押しながら実行すると、AnimationCurveごと削除します。
■ 余談
同じような条件のアトリビュートでも、場合によっては必要なものとして残しているものもありますが・・・経験上、ただのゴミであることが多いです。
リグを制作する際に、Animatableでないアトリビュートは ロック しておくと、このようなゴミアトリビュートが発生しにくいので、リグ制作の際は忘れずに。
以上です。