Skip to content

Instantly share code, notes, and snippets.

@Ooseykins
Created August 15, 2022 02:57
Show Gist options
  • Save Ooseykins/542926c5386f1971b73d937a55280b3b to your computer and use it in GitHub Desktop.
Save Ooseykins/542926c5386f1971b73d937a55280b3b to your computer and use it in GitHub Desktop.
Simpler Unity receiver for IFacialMocap. Statically access IFacialMocapReciever.currentFrame to get the most recent weights and transforms.
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
public class IFacialMocapReciever : MonoBehaviour
{
const string KEY_IFACIALMOCAP = "iFacialMocap_sahuasouryya9218sauhuiayeta91555dy3719";
const string KEY_FACEMOTION3D = "FACEMOTION3D_OtherStreaming";
const string KEY_DISCONNECT = "StopStreaming_FACEMOTION3D";
const string KEY_LOOKFORWARD = "iFacialMocap_lookForward";
static MocapFrame _currentFrame = new();
public static MocapFrame currentFrame => _currentFrame;
public class MocapFrame
{
public Dictionary<string, float> shapeWeights = new();
public Dictionary<string, Vector3> transformAngles = new();
public Dictionary<string, Vector3> transformPositions = new();
public override string ToString()
{
StringBuilder b = new StringBuilder();
foreach(var k in shapeWeights.Keys)
{
b.Append($"{k}, {shapeWeights[k]}\n");
}
foreach (var k in transformAngles.Keys)
{
b.Append($"Transform {k}, Position {transformPositions[k]}, Angles {transformAngles[k]}\n");
}
return b.ToString();
}
}
Queue<MocapFrame> mocapFrames = new();
bool terminateThread;
Thread thread;
UdpClient udpClient;
public string address;
public int port = 49993;
public int localPort = 49983;
private void Update()
{
if ( thread == null && !terminateThread)
{
Debug.Log("Starting IFacialMocapRecieverThread");
terminateThread = false;
SendMessage(KEY_FACEMOTION3D, port, 6);
SendMessage(KEY_IFACIALMOCAP, port, 6);
udpClient = new UdpClient(localPort);
udpClient.Client.ReceiveTimeout = 10000;
thread = new Thread(new ThreadStart(ThreadMethod));
thread.Start();
}
if(mocapFrames.Count > 0)
{
_currentFrame = mocapFrames.Dequeue();
}
}
private void OnEnable()
{
terminateThread = false;
}
private void OnDisable()
{
terminateThread = true;
udpClient.Dispose();
}
void ThreadMethod()
{
SendMessage(KEY_IFACIALMOCAP, port, 6);
SendMessage(KEY_FACEMOTION3D, port, 6);
while (true)
{
try
{
IPEndPoint RemoteIpEndPoint = null;
byte[] data = udpClient.Receive(ref RemoteIpEndPoint);
MocapFrame frame = new MocapFrame();
string dataString = Encoding.ASCII.GetString(data);
char delimiter = dataString.Contains('&') ? '&' : '-';
foreach (string kv1 in dataString.Split('|'))
{
if (kv1.Contains("#"))
{
string[] kv2 = kv1.Split('#');
if (kv2.Length == 2)
{
string[] pa = kv2[1].Split(',');
if (pa.Length == 6)
{
Vector3 a = new Vector3(ParseFloat(pa[0]), ParseFloat(pa[1]), ParseFloat(pa[2]));
Vector3 p = new Vector3(ParseFloat(pa[3]), ParseFloat(pa[4]), ParseFloat(pa[5]));
frame.transformAngles[kv2[0]] = a;
frame.transformPositions[kv2[0]] = p;
}
else if(pa.Length == 3)
{
Vector3 a = new Vector3(ParseFloat(pa[0]), ParseFloat(pa[1]), ParseFloat(pa[2]));
frame.transformAngles[kv2[0]] = a;
frame.transformPositions[kv2[0]] = Vector3.zero;
}
}
}
else
{
string[] kv2 = kv1.Split(delimiter);
if (kv2.Length == 2)
{
frame.shapeWeights[kv2[0]] = ParseFloat(kv2[1]);
}
}
}
lock (mocapFrames)
{
mocapFrames.Enqueue(frame);
}
}
catch (SocketException e) {
if( e.SocketErrorCode == SocketError.TimedOut)
{
Debug.Log("IFacialMocapReceiver disconnected due to timeout");
}
else if (e.SocketErrorCode == SocketError.Interrupted)
{
Debug.Log("IFacialMocapReceiver socket was forcibly closed");
}
else
{
Debug.LogError($"IFacialMocapReceiver some socket error has occured: {e.SocketErrorCode}");
Debug.LogError(e);
}
break;
}
catch(Exception e)
{
Debug.LogError($"IFacialMocapReceiver some other error occured:");
Debug.LogError(e);
break;
}
if (terminateThread)
{
Debug.Log("IFacialMocapReciever thread terminating");
break;
}
}
SendMessage(KEY_DISCONNECT, port, 6);
udpClient.Dispose();
Debug.Log("IFacialMocapReciever is shut down");
static float ParseFloat(string k)
{
if (float.TryParse(k, out var f))
{
return f;
}
return 0f;
}
}
void SendMessage(string sendMessage, int send_port, int repeats = 1)
{
try
{
UdpClient c = new UdpClient();
c.Connect(address, send_port);
byte[] dgram = Encoding.UTF8.GetBytes(sendMessage);
for (int i = 0; i < repeats; i++)
{
c.Send(dgram, dgram.Length);
}
}
catch (Exception e)
{
Debug.LogError(e);
}
}
public void LookForward()
{
SendMessage(KEY_LOOKFORWARD, port, 1);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment