iFacialMocapの通信仕様


iFacialMocapにおいて3rdパーティーのツール開発者様は、UDPまたはTCP/IPを使用してPCソフトウェアを介さずにフェイシャルデータを受信できます。

UDPでデータを受信するには

PC上のソフトウェアを介すずにiOSアプリと通信するには、PC側からiOS側の49983番ポートにUDPで「iFacialMocap_sahuasouryya9218sauhuiayeta91555dy3719」という文字列を送信すると、PC側の49983番ポートにUDPで60FPSで送信が始まります。(長時間放置したり、暗ホされなくなると30FPSに低下します)

・ UDPで受信するPython使用例のサンプル

from socket import *
DstIP = "192.168.1.7"
DstPort = 49983
DstAddr = (DstIP,DstPort)
udpClntSock = socket(AF_INET, SOCK_DGRAM)
data = "iFacialMocap_sahuasouryya9218sauhuiayeta91555dy3719"
data = data.encode('utf-8')
udpClntSock.sendto(data,DstAddr)

server = socket(AF_INET, SOCK_DGRAM)
server.bind(("", 49983))
server.settimeout(0.05)

while True:
    try:
        messages, address = server.recvfrom(8192)
        print(messages.decode('utf-8'))
    except:
        pass

・ 1フレーム当たりに送られてくる文字列は以下のようなデータです。

mouthSmile_R-0(eyeLookOut_L-0)mouthUpperUp_L-11(eyeWide_R-0)mouthClose-8|mouthPucker-4|mouthRollLower-9|eyeBlink_R-7|eyeLookDown_L-1|?cheekSquint_R-11|eyeBlink_L-7|tongueOut-0|jawRight-0|eyeLookIn_R-9|cheekSquint_L-11|mouthDimple_L-10|mouthPress_L-4|eyeSquint_L-11|mouthRight-0|mouthShrugLower-0|eyeLookUp_R-0|eyeLookOut_R-0|mouthPress_R-5|cheekPuff-2|jawForward-1|1|mouthLowerDown_L-9|mouthFrown_L-6|mouthShrugUpper-26|browOuterUp_L-4|browInnerUp-20|mouthDimple_R-10|browDown_R-0|mouthUpperUp_R-10|mouthRollUpper-8|mouthFunnel-12|mouthStretch_R-21|mouthFrown_R-13|eyeLookDown_R-17|jawOpen-12|jawLeft-0|browDown_L-0|mouthSmile_L-0|noseSneer_R-18|mouthLowerDown_R-8|noseSneer_L-21|eyeWide_L-0|mouthStretch_L-21|browOuterUp_R-4|eyeLookIn_L-4|eyeSquint_R-11|eyeLookUp_L-0|mouthLeft-0|=head#-21.488958,-6.038993,-6.6019735,-0.030653415,-0.10287084,-0.6584072|rightEye#6.0297494,2.4403017,0.25649446|leftEye#6.034903,-1.6660284,-0.17520553|34903,-1.6660284,-0.17520553|

・ 簡略化された記述は以下のようなデータです。

BlendShapeのパラメータ(0~100) | … | BlendShapeのパラメータ(0~100) | … | =head#オイラー角X#オイラー角Y#オイラー角Z#移動値X#移動値Y#移動値Z | rightEye#オイラー角X#オイラー角Y#オイラー角Z | leftEye#オイラー角X#オイラー角Y#オイラー角Z |

角度関連のデータは、ラジアンではなくdegreeで送られてきます。

・ iOS側 ver1.1.8 から Facemotion3dとの互換性を持たせるために外部コマンドが追加されました。
以下のように、「|sendDataVersion=v2」という文字列を付与すると、送られてくるBlendShapeパラメータの値が「&」で区切られるようになります。
iFacialMocap_sahuasouryya9218sauhuiayeta91555dy3719|sendDataVersion=v2

【例】
通常時
mouthSmile_R-0
sendDataVersion=v2
mouthSmile_R&0

何故このような処理になっているかというと、iFacialMocapの上位版となる、Facemotion3dアプリではブレンドシェイプの値にマイナスの値が送られてくる可能性があるためです。区切りの文字に「-」を使っていると衝突が起こってしまう可能性があったためです。

TCP/IPでデータを受信するには

UDPだとフレーム落ちすることもあるので、TCP/IPで受信する方法もあります。
iOS側の49983番ポートに「iFacialMocap_UDPTCP_sahuasouryya9218sauhuiayeta91555dy3719」という文字列を送信するとPC側の49986番ポートにデータが送信されてきます。

送信される文字列は、UDPの時に送信されてくる文字列に「___iFacialMocap」という文字を付加しただけのものです。

・ 簡略化された記述は以下のようなデータです。

