【Maya tools and scripts】DreamWall Pickerの使い方

Mayaでアニメーションを作っていると、コントローラーを選ぶだけで意外と時間がかかります。人型の絵の上をクリックして選ぶピッカーが、配布リグに付いてくることが多く、中身は AnimSchool Picker か MG-Picker Studio のものが大半です。AnimSchool 同梱なら、公式ストアでライセンスを有効化するところから始まります。
結論から言うと、私がいま使っているのは DreamWall Picker(dwPicker) です。ベルギーのアニメーションスタジオ DreamWall が公開している、完全無料・MITライセンスのオープンソース ピッカーです。商用案件でもスタジオ内でも、ライセンスの縛りがありません。AnimSchool Picker の .pkr を標準機能で取り込める ので、ボタンを並べ直す必要は基本的になく、AnimSchool 本体を入れなくても同梱の .pkr だけで使えます。
MG-Picker を使っているリグの場合は、AnimSchool と違って dwPicker へ一発では移せません。どうしても DreamWall Picker 一本に統一したいときは、画面を見ながらボタンを置き直すなど、手動で移行することはできます。
入れ方、基本操作、AnimSchool の .pkr の取り込み、自作まで書きます。作例は、以前紹介した MegaBuBu さんの Reimu Animation Rig です。
リグそのもののレビューは、過去記事にまとめてあります。
関連記事「Reimu Animation Rig」Mayaリグレビュー公式リポジトリは GitHub(DreamWall-Animation/dwpicker) です。ドキュメントは Official Documentation にあります。
DreamWall Picker とは

dwPicker は、Maya 上でキャラクターのコントローラーを GUI から選ぶためのピッカーです。人型のガイド画像の上にボタンを置き、クリックでコントローラーを選択します。Python / MEL のコマンドボタンも置けます。
作者は Lionel Brouyère さんと Olivier Evers さんです。Hotbox Designer のフォークから始まっています。
2021年の暮れ、DreamWall はそれまで使っていた AnimSchool Picker のライセンス事情で、制作中のピッカー 200 個以上にアクセスできなくなりかけました。現場を止めるわけにはいかないので、自分たちで代替を書き、同じ事情のスタジオにも使えるようオープンソースで無料公開しています。AnimSchool の .pkr を標準で取り込めるのは、そのときのピッカーを並べ直さずに使い続ける必要があったからです。
公式の対応表記は Maya 2018〜2025 です(README 上は Maya 2017 以降)。Maya 2025 向けの PySide6 対応は Release に入っています。Maya 2026 と 2027 は公式の対応表にはまだ載っていません。Maya 2027 では、ドラッグ&ドロップで入り、シェルフからウィンドウが開きました。
入れるときは、GitHub の Releases の 最新版 を使ってください。AnimSchool の取り込み修正は 1.0.3 以降 に入っています。本稿執筆時点(2026年9月)の最新は 1.0.4 です。
なぜ今 dwPicker なのか
Maya 向けのピッカーはいくつかあります。主なものを並べます。
| ツール名 | タイプ | 主な強み | コスト / ライセンス |
|---|---|---|---|
| DreamWall Picker | GUI / 汎用 | 軽量、オープンソース、JSON、AnimSchool の .pkr を取り込める | 無料(MIT) |
| AnimSchool Picker | GUI / 汎用 | 長年の定番、操作感が完成している | 条件付き無料 / サブスク有料 |
| MG-Picker Studio | GUI / 高機能 | 配布リグ同梱が多い、機能が多い | Animator 版無料 / 作成は有料 |
| FT Anim Picker | GUI / マルチ | Blender と Maya の両方 | 無料(オープンソース) |
| mGear Anim Picker | 統合型 | mGear リグとの連動 | 無料(オープンソース) |
| Studio Library | リスト型 | ポーズ・ミラー・セット選択 | 無料 |
私が dwPicker を選んでいる理由です。
- 完全無料・MIT: 商用でも再配布でも、ライセンスで止まらない
- AnimSchool からの移行が簡単:
.pkrを File → Import するだけ(Reimu で後述) - データが JSON: プレーンテキストなので、壊れてもテキストエディタで中を見られる
- コードが GitHub にある: Maya のバージョンが上がっても、自分たちで直せる/直してもらえる余地がある
AnimSchool Picker は今でも使えます。入手は AnimSchool Store で、ライセンスキーの有効化が必要です。Indie は年収 8 万ドル未満なら無料、それを超えると有料のサブスクです。dwPicker なら、その手続きなしで Reimu の .pkr が読めます。
MG-Picker は高機能ですが、保存は独自の暗号化(.mgpkr)です。dwPicker が取り込めるのは AnimSchool の .pkr だけで、.mgpkr は直接読めません。 MG-Picker 側も、標準では AnimSchool の .pkr を開きません。Animator 版は同梱の .mgpkr を使うためのものです。
他ツールとの使い分け
ピッカーの用途は、基本的にコントローラーの選択です。ポーズやアニメーションの登録・呼び出しには別のツールが要ります。現場では Studio Library と併用することが多いです。
Studio Library と併用する
人型の絵の上で選ぶのが dwPicker、ポーズやクリップの登録・呼び出し・ミラーが Studio Library です。
関連記事【Maya tools and scripts】Studio Library の使い方Studio Library の Selection Set だけでもコントローラー選択はできます。ピッカーが無いリグでは十分役に立ちます。ただし人型の絵の上をクリックする速さには、GUI ピッカーのほうが勝ります。
FT Anim Picker という選択肢
FT Anim Picker は Maya と Blender の両方で使えるオープンソースのピッカーです。SVG でボタン形状を作れるなど、見た目の自由度は高いです。Blender と Maya をまたいで同じピッカー環境にしたい人向きです。
Maya 単体で、今ある AnimSchool の .pkr を活かしたいなら dwPicker です。
mGear のリグなら、付属の Anim Picker で足ります。汎用ピッカーとして dwPicker を足す必要はありません。Anim Picker の保存も .pkr ですが、AnimSchool の .pkr とは別物で、dwPicker では読めません。
インストールと起動
ダウンロード
GitHub の Releases から、最新の zip をダウンロードします。ソースの main ブランチを直接使うより、Release のほうが安全です。
1.0.3 以降 を入れてください。これより前だと、新しい AnimSchool 形式の .pkr 取り込みで失敗することがあります。本稿執筆時点の最新は 1.0.4 です。Reimu の .pkr を読む前に、ここを済ませておきます。
ドラッグ&ドロップで入れる
公式の入れ方です。Maya 2027 でも、この手順どおり入りました。
- zip を解凍する
- 解凍したフォルダの中の
drag_and_drop_to_maya_install.pyを、Maya のビューポートへドラッグ&ドロップする - ダイアログで入れ方を選ぶ
入れ方は2つあります。
| モード | 内容 | 向いている人 |
|---|---|---|
| Into Maya's Scripts Folder | 起動中の Maya の scripts フォルダへコピーし、シェルフボタンを作る | 普通はこちら |
| From the Current Folder | 今ある場所を参照するシェルフボタンだけ作る | フォルダを動かさない人 |
特別な事情がなければ、Into Maya's Scripts Folder を選んでください。

