-
-
Save yosun/e142738dae5bb740dec369733a9492b3 to your computer and use it in GitHub Desktop.
BlendShaperReader and Helper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*// BlendShapeHelper.cs v0.03 (Created November 1, 2017 | I. Yosun Chang) added transform | |
/* | |
MIT License | |
Copyright(c) 2017-2018 | |
I. Yosun Chang [email protected] [email protected] 415.779.6786 | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
SOFTWARE.*/ | |
using System.Collections.Generic; | |
using Unity.Collections; | |
using UnityEngine; // ironically only needed for Debug.Log | |
using UnityEngine.XR.ARKit; | |
#if UNITY_EDITOR | |
//using ARKitFaceSubsystem = ARFoundationRemote.Runtime.FaceSubsystem; | |
#endif | |
public partial class facedHelper { // BlendShapeHelper | |
float lastval = 0; | |
public static string DumpBlendShapes(List<NativeArray<ARKitBlendShapeCoefficient>> listBlendShapes, List<float> listTimes, List<Vector3> pos, List<Quaternion> rot, List<Quaternion> camrot) | |
{ | |
string s = ""; | |
for (int i = 0; i < listBlendShapes.Count; i++) | |
{ | |
s += listTimes[i].ToString("F6") + "," + GenBlendlet(listBlendShapes[i]); // first blendlet has time attached to it | |
// Debug.Log("jawOpen "+i+" "+listBlendShapes[i]["jawOpen"]); | |
s += "*" + pos[i].ToString("F4") + "~" + rot[i].ToString("F4") + "~" + camrot[i].ToString("F4"); | |
s += "^"; | |
} | |
Debug.Log("DumpBlendShapes " + listBlendShapes.Count); | |
return s; | |
} | |
public static string DumpBlendShapes() | |
{ | |
return DumpBlendShapes(facedRecorder.listBlendShapes, facedRecorder.listTimes, facedRecorder.listPos, facedRecorder.listRot, facedRecorder.camRot); | |
} | |
static string GenBlendlet(NativeArray<ARKitBlendShapeCoefficient> bs) | |
{ | |
string s = ""; | |
ARKitBlendShapeCoefficient[] blendshapes = bs.ToArray(); | |
for (int i = 0; i < blendshapes.Length; i++) | |
{ | |
//s += kvp.Key + "," + kvp.Value + ";"; | |
s += bs[i].blendShapeLocation + "," + bs[i].coefficient + ";"; | |
// s += bs[i].coefficient + "," + bs[i].coefficient + ";"; | |
} | |
return s; | |
} | |
static string DumpAppleKeys(string s){ | |
string[] str = Parse.SSV (s); string dump = "{"; | |
for (int i = 0; i < str.Length; i++) { | |
string[] str2 = Parse.CSV (str [i]); | |
dump += "\""+str2 [0]+"\","; | |
} | |
return dump.Substring (0, dump.Length - 1) + "}"; | |
} | |
static string DumpAppleKeysEnum(string s) { | |
string[] str = Parse.SSV(s); string dump = "{"; | |
for (int i = 0; i < str.Length; i++) { | |
string[] str2 = Parse.CSV(str[i]); | |
dump += str2[0] + ",\n"; | |
} | |
return dump.Substring(0, dump.Length - 1) + "}"; | |
} | |
static Dictionary<string,float> ParseBlendlet(string s){ | |
Dictionary<string,float> blendlet = new Dictionary<string,float> (); | |
string[] str = Parse.SSV (s); | |
for (int i = 0; i < str.Length; i++) { | |
// Debug.Log (str [i]); | |
string[] str2 = Parse.CSV (str [i]); | |
if (blendlet.ContainsKey(str2[0])) print(str2[0]+ " blendlet contained!"); | |
else | |
blendlet.Add (str2[0],Mathf2.String2Float(str2[1])); | |
} | |
return blendlet; | |
} | |
/*static List<float> ParseTime(string s){ | |
List<float> times = new List<float> (); | |
string[] str = Parse.SSV (s); | |
for (int i = 0; i < str.Length; i++) { | |
string[] str2 = Parse.CSV (str [i]); | |
times.Add (Mathf2.String2Float(str2[0])); | |
} | |
return times; | |
}*/ //deprecated | |
public static void ReadBlendShapes(string s,out List<Dictionary<string,float>> list,out List<float> times,out List<Vector3> pos,out List<Quaternion> rot,out List<Quaternion> camrot){ | |
list = new List<Dictionary<string,float>> (); | |
times = new List<float> (); | |
pos = new List<Vector3>(); | |
rot = new List<Quaternion>(); | |
camrot = new List<Quaternion>(); | |
if (s.Length > 3) { | |
string[] str = Parse.CaretSV (s); | |
Debug.Log ("TotalBlendShapeFrames: "+str.Length); | |
for (int i = 0; i < str.Length; i++) { | |
string[] sstar = Parse.StarSV(str[i]); | |
string processed = sstar [0]; | |
string[] csv = Parse.CSV (processed); | |
float t = Mathf2.String2Float (csv [0]); | |
processed = DumpDelimiterAfter (1, ",", csv); | |
list.Add (ParseBlendlet (processed)); | |
times.Add (t); | |
if (sstar.Length > 1) { | |
string[] ttemp = Parse.TSV(sstar[1]); | |
pos.Add(Mathf2.String2Vector3(ttemp[0])); | |
rot.Add(Mathf2.String2Quat(ttemp[1])); | |
if(ttemp.Length>2) | |
camrot.Add(Mathf2.String2Quat(ttemp[2])); | |
} | |
/* if (i == 0) | |
Debug.Log(DumpAppleKeys (processed)); | |
if (i == 0) | |
Debug.Log(DumpAppleKeysEnum(processed));*/ | |
} | |
if (times [0] > 1f) { | |
int timedelta = Mathf.FloorToInt(times[0]); | |
for (int i = 0; i < times.Count; i++) { | |
times [i] -= timedelta; | |
} | |
} | |
} else | |
Debug.Log (s.Length); | |
} | |
static string DumpDelimiterAfter(int n, string delimiter, string[] s) | |
{ | |
string processed = ""; | |
for (int i = n; i < s.Length; i++) | |
{ | |
processed += s[i] + delimiter; | |
} | |
return processed.Substring(0, processed.Length - 1); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*// BlendShapeReader.cs v0.02 //TODO use coroutines for timer instead of update lolz | |
MIT License | |
Copyright(c) 2017-2018 | |
I. Yosun Chang [email protected] [email protected] 415.779.6786 | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
SOFTWARE.*/ | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class BlendShapeReader : MonoBehaviour | |
{ | |
static List<Dictionary<string, float>> listBlendShapes = new List<Dictionary<string, float>>(); | |
static List<float> listTimes = new List<float>(); | |
static List<Vector3> listPos = new List<Vector3>(); | |
static List<Quaternion> listRot = new List<Quaternion>(); | |
public List<Quaternion> camRot = new List<Quaternion>(); | |
public bool playing = false; float time = 0f; | |
float nextTime = 0f; int current = 0; | |
public BlendShapeMapper bsm; | |
public string teststringurl = ""; | |
public bool useDelegate = false; | |
public delegate void ProcessEachBlendShapeUpdate(float time, Dictionary<string, float> blendshapes, Vector3 pos, Quaternion rot, Quaternion camrot); | |
public static ProcessEachBlendShapeUpdate SubscribeEachBlendShapeUpdate; | |
public delegate void ProcessEachBlendShapeUpdateBasic(float time, Dictionary<string, float> blendshapes); | |
public static ProcessEachBlendShapeUpdateBasic SubscribeEachBlendShapeUpdateBasic; | |
public UIInputWait inputwait; | |
public Transform tHead; | |
void Start() | |
{ | |
//LoadBlendShapesFile(teststringurl); //test | |
UIInputWait.SubscribeWhenStringReceived += LoadBlendShapesURL; | |
// SubscribeEachBlendShapeUpdate += CustomProcessBlendShape(time,dicBlendShapes); | |
} | |
public void LoadBlendShapesFile(string filepath) | |
{ | |
print("LoadBlendShapesFile " + filepath); | |
bsLoaded = true; | |
LoadBlendShapes(SetFilename.ReadFile(filepath)); | |
} | |
public void LoadBlendShapesURL(string url) | |
{ | |
if (url == null || url.Length < 5) return; | |
if (url != PlayerPrefs.GetString("lastblendshape_url")) | |
{ | |
StartCoroutine(ActuallyLoadBlendShape(url)); | |
} | |
else | |
LoadBlendShapes(PlayerPrefs.GetString("lastblendshape_string")); | |
} | |
public static bool bsLoaded = false; | |
IEnumerator ActuallyLoadBlendShape(string url) | |
{ | |
bsLoaded = false; | |
WWW w = new WWW(url); | |
print("Loading " + url); | |
yield return w; | |
if (w.error == null) | |
{ | |
PlayerPrefs.SetString("lastblendshape_url", url); | |
PlayerPrefs.SetString("lastblendshape_string", w.text); | |
LoadBlendShapes(w.text); | |
inputwait.UI_DoneWaiting(); | |
bsLoaded = true; | |
} | |
else | |
{ | |
print(w.error); | |
} | |
//inputwait.SetInputText(w.error); | |
} | |
public void LoadBlendShapes(string s) | |
{ | |
if (string.IsNullOrEmpty(s)) return; | |
facedHelper.ReadBlendShapes(s, out listBlendShapes, out listTimes, out listPos, out listRot, out camRot); | |
time = 0f; | |
nextTime = listTimes[0]; | |
print("Loaded BlendShapeString Characters: " + s.Length + " frames: " + listTimes.Count); | |
} | |
#if UNITY_EDITOR | |
private void OnGUI() | |
{ | |
if (GUI.Button(new Rect(10, 10, 100, 50), "x")) | |
{ | |
StartPlaying(); | |
} | |
} | |
#endif | |
void Update() | |
{ | |
if (playing) | |
{ | |
time += Time.deltaTime; | |
if (NextTimeInc()) | |
{ | |
LoadBlendShapes(nextTime, listBlendShapes[current], listPos[current], listRot[current], camRot[current]); | |
} | |
//else { playing = false; tpu.UI_Only_Play(); } | |
} | |
} | |
public void StartPlaying() | |
{ | |
print("StartPlaying"); | |
playing = true; | |
current = 0; | |
time = 0f; | |
nextTime = listTimes[0]; | |
if (listRot.Count > 0 && listPos.Count > 0 && camRot.Count > 0) | |
LoadBlendShapes(nextTime, listBlendShapes[0], listPos[0], listRot[0], camRot[0]); | |
else | |
LoadBlendShapes(nextTime, listBlendShapes[0]); | |
} | |
public ThePlayUI tpu; | |
public void StopPlaying() | |
{ | |
print("StopPlaying"); | |
playing = false; | |
} | |
public void TogglePlaying() | |
{ | |
if (playing) | |
StopPlaying(); | |
else | |
StartPlaying(); | |
} | |
void LoadBlendShapes(float t, Dictionary<string, float> blendshapes) | |
{ | |
if (useDelegate) | |
SubscribeEachBlendShapeUpdateBasic(t, blendshapes); | |
else | |
bsm.PlayConvertedRemapping(t, blendshapes); | |
} | |
public bool useTransforms; | |
void LoadBlendShapes(float t, Dictionary<string, float> blendshapes, Vector3 pos, Quaternion rot, Quaternion camrot) | |
{ | |
if (useDelegate) | |
{ | |
SubscribeEachBlendShapeUpdate(t, blendshapes, pos, rot, camrot); | |
} | |
else | |
{ | |
bsm.PlayConvertedRemapping(t, blendshapes); | |
if (pos != null && useTransforms) | |
{ | |
tHead.transform.position = pos; | |
tHead.transform.rotation = rot * Quaternion.Euler(0, 180f, 0); | |
//Camera.main.transform.rotation = camrot; | |
} | |
} | |
} | |
public bool loopMe = true; | |
bool NextTimeInc() | |
{ | |
if (time > nextTime) | |
{ | |
current++; | |
if (current >= listTimes.Count) | |
{ | |
if (loopMe) | |
{ | |
current = 0; | |
time = 0f; | |
} | |
else { playing = false; tpu.UI_Only_Play(); return false; } | |
} | |
nextTime = listTimes[current]; | |
//print (nextTime); | |
return true; | |
} | |
else | |
return false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment