
[Maya] Pythonで作業を楽にしよう③:スキンバインドの移植自動化
初めに
Volca の Rikuです。
「Pythonで作業を楽にしよう」シリーズの第三弾になります。
Mayaでキャラクター3Dモデルなどを作成する際、
スキンバインド後にパーツを追加したり、ポリゴンを調整したりすると、
修正のたびにスキンバインドの移植作業が必要になることがあります。
そこで今回は、このような煩雑な作業をワンクリックで実行できるスクリプトをご紹介します。
< 注意 >
このシリーズの記事はMaya 2022以降のバージョンをもとに紹介します(Python 3.x対応)
手動で作業する場合の手順
通常、バインド済みのモデルAのバインドをモデルBに移植する際の手順は
モデル A にバインドしたジョイントを選択
モデル B を追加で選択
Skin Bindを実行
選択を全解除後、再度「移植元(A)」→「移植先(B)」の順で選択
Copy Weightを実行して完了
となります。
この作業は、特にローポリモデルAからハイポリモデルBに移したい場合なんかによく発生します。具体的には、
モデルAを複製し、モデルBにリネーム
BにMesh Smoothを適用
BのHistoryを削除(バインドの邪魔になるため)
上記の手順に従って、AのバインドをBに移植
といった工程になります。
これらの手動作業をスクリプト化することで、大幅に効率化できます。
今回使うコマンドの紹介
以下は、前前回の第一弾「メッシュごとのFBXエクスポート」で紹介したコマンドです。
import maya.cmds as cmds
print()
cmds.ls()
cmds.select()
for文
今回新たに以下のコマンドを使います。
def xx():
一連のコマンドを一つにまとめて再利用可能にする「関数化」を行います。一度宣言すれば、後は呼び出すだけで実行可能になる便利な機能です。cmds. skinCluster()
スキンクラスタを操作するコマンドです。
移植元のジョイント取得や移植先のバインド作成に使用します。cmds.duplicate()
オブジェクトを複製するコマンドです。
複製時に名前を変更することもできます。cmds.polySmooth()
モデルにスムーズを適用するコマンドです。
今回はこれを使ってハイポリモデルを作成します。cmds.listRelatives()
指定したモデルに関連付けられた要素を取得するコマンドです。
今回はヒストリ内のスキンクラスタを取得するために使用します。cmds.listHistory()
モデルのヒストリを操作するコマンドです。
今回はShapeとリンクしているスキンクラスタを取得するために使用します。cmds.delete()
オブジェクトやヒストリなどを削除する際に使用します。
今回はモデルの不要なヒストリを削除します。cmds.rename()
オブジェクト名を変更するコマンドです。append()
リストに新しい要素を追加するためのメソッドです。
今回はジョイントリストにモデルを追加する際に使用します。
細かい説明は省いて、早速実践に進みましょう。
( コマンドの詳細については、公式コマンドドキュメントをご参照ください )
復習:Pythonの基本的な書き方
以下のサンプルコードは、選択したモデルにバインドされているジョイントを取得するものとなっています。
スクリプトエディタに以下のコードを入力して、
バインド済みモデルを選択した状態で「Execute All」で実行してみましょう。
import maya.cmds as cmds
print('処理スタート')
selectedObjects=cmds.ls(selection=True, type='transform')
#リストのコマンド、絞り込み条件は選択中かつtransform属性を持っているもの
for perObject in selectedObjects:
joints=cmds.skinCluster(perObject, query=True,influence=True)
#バインドしているジョイントを取得
print(joints)
print('処理終わり')
画像のような結果が得られます。

