using UnityEngine; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Collections.Generic; using System; using System.Collections; using System.Globalization; public class UnityRecieve_FACEMOTION3D_and_iFacialMocap : MonoBehaviour { [Header("Connection Settings")] public bool gameStartWithConnect = true; public string iOS_IPAddress = "255.255.255.255"; public int LOCAL_PORT = 49983; [Header("Target Objects")] public List meshTargetList; public List headObjectArray; public List rightEyeObjectArray; public List leftEyeObjectArray; public List headPositionObjectArray; private UdpClient client; private bool StartFlag = true; private UdpClient udp; private Thread thread; private string messageString = ""; private bool isReconnecting = false; private bool isConnected = false; void Start() { if (!string.IsNullOrEmpty(iOS_IPAddress) && LOCAL_PORT != 0) { StartConnection(); } } void StartConnection() { Debug.Log("연결 시작 중..."); if (StartFlag) { StartFlag = false; isConnected = true; if (gameStartWithConnect) { Connect_to_iOS_App(); } CreateUdpServer(); } } void CreateUdpServer() { try { if (LOCAL_PORT <= 0 || LOCAL_PORT > 65535) { throw new ArgumentException("유효하지 않은 포트 번호입니다."); } udp = new UdpClient(LOCAL_PORT); udp.Client.ReceiveTimeout = 5000; thread = new Thread(new ThreadStart(ThreadMethod)); thread.IsBackground = true; thread.Start(); Debug.Log("UDP 서버 생성 완료"); } catch (Exception e) { Debug.LogError($"UDP 서버 생성 실패: {e.Message}"); isConnected = false; } } void Connect_to_iOS_App() { SendMessage_to_iOSapp("iFacialMocap_sahuasouryya9218sauhuiayeta91555dy3719", 49983); SendMessage_to_iOSapp("FACEMOTION3D_OtherStreaming", 49993); } void StopStreaming_iOS_App() { SendMessage_to_iOSapp("StopStreaming_FACEMOTION3D", 49993); } void SendMessage_to_iOSapp(string sendMessage, int send_port) { try { client = new UdpClient(); client.Connect(iOS_IPAddress, send_port); byte[] dgram = Encoding.UTF8.GetBytes(sendMessage); client.Send(dgram, dgram.Length); client.Send(dgram, dgram.Length); client.Send(dgram, dgram.Length); client.Send(dgram, dgram.Length); client.Send(dgram, dgram.Length); } catch { } } void Update() { try { SetAnimation_inside_Unity_settings(); } catch { } } void SetBlendShapeWeightFromStrArray(string[] strArray2) { string mappedShapeName = strArray2[0].Replace("_R", "Right").Replace("_L", "Left"); float weight = float.Parse(strArray2[1], CultureInfo.InvariantCulture); foreach (SkinnedMeshRenderer meshTarget in meshTargetList) { var shared_mesh = meshTarget.sharedMesh; int index = shared_mesh.GetBlendShapeIndex(mappedShapeName); if (index > -1) { meshTarget.SetBlendShapeWeight(index, weight); } } } void SetAnimation_inside_Unity_settings() { try { string[] strArray1 = messageString.Split('='); if (strArray1.Length >= 2) { foreach (string message in strArray1[0].Split('|')) { string[] strArray2 = new string[3]; if (message.Contains("&")) { strArray2 = message.Split('&'); } else { strArray2 = message.Split('-'); } if (strArray2.Length == 2) { SetBlendShapeWeightFromStrArray(strArray2); } } foreach (string message in strArray1[1].Split('|')) { string[] strArray2 = message.Split('#'); if (strArray2.Length == 2) { string[] commaList = strArray2[1].Split(','); if (strArray2[0] == "head") { foreach (GameObject headObject in headObjectArray) { headObject.transform.localRotation = Quaternion.Euler(float.Parse(commaList[0], CultureInfo.InvariantCulture), -float.Parse(commaList[1], CultureInfo.InvariantCulture), -float.Parse(commaList[2], CultureInfo.InvariantCulture)); } foreach (GameObject headPositionObject in headPositionObjectArray) { headPositionObject.transform.localPosition = new Vector3(-float.Parse(commaList[3], CultureInfo.InvariantCulture), float.Parse(commaList[4], CultureInfo.InvariantCulture), float.Parse(commaList[5], CultureInfo.InvariantCulture)); } } else if (strArray2[0] == "rightEye") { foreach (GameObject rightEyeObject in rightEyeObjectArray) { rightEyeObject.transform.localRotation = Quaternion.Euler(float.Parse(commaList[0], CultureInfo.InvariantCulture), -float.Parse(commaList[1], CultureInfo.InvariantCulture), float.Parse(commaList[2], CultureInfo.InvariantCulture)); } } else if (strArray2[0] == "leftEye") { foreach (GameObject leftEyeObject in leftEyeObjectArray) { leftEyeObject.transform.localRotation = Quaternion.Euler(float.Parse(commaList[0], CultureInfo.InvariantCulture), -float.Parse(commaList[1], CultureInfo.InvariantCulture), float.Parse(commaList[2], CultureInfo.InvariantCulture)); } } } } } } catch { } } void ThreadMethod() { while (isConnected) { try { IPEndPoint remoteEP = null; byte[] data = udp.Receive(ref remoteEP); messageString = Encoding.ASCII.GetString(data); } catch (SocketException) { } catch (ThreadAbortException) { break; } catch (Exception e) { Debug.LogError($"데이터 수신 중 오류 발생: {e.Message}"); } Thread.Sleep(5); } } void OnApplicationQuit() { if (StartFlag == false) { StartFlag = true; StopUDP(); } } public void StopUDP() { if (gameStartWithConnect == true) { StopStreaming_iOS_App(); } if (udp != null) { udp.Dispose(); udp = null; } if (thread != null && thread.IsAlive) { thread.Abort(); thread = null; } } } public static class FM3D_and_iFacialMocap_GetAllChildren { public static List GetAll(this GameObject obj) { List allChildren = new List(); allChildren.Add(obj); GetChildren(obj, ref allChildren); return allChildren; } public static void GetChildren(GameObject obj, ref List allChildren) { Transform children = obj.GetComponentInChildren(); if (children.childCount == 0) { return; } foreach (Transform ob in children) { allChildren.Add(ob.gameObject); GetChildren(ob.gameObject, ref allChildren); } } }