647 lines
26 KiB
C#
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);
|
|
}
|
|
}
|
|
} |