338 lines
7.1 KiB
C#
338 lines
7.1 KiB
C#
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
|
|
{
|
|
// broadcast address
|
|
public bool gameStartWithConnect = true;
|
|
public string iOS_IPAddress = "255.255.255.255";
|
|
private UdpClient client;
|
|
private bool StartFlag = true;
|
|
|
|
//object references
|
|
public SkinnedMeshRenderer[] faceMeshRenderers;
|
|
public Transform headBone;
|
|
public Transform rightEyeBone;
|
|
public Transform leftEyeBone;
|
|
public Transform headPositionObject;
|
|
|
|
private UdpClient udp;
|
|
private Thread thread;
|
|
private string messageString = "";
|
|
public int LOCAL_PORT = 49983;
|
|
|
|
// Start is called
|
|
void StartFunction()
|
|
{
|
|
if (StartFlag == true)
|
|
{
|
|
StartFlag = false;
|
|
|
|
FindGameObjectsInsideUnitySettings();
|
|
|
|
//Send to iOS
|
|
if (gameStartWithConnect == true)
|
|
{
|
|
Connect_to_iOS_App();
|
|
}
|
|
|
|
//Recieve udp from iOS
|
|
CreateUdpServer();
|
|
}
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
StartFunction();
|
|
}
|
|
|
|
void CreateUdpServer()
|
|
{
|
|
try
|
|
{
|
|
udp = new UdpClient(LOCAL_PORT);
|
|
udp.Client.ReceiveTimeout = 5;
|
|
|
|
thread = new Thread(new ThreadStart(ThreadMethod));
|
|
thread.Start();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[iFacialMocap] UDP 서버 생성 실패: {e.Message}");
|
|
}
|
|
}
|
|
|
|
IEnumerator WaitProcess(float WaitTime)
|
|
{
|
|
yield return new WaitForSeconds(WaitTime);
|
|
}
|
|
|
|
void Connect_to_iOS_App()
|
|
{
|
|
try
|
|
{
|
|
//iFacialMocap
|
|
SendMessage_to_iOSapp("iFacialMocap_sahuasouryya9218sauhuiayeta91555dy3719", 49983);
|
|
|
|
//Facemotion3d
|
|
SendMessage_to_iOSapp("FACEMOTION3D_OtherStreaming", 49993);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[iFacialMocap] iOS 앱 연결 실패: {e.Message}");
|
|
}
|
|
}
|
|
|
|
void StopStreaming_iOS_App()
|
|
{
|
|
SendMessage_to_iOSapp("StopStreaming_FACEMOTION3D", 49993);
|
|
}
|
|
|
|
//iOSアプリに通信開始のメッセージを送信
|
|
//Send a message to the iOS application to start streaming
|
|
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);
|
|
|
|
// 메시지 전송 시도
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
client.Send(dgram, dgram.Length);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[iFacialMocap] 메시지 전송 실패: {e.Message}");
|
|
}
|
|
}
|
|
|
|
// Update is called once per frame
|
|
void Update()
|
|
{
|
|
try
|
|
{
|
|
SetAnimation_inside_Unity_settings();
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
|
|
//BlendShapeの設定
|
|
//set blendshapes
|
|
void SetBlendShapeWeightFromStrArray(string[] strArray2)
|
|
{
|
|
string mappedShapeName = strArray2[0].Replace("_R", "Right").Replace("_L", "Left");
|
|
float weight = float.Parse(strArray2[1], CultureInfo.InvariantCulture);
|
|
|
|
if (faceMeshRenderers != null)
|
|
{
|
|
foreach (var meshRenderer in faceMeshRenderers)
|
|
{
|
|
if (meshRenderer != null && meshRenderer.sharedMesh != null)
|
|
{
|
|
int index = meshRenderer.sharedMesh.GetBlendShapeIndex(mappedShapeName);
|
|
if (index > -1)
|
|
{
|
|
meshRenderer.SetBlendShapeWeight(index, weight);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//BlendShapeとボーンの回転の設定
|
|
//set blendshapes & bone rotation
|
|
void SetAnimation_inside_Unity_settings()
|
|
{
|
|
try
|
|
{
|
|
string[] strArray1 = messageString.Split('=');
|
|
|
|
if (strArray1.Length >= 2)
|
|
{
|
|
//blendShapes
|
|
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" && headBone != null)
|
|
{
|
|
headBone.localRotation = Quaternion.Euler(float.Parse(commaList[0], CultureInfo.InvariantCulture), -float.Parse(commaList[1], CultureInfo.InvariantCulture), -float.Parse(commaList[2], CultureInfo.InvariantCulture));
|
|
|
|
if (headPositionObject != null)
|
|
{
|
|
headPositionObject.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" && rightEyeBone != null)
|
|
{
|
|
rightEyeBone.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" && leftEyeBone != null)
|
|
{
|
|
leftEyeBone.localRotation = Quaternion.Euler(float.Parse(commaList[0], CultureInfo.InvariantCulture), -float.Parse(commaList[1], CultureInfo.InvariantCulture), float.Parse(commaList[2], CultureInfo.InvariantCulture));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
void FindGameObjectsInsideUnitySettings()
|
|
{
|
|
// 모든 Transform 참조는 이미 인스펙터에서 할당되므로 추가 초기화가 필요 없음
|
|
}
|
|
|
|
void ThreadMethod()
|
|
{
|
|
//Process once every 5ms
|
|
long next = DateTime.Now.Ticks + 50000;
|
|
long now;
|
|
|
|
while (true)
|
|
{
|
|
try
|
|
{
|
|
IPEndPoint remoteEP = null;
|
|
byte[] data = udp.Receive(ref remoteEP);
|
|
messageString = Encoding.ASCII.GetString(data);
|
|
}
|
|
catch (SocketException e)
|
|
{
|
|
if (e.SocketErrorCode != SocketError.TimedOut)
|
|
{
|
|
Debug.LogError($"[iFacialMocap] 데이터 수신 오류: {e.Message}");
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[iFacialMocap] 예상치 못한 오류: {e.Message}");
|
|
}
|
|
|
|
do
|
|
{
|
|
now = DateTime.Now.Ticks;
|
|
}
|
|
while (now < next);
|
|
next += 50000;
|
|
}
|
|
}
|
|
|
|
|
|
public string GetMessageString()
|
|
{
|
|
return messageString;
|
|
}
|
|
|
|
void OnEnable()
|
|
{
|
|
StartFunction();
|
|
}
|
|
|
|
void OnDisable()
|
|
{
|
|
try
|
|
{
|
|
OnApplicationQuit();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
void OnApplicationQuit()
|
|
{
|
|
if (StartFlag == false)
|
|
{
|
|
StartFlag = true;
|
|
StopUDP();
|
|
}
|
|
}
|
|
|
|
|
|
public void StopUDP()
|
|
{
|
|
if (gameStartWithConnect == true)
|
|
{
|
|
StopStreaming_iOS_App();
|
|
}
|
|
udp.Dispose();
|
|
thread.Abort();
|
|
}
|
|
|
|
private bool HasBlendShapes(SkinnedMeshRenderer skin)
|
|
{
|
|
if (!skin.sharedMesh)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (skin.sharedMesh.blendShapeCount <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
}
|
|
public static class FM3D_and_iFacialMocap_GetAllChildren
|
|
{
|
|
public static List<GameObject> GetAll(this GameObject obj)
|
|
{
|
|
List<GameObject> allChildren = new List<GameObject>();
|
|
allChildren.Add(obj);
|
|
GetChildren(obj, ref allChildren);
|
|
return allChildren;
|
|
}
|
|
|
|
public static void GetChildren(GameObject obj, ref List<GameObject> allChildren)
|
|
{
|
|
Transform children = obj.GetComponentInChildren<Transform>();
|
|
if (children.childCount == 0)
|
|
{
|
|
return;
|
|
}
|
|
foreach (Transform ob in children)
|
|
{
|
|
allChildren.Add(ob.gameObject);
|
|
GetChildren(ob.gameObject, ref allChildren);
|
|
}
|
|
}
|
|
} |