ファイルは次のフォルダに入ります。中に dwpicker フォルダができます。
- Windows:
C:\Users\ユーザー名\Documents\maya\<バージョン>\scripts - macOS:
~/Library/Preferences/Autodesk/maya/<バージョン>/scripts - Linux:
~/maya/<バージョン>/scripts
シェルフから起動する
インストールが通ると、シェルフに起動ボタンが付きます。Maya 2027 では、このボタンからウィンドウが開きました。初回はキャンバスが空で、メニューは File / Edit / Help です。中身は次です。
import dwpicker
dwpicker.show()
ボタンが付かない、または消してしまった場合は、スクリプトエディタ(Python)に貼って実行し、シェルフへ中ボタンドラッグで登録してください。ホットキーで出したり消したりするなら、同じ import のあとに dwpicker.toggle() を登録します。実行するたびに表示が切り替わります。
基本的な使い方
シェルフから dwPicker を開いた直後の操作です。ピッカーがまだ空なら、File → Open で .json を出すか、File → Import で AnimSchool の .pkr を取り込みます。Reimu での取り込み手順は次の章です。
ビューの操作
キャンバスは、一般的なピッカーと同じ感覚です。
- ズーム … ホイール、または Maya と同じ Alt + 右ドラッグ
- パン … 中ドラッグ
- ビューのリセット …
F(Focus)。既定ではボタンに合わせる。背景画像に合わせる方法は、後半の背景の節 - 単一選択 … ボタンを左クリック
- 追加選択 … Shift + クリック
- 範囲選択 … ドラッグでボックス選択
選択は Maya のビューポートと同期します(既定でオン)。ピッカーで選ぶとシーン側も選ばれ、逆も同じです。
ネームスペース(複数キャラ)
リファレンスしたキャラにはネームスペースが付きます。dwPicker は、ウィンドウ上部のコンボボックスで対象を選びます。ツールバーが出ていないときは、設定から Namespace Toolbar を表示してください。
同じリグを複数体入れるとき(Reimu が2人など)は、このコンボボックスで切り替えます。選択ボタンは、コンボボックスをリファレンスのネームスペースに合わせます。Reimu なら Outliner の : より前(例: Reimu_Rig_master)です。AnimSchool のときのように : に戻す必要はありません。入れ子のネームスペースは標準では1段だけです。
Sanae を同じシーンに足すときは、Reimu のピッカーのネームスペースを切り替えるより、Sanae 同梱のピッカーを別途読み込んでください。 コンボボックスでも体の選択はできますが、衣装や小物のコントローラーはリグごとに違うので、Sanae は Sanae のものを使った方が確実です。
FK/IK マッチのようなコマンドボタンは別です。Reimu の例は取り込みの章にあります。
パネル(Body / Face など)
メインウィンドウのタブは、開いているピッカーファイルの数です。Reimu の Body と Face を別々に Import するとタブが2つになります。Sanae も同じだと4つです。
1つの JSON の中を全身/顔で分けるのが パネル です。T(Edit → Toggle Panel Display Mode)で、左右分割とサブタブを切り替えます。作り方は後半の Advanced Editor です。
階層選択
ボタンに親子が付いていると、ダブルクリック でそのボタンと配下をまとめて選べます。キャンバス上の矢印は、子から親へ向かって描画されます。
Reimu の .pkr 取り込みでは、親子は来ません。設定のオンオフではなく、Advanced Editor で子ボタンを Alt ドラッグして親へドロップすると付きます。肩なら、肘と手首を肩へドロップします。矢印が出ていれば、ダブルクリックで配下まで選べます。
矢印が邪魔なら Edit → Toggle Hierarchy Display、または Y で隠せます。
よく使うショートカット
既定のホットキーです。
| キー | 動作 |
|---|---|
F | ビューをリセット(Focus) |
T | パネルの分割/タブ表示を切り替え |
Y | 階層の矢印表示を切り替え |
Ctrl + E | Advanced Editor(編集) |
Ctrl + O | 開く |
Ctrl + S | 保存 |
Ctrl + N | 新規 |
Ctrl + Z / Ctrl + Y | アンドゥ / リドゥ |
アニメーション中は、F とタブ切り替えとネームスペースが分かっていれば作業できます。
今回の作例——MegaBuBu「Reimu Animation Rig」
取り込みの実例に使うのは、MegaBuBu さん(Chonlawat Thammawan さん)の Reimu Animation Rig です。Gumroad から 無料 で入手できます。ShaderFX のトゥーンシェーダー付きで、Viewport 2.0 のままプレイブラストしても見栄えがします。同梱ピッカーは AnimSchool Picker です。Body と Face が別ファイルになっています。
以前のレビューでは、AnimSchool Picker 本体の入手が難点でした。dwPicker ならそこを通らずに済みます。ただし取り込みだけでは Match FK to IK / Match IK to FK は動きません。 選択はすぐ使えます。Match の直し方は後述です。リグの中身(スカートのコリジョン、目のプリセット、FK/IK など)はレビュー側を見てください。
仕様がほぼ同じ Sanae も、同梱の .pkr を同じ手順で取り込みます。Reimu のピッカーを流用するより、Sanae のものを読んでください。リグの詳細は、冒頭のレビュー記事を見てください。
関連記事「Reimu Animation Rig」MayaリグレビューReimu のピッカーを dwPicker に取り込む
AnimSchool で作った .pkr は、作り直しなしで取り込めます。 Reimu で一度やれれば、他の配布リグの .pkr も自作の .pkr も同じです。
(※ここに Reimu のフォルダ内で .pkr が見えているエクスプローラーのスクショを挿入予定)
1. リグを入手して解凍する
- Reimu Animation Rig(Gumroad) からダウンロードする
- zip を解凍する
Pickerフォルダの中を.pkrで探す(Body 用と Face 用が分かれている)
私が使ったバージョンでは Reimu_Picker_Body_v3.pkr と Reimu_Picker_Face_v3.pkr でした。名前は配布バージョンで違うことがあります。Maya のシーンファイル(.ma / .mb)も、同じ配布物の中にあります。
2. リグをシーンへリファレンスする

