public static int FindBlendSystems(BlendSystemUser component) { blendSystems = new List <Type>(); blendSystemNames = new List <string>(); blendSystems.Add(null); blendSystemNames.Add("None"); foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) { foreach (Type t in a.GetTypes()) { if (t.IsSubclassOf(typeof(BlendSystem))) { blendSystems.Add(t); blendSystemNames.Add(LipSyncEditorExtensions.AddSpaces(t.Name)); } } } if (component.blendSystem != null) { return(blendSystems.IndexOf(component.blendSystem.GetType())); } return(0); }
void OnGUI() { if (emotionsList == null) { Setup(); } if (centeredStyle == null) { centeredStyle = new GUIStyle(EditorStyles.whiteLabel); centeredStyle.alignment = TextAnchor.MiddleCenter; } EditorGUI.BeginChangeCheck(); GUILayout.Space(10); emotionsList.DoLayoutList(); if (EditorGUI.EndChangeCheck()) { setup.changed = true; setup.previewOutOfDate = true; } GUILayout.Space(10); LipSyncEditorExtensions.BeginPaddedHorizontal(20); if (GUILayout.Button("Done", GUILayout.MaxWidth(200), GUILayout.Height(30))) { Close(); } LipSyncEditorExtensions.EndPaddedHorizontal(20); }
void OnGUI() { if (emotionsList == null) { Setup(); } if (centeredStyle == null) { centeredStyle = new GUIStyle(EditorStyles.whiteLabel); centeredStyle.alignment = TextAnchor.MiddleCenter; } GUILayout.Space(10); var oldMixingMode = mixer.mixingMode; mixer.mixingMode = (EmotionMixer.MixingMode)EditorGUILayout.EnumPopup("Mixing Mode", mixer.mixingMode); if (oldMixingMode != mixer.mixingMode) { if (mixer.mixingMode == EmotionMixer.MixingMode.Normal && oldMixingMode != EmotionMixer.MixingMode.Normal) { if (EditorUtility.DisplayDialog("Reset Mixer Values?", "Switching to 'Normal' mixing mode will reset emotion percentages.", "Reset", "Cancel")) { for (int i = 0; i < mixer.emotions.Count; i++) { var em = mixer.emotions[i]; em.weight = 1f / mixer.emotions.Count; mixer.emotions[i] = em; } } else { mixer.mixingMode = oldMixingMode; } } else if (mixer.mixingMode == EmotionMixer.MixingMode.Additive && oldMixingMode != EmotionMixer.MixingMode.Additive) { if (!EditorUtility.DisplayDialog("Unlock Mixer Values?", "Switching to 'Additive' mixing mode will unlock emotion percentages so they can equal more than 100%. You will not be able to switch back to 'Normal' mode without losing these percentages.", "Unlock", "Cancel")) { mixer.mixingMode = oldMixingMode; } } } EditorGUI.BeginChangeCheck(); GUILayout.Space(10); emotionsList.DoLayoutList(); if (EditorGUI.EndChangeCheck()) { setup.changed = true; setup.previewOutOfDate = true; } GUILayout.Space(10); LipSyncEditorExtensions.BeginPaddedHorizontal(20); if (GUILayout.Button("Done", GUILayout.MaxWidth(200), GUILayout.Height(30))) { Close(); } LipSyncEditorExtensions.EndPaddedHorizontal(20); }
public static void ShowWindow(LipSync component, AnimatorController controller) { GestureSetupWizard window = EditorWindow.GetWindow <GestureSetupWizard>(true); window.component = component; window.controller = controller; window.topMessage = "Setting up Gestures for " + controller.name + "."; window.totalSteps = 2; window.Focus(); window.titleContent = new GUIContent("Gesture Setup Wizard"); window.settings = LipSyncEditorExtensions.GetProjectFile(); }
public override void OnInteractivePreviewGUI(Rect r, GUIStyle background) { if (lsdTarget.length == 0) { lsdTarget.length = lsdTarget.clip.length; } #if UNITY_5_3_6 || UNITY_5_4_OR_NEWER if (lsdTarget.clip != null) { AudioUtility.DrawWaveForm(lsdTarget.clip, 0, new Rect(0, r.y + 3, EditorGUIUtility.currentViewWidth, r.height)); } #else if (waveform == null && lsdTarget.clip != null) { waveform = AudioUtility.GetWaveForm(lsdTarget.clip, 0, EditorGUIUtility.currentViewWidth, 128); } if (lsdTarget.clip != null && waveform != null) { GUI.DrawTexture(new Rect(0, r.y + 3, EditorGUIUtility.currentViewWidth, r.height), waveform); } #endif //Playhead if (Event.current.button != 1) { seekPosition = GUI.HorizontalSlider(new Rect(0, r.y + 3, EditorGUIUtility.currentViewWidth, r.height), seekPosition, 0, 1, GUIStyle.none, GUIStyle.none); } GUI.DrawTexture(new Rect((seekPosition * EditorGUIUtility.currentViewWidth) - 3, r.y, 7, r.height), playhead_line); GUI.DrawTexture(new Rect((seekPosition * EditorGUIUtility.currentViewWidth) - 7, r.y, 15, 15), playhead_top); GUI.DrawTexture(new Rect((seekPosition * EditorGUIUtility.currentViewWidth) - 7, r.y + r.height - 16, 15, 15), playhead_bottom); if (Event.current.type == EventType.Repaint) { LipSyncEditorExtensions.DrawTimeline(r.y, 0, lsdTarget.length, r.width); } if (visualPreview && previewTarget != null) { EditorGUI.HelpBox(new Rect(20, r.y + r.height - 45, r.width - 40, 25), "Preview mode active. Note: only Phonemes and Emotions will be shown in the preview.", MessageType.Info); } else if (previewTarget != null) { UpdatePreview(0); previewTarget = null; } }
void FindBlendSystems() { blendSystems = new List <System.Type>(); blendSystemNames = new List <string>(); blendSystems.Add(null); blendSystemNames.Add("None"); foreach (System.Type t in typeof(BlendshapeBlendSystem).Assembly.GetTypes()) { if (t.IsSubclassOf(typeof(BlendSystem))) { blendSystems.Add(t); blendSystemNames.Add(LipSyncEditorExtensions.AddSpaces(t.Name)); } } if (lsTarget.blendSystem != null) { blendSystemNumber = blendSystems.IndexOf(lsTarget.blendSystem.GetType()); } }
public static ASMontrealLanguageModel Load(int index) { string[] languageModelGUIDs = AssetDatabase.FindAssets("t:ASMontrealLanguageModel"); var settings = LipSyncEditorExtensions.GetProjectFile(); if (settings == null) { return(null); } if (settings.phonemeSet == null) { return(null); } if (languageModelGUIDs.Length > 0 && languageModelGUIDs.Length > index) { ASMontrealLanguageModel model = AssetDatabase.LoadAssetAtPath <ASMontrealLanguageModel>(AssetDatabase.GUIDToAssetPath(languageModelGUIDs[index])); if (model != null) { if (model.mappingMode == AutoSyncPhonemeMap.MappingMode.InternalMap && !string.IsNullOrEmpty(model.recommendedPhonemeSet) && model.recommendedPhonemeSet != settings.phonemeSet.scriptingName) { if (!EditorUtility.DisplayDialog("Wrong Phoneme Set", "Warning: You are using the '" + settings.phonemeSet.scriptingName + "' Phoneme Set, and this language model is designed for use with '" + model.recommendedPhonemeSet + "'. This may not provide usable results, are you sure you want to continue?", "Yes", "No")) { return(null); } } return(model); } } else { Debug.LogError("LipSync: Invalid Montreal language model index provided."); } return(null); }
private List <PhonemeMarker> ParseOutput(string[] lines, ASPocketSphinxLanguageModel lm, AudioClip clip) { List <PhonemeMarker> results = new List <PhonemeMarker>(); Dictionary <string, string> phonemeMapper = null; var settings = LipSyncEditorExtensions.GetProjectFile(); bool needsMapping = true; if (lm.sourcePhoneticAlphabetName == settings.phonemeSet.scriptingName) { needsMapping = false; } else { needsMapping = true; switch (lm.mappingMode) { case AutoSyncPhonemeMap.MappingMode.InternalMap: phonemeMapper = lm.phonemeMap.GenerateAtoBDictionary(); break; case AutoSyncPhonemeMap.MappingMode.ExternalMap: if (lm.externalMap) { phonemeMapper = lm.externalMap.phonemeMap.GenerateAtoBDictionary(); } else { Debug.LogError("Language Model specifies an external phoneme map, but no phoneme map was provided."); return(null); } break; default: case AutoSyncPhonemeMap.MappingMode.AutoDetect: phonemeMapper = AutoSyncUtility.FindBestFitPhonemeMap(lm.sourcePhoneticAlphabetName, settings.phonemeSet.scriptingName); if (phonemeMapper == null) { Debug.LogErrorFormat("No PhonemeMap could be found to map from '{0}' to the current PhonemeSet '{1}'.", lm.sourcePhoneticAlphabetName, settings.phonemeSet.scriptingName); return(null); } break; } if (phonemeMapper.Count == 0) { Debug.LogWarning("PhonemeMap is empty - this may be due to the language model's mapping mode being set to 'InternalMap' but with no entries being added to the map. Phonemes may not be generated."); } } NumberStyles style = NumberStyles.Number; CultureInfo culture = CultureInfo.InvariantCulture; foreach (string line in lines) { if (string.IsNullOrEmpty(line)) { break; } string[] tokens = line.Split(' '); try { if (tokens[0] != "SIL") { string phonemeName = needsMapping ? phonemeMapper[tokens[0]] : tokens[0]; float startTime = -1; float.TryParse(tokens[1], style, culture, out startTime); if (startTime > -1) { startTime /= clip.length; } else { Debug.LogWarning("Phoneme mapper returned invalid timestamp. Skipping this entry."); continue; } bool found = false; int phoneme; for (phoneme = 0; phoneme < settings.phonemeSet.phonemes.Length; phoneme++) { if (settings.phonemeSet.phonemes[phoneme].name == phonemeName) { found = true; break; } } if (found) { results.Add(new PhonemeMarker(phoneme, startTime)); } else { Debug.LogWarning("Phoneme mapper returned '" + phonemeName + "' but this phoneme does not exist in the current set. Skipping this entry."); } } } catch (ArgumentOutOfRangeException) { Debug.LogWarning("Phoneme Label missing from return data. Skipping this entry."); } catch (KeyNotFoundException) { Debug.LogWarning("Phoneme Label '" + tokens[0] + "' not found in phoneme mapper. Skipping this entry."); } } return(results); }
private void FinishedProcessingMulti(LipSyncData outputData, AutoSync.ASProcessDelegateData data) { if (data.success) { var settings = LipSyncEditorExtensions.GetProjectFile(); // Create File string outputPath = AssetDatabase.GetAssetPath(outputData.clip); outputPath = Path.ChangeExtension(outputPath, xmlMode ? "xml" : "asset"); try { LipSyncClipSetup.SaveFile(settings, outputPath, xmlMode, outputData.transcript, outputData.length, outputData.phonemeData, outputData.emotionData, outputData.gestureData, outputData.clip); } catch (Exception e) { Debug.LogError(e.StackTrace); } } else { batchIncomplete = true; string clipName = "Undefined"; if (outputData.clip) { clipName = outputData.clip.name; } Debug.LogErrorFormat("AutoSync: Processing failed on clip '{0}'. Continuing with batch.", clipName); } if (currentClip < clips.Count) { currentClip++; if (autoSyncInstance == null) { autoSyncInstance = new AutoSync(); } LipSyncData tempData = CreateInstance <LipSyncData>(); tempData.clip = clips[currentClip]; tempData.length = tempData.clip.length; if (loadTranscripts) { tempData.transcript = AutoSyncUtility.TryGetTranscript(tempData.clip); } autoSyncInstance.RunSequence(currentModules.ToArray(), FinishedProcessingMulti, tempData); } else { AssetDatabase.Refresh(); EditorUtility.ClearProgressBar(); if (!batchIncomplete) { setup.ShowNotification(new GUIContent("Batch AutoSync Completed Successfully")); } else { setup.ShowNotification(new GUIContent("Batch AutoSync Completed With Errors")); } Close(); } }
public override void Process(LipSyncData inputClip, AutoSync.ASProcessDelegate callback) { string mfaPath = EditorPrefs.GetString("as_montrealfa_application_path"); string audioPath = AssetDatabase.GetAssetPath(inputClip.clip).Substring("/Assets".Length); if (audioPath == null) { callback.Invoke(inputClip, new AutoSync.ASProcessDelegateData(false, "Audio path could not be found.", ClipFeatures.None)); return; } if (!AutoSyncUtility.VerifyProgramAtPath(mfaPath, "align")) { callback.Invoke(inputClip, new AutoSync.ASProcessDelegateData(false, "Montreal Forced Aligner application path is not verified.", ClipFeatures.None)); return; } // Get absolute path audioPath = Application.dataPath + "/" + audioPath; // Check Path if (audioPath.IndexOfAny(Path.GetInvalidPathChars()) >= 0 || Path.GetFileNameWithoutExtension(audioPath).IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) { callback.Invoke(inputClip, new AutoSync.ASProcessDelegateData(false, "Audio path contains invalid characters.", ClipFeatures.None)); return; } // Load Language Model ASMontrealLanguageModel model = ASMontrealLanguageModel.Load(languageModel); if (model == null) { callback.Invoke(inputClip, new AutoSync.ASProcessDelegateData(false, "Language Model failed to load.", ClipFeatures.None)); return; } string basePath = model.GetBasePath(); string lexiconPath = ""; if (model.usePredefinedLexicon) { lexiconPath = basePath + model.lexiconPath; } else { callback.Invoke(inputClip, new AutoSync.ASProcessDelegateData(false, "Support for generated lexicons using a G2P model is coming soon.", ClipFeatures.None)); return; } string adjustedName = Path.GetFileNameWithoutExtension(audioPath).Replace('.', '_').Replace(' ', '_').Replace('\\', '_').Replace('/', '_'); string corpusPath = Application.temporaryCachePath + "/" + adjustedName + "_MFA_Corpus"; string outputPath = Application.temporaryCachePath + "/" + adjustedName + "_MFA_Output"; // Delete folders if they already exist try { if (Directory.Exists(corpusPath)) { Directory.Delete(corpusPath, true); } if (Directory.Exists(outputPath)) { Directory.Delete(outputPath, true); } } catch { callback.Invoke(inputClip, new AutoSync.ASProcessDelegateData(false, "Attempt to clear temporary MFA folders failed. Are they open in another application?", ClipFeatures.None)); return; } // Create temporary folders Directory.CreateDirectory(corpusPath); Directory.CreateDirectory(outputPath); // Copy or convert audio clip to corpus folder if (AutoSyncConversionUtility.IsConversionAvailable && useAudioConversion) { AutoSyncConversionUtility.StartConversion(audioPath, corpusPath + "/" + adjustedName + ".wav", AutoSyncConversionUtility.AudioFormat.WavPCM, 16000, 16, 1); } else { File.Copy(audioPath, corpusPath + "/" + adjustedName + Path.GetExtension(audioPath)); } // Create transcript file in corpus folder StreamWriter transcriptWriter = File.CreateText(corpusPath + "/" + adjustedName + ".lab"); transcriptWriter.Write(inputClip.transcript.Replace('-', ' ')); transcriptWriter.Close(); // Run aligner Directory.SetCurrentDirectory(Application.dataPath.Remove(Application.dataPath.Length - 6)); mfaPath = Path.GetFullPath(mfaPath); System.Diagnostics.Process process = new System.Diagnostics.Process(); process.StartInfo.FileName = mfaPath; #if UNITY_EDITOR_WIN process.StartInfo.Arguments = "\"" + corpusPath + "\" \"" + lexiconPath + "\" \"" + basePath + model.acousticModelPath + "\" \"" + outputPath + "\" --quiet"; #elif UNITY_EDITOR_OSX process.StartInfo.Arguments = "\"" + corpusPath + "\" \"" + lexiconPath + "\" \"" + basePath + model.acousticModelPath + "\" \"" + outputPath + "\""; #endif process.StartInfo.UseShellExecute = true; process.StartInfo.CreateNoWindow = true; process.Start(); process.WaitForExit(15000); if (!process.HasExited) { process.Kill(); process.Close(); } var outputFiles = Directory.GetFiles(outputPath, "*", SearchOption.AllDirectories); string textGridPath = ""; List <string> oovs = new List <string>(); bool nothingFound = true; for (int i = 0; i < outputFiles.Length; i++) { if (Path.GetExtension(outputFiles[i]).ToLowerInvariant() == ".textgrid") { textGridPath = outputFiles[i]; nothingFound = false; } else if (Path.GetExtension(outputFiles[i]).ToLowerInvariant() == ".txt") { string name = Path.GetFileNameWithoutExtension(outputFiles[i]); var reader = new StreamReader(outputFiles[i]); if (name == "oovs_found") { while (!reader.EndOfStream) { oovs.Add(reader.ReadLine()); } } reader.Close(); } } // Detect out-of-vocab words, filter and retry if enabled. if (oovs.Count > 0) { Debug.Log("Found out-of-vocabulary words:"); for (int i = 0; i < oovs.Count; i++) { Debug.Log(oovs[i]); } } if (nothingFound) { if (autoRetry) { if (attempts < maxAttempts - 1) { attempts++; Process(inputClip, callback); return; } } callback.Invoke(inputClip, new AutoSync.ASProcessDelegateData(false, "MFA Application Failed. Check your audio encoding or enable conversion.", ClipFeatures.None)); return; } // Load in TextGrid TextGridUtility.TextGridItem[] items = TextGridUtility.ParseTextGridFile(textGridPath); var settings = LipSyncEditorExtensions.GetProjectFile(); bool needsMapping = true; Dictionary <string, string> phonemeMapper = null; if (model.sourcePhoneticAlphabetName == settings.phonemeSet.scriptingName) { needsMapping = false; } else { needsMapping = true; switch (model.mappingMode) { case AutoSyncPhonemeMap.MappingMode.InternalMap: phonemeMapper = model.phonemeMap.GenerateAtoBDictionary(); break; case AutoSyncPhonemeMap.MappingMode.ExternalMap: if (model.externalMap) { phonemeMapper = model.externalMap.phonemeMap.GenerateAtoBDictionary(); } else { callback.Invoke(inputClip, new AutoSync.ASProcessDelegateData(false, "Language Model specifies an external phoneme map, but no phoneme map was provided.", ClipFeatures.None)); return; } break; default: case AutoSyncPhonemeMap.MappingMode.AutoDetect: phonemeMapper = AutoSyncUtility.FindBestFitPhonemeMap(model.sourcePhoneticAlphabetName, settings.phonemeSet.scriptingName); if (phonemeMapper == null) { callback.Invoke(inputClip, new AutoSync.ASProcessDelegateData(false, string.Format("No PhonemeMap could be found to map from '{0}' to the current PhonemeSet '{1}'.", model.sourcePhoneticAlphabetName, settings.phonemeSet.scriptingName), ClipFeatures.None)); return; } break; } if (phonemeMapper.Count == 0) { Debug.LogWarning("PhonemeMap is empty - this may be due to the language model's mapping mode being set to 'InternalMap' but with no entries being added to the map. Phonemes may not be generated."); } } // Get Phones List <PhonemeMarker> data = new List <PhonemeMarker>(); if (items != null && items.Length == 2) { for (int i = 0; i < items[1].intervals.Length; i++) { if (items[1].intervals[i] == null) { Debug.LogFormat("Interval {0} is null :o", i); continue; } string label = items[1].intervals[i].text.Split('"')[1]; label = System.Text.RegularExpressions.Regex.Replace(label, "[0-9]", ""); if (label != "sil") { if (phonemeMapper.ContainsKey(label)) { string phonemeName = needsMapping ? phonemeMapper[label] : label; bool found = false; int phoneme; for (phoneme = 0; phoneme < settings.phonemeSet.phonemes.Length; phoneme++) { if (settings.phonemeSet.phonemes[phoneme].name == phonemeName) { found = true; break; } } if (found) { double start = items[1].intervals[i].xmin / inputClip.length; double end = items[1].intervals[i].xmax / inputClip.length; double length = end - start; if ((length * inputClip.length) < minLengthForSustain) { data.Add(new PhonemeMarker(phoneme, (float)(start + (length / 2)))); } else { data.Add(new PhonemeMarker(phoneme, (float)start, 1, true)); data.Add(new PhonemeMarker(phoneme, (float)end)); } } else { Debug.LogWarning("Phoneme mapper returned '" + phonemeName + "' but this phoneme does not exist in the current set. Skipping this entry."); } } else { Debug.LogWarning("Phoneme mapper does not contain '" + label + "' Skipping this entry."); } } } } else { callback.Invoke(inputClip, new AutoSync.ASProcessDelegateData(false, "Data loaded from MFA TextGrid file was invalid or incomplete.", ClipFeatures.None)); return; } inputClip.phonemeData = data.ToArray(); if (oovs.Count > 0) { callback.Invoke(inputClip, new AutoSync.ASProcessDelegateData(true, "Completed, but some words were not found. Check the console.", GetOutputCompatibility())); } else { callback.Invoke(inputClip, new AutoSync.ASProcessDelegateData(true, "", GetOutputCompatibility())); } return; }
public override void DrawSetupWizardSection() { EditorGUILayout.HelpBox("The Montreal Forced Aligner contains multiple executables, the one required below is \"bin/mfa_align.exe\" on Windows, or \"lib/align\" on macOS - used to align phonemes with audio.", MessageType.Info); applicationPath = LipSyncEditorExtensions.DrawPathField("MFA Aligner Application Path", applicationPath, "ls_debug", "Find mfa_align executable"); }
public override void OnInspectorGUI() { // Create styles if necesarry if (inlineToolbar == null) { inlineToolbar = new GUIStyle((GUIStyle)"TE toolbarbutton"); inlineToolbar.fixedHeight = 0; inlineToolbar.fixedWidth = 0; } LipSyncEditorExtensions.BeginPaddedHorizontal(); GUILayout.Box(logo, GUIStyle.none); LipSyncEditorExtensions.EndPaddedHorizontal(); GUILayout.Space(20); serializedObject.Update(); Rect lineRect; EditorGUILayout.HelpBox("Enable or disable Eye Controller functionality below.", MessageType.Info); GUILayout.Space(10); blendSystemNumber = BlendSystemEditor.DrawBlendSystemEditor(myTarget, blendSystemNumber, "EyeController requires a blend system to function."); if (myTarget.blendSystem != null) { if (myTarget.blendSystem.isReady) { if (blendables == null) { myTarget.blendSystem.onBlendablesChanged += GetBlendShapes; GetBlendShapes(); } EditorGUILayout.PropertyField(boneUpdateAnimation, new GUIContent("Account for Animation", "If true, will calculate relative bone positions/rotations each frame. Improves results when using animation, but will cause errors when not.")); GUILayout.Space(10); BlendSystemEditor.DrawBlendSystemButtons(myTarget.blendSystem); GUILayout.Space(10); // Blinking lineRect = EditorGUILayout.BeginHorizontal(); GUI.Box(lineRect, "", (GUIStyle)"flow node 0"); GUILayout.Space(10); blinkingEnabled.boolValue = EditorGUILayout.ToggleLeft("Blinking", blinkingEnabled.boolValue, EditorStyles.largeLabel, GUILayout.ExpandWidth(true), GUILayout.Height(24)); showBlinking.target = blinkingEnabled.boolValue; GUILayout.FlexibleSpace(); blinkingControlMode.enumValueIndex = GUILayout.Toolbar(blinkingControlMode.enumValueIndex, System.Enum.GetNames(typeof(EyeController.ControlMode)), inlineToolbar, GUILayout.MaxWidth(300), GUILayout.Height(24)); showBlinkingClassicControl.target = blinkingControlMode.enumValueIndex == (int)EyeController.ControlMode.Classic; EditorGUILayout.EndHorizontal(); EditorGUI.indentLevel++; if (EditorGUILayout.BeginFadeGroup(showBlinking.faded)) { GUILayout.Space(5); // Classic Mode if (EditorGUILayout.BeginFadeGroup(showBlinkingClassicControl.faded)) { if (blendables != null) { leftEyeBlinkBlendshape.intValue = EditorGUILayout.Popup("Left Eye Blink Blendshape", leftEyeBlinkBlendshape.intValue, blendables, GUILayout.MaxWidth(500)); rightEyeBlinkBlendshape.intValue = EditorGUILayout.Popup("Right Eye Blink Blendshape", rightEyeBlinkBlendshape.intValue, blendables, GUILayout.MaxWidth(500)); } } LipSyncEditorExtensions.FixedEndFadeGroup(showBlinkingClassicControl.faded); // Pose Mode if (EditorGUILayout.BeginFadeGroup(1 - showBlinkingClassicControl.faded)) { this.DrawShapeEditor(myTarget.blendSystem, blendables, true, true, myTarget.blinkingShape, "Blinking", 0); } LipSyncEditorExtensions.FixedEndFadeGroup(1 - showBlinkingClassicControl.faded); GUILayout.Space(10); float minGap = minimumBlinkGap.floatValue; float maxGap = maximumBlinkGap.floatValue; MinMaxSliderWithNumbers(new GUIContent("Blink Gap", "Time, in seconds, between blinks."), ref minGap, ref maxGap, 0.1f, 20); minimumBlinkGap.floatValue = minGap; maximumBlinkGap.floatValue = maxGap; EditorGUILayout.PropertyField(blinkDuration, new GUIContent("Blink Duration", "How long each blink takes.")); GUILayout.Space(10); } LipSyncEditorExtensions.FixedEndFadeGroup(showBlinking.faded); EditorGUI.indentLevel--; GUILayout.Space(2); // Random Look Direction lineRect = EditorGUILayout.BeginHorizontal(); GUI.Box(lineRect, "", (GUIStyle)"flow node 0"); GUILayout.Space(10); randomLookingEnabled.boolValue = EditorGUILayout.ToggleLeft("Random Looking", randomLookingEnabled.boolValue, EditorStyles.largeLabel, GUILayout.ExpandWidth(true), GUILayout.Height(24)); showRandomLook.target = randomLookingEnabled.boolValue; GUILayout.FlexibleSpace(); lookingControlMode.enumValueIndex = GUILayout.Toolbar(lookingControlMode.enumValueIndex, System.Enum.GetNames(typeof(EyeController.ControlMode)), inlineToolbar, GUILayout.MaxWidth(300), GUILayout.Height(24)); showLookingClassicControl.target = lookingControlMode.enumValueIndex == (int)EyeController.ControlMode.Classic; EditorGUILayout.EndHorizontal(); EditorGUI.indentLevel++; if (EditorGUILayout.BeginFadeGroup(showRandomLook.faded)) { GUILayout.Space(5); float minGap = minimumChangeDirectionGap.floatValue; float maxGap = maximumChangeDirectionGap.floatValue; MinMaxSliderWithNumbers(new GUIContent("Change Direction Gap", "Time, in seconds, between the eyes turning to a new direction."), ref minGap, ref maxGap, 1f, 30); minimumChangeDirectionGap.floatValue = minGap; maximumChangeDirectionGap.floatValue = maxGap; GUILayout.Space(10); } LipSyncEditorExtensions.FixedEndFadeGroup(showRandomLook.faded); EditorGUI.indentLevel--; // Look Targets lineRect = EditorGUILayout.BeginHorizontal(); GUI.Box(lineRect, "", (GUIStyle)"flow node 0"); GUILayout.Space(10); EditorGUI.BeginDisabledGroup(lookingControlMode.enumValueIndex == (int)EyeController.ControlMode.PoseBased); targetEnabled.boolValue = EditorGUILayout.ToggleLeft("Look At Target", targetEnabled.boolValue, EditorStyles.largeLabel, GUILayout.ExpandWidth(true), GUILayout.Height(24)) && lookingControlMode.enumValueIndex == (int)EyeController.ControlMode.Classic; showLookTarget.target = targetEnabled.boolValue; EditorGUI.EndDisabledGroup(); GUILayout.FlexibleSpace(); GUILayout.Space(24); EditorGUILayout.EndHorizontal(); EditorGUI.indentLevel++; if (EditorGUILayout.BeginFadeGroup(showLookTarget.faded)) { GUILayout.Space(5); if (EditorGUILayout.BeginFadeGroup(1 - showAutoTarget.faded)) { EditorGUILayout.PropertyField(viewTarget, new GUIContent("Target", "Transform to look at.")); GUILayout.Space(10); } LipSyncEditorExtensions.FixedEndFadeGroup(1 - showAutoTarget.faded); EditorGUILayout.PropertyField(autoTarget, new GUIContent("Use Auto Target")); showAutoTarget.target = myTarget.autoTarget; if (EditorGUILayout.BeginFadeGroup(showAutoTarget.faded)) { EditorGUI.indentLevel++; EditorGUILayout.PropertyField(autoTargetTag, new GUIContent("Auto Target Tag", "Tag to use when searching for targets.")); EditorGUILayout.PropertyField(autoTargetDistance, new GUIContent("Auto Target Distance", "The maximum distance between a target and the character for it to be targeted.")); EditorGUI.indentLevel--; GUILayout.Space(10); } LipSyncEditorExtensions.FixedEndFadeGroup(showAutoTarget.faded); EditorGUILayout.Slider(targetWeight, 0, 1, new GUIContent("Look At Amount")); GUILayout.Space(10); } LipSyncEditorExtensions.FixedEndFadeGroup(showLookTarget.faded); if (lookingControlMode.enumValueIndex == (int)EyeController.ControlMode.PoseBased) { EditorGUILayout.HelpBox("Targeting is only available in classic mode.", MessageType.Warning); } EditorGUI.indentLevel--; // Shared Look Controls GUILayout.Space(-2); lineRect = EditorGUILayout.BeginHorizontal(); GUI.Box(lineRect, "", (GUIStyle)"flow node 0"); GUILayout.Space(24); GUILayout.Label("Looking (Shared)", EditorStyles.largeLabel, GUILayout.ExpandWidth(true), GUILayout.Height(24)); GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); showLookShared.target = myTarget.targetEnabled || myTarget.randomLookingEnabled; EditorGUI.indentLevel++; if (EditorGUILayout.BeginFadeGroup(showLookShared.faded)) { GUILayout.Space(5); // Classic Mode if (EditorGUILayout.BeginFadeGroup(showLookingClassicControl.faded)) { EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(leftEyeLookAtBone); EditorGUILayout.PropertyField(rightEyeLookAtBone); if (EditorGUI.EndChangeCheck()) { myTarget.LeftEyeLookAtBone = (Transform)leftEyeLookAtBone.objectReferenceValue; myTarget.RightEyeLookAtBone = (Transform)rightEyeLookAtBone.objectReferenceValue; } GUILayout.Space(5); MinMaxSliderWithNumbers(new GUIContent("X Axis Range"), eyeRotationRangeX, -90, 90); MinMaxSliderWithNumbers(new GUIContent("Y Axis Range"), eyeRotationRangeY, -90, 90); GUILayout.Space(5); EditorGUILayout.PropertyField(eyeLookOffset); EditorGUILayout.PropertyField(eyeForwardAxis); } LipSyncEditorExtensions.FixedEndFadeGroup(showLookingClassicControl.faded); // Pose Mode if (EditorGUILayout.BeginFadeGroup(1 - showLookingClassicControl.faded)) { this.DrawShapeEditor(myTarget.blendSystem, blendables, true, true, myTarget.lookingUpShape, "Looking Up", 1); this.DrawShapeEditor(myTarget.blendSystem, blendables, true, true, myTarget.lookingDownShape, "Looking Down", 2); this.DrawShapeEditor(myTarget.blendSystem, blendables, true, true, myTarget.lookingLeftShape, "Looking Left", 3); this.DrawShapeEditor(myTarget.blendSystem, blendables, true, true, myTarget.lookingRightShape, "Looking Right", 4); } LipSyncEditorExtensions.FixedEndFadeGroup(1 - showLookingClassicControl.faded); GUILayout.Space(5); EditorGUILayout.PropertyField(eyeTurnSpeed, new GUIContent("Eye Turn Speed", "The speed at which eyes rotate.")); GUILayout.Space(10); } LipSyncEditorExtensions.FixedEndFadeGroup(showLookShared.faded); EditorGUI.indentLevel--; GUILayout.Space(10); } if (LipSyncEditorExtensions.oldToggle != LipSyncEditorExtensions.currentToggle && LipSyncEditorExtensions.currentTarget == myTarget) { Shape oldShape = null; Shape newShape = null; switch (LipSyncEditorExtensions.oldToggle) { case 0: oldShape = myTarget.blinkingShape; break; case 1: oldShape = myTarget.lookingUpShape; break; case 2: oldShape = myTarget.lookingDownShape; break; case 3: oldShape = myTarget.lookingLeftShape; break; case 4: oldShape = myTarget.lookingRightShape; break; } switch (LipSyncEditorExtensions.currentToggle) { case 0: newShape = myTarget.blinkingShape; break; case 1: newShape = myTarget.lookingUpShape; break; case 2: newShape = myTarget.lookingDownShape; break; case 3: newShape = myTarget.lookingLeftShape; break; case 4: newShape = myTarget.lookingRightShape; break; } if (LipSyncEditorExtensions.oldToggle > -1) { if (oldShape != null) { foreach (BoneShape boneshape in oldShape.bones) { if (boneshape.bone != null) { boneshape.bone.localPosition = boneshape.neutralPosition; boneshape.bone.localEulerAngles = boneshape.neutralRotation; } } foreach (int blendable in oldShape.blendShapes) { myTarget.blendSystem.SetBlendableValue(blendable, 0); } } } if (LipSyncEditorExtensions.currentToggle > -1) { foreach (BoneShape boneshape in newShape.bones) { if (boneshape.bone != null) { boneshape.bone.localPosition = boneshape.endPosition; boneshape.bone.localEulerAngles = boneshape.endRotation; } } for (int b = 0; b < newShape.blendShapes.Count; b++) { myTarget.blendSystem.SetBlendableValue(newShape.blendShapes[b], newShape.weights[b]); } } LipSyncEditorExtensions.oldToggle = LipSyncEditorExtensions.currentToggle; } if (GUI.changed) { if (blendables == null) { GetBlendShapes(); } Shape newShape = null; switch (LipSyncEditorExtensions.currentToggle) { case 0: newShape = myTarget.blinkingShape; break; case 1: newShape = myTarget.lookingUpShape; break; case 2: newShape = myTarget.lookingDownShape; break; case 3: newShape = myTarget.lookingLeftShape; break; case 4: newShape = myTarget.lookingRightShape; break; } if (LipSyncEditorExtensions.currentToggle > -1 && LipSyncEditorExtensions.currentTarget == myTarget) { for (int b = 0; b < newShape.blendShapes.Count; b++) { myTarget.blendSystem.SetBlendableValue(newShape.blendShapes[b], newShape.weights[b]); } } EditorUtility.SetDirty(myTarget); serializedObject.SetIsDifferentCacheDirty(); } serializedObject.ApplyModifiedProperties(); } }
public static void ShowWindow() { var settings = LipSyncEditorExtensions.GetProjectFile(); Selection.activeObject = settings; }
public override void OnInspectorGUI() { serializedObject.Update(); LipSyncEditorExtensions.DrawVerifiedPathField(serializedObject.FindProperty("applicationPath"), "as_montrealfa_application_path", "as_montrealfa_application_path_verified", "Find Montreal Forced Aligner Application", Verify); serializedObject.ApplyModifiedProperties(); }