実践A:バインド済みのモデルAのバインドをモデルBに移植
defを使用する場合、インデント(Tab)の数が変更されるため注意が必要です。
def xx()の内部コードは、外部のコードより1段下げる必要があります(インデントを正確に揃えることが重要です)。
バインド済みのモデルAと未バインドのモデルBを用意し、モデルA→モデルBの順番で選択した状態で、以下のスクリプトを実行してみてください。
import maya.cmds as cmds
def bindAtoB(modelA,modelB,*args):
#1.モデルAにバインドしたジョイントを選択
joints=cmds.skinCluster(modelA, query=True,influence=True)
#2.モデルBを選択に追加
joints.append(modelB)
#3.Skin Bindを行う
modelBsc=cmds.skinCluster(joints,toSelectedBones=True)
modelBsc=modelBsc[0]
#4.modelA の SkinCluster を History経由で取得
modelAshape=cmds.listRelatives(modelA, shapes=1, noIntermediate=1)
modelAhstr=cmds.listHistory(modelAshape[0],pruneDagObjects=1,interestLevel=2)
modelAsc=cmds.ls(modelAhstr,type="skinCluster")[0]
print('modelAのSkinClusterは:')
print(modelAsc)
print('modelBのSkinClusterは:')
print(modelBsc)
#5.Copy Weight を行う
#modelA の skinCluster から取得
cmds.copySkinWeights(
sourceSkin=modelAsc,
destinationSkin=modelBsc,
noMirror=1,
influenceAssociation="oneToOne",
surfaceAssociation="rayCast",
)
print('移植完了')
#-----
print('処理スタート')
selectedObjects=cmds.ls(selection=True, type='transform')
bindAtoB(selectedObjects[0],selectedObjects[1])
print('処理終わり')
#-----
画像のような結果が得られます。
エラーが出なければ、移植完了です。

実践B:バインド済のモデルAをハイモデル化
実践Aで作成した関数 bindAtoB を再利用して、こんどは以下のプロセスもスクリプトで自動化します:
モデルAを元に移植先のモデルBを作成。
自動的に bindAtoB を適用し、モデルAをワンクリックでハイポリ化。
シーンにローポリのモデルAを用意し、以下のコードを実行してみましょう。
import maya.cmds as cmds
smoothLevel=2
# Smooth をかける倍率
# smoothLevel の値で mesh smooth の倍率を変えられる
def bindAtoB(modelA,modelB,*args):
#1.モデルAにバインドしたジョイントを選択
joints=cmds.skinCluster(modelA, query=True,influence=True)
#2.モデルBを選択に追加
joints.append(modelB)
#3.Skin Bindを行う
modelBsc=cmds.skinCluster(joints,toSelectedBones=True)
modelBsc=modelBsc[0]
#4.modelA の SkinCluster を History経由で取得
modelAshape=cmds.listRelatives(modelA, shapes=1, noIntermediate=1)
modelAhstr=cmds.listHistory(modelAshape[0],pruneDagObjects=1,interestLevel=2)
modelAsc=cmds.ls(modelAhstr,type="skinCluster")[0]
print('modelAのSkinCluster:')
print(modelAsc)
print('modelBのSkinCluster:')
print(modelBsc)
#5.Copy Weight を行う
#modelA の skinCluster から取得
cmds.copySkinWeights(
sourceSkin=modelAsc,
destinationSkin=modelBsc,
noMirror=1,
influenceAssociation="oneToOne",
surfaceAssociation="rayCast",
)
print('移植完了')
#-----
print('処理スタート')
selectedObjects=cmds.ls(selection=True, type='transform')
model_lo=selectedObjects[0]
model_hi=cmds.duplicate(model_lo,n=model_lo+'_hi')
#対象モデルを複製し、リネーム
cmds.polySmooth(model_hi,dv=smoothLevel)
#Smoothをかける
cmds.delete(model_hi,ch=1)
model_hi=cmds.ls(model_hi, type='transform')[0]
#SmoothのHistoryを削除
bindAtoB(model_lo,model_hi)
print('処理終わり')
#-----
画像のような結果が得られます。

終わりに
スキンバインドの移植のスクリプト紹介は以上です。
スクリプトの複雑さが増すと、使い方を覚えるのがだんだん大変になってきますね。
というわけで次回は、UIを導入してスクリプトをより使いやすく改造する方法を紹介します。
次回の記事もお楽しみに!