Maya では、配布リグは リファレンス で読むのが基本です。アップデートと、アニメーションシーンの容量の両方に効きます。以前のレビューでも、Reimu はリファレンス運用を前提に書いています。
- File → Create Reference
- Reimu の
.ma(または.mb)を指定する - ビューポートにキャラが出ていることを確認する
インポート(ファイルをシーンに飲み込む)でもピッカーは読めますが、このあとのネームスペース切り替えを考えると、リファレンスのほうが後が楽です。
(※ここにリファレンス後の Reimu と、Reference Editor のスクショを挿入予定)
3. dwPicker で .pkr を Import する
- シェルフから dwPicker を開く(
dwpicker.show()) - File → Import を選ぶ
- Reimu_Picker_Body_v3.pkr を指定する
- JSON に変換されて、dwPicker のタブに載る
- 同じ手順で Reimu_Picker_Face_v3.pkr も Import する
AnimSchool Picker は起動しません。登録も不要です。File → Import が、.pkr を dwPicker 形式へ変換する入口です。
取り込み後は File → Save(Ctrl + S)で、それぞれ .json として保存してください。次回からは JSON を Open すれば済みます。Reimu のフォルダに並べて置くと、後から探しやすいです。
4. 取り込み後に確認すること

ボタンの再配置は、基本的にしなくて大丈夫です。取り込んだあとに私が見ているところだけ挙げます。
- ネームスペース … リファレンスしているので、ウィンドウ上部のコンボボックスが Reimu のネームスペースになっているか。ツールバーが出ていないときは、設定から Namespace Toolbar を表示する
- Body と Face … タブが2つあるか。片方しか読んでいないと、顔または全身が選べない
- クリックで選べるか … 手足のコントローラーを1つ押し、ビューポートの選択が連動するか
公式ドキュメントの対象は「2022年より前に作った AnimSchool ピッカー」です。それ以降の形式(AnimSchool v4 など)は、以前インポートが壊れることがあり、1.0.3 で修正 されています。Reimu の .pkr が読めないときは、ボタンを並べ直す前に dwPicker の Release が最新か を疑ってください。
IK/FK マッチのボタンについて
Reimu リグには Match FK to IK / Match IK to FK があります。IK で置いた手足を FK に渡す、その逆も、ボタン1つです。AnimSchool では重宝していましたが、リファレンスだとピッカーのネームスペースを : に戻してから押す必要がありました。
dwPicker に取り込むとスクリプトは空になります。ボタンは残りますが、押しても無反応です。リファレンスでもインポートでも同じです。次のコードなら、リファレンスのままで動きます。
載せ直すときは、空の Scripts を直接いじるのではなく Add command です。Ctrl + E で Advanced Editor を開き、左のキャンバスで Match FK to IK(または Match IK to FK)を選びます。右の Action で、Targets は空のまま、Scripts の Add command を押します。

Edit/Create command が開きます。Language は python、Mouse button は left。Unique undo はオン、Eval deferred はオフ。Ctrl と Shift はオフのままです。Code 欄を空にして、次の Python を貼って Ok します。

