iFacialMocap 통신 사양


iFacialMocap에서는 서드파티 도구 개발자가 PC 소프트웨어를 거치지 않고 UDP 또는 TCP/IP를 사용해 페이셜 데이터를 받을 수 있습니다.

UDP로 데이터를 받는 방법

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 앱에서 blendShape 값으로 음수가 전송될 가능성이 있기 때문입니다.
"-"를 구분 문자로 사용하면 값과 충돌할 수 있었습니다.

TCP/IP로 데이터를 받는 방법

UDP에서는 프레임이 누락될 수 있으므로 TCP/IP로 수신하는 방법도 있습니다.
iOS 쪽 49983번 포트로 "iFacialMocap_UDPTCP_sahuasouryya9218sauhuiayeta91555dy3719" 문자열을 UDP로 보내면 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 전송을 중지하려면 49983번 포트로 "iFacialMocap_UDPTCPSTOP_sahuasouryya9218sauhuiayeta91555dy3719" 문자열을 보내세요.

・ 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 앱에서 blend shape 값으로 음수가 전송될 가능성이 있기 때문입니다. "-"를 구분 문자로 사용하면 값과 충돌할 수 있었습니다.

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 출시 당시 제가 의도했던 기능은 아니었지만, 공개된 사양 범위 안에서는 서드파티 개발자가 자유롭게 사용하셔도 괜찮습니다. 다만 후속 앱 개발에서는 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에서 사용하고 싶다면 직접 작성하시거나 이메일로 문의해 주세요.