public static void ConvertPreset() { Object[] selection = Selection.GetFiltered(typeof(BlendshapePreset), SelectionMode.Assets); foreach (Object preset in selection) { BlendshapePreset oldPreset = (BlendshapePreset)preset; LipSyncPreset newPreset = ScriptableObject.CreateInstance <LipSyncPreset>(); string path = AssetDatabase.GetAssetPath(oldPreset); path = System.IO.Path.GetDirectoryName(path); newPreset.CreateFromShapes(oldPreset.phonemeShapes.ToArray(), null); AssetDatabase.CreateAsset(newPreset, path + "/" + oldPreset.name + "_converted.Asset"); AssetDatabase.Refresh(); } }
public void OnEnable() { target = (LipSyncPreset)base.target; }
void LoadPreset(object data) { string file = (string)data; if (file.EndsWith(".asset", true, null)) { LipSyncPreset preset = AssetDatabase.LoadAssetAtPath <LipSyncPreset>("Assets" + file.Substring((Application.dataPath).Length)); if (preset != null) { List <PhonemeShape> newPhonemes = new List <PhonemeShape>(); // Phonemes for (int shape = 0; shape < preset.phonemeShapes.Length; shape++) { newPhonemes.Add(new PhonemeShape(preset.phonemeShapes[shape].phoneme)); for (int blendable = 0; blendable < preset.phonemeShapes[shape].blendables.Length; blendable++) { int finalBlendable = preset.FindBlendable(preset.phonemeShapes[shape].blendables[blendable], lsTarget.blendSystem); if (finalBlendable >= 0) { newPhonemes[shape].blendShapes.Add(finalBlendable); newPhonemes[shape].weights.Add(preset.phonemeShapes[shape].blendables[blendable].weight); } } for (int bone = 0; bone < preset.phonemeShapes[shape].bones.Length; bone++) { BoneShape newBone = new BoneShape(); newBone.bone = preset.FindBone(preset.phonemeShapes[shape].bones[bone], lsTarget.transform); newBone.SetNeutral(); newBone.endPosition = preset.phonemeShapes[shape].bones[bone].localPosition; newBone.endRotation = preset.phonemeShapes[shape].bones[bone].localRotation; newBone.lockPosition = preset.phonemeShapes[shape].bones[bone].lockPosition; newBone.lockRotation = preset.phonemeShapes[shape].bones[bone].lockRotation; newPhonemes[shape].bones.Add(newBone); } } lsTarget.phonemes = newPhonemes; for (int bShape = 0; bShape < lsTarget.blendSystem.blendableCount; bShape++) { lsTarget.blendSystem.SetBlendableValue(bShape, 0); } if (markerTab == 0) { if (LipSyncEditorExtensions.currentToggle >= 0) { int b = 0; foreach (int shape in lsTarget.phonemes[LipSyncEditorExtensions.currentToggle].blendShapes) { lsTarget.blendSystem.SetBlendableValue(shape, lsTarget.phonemes[LipSyncEditorExtensions.currentToggle].weights[b]); b++; } } } } } }
public override void OnInspectorGUI() { if (serializedTarget == null) { OnEnable(); } if (miniLabelDark == null) { miniLabelDark = new GUIStyle(EditorStyles.miniLabel); miniLabelDark.normal.textColor = Color.black; } serializedTarget.Update(); EditorGUI.BeginDisabledGroup(saving); Rect fullheight = EditorGUILayout.BeginVertical(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); GUILayout.Box(logo, GUIStyle.none); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); if (blendSystems == null) { FindBlendSystems(); } if (blendSystems.Count == 0) { EditorGUILayout.Popup("Blend System", 0, new string[] { "No BlendSystems Found" }); } else { if (lsTarget.blendSystem == null) { EditorGUI.BeginChangeCheck(); blendSystemNumber = EditorGUILayout.Popup("Blend System", blendSystemNumber, blendSystemNames.ToArray(), GUIStyle.none); if (EditorGUI.EndChangeCheck()) { ChangeBlendSystem(); } GUI.Box(new Rect(EditorGUIUtility.labelWidth + GUILayoutUtility.GetLastRect().x, GUILayoutUtility.GetLastRect().y, GUILayoutUtility.GetLastRect().width, GUILayoutUtility.GetLastRect().height), "Select a BlendSystem", EditorStyles.popup); } else { EditorGUI.BeginChangeCheck(); blendSystemNumber = EditorGUILayout.Popup("Blend System", blendSystemNumber, blendSystemNames.ToArray()); if (EditorGUI.EndChangeCheck()) { ChangeBlendSystem(); } } } if (lsTarget.blendSystem == null) { GUILayout.Label("No BlendSystem Selected"); EditorGUILayout.HelpBox("A Blend System is required to use LipSync.", MessageType.Info); } EditorGUILayout.Space(); if (lsTarget.blendSystem != null) { if (blendSystemEditor == null) { CreateBlendSystemEditor(); } blendSystemEditor.OnInspectorGUI(); if (!lsTarget.blendSystem.isReady) { GUILayout.Space(10); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Continue", GUILayout.MaxWidth(200))) { lsTarget.blendSystem.OnVariableChanged(); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(10); } } if (lsTarget.blendSystem != null) { if (lsTarget.blendSystem.isReady) { EditorGUILayout.Space(); EditorGUILayout.PropertyField(audioSource, new GUIContent("Audio Source", "AudioSource to play dialogue from.")); EditorGUILayout.Space(); EditorGUILayout.PropertyField(useBones, new GUIContent("Use Bone Transforms", "Allow BoneShapes to be added to phoneme poses. This enables the use of bone based facial animation.")); showBoneOptions.target = lsTarget.useBones; if (EditorGUILayout.BeginFadeGroup(showBoneOptions.faded)) { 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.")); EditorGUILayout.Space(); } FixedEndFadeGroup(showBoneOptions.faded); EditorGUILayout.Space(); if (blendSystemButtons.Length > 0 && blendSystemButtons.Length < 3) { Rect buttonPanel = EditorGUILayout.BeginHorizontal(); EditorGUI.HelpBox(new Rect(buttonPanel.x, buttonPanel.y - 4, buttonPanel.width, buttonPanel.height + 8), "BlendSystem Commands:", MessageType.Info); GUILayout.FlexibleSpace(); DrawBlendSystemButtons(); GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); } else if (blendSystemButtons.Length >= 3) { Rect buttonPanel = EditorGUILayout.BeginHorizontal(); EditorGUI.HelpBox(new Rect(buttonPanel.x, buttonPanel.y - 4, buttonPanel.width, buttonPanel.height + 8), "BlendSystem Commands:", MessageType.Info); GUILayout.FlexibleSpace(); DrawBlendSystemButtons(); GUILayout.Space(5); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); } int oldTab = markerTab; GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); EditorGUI.BeginDisabledGroup(true); markerTab = GUILayout.Toolbar(markerTab, new GUIContent[] { new GUIContent("Phonemes"), new GUIContent("Emotions"), new GUIContent("Gestures") }, GUILayout.MaxWidth(400), GUILayout.MinHeight(23)); EditorGUI.EndDisabledGroup(); Rect presetRect = EditorGUILayout.BeginHorizontal(); if (GUILayout.Button(new GUIContent(presetsIcon, "Presets"), GUILayout.MaxWidth(32), GUILayout.MinHeight(23))) { GenericMenu menu = new GenericMenu(); string[] directories = Directory.GetDirectories(Application.dataPath, "Presets", SearchOption.AllDirectories); bool noItems = true; foreach (string directory in directories) { foreach (string file in Directory.GetFiles(directory)) { if (Path.GetExtension(file).ToLower() == ".asset") { LipSyncPreset preset = AssetDatabase.LoadAssetAtPath <LipSyncPreset>("Assets" + file.Substring((Application.dataPath).Length)); if (preset != null) { noItems = false; menu.AddItem(new GUIContent(Path.GetFileNameWithoutExtension(file)), false, LoadPreset, file); } } } string[] subdirectories = Directory.GetDirectories(directory); foreach (string subdirectory in subdirectories) { foreach (string file in Directory.GetFiles(subdirectory)) { if (Path.GetExtension(file).ToLower() == ".asset") { LipSyncPreset preset = AssetDatabase.LoadAssetAtPath <LipSyncPreset>("Assets" + file.Substring((Application.dataPath).Length)); if (preset != null) { noItems = false; menu.AddItem(new GUIContent(Path.GetFileName(subdirectory) + "/" + Path.GetFileNameWithoutExtension(file)), false, LoadPreset, file); } } } } } if (noItems) { menu.AddDisabledItem(new GUIContent("No Presets Found")); } menu.AddSeparator(""); menu.AddItem(new GUIContent("Save New Preset"), false, NewPreset); if (AssetDatabase.FindAssets("t:BlendShapePreset").Length > 0) { menu.AddDisabledItem(new GUIContent("Old-style presets found. Convert them to use.")); } menu.DropDown(presetRect); } EditorGUILayout.EndHorizontal(); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(10); GUILayout.Label("Upgrade to LipSync Pro to unlock Emotions and Gestures, along with many more features!"); if (markerTab != oldTab) { if (oldTab == 0) { foreach (PhonemeShape phoneme in lsTarget.phonemes) { foreach (int shape in phoneme.blendShapes) { lsTarget.blendSystem.SetBlendableValue(shape, 0); } } } if (LipSyncEditorExtensions.currentTarget == lsTarget) { LipSyncEditorExtensions.currentToggle = -1; } } if (markerTab == 0) { int a = 0; foreach (PhonemeShape phoneme in lsTarget.phonemes) { this.DrawShapeEditor(lsTarget.blendSystem, lsTarget.useBones, phoneme, phoneme.phoneme.ToString() + " Phoneme", a); a++; } } EditorGUILayout.Space(); GUILayout.Box("General Animation Settings", EditorStyles.boldLabel); EditorGUILayout.PropertyField(animationTimingMode, new GUIContent("Timing Mode", "How animations are sampled: AudioPlayback uses the audioclip, CustomTimer uses a framerate independent timer, FixedFrameRate is framerate dependent.")); showFixedFrameRate.target = lsTarget.animationTimingMode == LipSync.AnimationTimingMode.FixedFrameRate; if (EditorGUILayout.BeginFadeGroup(showFixedFrameRate.faded)) { EditorGUILayout.PropertyField(frameRate, new GUIContent("Frame Rate", "The framerate to play the animation at.")); } EditorGUILayout.EndFadeGroup(); EditorGUILayout.PropertyField(playOnAwake, new GUIContent("Play On Awake", "If checked, the default clip will play when the script awakes.")); showPlayOnAwake.target = lsTarget.playOnAwake; if (EditorGUILayout.BeginFadeGroup(showPlayOnAwake.faded)) { EditorGUILayout.PropertyField(defaultClip, new GUIContent("Default Clip", "The clip to play on awake.")); EditorGUILayout.PropertyField(defaultDelay, new GUIContent("Default Delay", "The delay between the scene starting and the clip playing.")); } EditorGUILayout.EndFadeGroup(); EditorGUILayout.PropertyField(loop, new GUIContent("Loop Clip", "If true, will make any played clip loop when it finishes.")); EditorGUILayout.PropertyField(scaleAudioSpeed, new GUIContent("Scale Audio Speed", "Whether or not the speed of the audio will be slowed/sped up to match Time.timeScale.")); EditorGUILayout.Space(); GUILayout.Box("Phoneme Animation Settings", EditorStyles.boldLabel); EditorGUILayout.PropertyField(restTime, new GUIContent("Rest Time", "If there are no phonemes within this many seconds of the previous one, a rest will be inserted.")); EditorGUILayout.PropertyField(restHoldTime, new GUIContent("Pre-Rest Hold Time", "The time, in seconds, a shape will be held before blending when a rest is inserted.")); EditorGUILayout.PropertyField(phonemeCurveGenerationMode, new GUIContent("Phoneme Curve Generation Mode", "How tangents are generated for animations. Tight is more accurate, Loose is more natural.")); EditorGUILayout.Space(); GUILayout.Space(20); EditorGUILayout.PropertyField(onFinishedPlaying); if (LipSyncEditorExtensions.oldToggle != LipSyncEditorExtensions.currentToggle && LipSyncEditorExtensions.currentTarget == lsTarget) { if (LipSyncEditorExtensions.oldToggle > -1) { if (markerTab == 0) { if (lsTarget.useBones) { foreach (BoneShape boneshape in lsTarget.phonemes[LipSyncEditorExtensions.oldToggle].bones) { if (boneshape.bone != null) { boneshape.bone.localPosition = boneshape.neutralPosition; boneshape.bone.localEulerAngles = boneshape.neutralRotation; } } } foreach (PhonemeShape shape in lsTarget.phonemes) { foreach (int blendable in shape.blendShapes) { lsTarget.blendSystem.SetBlendableValue(blendable, 0); } } } } if (LipSyncEditorExtensions.currentToggle > -1) { if (markerTab == 0) { if (lsTarget.useBones) { foreach (BoneShape boneshape in lsTarget.phonemes[LipSyncEditorExtensions.currentToggle].bones) { if (boneshape.bone != null) { boneshape.bone.localPosition = boneshape.endPosition; boneshape.bone.localEulerAngles = boneshape.endRotation; } } } for (int b = 0; b < lsTarget.phonemes[LipSyncEditorExtensions.currentToggle].blendShapes.Count; b++) { lsTarget.blendSystem.SetBlendableValue(lsTarget.phonemes[LipSyncEditorExtensions.currentToggle].blendShapes[b], lsTarget.phonemes[LipSyncEditorExtensions.currentToggle].weights[b]); } } } LipSyncEditorExtensions.oldToggle = LipSyncEditorExtensions.currentToggle; } if (GUI.changed) { if (blendables == null) { GetBlendShapes(); } if (LipSyncEditorExtensions.currentToggle > -1 && LipSyncEditorExtensions.currentTarget == lsTarget) { if (markerTab == 0) { for (int b = 0; b < lsTarget.phonemes[LipSyncEditorExtensions.currentToggle].blendShapes.Count; b++) { lsTarget.blendSystem.SetBlendableValue(lsTarget.phonemes[LipSyncEditorExtensions.currentToggle].blendShapes[b], lsTarget.phonemes[LipSyncEditorExtensions.currentToggle].weights[b]); } } } EditorUtility.SetDirty(lsTarget); serializedTarget.SetIsDifferentCacheDirty(); } } else { EditorGUILayout.HelpBox(lsTarget.blendSystem.notReadyMessage, MessageType.Warning); } } EditorGUI.EndDisabledGroup(); EditorGUILayout.EndVertical(); if (saving) { GUI.Box(new Rect(40, fullheight.y + (fullheight.height / 2) - 60, fullheight.width - 80, 120), "", (GUIStyle)"flow node 0"); GUI.Box(new Rect(50, fullheight.y + (fullheight.height / 2) - 50, fullheight.width - 100, 20), "Create New Preset", EditorStyles.label); GUI.Box(new Rect(50, fullheight.y + (fullheight.height / 2) - 20, 80, 20), "Preset Path", EditorStyles.label); savingName = EditorGUI.TextField(new Rect(140, fullheight.y + (fullheight.height / 2) - 20, fullheight.width - 290, 20), "", savingName); if (GUI.Button(new Rect(fullheight.width - 140, fullheight.y + (fullheight.height / 2) - 20, 80, 20), "Browse")) { GUI.FocusControl(""); string newPath = EditorUtility.SaveFilePanelInProject("Chose Preset Location", "New Preset", "asset", ""); if (newPath != "") { savingName = newPath.Substring("Assets/".Length); } } if (GUI.Button(new Rect(100, fullheight.y + (fullheight.height / 2) + 15, (fullheight.width / 2) - 110, 25), "Cancel")) { GUI.FocusControl(""); savingName = ""; saving = false; } if (GUI.Button(new Rect((fullheight.width / 2) + 10, fullheight.y + (fullheight.height / 2) + 15, (fullheight.width / 2) - 110, 25), "Save")) { if (!Path.GetDirectoryName(savingName).Contains("Presets")) { EditorUtility.DisplayDialog("Invalid Path", "Presets must be saved in a folder called Presets, or a subfolder of one.", "OK"); return; } else if (!Directory.Exists(Application.dataPath + "/" + Path.GetDirectoryName(savingName))) { EditorUtility.DisplayDialog("Directory Does Not Exist", "The directory " + Path.GetDirectoryName(savingName) + " does not exist.", "OK"); return; } else if (!Path.HasExtension(savingName)) { savingName = Path.GetDirectoryName(savingName) + "/" + Path.GetFileNameWithoutExtension(savingName) + ".asset"; } else if (Path.GetExtension(savingName) != ".asset") { savingName = Path.GetDirectoryName(savingName) + "/" + Path.GetFileNameWithoutExtension(savingName) + ".asset"; } LipSyncPreset preset = ScriptableObject.CreateInstance <LipSyncPreset>(); preset.phonemeShapes = new LipSyncPreset.PhonemeShapeInfo[lsTarget.phonemes.Count]; // Add phonemes for (int p = 0; p < lsTarget.phonemes.Count; p++) { LipSyncPreset.PhonemeShapeInfo phonemeInfo = new LipSyncPreset.PhonemeShapeInfo(); phonemeInfo.phoneme = lsTarget.phonemes[p].phoneme; phonemeInfo.blendables = new LipSyncPreset.BlendableInfo[lsTarget.phonemes[p].blendShapes.Count]; phonemeInfo.bones = new LipSyncPreset.BoneInfo[lsTarget.phonemes[p].bones.Count]; // Add blendables for (int b = 0; b < lsTarget.phonemes[p].blendShapes.Count; b++) { LipSyncPreset.BlendableInfo blendable = new LipSyncPreset.BlendableInfo(); blendable.blendableNumber = lsTarget.phonemes[p].blendShapes[b]; blendable.blendableName = blendables[lsTarget.phonemes[p].blendShapes[b]]; blendable.weight = lsTarget.phonemes[p].weights[b]; phonemeInfo.blendables[b] = blendable; } // Add bones for (int b = 0; b < lsTarget.phonemes[p].bones.Count; b++) { LipSyncPreset.BoneInfo bone = new LipSyncPreset.BoneInfo(); bone.name = lsTarget.phonemes[p].bones[b].bone.name; bone.localPosition = lsTarget.phonemes[p].bones[b].endPosition; bone.localRotation = lsTarget.phonemes[p].bones[b].endRotation; bone.lockPosition = lsTarget.phonemes[p].bones[b].lockPosition; bone.lockRotation = lsTarget.phonemes[p].bones[b].lockRotation; string path = ""; Transform level = lsTarget.phonemes[p].bones[b].bone.parent; while (level != null) { path += level.name + "/"; level = level.parent; } bone.path = path; phonemeInfo.bones[b] = bone; } preset.phonemeShapes[p] = phonemeInfo; } AssetDatabase.CreateAsset(preset, "Assets/" + savingName); AssetDatabase.Refresh(); savingName = ""; saving = false; } } serializedTarget.ApplyModifiedProperties(); }