コメントは 英数字のみ にしてください。日本語が入ると、Windows では File → Open で真っ白になります(UTF-8 ではなくシステムエンコードで開くため)。
dwpicker.current_namespace() は使いません。取り込み後のターゲットは ::ctrl のままで、空が返るからです。短い名前があればそれを使い、なければ *:名前 で拾います。Maya 2027 の Reimu で、リファレンス(Reimu_Rig_master:)とネームスペースなしのインポートの両方を確認しています。
Reimu v8 の IKFK は 0 が IK、1 が FK です。割り当てはリグによって違うので、流用するときは確認してください。初期値は腕が FK(1)、足が IK(0)で、これは仕様です。AnimSchool 同梱も同じ値なので、記事のスクリプトも合わせています。Match の前に、いま操作している側のコントローラーでポーズを付けてから押してください。
AnimSchool 同梱は matchTransform ではなく、option の message 属性(fkC1〜fkC3、ikJ1〜ikJ3、fkJ3 など)からノードを取り、一時 parentConstraint で合わせます。下のスクリプトは、焼き付け(行列の読み出し→constraint 削除→書き戻し)を足しています。
ボタン名は 切り替え先 です。
| ボタン | やること | 切り替え後のモード |
|---|---|---|
| Match FK to IK | いまの FK ポーズに IK を合わせる → IK モードへ | IK(IKFK = 0) |
| Match IK to FK | いまの IK ポーズに FK を合わせる → FK モードへ | FK(IKFK = 1) |
スクリプトで気をつけたところです。
- 焼き付け … 一時
parentConstraintのあと、ワールド行列/位置を読んでから constraint を消し、値を書き戻してキーを打つ。消す前にキーだけ打つと、ポーズがデフォルトに戻ることがある - 足の足首 … FK と IK でローカル軸が違う。同じ
Rotate Yでも向きが合わない。fkJ3(L_ik_ankle_orientOffset_drvjnt/R_…、jointOrient 約 90,0,90)を使い、FK→IK はfkJ3→ikC3、IK→FK はfkC3_world = inv(JO) * ikC3_world - 腕 … AnimSchool 同梱どおり
fkJ3/ikJのワールド合わせ - 選択 … 何も選ばないと四肢すべて。片肢だけなら、そのコントローラーを選んでから押す
Maya 2027 の Reimu v8 で、立ちポーズと動かしたポーズの往復を確認済みです。
Match FK to IK(いまの IK ポーズに FK を合わせ、FK へ切り替える):
from maya import cmds
import maya.OpenMaya as om
def n(name):
short = name.split(':')[-1]
if cmds.objExists(short):
return short
hits = cmds.ls('*:' + short) or []
if hits:
return hits[0]
cmds.warning('missing ' + short)
return None
def conn(opt, attr):
node = n(opt)
if not node:
return None
hits = cmds.listConnections(node + '.' + attr, s=True, d=False) or []
return hits[0] if hits else None
LEG_OPTS = frozenset(('L_leg_option_ctrl', 'R_leg_option_ctrl'))
FOOT_OPTION = {
'L_leg_option_ctrl': 'IK_L_foot_option_ctrl',
'R_leg_option_ctrl': 'IK_R_foot_option_ctrl',
}
def zero_local(name):
node = n(name)
if not node:
return
for attr in ('tx', 'ty', 'tz', 'rx', 'ry', 'rz'):
plug = node + '.' + attr
if cmds.getAttr(plug, settable=True):
cmds.setAttr(plug, 0)
def match_ik_to_fk(option):
# Snap IK controls to FK pose (used by Match FK to IK)
ikC1 = conn(option, 'ikC1')
ikC2 = conn(option, 'ikC2')
ikC3 = conn(option, 'ikC3')
fkC3 = conn(option, 'fkC3')
fkJ1 = conn(option, 'fkJ1')
fkJ2 = conn(option, 'fkJ2')
fkJ3 = conn(option, 'fkJ3')
is_leg = option in LEG_OPTS
tip_src = fkJ3
if not all((ikC1, ikC2, ikC3, fkJ1, fkJ2, tip_src)):
cmds.warning('missing FK/IK links on ' + str(option))
return
if is_leg and not fkC3:
cmds.warning('missing FK ankle on ' + str(option))
return
# Root: translate only. Bake BEFORE deleting constraint.
c1 = cmds.parentConstraint(fkJ1, ikC1, sr=['x', 'y', 'z'], mo=False)[0]
t1 = cmds.xform(ikC1, q=True, ws=True, t=True)
cmds.delete(c1)
cmds.xform(ikC1, ws=True, t=t1)
# Tip: arms and legs both use fkJ3 (orientOffset) world match
c3 = cmds.parentConstraint(tip_src, ikC3, mo=False)[0]
m3 = cmds.xform(ikC3, q=True, ws=True, matrix=True)
cmds.delete(c3)
if is_leg:
t3 = cmds.xform(fkC3, q=True, ws=True, t=True)
else:
t3 = [m3[12], m3[13], m3[14]]
cmds.xform(ikC3, ws=True, matrix=m3)
cmds.xform(ikC3, ws=True, t=t3)
if is_leg:
foot = n(FOOT_OPTION.get(option, ''))
if foot:
zero_local(foot)
a = om.MVector(*cmds.xform(fkJ1, ws=True, q=True, t=True))
b = om.MVector(*cmds.xform(fkJ2, ws=True, q=True, t=True))
c = om.MVector(*cmds.xform(fkC3 if is_leg else tip_src, ws=True, q=True, t=True))
mid = (c + a) * 0.5
pv = (b - mid) * 2 + mid
cmds.move(pv.x, pv.y, pv.z, ikC2, ws=True)
cmds.setKeyframe(ikC1, ikC2, ikC3)
LIMBS = (
('L_arm_option_ctrl', ('L_arm_option_ctrl', 'FK_L_arm', 'IK_L_arm')),
('R_arm_option_ctrl', ('R_arm_option_ctrl', 'FK_R_arm', 'IK_R_arm')),
(
'L_leg_option_ctrl',
('L_leg_option_ctrl', 'FK_L_leg', 'IK_L_leg', 'FK_L_foot', 'IK_L_foot'),
),
(
'R_leg_option_ctrl',
('R_leg_option_ctrl', 'FK_R_leg', 'IK_R_leg', 'FK_R_foot', 'IK_R_foot'),
),
)
def options_to_match():
sel = cmds.ls(sl=True) or []
if not sel:
return [name for name, _ in LIMBS]
matched = []
for opt_name, prefixes in LIMBS:
for node in sel:
short = node.split(':')[-1]
if any(short == p or short.startswith(p) for p in prefixes):
matched.append(opt_name)
break
return matched if matched else [name for name, _ in LIMBS]
cmds.undoInfo(openChunk=True)
try:
for opt in options_to_match():
match_ik_to_fk(opt)
node = n(opt)
if node:
cmds.setAttr(node + '.IKFK', 0)
finally:
cmds.undoInfo(closeChunk=True)Match IK to FK(いまの IK ポーズに FK を合わせ、FK へ切り替える):
from maya import cmds
import maya.api.OpenMaya as om2
import math
def n(name):
short = name.split(':')[-1]
if cmds.objExists(short):
return short
hits = cmds.ls('*:' + short) or []
if hits:
return hits[0]
cmds.warning('missing ' + short)
return None
def conn(opt, attr):
node = n(opt)
if not node:
return None
hits = cmds.listConnections(node + '.' + attr, s=True, d=False) or []
return hits[0] if hits else None
LEG_OPTS = frozenset(('L_leg_option_ctrl', 'R_leg_option_ctrl'))
FOOT_ZERO = {
'L_leg_option_ctrl': ('FK_L_foot_heel_ctrl', 'FK_L_foot_ball_ctrl'),
'R_leg_option_ctrl': ('FK_R_foot_heel_ctrl', 'FK_R_foot_ball_ctrl'),
}
def zero_local(name):
node = n(name)
if not node:
return
for attr in ('tx', 'ty', 'tz', 'rx', 'ry', 'rz'):
plug = node + '.' + attr
if cmds.getAttr(plug, settable=True):
cmds.setAttr(plug, 0)
def world_matrix(node):
return om2.MMatrix(cmds.xform(node, q=True, ws=True, matrix=True))
def jo_matrix(joint):
rx, ry, rz = cmds.getAttr(joint + '.jointOrient')[0]
e = om2.MEulerRotation(
math.radians(rx), math.radians(ry), math.radians(rz),
om2.MEulerRotation.kXYZ,
)
return e.asMatrix()
def match_fk_to_ik(option):
# Snap FK controls to IK pose (used by Match IK to FK)
fkC1 = conn(option, 'fkC1')
fkC2 = conn(option, 'fkC2')
fkC3 = conn(option, 'fkC3')
ikC3 = conn(option, 'ikC3')
fkJ3 = conn(option, 'fkJ3')
ikJ1 = conn(option, 'ikJ1')
ikJ2 = conn(option, 'ikJ2')
ikJ3 = conn(option, 'ikJ3')
is_leg = option in LEG_OPTS
if not all((fkC1, fkC2, fkC3, ikJ1, ikJ2, ikJ3)):
cmds.warning('missing FK/IK links on ' + str(option))
return
if is_leg and not (ikC3 and fkJ3):
cmds.warning('missing leg ankle links on ' + str(option))
return
# Root: rotate only. Bake BEFORE deleting constraint.
c1 = cmds.parentConstraint(ikJ1, fkC1, st=['x', 'y', 'z'], mo=False)[0]
m1 = cmds.xform(fkC1, q=True, ws=True, matrix=True)
cmds.delete(c1)
cmds.xform(fkC1, ws=True, matrix=m1)
axis_map = (
('rx', ['y', 'z']),
('ry', ['x', 'z']),
('rz', ['x', 'y']),
)
for axis, skip_rot in axis_map:
if cmds.getAttr(fkC2 + '.' + axis, lock=True):
continue
c2 = cmds.parentConstraint(
ikJ2, fkC2, st=['x', 'y', 'z'], sr=skip_rot, mo=False
)[0]
m2 = cmds.xform(fkC2, q=True, ws=True, matrix=True)
cmds.delete(c2)
cmds.xform(fkC2, ws=True, matrix=m2)
if is_leg:
# Inverse of fkJ3->ikC3: fkC3_world = inv(JO) * ikC3_world
wi = world_matrix(ikC3)
wf = jo_matrix(fkJ3).inverse() * wi
t = cmds.xform(ikC3, q=True, ws=True, t=True)
cmds.xform(fkC3, ws=True, matrix=list(wf))
cmds.xform(fkC3, ws=True, t=t)
else:
c3 = cmds.parentConstraint(ikJ3, fkC3, st=['x', 'y', 'z'], mo=False)[0]
m3 = cmds.xform(fkC3, q=True, ws=True, matrix=True)
cmds.delete(c3)
cmds.xform(fkC3, ws=True, matrix=m3)
cmds.setKeyframe(fkC1, fkC2, fkC3, attribute='rotate')
if is_leg:
for foot in FOOT_ZERO.get(option, ()):
zero_local(foot)
LIMBS = (
('L_arm_option_ctrl', ('L_arm_option_ctrl', 'FK_L_arm', 'IK_L_arm')),
('R_arm_option_ctrl', ('R_arm_option_ctrl', 'FK_R_arm', 'IK_R_arm')),
(
'L_leg_option_ctrl',
('L_leg_option_ctrl', 'FK_L_leg', 'IK_L_leg', 'FK_L_foot', 'IK_L_foot'),
),
(
'R_leg_option_ctrl',
('R_leg_option_ctrl', 'FK_R_leg', 'IK_R_leg', 'FK_R_foot', 'IK_R_foot'),
),
)
def options_to_match():
sel = cmds.ls(sl=True) or []
if not sel:
return [name for name, _ in LIMBS]
matched = []
for opt_name, prefixes in LIMBS:
for node in sel:
short = node.split(':')[-1]
if any(short == p or short.startswith(p) for p in prefixes):
matched.append(opt_name)
break
return matched if matched else [name for name, _ in LIMBS]
cmds.undoInfo(openChunk=True)
try:
for opt in options_to_match():
match_fk_to_ik(opt)
node = n(opt)
if node:
cmds.setAttr(node + '.IKFK', 1)
finally:
cmds.undoInfo(closeChunk=True)
Match ボタンは、ウィンドウ上部のネームスペース切り替えを合わせなくても押せます。インポートでネームスペースが無いときも、そのままで足ります。手足の IK / FK スイッチでの切り替え自体は、スクリプトなしでもできます。
CTRL / GEO の表示ボタン
Body と Face の左下に、CTRL(FACE / HAIR / CLOTH)と GEO(PROXY / BODY / CLOTH)の緑・赤があります。緑が出す、赤が消す、です。ラベルの文字自体は押しても何も起きません。効くのは横の四角です。
こちらは Match と違い、取り込み後も MEL が残っています。中身は setAttr ":option_ctrl.allFacialCtrl" 1; のような書き方です。先頭の : はネームスペースなしなので、リファレンスだとノードが見つかりません。顔カーブを出すには、option_ctrl.allFacialCtrl に加えて、ディスプレイレイヤ REMU_facial_ctrl_LY の .v も切る必要があります。Channel Box では allFacialCtrl がオンオフし、レイヤエディタのマークは付かないままでも、ビューポートは動きます。レイヤの行をスクリプトから外すと、また効かなくなります。服は REMU_clothing_ctrl_LY、髪は REMU_hair_ctrl_LY です。
直し方は、Scripts に残っている leftClick (mel) の鉛筆を押し、Language を python に変えてコードを差し替える、です。Match のように Add command すると、古い MEL が残ります。すでに足してしまった場合は、MEL のほうをゴミ箱で消してください。コメントは英数字のみです。
CTRL FACE の緑(顔コントローラーを出す)です。赤は、下の val = 1 を val = 0 にするだけです。
from maya import cmds
def n(name):
short = name.split(':')[-1]
if cmds.objExists(short):
return short
hits = cmds.ls('*:' + short) or []
if hits:
return hits[0]
cmds.warning('missing ' + short)
return None
val = 1
node = n('option_ctrl')
if node:
cmds.setAttr(node + '.allFacialCtrl', val)
layer = n('REMU_facial_ctrl_LY')
if layer:
cmds.setAttr(layer + '.v', val)
HAIR / CLOTH も同じ形です。差し替えるのは '.allFacialCtrl' とレイヤ名です。ドットは残してください。node + 'allHairCtrl' だとノード名とアトリビュートがつながって失敗します。GEO にレイヤは不要です。Body タブにも同じ四角があるので、使うなら同じコードを載せます。同じボタン名が表に複数行あるときは、その行を全部、1つのボタンへ書きます。GEO PROXY の緑なら、option_ctrl に対して次の3行です。
if node:
cmds.setAttr(node + '.proxyGeo', 1)
cmds.setAttr(node + '.characterGeo', 0)
cmds.setAttr(node + '.outlineGeo', 0)
GEO BODY / CLOTH はノードが2つあります。レイヤは使いません。それぞれ n() してから visibility を書きます。GEO BODY の緑です。
val = 1
for name in ('body_old', 'body_outline'):
node = n(name)
if node:
cmds.setAttr(node + '.visibility', val)
| ボタン | ノード | アトリビュート | 緑 | 赤 |
|---|---|---|---|---|
| CTRL FACE | option_ctrl | allFacialCtrl | 1 | 0 |
| CTRL FACE | REMU_facial_ctrl_LY | visibility(.v) | 1 | 0 |
| CTRL HAIR | option_ctrl | allHairCtrl | 1 | 0 |
| CTRL HAIR | REMU_hair_ctrl_LY | visibility(.v) | 1 | 0 |
| CTRL CLOTH | option_ctrl | allClothingCtrl | 1 | 0 |
| CTRL CLOTH | REMU_clothing_ctrl_LY | visibility(.v) | 1 | 0 |
| GEO PROXY | option_ctrl | proxyGeo | 1 | 0 |
| GEO PROXY | option_ctrl | characterGeo | 0 | 1 |
| GEO PROXY | option_ctrl | outlineGeo | 0 | 1 |
| GEO BODY | body_old | visibility | 1 | 0 |
| GEO BODY | body_outline | visibility | 1 | 0 |
| GEO CLOTH | clothing_grp | visibility | 1 | 0 |
| GEO CLOTH | clothing_grp_outline | visibility | 1 | 0 |
取り込み後に、必要なボタンへ上のコードを載せて、自分の JSON として保存してください。
MG-Picker について(直接は読めない)
The Mecha-Mechs のように、MG-Picker Studio 同梱のリグもあります。こちらの .mgpkr は独自の暗号化なので、dwPicker へ直接インポートはできません。 Reimu の .pkr とは手間が違います。
関連記事「The Mecha-Mechs」Mayaリグレビューどちらを使うかは、こう考えています。
- そのリグを今すぐ動かしたい … MG-Picker の Animator 版(閲覧・使用)を使う
- これから自作する/AnimSchool 資産(Reimu など)を移す … dwPicker を主軸にする
MG-Picker の画面を見ながら、dwPicker の Advanced Editor でボタンを置き直すことはできます。数分〜十数分で「使える代替」にはなります。ただしこれは移行機能ではありません。次の章と同じ、ゼロからの作成 です。
ゼロからピッカーを作る(自作リグ/MG-Picker の手動移行)
.pkr が無いリグ、自分で組んだリグ、MG-Picker 同梱を dwPicker に寄せたいときは、画面を自分で作ります。AnimSchool でピッカーを作っていた人は、操作の考え方はそのままです。保存先が JSON になり、ライセンスから解放される、という違いです。
Reimu のように .pkr があるなら Import で足ります。この章は飛ばして構いません。
Advanced Editor を開く

