KINDNICK_URP/Assets/Scripts/iFacialMocap/FacialReaderFromFileWindow.cs
2025-04-25 21:14:54 +09:00

647 lines
26 KiB
C#

/*
copyright : Yasushi Emoto
Created by 2024-10-22
version1.03
*/
using System.Linq;
using UnityEngine;
using UnityEditor;
using System.Collections;
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
public class FacialReaderFromFileWindow : EditorWindow {
private float oneFrameTime = 1.0f / 60.0f;
private float[] recordTimetArray = new float[0];
public float startTime = 0.0f;
private string facialFileString = "";
//object names
public string faceObjectGroupName = "";
public string headBoneName = "";
public string rightEyeBoneName = "";
public string leftEyeBoneName = "";
public string headPositionObjectName = "";
private SkinnedMeshRenderer meshTarget;
private List<SkinnedMeshRenderer> meshTargetList = new List<SkinnedMeshRenderer>();
private List<GameObject> meshTargetObjectArray = new List<GameObject>();
private List<GameObject> headObjectArray = new List<GameObject>();
private List<GameObject> rightEyeObjectArray = new List<GameObject>();
private List<GameObject> leftEyeObjectArray = new List<GameObject>();
private List<GameObject> headPositionObjectArray = new List<GameObject>();
private Dictionary<string,List<float>> BlendShapeNameAndValueList;
private List<string> blendShapeNameList = new List<string>();
private List<float> HeadRotationXList = new List<float>();
private List<float> HeadRotationYList = new List<float>();
private List<float> HeadRotationZList = new List<float>();
private List<float> RightEyeRotationXList = new List<float>();
private List<float> RightEyeRotationYList = new List<float>();
private List<float> RightEyeRotationZList = new List<float>();
private List<float> LeftEyeRotationXList = new List<float>();
private List<float> LeftEyeRotationYList = new List<float>();
private List<float> LeftEyeRotationZList = new List<float>();
private List<float> HeadPositionXList = new List<float>();
private List<float> HeadPositionYList = new List<float>();
private List<float> HeadPositionZList = new List<float>();
[MenuItem("Window/FacialReaderFromFile")]
public static void ShowWindow ()
{
GetWindow<FacialReaderFromFileWindow>("FacialReaderFromFile");
}
private void FindGameObjectsInsideUnitySettings()
{
//Find BlendShape Objects
meshTargetList = new List<SkinnedMeshRenderer>();
meshTargetObjectArray = new List<GameObject>();
BlendShapeNameAndValueList = new Dictionary<string,List<float>>();
blendShapeNameList = new List<string>();
HeadRotationXList = new List<float>();
HeadRotationYList = new List<float>();
HeadRotationZList = new List<float>();
RightEyeRotationXList = new List<float>();
RightEyeRotationYList = new List<float>();
RightEyeRotationZList = new List<float>();
LeftEyeRotationXList = new List<float>();
LeftEyeRotationYList = new List<float>();
LeftEyeRotationZList = new List<float>();
HeadPositionXList = new List<float>();
HeadPositionYList = new List<float>();
HeadPositionZList = new List<float>();
GameObject faceObjGrp = GameObject.Find(faceObjectGroupName);
if (faceObjGrp != null)
{
List<GameObject> list = FacialReaderFromFileWindow_GetAllChildren.GetAll(faceObjGrp);
foreach (GameObject obj in list)
{
meshTarget = obj.GetComponent<SkinnedMeshRenderer>();
if (meshTarget != null)
{
if (HasBlendShapes(meshTarget) == true)
{
meshTargetList.Add(meshTarget);
meshTargetObjectArray.Add(obj);
}
}
}
}
//Find Bone Objects
headObjectArray = new List<GameObject>();
foreach (string headString in headBoneName.Split(','))
{
GameObject headObject = GameObject.Find(headString);
if (headObject != null)
{
headObjectArray.Add(headObject);
}
}
rightEyeObjectArray = new List<GameObject>();
foreach (string rightEyeString in rightEyeBoneName.Split(','))
{
GameObject rightEyeObject = GameObject.Find(rightEyeString);
if (rightEyeObject != null)
{
rightEyeObjectArray.Add(rightEyeObject);
}
}
leftEyeObjectArray = new List<GameObject>();
foreach (string leftEyeString in leftEyeBoneName.Split(','))
{
GameObject leftEyeObject = GameObject.Find(leftEyeString);
if (leftEyeObject != null)
{
leftEyeObjectArray.Add(leftEyeObject);
}
}
headPositionObjectArray = new List<GameObject>();
foreach (string headPositionString in headPositionObjectName.Split(','))
{
GameObject headPositionObject = GameObject.Find(headPositionString);
if (headPositionObject != null)
{
headPositionObjectArray.Add(headPositionObject);
}
}
}
void OnGUI ()
{
GUILayout.Label("Apply facial movement from file", EditorStyles.boldLabel);
faceObjectGroupName = EditorGUILayout.TextField("Face Object Group Name: ", faceObjectGroupName);
headBoneName = EditorGUILayout.TextField("Head Bone Name: ", headBoneName);
rightEyeBoneName = EditorGUILayout.TextField("Right Eye Bone Name: ", rightEyeBoneName);
leftEyeBoneName = EditorGUILayout.TextField("Left Eye Bone Name: ", leftEyeBoneName);
headPositionObjectName = EditorGUILayout.TextField("Head Position Object Name: ", headPositionObjectName);
startTime = EditorGUILayout.FloatField("Start Time(s):", startTime);
if (GUILayout.Button("Read from file"))
{
FindGameObjectsInsideUnitySettings();
ReadFromFile();
}
}
void ReadFromFile ()
{
string path = EditorUtility.OpenFilePanel("Read from txt file", "", "txt");
if (path.Length != 0)
{
StreamReader reader = new StreamReader(path);
facialFileString = reader.ReadToEnd();
reader.Close(); // StreamReaderを閉じることを忘れないでください
string[] txtArray = new string[0];
try
{
using (StreamReader streamReader = new StreamReader(path)) // 変数名を変更
{
string line;
int lineNumber = 0;
while ((line = streamReader.ReadLine()) != null)
{
lineNumber++;
if (lineNumber == 3) // line3
{
txtArray = line.Split(new[] { "\",\"" }, StringSplitOptions.None);
break;
}
if (lineNumber == 4) // line4
{
recordTimetArray = ConvertStringToFloatArray(line);
break;
}
}
}
}
catch (IOException e)
{
Debug.LogError("File reading error: " + e.Message);
}
foreach (var txt in txtArray)
{
try
{
string txt_remove = txt.Replace("\"", "");
string[] strArray1 = txt.Split('=');
if (strArray1.Length == 2)
{
//blendShapes
foreach (string message in strArray1[0].Split('|'))
{
try
{
string[] strArray2 = message.Split('&');
if (strArray2.Length == 2)
{
var bs_name = strArray2[0].Replace("_L","Left").Replace("_R","Right");
//if key exists
if ( BlendShapeNameAndValueList.ContainsKey(bs_name) )
{
List<float> blendShape_values = new List<float>();
blendShape_values = BlendShapeNameAndValueList[bs_name];
blendShape_values.Add(float.Parse(strArray2[1], CultureInfo.InvariantCulture));
BlendShapeNameAndValueList[bs_name] = blendShape_values;
}
else
{
BlendShapeNameAndValueList.Add(bs_name,new List<float>(){float.Parse(strArray2[1], CultureInfo.InvariantCulture)});
blendShapeNameList.Add(bs_name);
}
}
}
catch(System.NullReferenceException e)
{
Debug.Log(e);
}
}
foreach (string message in strArray1[1].Split('|'))
{
try
{
string[] strArray2 = message.Split('#');
if (strArray2.Length == 2)
{
string[] commaList = strArray2[1].Split(',');
if (commaList.Length > 1)
{
if (strArray2[0] == "head")
{
HeadRotationXList.Add(float.Parse(commaList[0], CultureInfo.InvariantCulture));
HeadRotationYList.Add(-float.Parse(commaList[1], CultureInfo.InvariantCulture));
HeadRotationZList.Add(-float.Parse(commaList[2], CultureInfo.InvariantCulture));
HeadPositionXList.Add(-float.Parse(commaList[3], CultureInfo.InvariantCulture));
HeadPositionYList.Add(float.Parse(commaList[4], CultureInfo.InvariantCulture));
HeadPositionZList.Add(float.Parse(commaList[5], CultureInfo.InvariantCulture));
}
else if (strArray2[0] == "rightEye")
{
RightEyeRotationXList.Add(float.Parse(commaList[0], CultureInfo.InvariantCulture));
RightEyeRotationYList.Add(-float.Parse(commaList[1], CultureInfo.InvariantCulture));
RightEyeRotationZList.Add(0.0f);
}
else if (strArray2[0] == "leftEye")
{
LeftEyeRotationXList.Add(float.Parse(commaList[0], CultureInfo.InvariantCulture));
LeftEyeRotationYList.Add(-float.Parse(commaList[1], CultureInfo.InvariantCulture));
LeftEyeRotationZList.Add(0.0f);
}
}
}
}
catch(System.NullReferenceException e)
{
Debug.Log(e);
}
}
}
}
catch(System.NullReferenceException e)
{
Debug.Log(e);
}
}
try
{
foreach (var meshTargetObj in meshTargetObjectArray)
{
AnimationCurve curve;
Keyframe[] keys;
var _animation = meshTargetObj.GetComponent<Animation>();
if (!_animation) _animation = meshTargetObj.AddComponent<Animation>();
var clip = _animation.clip;
var clip_exists_flag = true;
if (!clip)
{
clip_exists_flag = false;
clip = new AnimationClip();
}
meshTarget = meshTargetObj.GetComponent<SkinnedMeshRenderer>();
if (meshTarget != null)
{
if (HasBlendShapes(meshTarget) == true)
{
var shared_mesh = meshTarget.sharedMesh;
for (int b_count = 0; b_count < shared_mesh.blendShapeCount; b_count++)
{
string sharedMeshBlendShapeName = shared_mesh.GetBlendShapeName(b_count);
foreach (var mappedShapeName in BlendShapeNameAndValueList.Keys)
{
if (sharedMeshBlendShapeName.Contains(mappedShapeName))
{
List<float> blendShape_values = new List<float>();
blendShape_values = BlendShapeNameAndValueList[mappedShapeName];
keys = new Keyframe[blendShape_values.Count];
for ( int i = 0 ; i < blendShape_values.Count ; i++ )
{
keys[i] = new Keyframe(startTime + oneFrameTime * i, blendShape_values[i]);
}
curve = new AnimationCurve(keys);
clip.SetCurve("", typeof(SkinnedMeshRenderer), "blendShape."+sharedMeshBlendShapeName, curve);
break;
}
}
}
}
}
if(clip_exists_flag == false)
{
clip.name = meshTargetObj.name+"_AnimClip"; // set name
clip.legacy = true; // change to legacy
_animation.clip = clip; // set default clip
_animation.AddClip(clip, clip.name); // add clip to animation component
AssetDatabase.CreateAsset(clip, "Assets/"+clip.name+".anim"); // to create asset
}
}
}
catch(System.NullReferenceException e)
{
Debug.Log(e);
}
try
{
foreach (var headObject in headObjectArray)
{
var _animation = headObject.GetComponent<Animation>();
if (!_animation) _animation = headObject.AddComponent<Animation>();
var clip = _animation.clip;
var clip_exists_flag = true;
if (!clip)
{
clip_exists_flag = false;
clip = new AnimationClip();
}
AnimationCurve curve_x;
Keyframe[] keys;
keys = new Keyframe[HeadRotationXList.Count];
for ( int i = 0 ; i < HeadRotationXList.Count ; i++ )
{
keys[i] = new Keyframe(startTime + oneFrameTime * i, HeadRotationXList[i]);
}
curve_x = new AnimationCurve(keys);
AnimationCurve curve_y;
keys = new Keyframe[HeadRotationYList.Count];
for ( int i = 0 ; i < HeadRotationYList.Count ; i++ )
{
keys[i] = new Keyframe(startTime + oneFrameTime * i, HeadRotationYList[i]);
}
curve_y = new AnimationCurve(keys);
AnimationCurve curve_z;
keys = new Keyframe[HeadRotationZList.Count];
for ( int i = 0 ; i < HeadRotationZList.Count ; i++ )
{
keys[i] = new Keyframe(startTime+ oneFrameTime * i, HeadRotationZList[i]);
}
curve_z = new AnimationCurve(keys);
clip.SetCurve("", typeof(Transform), "localEulerAngles.x", curve_x);
clip.SetCurve("", typeof(Transform), "localEulerAngles.y", curve_y);
clip.SetCurve("", typeof(Transform), "localEulerAngles.z", curve_z);
if(clip_exists_flag == false)
{
clip.name = headObject.name+"_AnimClip"; // set name
clip.legacy = true; // change to legacy
_animation.clip = clip; // set default clip
_animation.AddClip(clip, clip.name); // add clip to animation component
AssetDatabase.CreateAsset(clip, "Assets/"+clip.name+".anim"); // to create asset
}
}
foreach (var rightEyeObject in rightEyeObjectArray)
{
var _animation = rightEyeObject.GetComponent<Animation>();
if (!_animation) _animation = rightEyeObject.AddComponent<Animation>();
var clip = _animation.clip;
var clip_exists_flag = true;
if (!clip)
{
clip_exists_flag = false;
clip = new AnimationClip();
}
AnimationCurve curve_x;
Keyframe[] keys;
keys = new Keyframe[RightEyeRotationXList.Count];
for ( int i = 0 ; i < RightEyeRotationXList.Count ; i++ )
{
keys[i] = new Keyframe(startTime + oneFrameTime * i, RightEyeRotationXList[i]);
}
curve_x = new AnimationCurve(keys);
AnimationCurve curve_y;
keys = new Keyframe[RightEyeRotationYList.Count];
for ( int i = 0 ; i < RightEyeRotationYList.Count ; i++ )
{
keys[i] = new Keyframe(startTime + oneFrameTime * i, RightEyeRotationYList[i]);
}
curve_y = new AnimationCurve(keys);
AnimationCurve curve_z;
keys = new Keyframe[RightEyeRotationZList.Count];
for ( int i = 0 ; i < RightEyeRotationZList.Count ; i++ )
{
keys[i] = new Keyframe(startTime + oneFrameTime * i, RightEyeRotationZList[i]);
}
curve_z = new AnimationCurve(keys);
clip.SetCurve("", typeof(Transform), "localEulerAngles.x", curve_x);
clip.SetCurve("", typeof(Transform), "localEulerAngles.y", curve_y);
clip.SetCurve("", typeof(Transform), "localEulerAngles.z", curve_z);
if(clip_exists_flag == false)
{
clip.name = rightEyeObject.name+"_AnimClip"; // set name
clip.legacy = true; // change to legacy
_animation.clip = clip; // set default clip
_animation.AddClip(clip, clip.name); // add clip to animation component
AssetDatabase.CreateAsset(clip, "Assets/"+clip.name+".anim"); // to create asset
}
}
foreach (var leftEyeObject in leftEyeObjectArray)
{
var _animation = leftEyeObject.GetComponent<Animation>();
if (!_animation) _animation = leftEyeObject.AddComponent<Animation>();
var clip = _animation.clip;
var clip_exists_flag = true;
if (!clip)
{
clip_exists_flag = false;
clip = new AnimationClip();
}
AnimationCurve curve_x;
Keyframe[] keys;
keys = new Keyframe[LeftEyeRotationXList.Count];
for ( int i = 0 ; i < LeftEyeRotationXList.Count ; i++ )
{
keys[i] = new Keyframe(startTime + oneFrameTime * i, LeftEyeRotationXList[i]);
}
curve_x = new AnimationCurve(keys);
AnimationCurve curve_y;
keys = new Keyframe[LeftEyeRotationYList.Count];
for ( int i = 0 ; i < LeftEyeRotationYList.Count ; i++ )
{
keys[i] = new Keyframe(startTime + oneFrameTime * i, LeftEyeRotationYList[i]);
}
curve_y = new AnimationCurve(keys);
AnimationCurve curve_z;
keys = new Keyframe[LeftEyeRotationZList.Count];
for ( int i = 0 ; i < LeftEyeRotationZList.Count ; i++ )
{
keys[i] = new Keyframe(startTime + oneFrameTime * i, LeftEyeRotationZList[i]);
}
curve_z = new AnimationCurve(keys);
clip.SetCurve("", typeof(Transform), "localEulerAngles.x", curve_x);
clip.SetCurve("", typeof(Transform), "localEulerAngles.y", curve_y);
clip.SetCurve("", typeof(Transform), "localEulerAngles.z", curve_z);
if(clip_exists_flag == false)
{
clip.name = leftEyeObject.name+"_AnimClip"; // set name
clip.legacy = true; // change to legacy
_animation.clip = clip; // set default clip
_animation.AddClip(clip, clip.name); // add clip to animation component
AssetDatabase.CreateAsset(clip, "Assets/"+clip.name+".anim"); // to create asset
}
}
foreach (var headPositionObject in headPositionObjectArray)
{
var _animation = headPositionObject.GetComponent<Animation>();
if (!_animation) _animation = headPositionObject.AddComponent<Animation>();
var clip = _animation.clip;
var clip_exists_flag = true;
if (!clip)
{
clip_exists_flag = false;
clip = new AnimationClip();
}
AnimationCurve curve_x;
Keyframe[] keys;
keys = new Keyframe[HeadPositionXList.Count];
for ( int i = 0 ; i < HeadPositionXList.Count ; i++ )
{
keys[i] = new Keyframe(startTime + oneFrameTime * i, HeadPositionXList[i]);
}
curve_x = new AnimationCurve(keys);
AnimationCurve curve_y;
keys = new Keyframe[HeadPositionYList.Count];
for ( int i = 0 ; i < HeadPositionYList.Count ; i++ )
{
keys[i] = new Keyframe(startTime + oneFrameTime * i, HeadPositionYList[i]);
}
curve_y = new AnimationCurve(keys);
AnimationCurve curve_z;
keys = new Keyframe[HeadPositionZList.Count];
for ( int i = 0 ; i < HeadPositionZList.Count ; i++ )
{
keys[i] = new Keyframe(startTime + oneFrameTime * i, HeadPositionZList[i]);
}
curve_z = new AnimationCurve(keys);
clip.SetCurve("", typeof(Transform), "localPosition.x", curve_x);
clip.SetCurve("", typeof(Transform), "localPosition.y", curve_y);
clip.SetCurve("", typeof(Transform), "localPosition.z", curve_z);
if(clip_exists_flag == false)
{
clip.name = headPositionObject.name+"_AnimClip"; // set name
clip.legacy = true; // change to legacy
_animation.clip = clip; // set default clip
_animation.AddClip(clip, clip.name); // add clip to animation component
AssetDatabase.CreateAsset(clip, "Assets/"+clip.name+".anim"); // to create asset
}
}
}
catch(System.NullReferenceException e)
{
Debug.Log(e);
}
}
}
private static float[] ConvertStringToFloatArray(string jsonString)
{
string pattern = @"-?\d+(\.\d+)?(e[+-]?\d+)?";
MatchCollection matches = Regex.Matches(jsonString, pattern);
float[] floatArray = matches.OfType<Match>()
.Select(m => float.Parse(m.Value))
.ToArray();
return floatArray;
}
private bool HasBlendShapes(SkinnedMeshRenderer skin)
{
if (!skin.sharedMesh)
{
return false;
}
if (skin.sharedMesh.blendShapeCount <= 0)
{
return false;
}
return true;
}
}
public static class FacialReaderFromFileWindow_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);
}
}
}