/****************************************************************************************************/ public void OnGUI() { //Define styles titleStyle = new GUIStyle(EditorStyles.label); titleStyle.fontStyle = FontStyle.Bold; titleStyle.fontSize = 12; titleStyle.alignment = TextAnchor.UpperCenter; GUILayout.BeginHorizontal(); { GUILayout.FlexibleSpace(); GUILayout.Label(titleIcon, GUILayout.MinWidth(1)); GUILayout.FlexibleSpace(); } GUILayout.EndHorizontal(); EditorGUILayout.LabelField("Version " + LiveHelpers.CurrentVersion(), titleStyle); titleStyle.alignment = TextAnchor.LowerLeft; headingStyle = new GUIStyle(EditorStyles.label); headingStyle.fontStyle = FontStyle.Bold; headingStyle.fontSize = 11; headingStyle.alignment = TextAnchor.LowerLeft; //Draw UI mainScrollPos = EditorGUILayout.BeginScrollView(mainScrollPos); { CreateFileGUI(); CreateControlSetupGUI(); CreateExpressionSetGUI(); CreateSaveGUI(); CreateHelpGUI(); } EditorGUILayout.EndScrollView(); }
void IntializeRecording() { List <string> controlNames = character.GetControlList(); List <UnityEngine.Object> controls = LiveUnityInterface.GetControls(this.gameObject, controlNames); recordingTime = 0.0f; //Loop through controls and create anim curves for each for (int i = 0; i < controlNames.Count; i++) { FTIAnimCurve ftiCurve = new FTIAnimCurve(); UnityEngine.Object control = controls[i]; if (control is Transform) { Transform transfromControl = (Transform)control; ftiCurve.hierachyPath = LiveUnityInterface.GetRelativeGameObjectPath(transfromControl.gameObject, this.gameObject); ftiCurve.isBlendShape = false; int curveNum = 3; string attr = LiveHelpers.GetAttrString(controlNames [i]); if (attr == LiveCharacterSetup.rotationSuffix) { curveNum++; } for (int j = 0; j < curveNum; j++) { ftiCurve.animCurves.Add(new AnimationCurve()); //Intialize values to have at least 1 keyframe if (attr != LiveCharacterSetup.rotationSuffix) { ftiCurve.animCurves[j].AddKey(0f, transfromControl.localPosition[j]); } else { ftiCurve.animCurves[j].AddKey(0f, transfromControl.localRotation[j]); } } } else if (control is SkinnedMeshRenderer) { SkinnedMeshRenderer blendShapeControl = (SkinnedMeshRenderer)control; string attr = LiveHelpers.GetAttrString(controlNames[i]); int index = LiveUnityInterface.GetBlendShapeIndex(blendShapeControl, attr); ftiCurve.hierachyPath = LiveUnityInterface.GetRelativeGameObjectPath(blendShapeControl.gameObject, this.gameObject); ftiCurve.isBlendShape = true; ftiCurve.animCurves.Add(new AnimationCurve()); ftiCurve.animCurves[0].AddKey(0f, blendShapeControl.GetBlendShapeWeight(index)); } RecordedCurves.Add(controlNames[i], ftiCurve); } }
/****************************************************************************************************/ static public List <UnityEngine.Object> GetControls(GameObject rootObj, List <string> controlNameList) { List <UnityEngine.Object> ret = new List <UnityEngine.Object>(); foreach (string ctrlName in controlNameList) { string name; string attr; LiveHelpers.SplitNameAttr(ctrlName, out name, out attr); Transform objTransfrom = rootObj.transform.FindDeepChild(name); if (objTransfrom != null) { GameObject obj = objTransfrom.gameObject; if (attr == LiveCharacterSetup.translationSuffix || attr == LiveCharacterSetup.rotationSuffix) { ret.Add(obj.transform); } else { SkinnedMeshRenderer skinnedMesh = obj.GetComponent <SkinnedMeshRenderer>(); if (skinnedMesh != null) { ret.Add(skinnedMesh); } } } } return(ret); }
/****************************************************************************************************/ static public Dictionary <string, Vector4> GetControlValues(GameObject rootObj, List <string> controlList) { Dictionary <string, Vector4> ret = new Dictionary <string, Vector4>(); foreach (string control in controlList) { string name; string attr; LiveHelpers.SplitNameAttr(control, out name, out attr); Transform objTransfrom = rootObj.transform.FindDeepChild(name); if (objTransfrom != null) { GameObject obj = objTransfrom.gameObject; Vector4 value = new Vector4(); if (attr == LiveCharacterSetup.translationSuffix) { value.x = obj.transform.localPosition.x; value.y = obj.transform.localPosition.y; value.z = obj.transform.localPosition.z; value.w = float.NaN; } else if (attr == LiveCharacterSetup.rotationSuffix) { value.x = obj.transform.localRotation.x; value.y = obj.transform.localRotation.y; value.z = obj.transform.localRotation.z; value.w = obj.transform.localRotation.w; } else { SkinnedMeshRenderer skinnedMesh = obj.GetComponent <SkinnedMeshRenderer>(); if (skinnedMesh != null) { int index = GetBlendShapeIndex(skinnedMesh, attr); if (index >= 0) { value.x = skinnedMesh.GetBlendShapeWeight(index); value.y = float.NaN; value.z = float.NaN; value.w = float.NaN; } } } ret.Add(control, value); } } return(ret); }
/****************************************************************************************************/ static public List <string> ValidateControls(GameObject rootObj, List <string> controlList) { List <string> missingCtrlList = new List <string>(); foreach (string ctrl in controlList) { string name; string attr; LiveHelpers.SplitNameAttr(ctrl, out name, out attr); Transform objTransfrom = rootObj.transform.FindDeepChild(name); if (objTransfrom != null) { GameObject obj = objTransfrom.gameObject; SkinnedMeshRenderer[] smrs = obj.transform.GetComponentsInChildren <SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer smr in smrs) { if (attr == LiveCharacterSetup.translationSuffix) { continue; } else if (attr == LiveCharacterSetup.rotationSuffix) { continue; } int index = GetBlendShapeIndex(smr, attr); if (index >= 0) { continue; } missingCtrlList.Add(ctrl); } } else { missingCtrlList.Add(ctrl); } } return(missingCtrlList); }
/****************************************************************************************************/ static public List <string> GetControls(GameObject gameObject) { List <string> ret = new List <string>(); ret.Add(LiveHelpers.JoinNameAttr(gameObject.name, LiveCharacterSetup.translationSuffix)); ret.Add(LiveHelpers.JoinNameAttr(gameObject.name, LiveCharacterSetup.rotationSuffix)); SkinnedMeshRenderer skinnedMesh = gameObject.GetComponent <SkinnedMeshRenderer>(); if (skinnedMesh != null) { Mesh mesh = skinnedMesh.sharedMesh; if (mesh != null) { for (int i = 0; i < mesh.blendShapeCount; i++) { ret.Add(LiveHelpers.JoinNameAttr(gameObject.name, mesh.GetBlendShapeName(i))); } } } return(ret); }
// Note: Calibration can only be triggered if LiveServer and Unity are both on the same machine. // Calibration Logic utilizes Windows APIs to send a message directly to Live Server. public void CalibrateLiveServer() { IEnumerable <IntPtr> windows = LiveHelpers.FindWindowsWithText("Faceware Live"); LiveHelpers.COPYDATASTRUCT cds = new LiveHelpers.COPYDATASTRUCT(); // Live only utilizes the dwData at this time cds.dwData = (IntPtr)1; int liveServerCount = 0; foreach (var window in windows) { LiveHelpers.SendMessage(window, 0X004A, IntPtr.Zero, ref cds); liveServerCount++; } if (liveServerCount > 0) { Debug.Log("[Faceware Live] Calibration message sent to " + liveServerCount + " instance(s) of Live!"); } else { Debug.Log("[Faceware Live] No local instance of Live Server found! Please start Live Server!"); } }
/****************************************************************************************************/ static public void ApplyControlValues(GameObject rootObj, Dictionary <string, Vector4> values) { foreach (KeyValuePair <string, Vector4> kvp in values) { string name; string attr; LiveHelpers.SplitNameAttr(kvp.Key, out name, out attr); Transform objTransfrom = rootObj.transform.FindDeepChild(name); if (objTransfrom != null) { GameObject obj = objTransfrom.gameObject; if (attr == LiveCharacterSetup.translationSuffix) { Vector3 value = new Vector3(kvp.Value.x, kvp.Value.y, kvp.Value.z); obj.transform.localPosition = value; } else if (attr == LiveCharacterSetup.rotationSuffix) { Quaternion value = new Quaternion(kvp.Value.x, kvp.Value.y, kvp.Value.z, kvp.Value.w); obj.transform.localRotation = value; } else { SkinnedMeshRenderer skinnedMesh = obj.GetComponent <SkinnedMeshRenderer>(); if (skinnedMesh != null) { int index = GetBlendShapeIndex(skinnedMesh, attr); if (index >= 0) { skinnedMesh.SetBlendShapeWeight(index, kvp.Value.x); } } } } } }
public override void OnInspectorGUI() { EditorGUILayout.BeginVertical(); { GUILayout.Space(15); GUILayout.BeginHorizontal(); { GUILayout.FlexibleSpace(); GUILayout.Label(titleIcon, GUILayout.MinWidth(1)); GUILayout.FlexibleSpace(); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); { GUILayout.FlexibleSpace(); GUILayout.Label("Version " + LiveHelpers.CurrentVersion(), titleStyle); GUILayout.FlexibleSpace(); } GUILayout.EndHorizontal(); GUILayout.Label("Faceware Live Client for Unity", titleStyle); GUILayout.BeginVertical(); { //Server GUILayout.BeginHorizontal(); { EditorGUILayout.LabelField("Live Server Hostname: "); FwLive.LiveServerHostIP = EditorGUILayout.TextField("", FwLive.LiveServerHostIP, GUILayout.MinWidth(50)); GUILayout.FlexibleSpace(); } GUILayout.EndHorizontal(); //Port GUILayout.BeginHorizontal(); { EditorGUILayout.LabelField("Live Server Port: "); FwLive.LiveServerHostPort = EditorGUILayout.IntField("", FwLive.LiveServerHostPort, GUILayout.MinWidth(50)); GUILayout.FlexibleSpace(); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); { // Character Setup File EditorGUILayout.LabelField("Character Setup File: "); FwLive.ExpressionSetFile = (LiveCharacterSetupFile)EditorGUILayout.ObjectField("", FwLive.ExpressionSetFile, typeof(LiveCharacterSetupFile), false, GUILayout.MinWidth(50)); GUILayout.FlexibleSpace(); } GUILayout.EndHorizontal(); // Connect on Start Toggle FwLive.ConnectOnPlay = GUILayout.Toggle(FwLive.ConnectOnPlay, "Connect on Play"); // Reconnect on Server Lost FwLive.ReconnectOnLostConnection = GUILayout.Toggle(FwLive.ReconnectOnLostConnection, new GUIContent("Automatic Reconnect", "When connection to Live Server is lost, enabling this checkbox will allow the plugin to automatically attempt reconnecting")); // Drop Packets Flag FwLive.DropPackets = GUILayout.Toggle(FwLive.DropPackets, new GUIContent("Drop Packets on Update", "Drop packets when there is more than 1 packet from Live Server queued.")); EditorGUILayout.BeginVertical("Box"); //Begin Live Server Interface { EditorGUILayout.LabelField("Live Server", titleStyle); GUILayout.BeginHorizontal(); { if (GUILayout.Button("Connect")) { FwLive.Connect(); } if (GUILayout.Button("Disconnect")) { FwLive.Disconnect(); } } GUILayout.EndHorizontal(); #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN if (FwLive.LiveServerHostIP == "localhost" || FwLive.LiveServerHostIP == "127.0.0.1") { if (GUILayout.Button("Calibrate")) { FwLive.CalibrateLiveServer(); } } #endif } GUILayout.EndVertical(); } GUILayout.EndVertical(); FwLive.EnableRecording = GUILayout.Toggle(FwLive.EnableRecording, new GUIContent("Enable Animation Recording", "Enabling Recording will set up the script to record animation coming from Live and save it to a .anim file.")); if (FwLive.EnableRecording) { EditorGUILayout.BeginVertical("Box"); { if (FwLive.Recording) { EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField("CURRENTLY RECORDING", warningStyle); } EditorGUILayout.EndHorizontal(); } EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); { GUILayout.Label(new GUIContent("Animation Clip:", "Animation clip that recorded animation will be saved to. If left blank, a new animation clip will be created at the root assets folder.")); FwLive.ClipToWriteTo = EditorGUILayout.ObjectField(FwLive.ClipToWriteTo, typeof(AnimationClip), false) as AnimationClip; } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); string btnLabel = FwLive.Recording ? "Stop Recording" : "Start Recording"; if (GUILayout.Button(btnLabel)) { if (EditorApplication.isPlaying) { //Create a clip to write to if user hasn't specified if (FwLive.ClipToWriteTo == null) { #if UNITY_EDITOR && (UNITY_5 || UNITY_2017 || UNITY_2018 || UNITY_5_4_OR_NEWER) FwLive.ClipToWriteTo = new AnimationClip(); AssetDatabase.CreateAsset(FwLive.ClipToWriteTo, "Assets/" + GetNextAvailableClipName()); AssetDatabase.SaveAssets(); #else Debug.LogWarning("[Faceware Live] No animation will be recorded due to Animation Clip not being set. Please set it to an .anim file to record animation"); #endif } FwLive.OnToggleRecording(); } else { Debug.LogWarning("[Faceware Live] Can't start recording when not playing scene!"); } } FwLive.RecordOnStart = GUILayout.Toggle(FwLive.RecordOnStart, new GUIContent("Start Recording on Play", "Animation recording will start on start of the scene")); #if UNITY_EDITOR && (UNITY_5 || UNITY_2017 || UNITY_2018 || UNITY_5_4_OR_NEWER) if (FwLive.RecordOnStart && FwLive.ClipToWriteTo == null) { FwLive.ClipToWriteTo = new AnimationClip(); AssetDatabase.CreateAsset(FwLive.ClipToWriteTo, "Assets/" + GetNextAvailableClipName()); AssetDatabase.SaveAssets(); } #endif FwLive.KeyframeOnNewData = GUILayout.Toggle(FwLive.KeyframeOnNewData, new GUIContent("Keyframe only on new Data", "Enable this feature to set keyframes on controls only when their values have changed. Turning this off will yield keyframes for every control whenever Live Server sends new data, resulting is potentially very large .anim files")); #if UNITY_EDITOR && (UNITY_5 || UNITY_2017 || UNITY_2018) #if UNITY_5_4_OR_NEWER FwLive.keyframeTangentMode = (AnimationUtility.TangentMode)EditorGUILayout.EnumPopup(new GUIContent("Animation Curves:", "Curve type used between keyframes recorded. Smoother animation can be achieved by changing this to Auto if you are getting a slower FPS from Live Server. If 'Keyframe only on new Data' is enabled, it is highly recommended to have 'Constant' curves or the end animation may not look correct"), FwLive.keyframeTangentMode); #endif #endif EditorGUILayout.Space(); } EditorGUILayout.EndVertical(); } else { if (FwLive.Recording) { FwLive.OnToggleRecording(); } FwLive.Recording = false; } EditorGUILayout.Space(); EditorGUILayout.BeginVertical("Box"); //Begin help buttons region { EditorGUILayout.LabelField("Need Help?", titleStyle); EditorGUILayout.BeginHorizontal(); //Live client user guide region { GUILayout.FlexibleSpace(); if (GUILayout.Button("Live Client for Unity - User Guide")) { System.Diagnostics.Process.Start("http://support.facewaretech.com/live-client-for-unity"); } GUILayout.FlexibleSpace(); } EditorGUILayout.EndHorizontal(); //End user guide region EditorGUILayout.BeginHorizontal(); //Visit website region { GUILayout.FlexibleSpace(); if (GUILayout.Button("Visit www.facewaretech.com")) { System.Diagnostics.Process.Start("http://www.facewaretech.com/"); } GUILayout.FlexibleSpace(); } EditorGUILayout.EndHorizontal(); //End website region EditorGUILayout.BeginHorizontal(); //30 day trial region { GUILayout.FlexibleSpace(); if (GUILayout.Button(new GUIContent("30-Day Free Trial", "Click here to get your 30-day free trial of Faceware Live Server."))) { System.Diagnostics.Process.Start("http://facewaretech.com/products/software/free-trial/"); } GUILayout.FlexibleSpace(); } EditorGUILayout.EndHorizontal(); //End 30 day trial region } EditorGUILayout.Space(); EditorGUILayout.EndVertical(); } EditorGUILayout.EndVertical(); if (GUI.changed) { EditorUtility.SetDirty(FwLive); FwLive.OnSettingsChange(); } }
public void RecordFrame() { if (Recording && live.m_RecievedNewData) { live.m_RecievedNewData = false; //Grab values from rig Dictionary <string, Vector4> controlValues; if (cachedRigValues == null) { controlValues = LiveUnityInterface.GetControlValues(this.gameObject, character.GetControlList()); } else { controlValues = cachedRigValues; } //Write keyframes for each control, if keyframe on new data only check if there is new data foreach (KeyValuePair <string, Vector4> controlKvp in controlValues) { string controlName = controlKvp.Key; FTIAnimCurve curveData = RecordedCurves[controlName]; if (curveData.isBlendShape) { if (!KeyframeOnNewData || curveData.animCurves[0].keys[curveData.animCurves[0].keys.Length - 1].value != controlKvp.Value.x) { Keyframe newFrame = new Keyframe(recordingTime, controlKvp.Value.x); curveData.animCurves[0].AddKey(newFrame); } } else { if (!KeyframeOnNewData || curveData.animCurves[0].keys[curveData.animCurves[0].keys.Length - 1].value != controlKvp.Value.x) { Keyframe newFrame = new Keyframe(recordingTime, controlKvp.Value.x); curveData.animCurves[0].AddKey(newFrame); } if (!KeyframeOnNewData || curveData.animCurves[1].keys[curveData.animCurves[1].keys.Length - 1].value != controlKvp.Value.y) { Keyframe newFrame = new Keyframe(recordingTime, controlKvp.Value.y); curveData.animCurves[1].AddKey(newFrame); } if (!KeyframeOnNewData || curveData.animCurves[2].keys[curveData.animCurves[2].keys.Length - 1].value != controlKvp.Value.z) { Keyframe newFrame = new Keyframe(recordingTime, controlKvp.Value.z); curveData.animCurves[2].AddKey(newFrame); } string attr = LiveHelpers.GetAttrString(controlName); if (attr == LiveCharacterSetup.rotationSuffix) { if (!KeyframeOnNewData || curveData.animCurves[3].keys[curveData.animCurves[3].keys.Length - 1].value != controlKvp.Value.w) { Keyframe newFrame = new Keyframe(recordingTime, controlKvp.Value.w); curveData.animCurves[3].AddKey(newFrame); } } } } } }
public void OnToggleRecording() { if (RecordedCurves == null) { RecordedCurves = new Dictionary <string, FTIAnimCurve>(); } Recording = !Recording; if (!Recording) { //Write data to clip Debug.Log("[Faceware Live] Recording Stopped. Writing to animation clip. This may take a moment."); if (ClipToWriteTo != null) { foreach (KeyValuePair <string, FTIAnimCurve> curveKvp in RecordedCurves) { string controlName = curveKvp.Key; FTIAnimCurve curveData = curveKvp.Value; if (curveData.isBlendShape) { #if UNITY_EDITOR && (UNITY_5 || UNITY_2017 || UNITY_2018) #if UNITY_5_4_OR_NEWER //If in editor and a version that supports curve setting, set the curves to what is specified for (int i = 0; i < curveData.animCurves[0].keys.Length; i++) { UnityEditor.AnimationUtility.SetKeyLeftTangentMode(curveData.animCurves[0], i, keyframeTangentMode); UnityEditor.AnimationUtility.SetKeyRightTangentMode(curveData.animCurves[0], i, keyframeTangentMode); } #endif #endif string blendShapeAttr = LiveHelpers.GetAttrString(controlName); ClipToWriteTo.SetCurve(curveData.hierachyPath, typeof(SkinnedMeshRenderer), "blendShape." + blendShapeAttr, curveData.animCurves[0]); } else { string controlAttr = LiveHelpers.GetAttrString(controlName); if (controlAttr == LiveCharacterSetup.rotationSuffix) { ClipToWriteTo.SetCurve(curveData.hierachyPath, typeof(Transform), "m_LocalRotation.x", curveData.animCurves[0]); ClipToWriteTo.SetCurve(curveData.hierachyPath, typeof(Transform), "m_LocalRotation.y", curveData.animCurves[1]); ClipToWriteTo.SetCurve(curveData.hierachyPath, typeof(Transform), "m_LocalRotation.z", curveData.animCurves[2]); ClipToWriteTo.SetCurve(curveData.hierachyPath, typeof(Transform), "m_LocalRotation.w", curveData.animCurves[3]); } else if (controlAttr == LiveCharacterSetup.translationSuffix) { ClipToWriteTo.SetCurve(curveData.hierachyPath, typeof(Transform), "m_LocalPosition.x", curveData.animCurves[0]); ClipToWriteTo.SetCurve(curveData.hierachyPath, typeof(Transform), "m_LocalPosition.y", curveData.animCurves[1]); ClipToWriteTo.SetCurve(curveData.hierachyPath, typeof(Transform), "m_LocalPosition.z", curveData.animCurves[2]); } } } Debug.Log("[Faceware Live] Animation successfully written to " + ClipToWriteTo.name + ".anim"); RecordedCurves.Clear(); } else { Debug.LogWarning("[Faceware Live] Animtion could not be recorded as Animation Clip to write to was null. Please set an animation clip to write the animation to"); } } else { RecordedCurves.Clear(); IntializeRecording(); Debug.Log("[Faceware Live] Recording Started!"); } }