Edit → Advanced Editor、または Ctrl + E です。左側がキャンバス、右側がアトリビュート(Picker タブ / Shapes タブ)です。
配布してアニメーターに触られたくないときは、dwpicker.show(editable=False) で開けます。元ファイルは変わりません。
ボタンを一発で作る

いちばん速いのは、Maya でコントローラーを2つ以上選んでから、Advanced Editor のキャンバスを 右クリック → Add selection multiple buttons です。ツールバーや Shapes タブにはありません。1つしか選んでいないと項目がグレーになります。そのときは Add selection button(単数)です。
一括で作ると、ボタンは同じ場所に重なって置かれます。10個選ぶと10個重なるので、すぐドラッグして広げてください。下に隠れていて1個に見えることがあります。ボールのように2〜3個なら、Add selection button で1つずつ置いた方が位置が分かりやすいです。MG-Picker の画面を横に置いて同じ並びにするときも、一括は「作る」起点で、並べは手作業です。
親子階層も、この一括作成から付けるのが楽です。あとから付けるなら、Advanced Editor のキャンバスで Alt を押しながら、子ボタンを親へドラッグ&ドロップします。ダブルクリックで配下まで選べるようになります。
形・色・ラベル

キャンバスでボタンを選んでから、Shapes タブ先頭の Display → Shape です。ドロップダウンは square / round / rounded_rect / custom です。角の丸みは、rounded_rect にしたあと Dimensions の roundness です。サイズは同じ Shape 内の Dimensions です。塗りは下へスクロールした Appearance → Background color → normal、枠は Border color → normal です。ホバーとクリック用もここにあります。文字色は Text → Color、ラベルは Text → Content です。

