戦国時代で初のキリシタン大名というと大村純忠。
どうも、クリーク・アンド・リバー社 COYOTE CG STUDIO テクニカルチーム 戦国大好き人間の中林です。
先日、僕がMotionBuilder2020(以下、MB)で簡単なツールを作ったのですが、情報が少なく苦労したのでその時の役立ちそうなコマンドのTipsをまとめておきます。
そもそものキッカケは?
モーションさんからMB2020でキャラAとキャラBのジョイントをRelationのConstraintでRotation、Scaling、Translationのノードをつなぐだけのツールを相談されたことです。
それだけと言いながら40本のジョイントの3つノードを手動つなげると120本のノードをつなげることになります。聞いた瞬間に気が遠くなる作業だったのツールを作成することになりました。
色々と問題はあったけど、一番大きなの問題は僕がMBを使ったことがない!!
だと思ったのですがそれは些細な問題でした(笑)
一番の問題はスクリプトの情報が少ない
重要なのでもう一度、一番の問題はスクリプトの情報が少ないことです。
MayaのMelに慣れている人には信じられないと思いますが、Autodesk製品なので操作するたびに出てくるだろうで始めると一切出てきません。そうなると、リファレンスを思うのだけど正直、リファレンスは分かり難いです。
それなので、僕の助言はシンプルでMBのスクリプト諦めろです。
「天は自ら助くる者を助く」と言いますが、サポート側がスクリプトなどの情報を公開してユーザーに使いやすい状態にしないのなら、無理に使うことはないと思います。
とはいえ、モーションさんにがんばって120本のノードを手動でつないでとは言えないのと、あくまで内容がシンプルだったので作成しました。ただし、所々で手動をお願いした部分があります。
その中で、幾つか僕個人の備忘録を含めてコマンドのTipsを挙げておきます。
その前にこの門をくぐる人に一言伝えておきます。
ーーー汝等こゝに入るもの一切の望みを棄てよーーー
■最初に:モジュールについて
from pyfbsdk import *
最近のPythonの主流ではモジュールでアスタリクを使わないのが主流ですが、公式のリファレンスでも他で探したスクリプトでもこちらが主流だったのでアスタリクを使ってます。
また、MayaとMBでは同じオブジェクトでも呼び名が違います。書いてる僕自身がMayaに慣れているため無意識にMaya準拠の呼び方を書いてしまうけど、そこは生暖かくスルーしてください。
■TIPS:全コンポーネント検索
for _comp in FBSystem().Scene.Components:
print(_comp.name)
print(dir(_comp))
FBSystem().Scene.Componentsが最もよく使うコマンドです。
僕自身でも力業に感じますが全コンポーネントをfor文で回して、必要な情報を取得します。泥臭いですがdir()でClassの中身を見てそれらしい情報を探して使いました。
・例1:メッシュモデルのコンポーネント取得
_meshList = []
for _comp in FBSystem().Scene.Components:
if "FBModel" in str(type(_comp)):
_meshList.append(_comp)
print(_meshList)
・例2:joint(Skeleton)の取得
_jointList = []
for _comp in FBSystem().Scene.Components:
if "Skeleton" in str(type(_comp)):
_jointList.append(_comp)
print(_jointList)
個人的に初期にやらかしたことは、この取得のタイミングにコンポーネントを削除したためアドレスがズレて目的外のコンポーネントを削除してしまいました。
削除するものがある場合は、ここでは候補だけをリスト化して別シーケンスで削除することをお勧めします。
■TIPS:名前を指定してモデルを取得
_comp = FBFindModelByLabelName('名前')
これはモデル名から見つけるので名前が分かっている時は便利です。
以前のバージョンではFBFindModelByName()というコマンドがありましたがバグのために廃止されてます。
ここではバグフィックス版のコマンドを紹介します。
■TIPS:コンポーネントの削除
_comp = FBFindModelByLabelName('名前')
_comp.FBDelete()
_delList = []
for _comp in FBSystem().Scene.Components:
if '消したいコンポーネントの条件':
_delList.append(_comp)
_delObejList.reverse() # 親子関係可能性があるので念のため反転
for _del in _delList:
_del.FBDelete()
一括のデリートは今回は見当たりませんでした。
なので、今回はfor文などを利用して個別に削除をしています。
■TIPS:コンポーネントの親子付け
_root = FBModelNull("Null")
_Top = FBModelNull("Null")
_root.ConnectSrc(_Top)
見た目の結果がノードがつながって同じに見えるけど、失敗例は親子付けされてません。意気揚々とツールをリリースしたら、モーションさんから親を回転させたときに子が回転してないと指摘を受けました。
・正解例
_root = FBModelNull("Null")
_Top = FBModelNull("Null")
_Top.Parent = _root # 親子付け
コマンドを探そうとすると大変ですが、単純に考えるとparentクラスに親にしたいコンポーネントを代入するだけで簡単に親子付けできます。
ちなみにコマンドではなくてクラスの内容を直接変更することも色んな場合で有用です。
_comp = FBFindModelByLabelName('名前')
_comp.Color = FBColor(0.0, 0.5, 1.0) # ノードの色変更
_comp.Selected = True # 選択
一例ですがコマンドを探すよりも簡単に処理ができます。
■TIPS:ノードをスクリプトでつなぐ
RelationのConstraintのノードをスクリプトでつなぎます。
Constraintには明確に「sender(送り手)」と「recever(受け手)」があります。
# senderの登録とパラメータ取得
_sender = FBFindModelByLabelName('sendObj')
_sender = _rel.SetAsSource(_sender)
_sendRot = findAnimationNode( _sender.AnimationNodeOutGet(), 'Rotation' )
_sendScl = findAnimationNode( _sender.AnimationNodeOutGet(), 'Scaling' )
_sendTra = findAnimationNode( _sender.AnimationNodeOutGet(), 'Translation' )
# receverの登録とパラメータ取得
_recever = FBFindModelByLabelName('recObj')
_recever = _rel.ConstrainObject(_recever)
_recRot = findAnimationNode( _recever.AnimationNodeInGet(), 'Rotation' )
_recScl = findAnimationNode( _recever.AnimationNodeInGet(), 'Scaling' )
_recTra = findAnimationNode( _recever.AnimationNodeInGet(), 'Translation' )
# ノード同士の接続
FBConnect(_sendRot, _recRot)
FBConnect(_sendScl, _recScl)
FBConnect(_sendTra, _recTra)
今回のブログのメインの目的は未来の僕への備忘録ですが、MBのスクリプトに踏み入れてしまった人への一助になれば幸いです。
もし、このブログを最後まで読んだ人へMB地獄へようこそ、お互いこの困難な仕事を乗り切れるように頑張りましょう。
COYOTE 3DCG STUDIO
公式HP:https://3d.crdg.jp/
COYOTE 3DCG STUDIOはクリーク・アンド・リバー社が運営するゲーム専門3DCG制作集団です。
キャラモデル、背景モデル、3Dアニメーション、テクニカルアーティストによるツール開発などを得意としています。
新規立ち上げにおけるコンサルティングから量産制作まで幅広く対応可能な体制を保有しており、出向にも柔軟に対応しております。