ブラウザでもmocopiしたい

GMOソリューションパートナーのA.Sです。

以前、Sony製モーションキャプチャ―のmocopiを購入したのですが、動画制作や配信などをやっていないので、いまだ活用できていない状況です。何かしらやらないと意味が無いので、普段触ることが多いWebブラウザで何かできないかを考えてみました。
mocopiのセンサー
mocopiのセンサー 見た目◎
何を作るにしてもmocopiのデータをブラウザで読み取る必要があるので、今回は表示した3Dモデルを動かすところまでをやってみます。

モチベーション

  • mocopiを使ったWebアプリを考えたい
  • ブラウザの機能を調べてできることを増やしたい

実装方針

重要な点を先に書きますが、ブラウザ単体でmocopiデータを制御することはできませんでした。

mocopi自体はBluetooth接続なので、Web Bluetooth APIでゴニョゴニョすればどうにかなるかもと思ったのですが、ドライバの問題なのかペアリングすらできませんでした。スマホでもアプリ起動前はペアリングできずでした。
※そもそもセンサーだけ繋いでも全身の動きを推定できないことには後から気づきました。

データをブラウザに送るためmocopiアプリのデータ送信機能を使うのですが、用意されている通信方法(UDP)はブラウザで直接扱えないためWebSocketを経由します。

UDP受信 + WebSocket送信用サーバを立てます。試しなのでポート番号はとりあえず決め打ちです。 (UDPで受信した端からWebSocketに転送するJS)

結果

デモ動画に使用したモデルの利用規約上、動画を公開できないのですが動きを連動できました。

実装内容はこちらのファイルを参照ください。
cliでディレクトリに移動したら以下、順番に実行します 以下は今回の実装までの道のりです。

データの解析

まずはmocopiから送られてくるデータを解析します。

データを再利用するため、受信した順に1000回分くらいのデータをファイルに保存してみました。 最初に1821byteのデータが来て、その後1575byteのデータが続きます。

その後も時々1821byteのデータを受信していましたがほとんどが1575byteのデータでした。
mocopiのデータをファイルに保存した。1821byteのデータから始まり、1575byteのデータが続いている
データファイル一覧の画像
内容を見ると似たようなデータが入っていましたが1575byteの方が若干項目が少なかったのでそちらを使って実装していきます(UDP通信なので取得順は関係ないデータになっている想定です)。
1821byteのほうの画像
1575byteのほうの画像
冒頭の#head,ftyp,sony motion~~~はおそらくフォーマット宣言の部分なので一旦飛ばします。
続きを見るとbnid、tranという文字が度々も登場しているのがわかります。数は27です。mocopiの技術仕様によるとスケルトンのジョイント数が27なので、各ジョイントごとのデータを送っているのだと想像できます。

.btdt(=2E 00 00 00 62 74 64 74)ごとに区切りつつ、制御文字なども考慮して見てみると、bnidの後の2byte、tranの後の28byteが実際のデータっぽく見えます。
bnidとtranの実データ部分を強調した
該当箇所のハイライト

パースして必要そうなデータを抽出

.btdtごとに分割して、さらに必要そうなデータを抽出します。 (パーサーの全体)

bnidデータをパース

bnidは、mocopiのスケルトン定義のIndexです。2byte切り出して数値に変換します。

tranデータをパース

tranは、回転情報と位置情報がセットされています。

28byte切り出し、4byteごとに分割した後、それぞれを32bit Floatに変換します(下記コードの6~12行目)。
分割したデータの前半4つは回転情報、後半3つが位置情報になっていました。
実際に動かした後でわかったのですが座標系がWebGLと違うようなので、一部の値を反転しています。 

mocopiデータを3Dモデルにセットする

今回、VRMフォーマットで作られた3Dモデルを使います。
VRMは人型の3Dアバターに特化したファイルフォーマットです。mocopiのオリジナルアバターもVRMで配布されていたので相性が良いのだろうと考えました。
bnidとVRMのボーン名をマッピングします。対応させる情報は下記のページを参考にしました。

mocopi
https://www.sony.net/Products/mocopi-dev/jp/documents/Home/TechSpec.html

VRM
https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/humanoid.ja.md#%E3%83%92%E3%83%A5%E3%83%BC%E3%83%9E%E3%83%8E%E3%82%A4%E3%83%89%E3%83%9C%E3%83%BC%E3%83%B3%E3%81%AE%E4%B8%80%E8%A6%A7

この情報をもとに、mocopiのデータをVRMにセットする処理を実装します。 上記クラスの boneNameMap のキーはmocopiデータのbnid、値はVRMのボーン名となっています。
数が一致しないので一部が空白になっていますが、だいたい割り当てられていると思います。

setMocopiDataを実行するとVRMの各ボーンに回転情報、ルートのボーンには位置情報をセットします。
位置情報をルート以外にもセットしてしまうと3Dモデルが想定通りに表現されません(関節の位置がおかしくなりました)。

WebSocketで送られてきたデータをパース + 3Dモデルにセット

見出し通りに処理します。

課題

  • 足元が埋もれてしまうので補正する処理が必要。
    • 使う3Dモデルによっては反対に浮かんでしまうかもしれません。
  • データ1つあたりのパース時間はおよそ0.7msでしたが、さらに減らせないか検証したい。
  • データ転送処理(UDP→WebSocket)の実行環境を準備する手間を解消したい(直接実行できるファイルにしたい)。
  • これを使ったサービスのアイディアが浮かばない。

終わりに

今回データのパース処理をクライアント側に書いたのですが、単純な動作だったためか遅延をあまり感じないレベルだったので驚きました。
mocopiそのものの活用方法は浮かばなかったものの、ArrayBufferを使ったバイナリデータの操作や、WebSocketの通信など業務では扱うことのなかったブラウザの機能を調べるきっかけになったのは良かったなと思います。