Custom(ベクター形状)は見た目の自由度が高い反面、描画が重いです。公式も「基本形状の約50倍遅い」「1000個超えると FPS が落ちる」と書いています。飾りに数個、くらいに留めたほうがよいです。
左右をミラーする機能もあります。命名が L_ / R_ などのときは、ミラー時に検索置換を走らせるオプションがあります。
パネルを分ける
パネルは、1つのピッカーファイルの中を分割する機能です。メインウィンドウ上部のタブ(JSON を Open / Import するたびに増えるもの)とは別です。
ボールの例では、コントローラーをパネル 1、ガイド画像をパネル 2 に振っています。メインのタブは Bouncing_Ball_rig の1つだけで、中が左右に分かれます。

T(Edit → Toggle Panel Display Mode)を押すと、分割がサブタブになります。Panel 1 がコントローラー、Panel 2 がガイドです。同じ切替は、Picker タブの Display panels as tab でもできます。


2つ目のパネルは、追加ボタンではありません。Advanced Editor の右を Picker タブにします。Picker Panels に「1」と書かれた四角があります。下辺または右辺の矢印をドラッグすると、パネル 2 が増えます。Columns orientation が vertical だと、ピッカー側は左右に並びます。
既存のボタンを移すときは、キャンバスで選んで 右クリック → Assign to panel → 1 または 2 です。Shapes タブの Panel number は表示のみで、ここでは変えられません。新しく置くボタンは、Picker Panels で選んでいる番号に入ります。
ツールバーの Isolate を入れると、選んだパネルだけがキャンバスいっぱいに出ます。パネル 1 ならコントローラー、パネル 2 ならガイドです。全部同時に見たいときは Isolate を外します。


