mocopiとは

mocopi は、ソニーが開発・販売している小型・軽量のモバイルモーションキャプチャーデバイスです。6つのセンサーを頭、両手首、腰、両足首に装着することで、全身の動きをリアルタイムでトラッキングし、スマートフォンアプリを通じて3Dキャラクターやアバターに反映させることができます。

1.1. 主な特徴

1.2. 用途

1.3. 技術的特徴

1. Godotとは

Godot(ゴドー)は、オープンソースかつクロスプラットフォーム対応の2D/3Dゲームエンジンです。2014年にMITライセンスのもとで公開されました。

1.1. 特徴

1.2. レンダリングと物理エンジン

1.3. 用途と将来性

Godotはインディーゲーム開発者や学生に人気があり、その軽量さと使いやすさから広く利用されています。現在は商用ゲームにも徐々に採用され始めており、日本でも注目が高まっています。Godotは完全無料でありながら高機能で、多様なプラットフォームに対応しているため、小規模なプロジェクトから本格的なゲーム開発まで幅広い用途に適しています。

2. Godotにてmocopiのデータをリアルタイムトラッキング

Godotにてmocopiから送信されるUDPのモーションデータをリアルタイムに表示させます。

GotodでのUDPデータ受信には次のGDExtensionを利用しました。
GDExtensionの使い方はリンク先に詳しい解説がありますので、そちらを参照してください。

このGDExtensionをそのまま利用すると、最新のmocopiアプリでは動作しませんでした。ただし、BVH Senderアプリを使って送信したデータでは動作しました。
そこで、UDPデータをキャプチャして比較すると次の相違点がありました。

最新mocopiデータの場合は、uutmブロックとbtrsブロックの間にtmcdブロックが追加されています。GDExtensionは、tmcdブロックに対応していないため、データ解析に失敗しアニメーションが表示されない状態になっていました。

そこで、tmcdブロックがある場合にはスキップし、続きのbtrsブロックから解析を継続するようGDExtensionのlibのソースを次のように変更しました。
なお、tmcdブロックがどのような情報(タイムコード?)なのかは調査していません。

func _decode_btrs(stream: StreamPeerBuffer) -> bool:
    # ブロックのサイズを取得
    var size = stream.get_u32()

    # ブロックの識別子を確認
    var block_name = stream.get_string(4)

    # tmcdブロックを検出した場合は6バイトスキップ
    if block_name == "tmcd":
        print_debug("tmcdブロックを検出: 6バイトをスキップします")
        stream.get_data(6)  #6バイトスキップ
        # 次のブロック読み込み
        size = stream.get_u32()
        block_name = stream.get_string(4)

    if block_name != "btrs": return false

    var btrs_stream: StreamPeerBuffer = StreamPeerBuffer.new()
    var r = stream.get_data(size)
    if r[0] != OK: return false

    btrs_stream.data_array = PackedByteArray(r[1])

    ary_btdt.clear()
    ary_btdt.resize(MOCOPI_BONE_COUNT)

    valid_btdt = false

    for i in range(MOCOPI_BONE_COUNT):

        size = btrs_stream.get_u32()
        if btrs_stream.get_string(4) != "btdt": return valid_btdt

        var bnid: int = _parse_s16(btrs_stream, "bnid")
        var o: MocopiBtdt = MocopiBtdt.new(bnid)

        size = btrs_stream.get_u32()
        if btrs_stream.get_string(4) != "tran": return valid_btdt

        o.quat.x = btrs_stream.get_float()
        o.quat.y = btrs_stream.get_float()
        o.quat.z = btrs_stream.get_float()
        o.quat.w = btrs_stream.get_float()

        o.vct3.x = btrs_stream.get_float()
        o.vct3.y = btrs_stream.get_float()
        o.vct3.z = btrs_stream.get_float()

        ary_btdt[o.bnid] = o

    valid_btdt = true
    btdt_count += 1

    return valid_btdt

3. 人体3Dモデル

今回利用する3DモデルはAdobe Mixamoのモデルを利用します。

Mixamoからダウンロード可能なフォーマットはfbxですが、GDExtensionが想定しているモデルはvrmですので、Blenderにてfbxをインポートし、vrmでエクスポートすることで変換可能です。

4. mocopiとPCをWifiで接続

mocopiとPCのwifi接続は、説明書どおりに行えば特に問題なく繋がると思います。

このモーションキャプチャは通常モードでキャプチャしているため、頭、腰、両手首、両足首にセンサを取り付けています。
この状態でも膝の動き等も再現されています。

5. mocopiとPCを携帯回線で遠距離接続

Wifi接続の場合にはiPhoneとPCを同じWifiに接続する必要があります。Wifiは屋外の見通しのよい状態でも数十メートル程度しか接続できません。そのため、広いフィールドをランニングする場合には、リアルタイムでのモーションキャプチャは困難であり、スマートフォンに記録したデータをあとで抜き出して動作を確認する必要があります。

今回は、iPhoneをWifi接続するのではなく携帯回線(LTE回線)を使ってデータを送信します。特別な回線は必要なく、通常の携帯回線で問題ありません。

ただし、iPhoneと受信用のPCの間はWifiと同じように閉じたネットワークの状態にする必要があります。そのために、VPNというネットワークの機能を利用します。VPNを利用することで、携帯回線(インターネット回線)を利用しているにもかかわらず、Wifiと同じようにスマートフォンとPCを同じネットワーク内にあるように利用することが可能になります。

VPNを利用する方法はいろいろありますが、今回はTailscaleというサービスを利用します。

TailscaleはWindows、Mac、Android、iPhoneなどの環境に対応しており、それぞれに専用のアプリがあるため、ダウンロードしてVPNを設定します。設定自体はそれほど難しくはなく、同じアカウントでログインして接続すれば、自動的にVPNのネットワークが構築されます。

今回は、iPhoneとWindowsにアプリをインストールし、同じTailscaleのアカウントでログインすることで、iPhoneとWindows PC間にVPNを構築し、Wifiで接続した場合と同じようなネットワーク環境を構築します。

VPNを張った状態でWindows PCのIPアドレスを調べ、iPhoneのmocopiアプリのデータ送信先のIPアドレスに設定します。

これで、iPhoneに携帯電波が入る範囲内であれば、リアルタイムモーションキャプチャが可能になります。

次の動画はVPNでの動作検証です。Wifiが届かない範囲でもモーションキャプチャ可能であることを確認できました。今回は使用したPCのスペックが低かったため、Godotでの3Dモデル表示と画面の録画を行うと処理が重くなり、録画がコマ落ちしてしまいました。実際のモーションキャプチャアニメーションはもっとスムーズに動作しました。ただし、携帯回線がIoT用の低速度の回線であったことと無料のVPNサービスを利用したため、おそらく通信速度があまり出ておらず時々、コマ落ちしました。