Azure KinectのBody Trackingを使ってアバターを動かす(IKではなくFK)的なことを検索するとUnityの情報ばっかり出てきて、TouchDesignerでどうやんねんって情報が見つからなかったのでやってみました。
今回はこんな感じで、Blenderで作った簡単なモデルにボーンを入れて、ちゃんと動きに追従しますよというところまでです。
#AzureKinect でTrackingしたデータでアバターを動かすテスト pic.twitter.com/6u7kDOWWYq
— 岩谷成晃 (@nariakiiwatani) August 20, 2020
前提
前回までやっていたような、トラッキングされた各関節の__位置__に何かを表示するという場合は、モデルには親子階層構造を持たせずに、ワールド位置とワールド回転(?)を反映させるのが簡単です。
が、今回やろうとしているような、3Dモデル(アバター)を動かそうという場合はそれではいけません。関節間がモデルの体型を無視して演者のサイズに合わせて伸び縮みしてしまいます。
ですので、関節間の距離は無視して回転だけを適用するという手法がよく使われます。ルートノードから順に計算していく手法であるため、Forward Kinematics(FK)と呼ばれます。
ちなみに、末端の位置または向きを先に決め、そこからルートに向かって角度計算を伝播させていく手法をInverse Kinematics(IK)といいます。
今回はFKをやります。
やることを整理すると、
- Blenderでモデルを作って
- TouchDesignerにインポートして
- Azure KinectのBodyTrackingから取れるデータを使用して
- モデルを動かす
です。
Blenderでモデル作り
「僕、Blender触ったことないんですよね・・・」
マジです。Blender起動したことくらいはありますが、「え?オブジェクト選択できないんだけど?え?動かせないんだけど?え?え?え?」ってなって何もしてませんでした。
ということで入門してみました。
Blenderのバージョンは2.83.4です。
キーボードでサクサク操作できるのすんごい良いですね。
今回作るものはこういう、円錐にボーンが入ってるやつです。これを腕にします。
Blenderの話を飛ばしてTDの話を読みたい方はこちらへ
はじめてのモデル作成始めます。
まず最初に配置されてるキューブを消します。
選択してx
メッシュを作る
後から分かったんですが、はじめに知っておいた方がよかったことを書いておきます。
- Blender座標はZが上
- 変更は書き出し時に可能
- Blenderはメートル法
- このあとコーンを長さ4mとかで作ってしまう。50cmとかで作ればよかった
- 書き出し時にスケーリング可能
- BlenderのボーンはY方向を向いている
- 変更は書き出し時に可能
Shift+AでMesh(Cone)追加
クリックで選択
rで回転
yで回転軸(y)固定
90と打って角度を指定
sx2と打ってx方向2倍
gx2でx方向移動(コーンの底面が原点になる)
動かした時にどの軸で回転しているのかがわかるようにsy0.5でY方向に潰しておく
Shift+Dで複製
gx4でx方向移動(旧コーンの頂点に新コーンの底面)
Shift+D, gx4でもう一つ複製しておく
ボーンを入れる
Shift+Sで3Dカーソルを移動するメニューを開く
Cursor To Originを選んで原点(コーンの底面中心)へ移動させる
Shift+AでArmatuerがカーソル位置に作成される
こんな感じで作られる
ry90でコーンと同じ方向を向くように回転させる
TabでEditモードへ
Boneのtip(先っちょ)を選択してgx3でコーン先端へ移動させる
ex4で次のコーン用のボーンを作成
再度ex4
ボーンの向きを設定する
公式ドキュメントにある各関節の向きに合うようにボーンを回転させる
※軸のXYZは合ってなくていいから、矢印が同じ形になるように編集していく
ちなみにこれは左腕のつもり
メッシュとボーンの関連付け
aで全選択
Object->Parent->Armature Deform With Automatic Weightsすると、メッシュがArmatureの子になる
(Ctrl+Pでparentメニューへショートカット)
(動作確認)
Ctrl+TabでPoseモード
ボーンを選択してrで動かしてみる
FBXで書き出し
- Scaleを0.01にする
- BlenderもTDもメートルスケールのはずだが、こうしないとダメだった。多分どこかに設定がある
- ForwardをZに、UpをYに
- TD側の座標に合わせるため
- BoneAxisをPrimaryをXに、Secondaryを-Zに
- ボーンのローカル回転座標を公式ドキュメントに合わせるため
FBXをTouchDesignerで読む
FBXはTDのウィンドウにD&Dすれば読めます。
Blenderで作ったメッシュとボーンの構造がそのまま表れていますね。
今回気が回らなかったのですが、Blender側で最初のボーンを回転させて倒して作ってしまったために、TD側でもBone
に(180,0,0)
の回転が入ってしまっています。
このボーンはKinectからの値で動かしたいので、急場しのぎですがArmatureにその分の回転を押し付けました。((90,0,180)
=> (-90,0,180)
)
本来は、回転を操作しないルートノード的なボーンを一つ置いておけば良いのだと思います。
Azure Kinectから情報を取得
Azure Kinect TOP
を置いて、Azure Kinect CHOP
に食わせればスケルトンの情報が取れます。
今回は前作ったレコーダーで書き出したデータをMacで再生しています。
ここでDerivativeに感謝したいんですけど、Azure Kinectのドキュメントによると、Azure KinectのSDK自体は、回転の情報はワールドでのQuaternionしか渡してくれません。しかもその基準になる各関節の座標軸はドキュメントにある「独自の関節座標系」とのこと。
しかしThanks to Derivative, Azure Kinect CHOP
が面倒な計算をやってくれて、我々ユーザーはTDでそのまま使えるオイラー角での回転として使えます。
さらに、Kinect SDKが返す位置情報はミリメートル単位ですが、TDではメートルであるのもちゃんと考慮してくれているようです。
どこまでが親切でどこからがお節介なのかは決められませんが、分かって使う分にはお手軽で良い仕様だと思います。
今回は手探りだったので、Kinectのドキュメントに書いてあることとTDで実際に取れる値が違って戸惑ったこともありました。。
ともあれ、Azure Kinect CHOP
からは[プレイヤーインデックス]/[関節名]:[パラメータ名]
という名前で情報が取得できます。
パラメータ名は以下です。
- 位置: tx,ty,tz
- 回転(親からの相対): rx,ry,rz
- 回転(カメラ座標での絶対値): [関節名]_abs:rx,ry,rz
モデルへ適用
望みの関節の回転の値を対応するボーンに設定してやればOKです。
ボーンの数が多くなってくると手動でスクリプトを書くのが辛くなってくるので、こんな感じのTable DATを用意して、Export
スイッチ(右下の緑色のスイッチ)をオンにすると、指定したジョイントの姿勢をボーンに反映するのが比較的楽にできます。
path parameter value enable
Armature tx op('current_frame')['shoulder_l:tx'] 1
Armature ty op('current_frame')['shoulder_l:ty'] 1
Armature tz op('current_frame')['shoulder_l:tz'] 1
Bone rx op('current_frame')['shoulder_l:rx'] 1
Bone ry op('current_frame')['shoulder_l:ry'] 1
Bone rz op('current_frame')['shoulder_l:rz'] 1
Bone_001 rx op('current_frame')['elbow_l:rx'] 1
Bone_001 ry op('current_frame')['elbow_l:ry'] 1
Bone_001 rz op('current_frame')['elbow_l:rz'] 1
Bone_002 rx op('current_frame')['wrist_l:rx'] 1
Bone_002 ry op('current_frame')['wrist_l:ry'] 1
Bone_002 rz op('current_frame')['wrist_l:rz'] 1
これで左腕ができました。
あとは同じことを体全体でやればアバターが動かせるはずです。たぶん。