ガイド画像の敷き方は次の節です。
Reimu なら、Body をパネル 1、Face をパネル 2 にまとめます。メインのタブは1人1つです。Sanae をリファレンスしたときは、Sanae 用の JSON をもう1タブ開きます。ネームスペース切り替えは同じリグの複製向きで、Sanae の衣装・顔は Reimu のピッカーでは足りません。結果のタブは2つ(人数分)です。別ファイルのまま Import すると、2人でタブは4つです。
Visibility Layers は、Maya のディスプレイレイヤに近い「まとめて表示/非表示」です。右クリックの Create Layer from Selection で作ります。
背景画像を敷く

キャラのシルエットや三面図をガイドにすると、ボタン位置が決まります。MG-Picker を見ながら置き直すときも、同じガイドを敷くと早いです。
- Advanced Editor のツールバーで、txt の右隣を押す(ホバーすると Add background shape。見た目は緑の四角)
- 背景ロックを外して、そのシェイプをキャンバスで選ぶ
- 右の Shapes タブを、Image までスクロールする
- Path に画像を指定する
- その直下の Fit to shape を
Trueにする(画像を背景シェイプの矩形に合わせる。ビューのFとは別)
F で背景まで枠に入れたいときは、背景シェイプを選んで Shapes タブ先頭の Display → Ignored by focus を False にします。背景は既定で True なので、F はボタンだけを最大表示します。ボタンより背景が大きいなら、これだけで背景にフィットします。ボタン側を True にすると、背景だけが対象になります。
相対パス ../../images/... は公式に非対応です。絶対パス か、プロジェクト内で解決できるパスにしてください。背景を誤クリックしたくなければ、背景ロックを戻します。
タブに名前を入れる
名前を入れる場所は、Advanced Editor の Picker タブに2つあります。
Picker Name が、メインウィンドウ上部のタブ名です。ボールの例では Bouncing_Ball_rig になっています。Reimu と Sanae を並べるなら、ここにキャラ名を入れます。メインウィンドウのタブをダブルクリックするか、Edit → Change picker title でも同じです。
サブタブの名前は、その下の Panels Zoom Locked の Name です。既定は Panel 1 / Panel 2 です。セルをクリックして、Body / Face のように打ち直します。T でサブタブにしたときに、この名前が出ます。
コマンドボタンとネームスペース
選択だけでなく、Python / MEL を載せられます。IK/FK スイッチ、リセット、全選択などです。
短いノード名だけ書いて、あればその名前、なければ cmds.ls('*:名前') で実ノードを拾う方が確実です。取り込み後の .pkr はターゲットが ::ctrl のままなので、公式の dwpicker.current_namespace() は空を返し、ネームスペースなしの名前だけを探すとリファレンスで失敗します。Reimu の Match も、この探し方で、リファレンスとインポートの両方で動かしています。
ターゲットを差し替えたあとは、Advanced Editor で U を押すと更新できます。API の詳細は dwpicker Module と Scripts です。
保存と配布
保存の経路は2つあります。Reimu の取り込み結果を残すときも、同じです。
シーンに埋め込む
dwPicker は、開いているピッカーを Maya シーン側にも持ちます。Reimu をリファレンスしたアニメーションシーンを保存し、次回開いて dwPicker を起動すると、前回のピッカーが載ります。アニメーターが「JSON を別途開く」必要がないのが利点です。
JSON として書き出す
File → Save(Ctrl + S)または Save As で、外部の .json に出します。Reimu なら Body と Face を別 JSON にして、リグのフォルダへ並べておくと分かりやすいです。BOOTH やチーム共有でも、リグファイルとは別に JSON を置く運用が楽です。
JSON はテキストです。Git で差分も追えます。万一壊れても、テキストエディタで中を確認できます。バイナリの .mgpkr や、AnimSchool の .pkr より扱いやすいです。
読み込みは File → Open(Ctrl + O)です。スクリプトからなら次です。パスは自分の環境に合わせてください。
import dwpicker
dwpicker.show()
dwpicker.open_picker_file(r'C:\path\to\reimu_body.json')
dwpicker.open_picker_file(r'C:\path\to\reimu_face.json')
リファレンス時の注意
- ネームスペースは、ツールバーで切り替える(Reimu の取り込み後と同じ)
- JSON 内のターゲット名は、ルートのネームスペース1段を前提にする
- 背景画像のパスが切れることがある。受け取り側でも辿れる場所に置く
まとめ
DreamWall Picker は、AnimSchool Picker が現場から引き剥がされたときに、スタジオが自分たちで代替を書いて公開したツールです。だから .pkr の取り込みが最初からある し、ライセンスは MIT で商用も問題ありません。
今回は MegaBuBu の Reimu を例にしました。やったことはこれだけです。
- dwPicker を入れる(最新の Release。下限は 1.0.3、本稿時点は 1.0.4)
- Reimu をリファレンスする
- File → Import で Body / Face の
.pkrを読む - ネームスペースを合わせて、選択できるか確認する
- Match が空なら、本稿の Python を Add command に載せる
- CTRL / GEO が効かないなら、FACE の例と同じ
n()でノードを探してsetAttrする - JSON で保存する
AnimSchool 本体の手続きは不要です。他の .pkr 同梱リグも、同じ Import です。
自作リグや MG-Picker 同梱は、Advanced Editor でゼロから作ります。選択からボタン一発、背景、パネル、コマンドは短いノード名と *:名前 です。
関連記事「Reimu Animation Rig」Mayaリグレビュー
関連記事【Maya tools and scripts】Studio Library の使い方
関連記事MayaでRigging まとめ
関連記事MayaでRigging まとめ


コメント
まだコメントはありません