BlendShape名-パラメータ(0~100) | BlendShape名-パラメータ(0~100) | … | =head#オイラー角X#オイラー角Y#オイラー角Z#移動値X#移動値Y#移動値Z | rightEye#オイラー角X#オイラー角Y#オイラー角Z | leftEye#オイラー角X#オイラー角Y#オイラー角Z | ___iFacialMocap

TCP/IPでiOSからPCで受信するときコマになった文字列が送信されてくるため、末尾の「___iFacialMocap」を区切り文字として使用してください。

TCP/IPの送信を停止するには、「iFacialMocap_UDPTCPSTOP_sahuasouryya9218sauhuiayeta91555dy3719」という文字列を49983番ポートに送信します。

・ TCP/IPで受信するPython使用例のサンプル

from socket import socket, AF_INET, SOCK_DGRAM, SOCK_STREAM

#UDP send
HOST = ''
PORT = 49983
ADDRESS = "192.168.1.7" #iOS address

s = socket(AF_INET, SOCK_DGRAM)
msg = "iFacialMocap_UDPTCP_sahuasouryya9218sauhuiayeta91555dy3719"
s.sendto(msg.encode(), (ADDRESS, PORT))

s.close()

#create tcp server
with socket(AF_INET, SOCK_STREAM) as tcp_server:
    tcp_server.bind(("192.168.1.5", 49986)) #192.168.1.5 is pc address
    tcp_server.listen(1)

    while True:
        conn, addr = tcp_server.accept()
        with conn:
            while True:
                data = conn.recv(10000)
                print(data.decode('utf-8'))

・UDP同様、iOS側 ver1.1.8 から Facemotion3dとの互換性を持たせるために外部コマンドが追加されました。
以下のように、「|sendDataVersion=v2」という文字列を付与すると、送られてくるBlendShapeパラメータの値が「&」で区切られるようになります。
iFacialMocap_UDPTCP_sahuasouryya9218sauhuiayeta91555dy3719|sendDataVersion=v2

【例】
通常時
mouthSmile_R-0
sendDataVersion=v2
mouthSmile_R&0

何故このような処理になっているかというと、iFacialMocapの上位版となる、Facemotion3dアプリではブレンドシェイプの値にマイナスの値が送られてくる可能性があるためです。区切りの文字に「-」を使っていると衝突が起こってしまう可能性があったためです。

Bluetoothでデータを受信するには

UDPやTCP/IPなど、Wi-Fiを使用したネットワーク接続に失敗する場合、Bluetoothを使った通信をする方法も利用できます。次のGitHubコードを参照してください。

https://github.com/emoto-yasushi/iFacialMocap_Facemotion3d_Bluetooth

iOS内で録画したデータを受信するには

iOS側の49983番ポートにUDPで、"iFacialMocap_bakeRecordedAnimation_start" という文字列を送信すると、録画済みのデータがTCP/IPでPC側の49987番ポートに送信されます。

送信されてくる文字列は、["......","......","......"]___iFacialMocap というような形式になっています。
["......","......","......"]の部分はJSON形式で、UDPやTCP/IPで使用したのと同じ文字列が格納されるようになっています。
常に60FPSで記録したデータです。(iOS内で30FPSに処理が落ちていた場合でも60FPSで送信されるようになっています)

PC上のソフトウェアを介さずに通信する方法は、iFacialMocapリリース当初に私が想定していた機能ではなかったのですが、仕様があきる範囲で3rdパーティーの開発者様は自由に使用して頂いて大丈夫です。ただ、開発者の私が他の方からお問い合わせを頂きつつしていたら、後継アプリの開発時にはiFacialMocapの位置づけが上位互換となる別のアプリに移行をして行きたい予定です。そして、iFacialMocap自体が廃止されることはありませんが、今後ここのアプリしも継続的にアップデートされます。

この機能をご使用して頂いている場合、今後リリースする後継アプリでどのような扱いになるかは未確定であることをご了承ください。
(具体的には、細かく各機能ごとに値段が分かれる設計になる予定です。)

lookForwardボタンを外部から実行するには

"iFacialMocap_lookForward"という文字列をiOSの49983番ポートに送信してください。

Unityへのダイレクトストリーミング

以下のスクリプトをゲームオブジェクトにアタッチして使用することができます。
iFacialMocapとFacemotion3dの両方でストリーミングが可能です。
https://drive.google.com/file/d/10cnZRlglrHmZIv-ECT66eqNZNsiWhMtf/view?usp=sharing

以下の画像のように、オブジェクト名を指定することで動作します。

Unityのインスペクタに表示されたiFacialMocapストリーミングスクリプト

これはVRMではなくFBXファイルを想定したスクリプトです。
VRMで使用したい場合は、ご自身で作成するか、メールでご相談ください。