// Functions /// <summary> /// Returns the index of the blendable in blendSystem that best matches the supplied BlendableInfo. /// </summary> /// <param name="blendable"></param> /// <param name="blendSystem"></param> /// <returns>The index of the blendable if found, or -1 if not.</returns> public int FindBlendable(BlendableInfo blendable, BlendSystem blendSystem) { // First attempts to match based on name, then index. If both fail, returns -1. if (!string.IsNullOrEmpty(blendable.blendableName)) { string cleanName = blendable.blendableName; if (cleanName.Contains("(" + blendable.blendableNumber.ToString() + ")")) { string[] parts = cleanName.Split(new string[] { "(" + blendable.blendableNumber.ToString() + ")" }, System.StringSplitOptions.RemoveEmptyEntries); if (parts.Length > 0) { cleanName = parts[0]; } } string[] blendables = blendSystem.GetBlendables(); for (int a = 0; a < blendables.Length; a++) { string cleanBlendableName = blendables[a]; if (cleanBlendableName.Contains("(" + a.ToString() + ")")) { string[] parts = cleanBlendableName.Split(new string[] { "(" + a.ToString() + ")" }, System.StringSplitOptions.RemoveEmptyEntries); if (parts.Length > 0) { cleanBlendableName = parts[0]; } } if (cleanBlendableName == cleanName) { return(a); } } } if (blendable.blendableNumber < blendSystem.blendableCount) { if (!string.IsNullOrEmpty(blendable.blendableName)) { if (blendable.blendableName != blendSystem.GetBlendables()[blendable.blendableNumber]) { Debug.LogWarning("[LipSync] Blendable " + blendable.blendableName + " used in the '" + this.name + "' preset couldn't be matched based on name, and the blendable at the same index in the " + blendSystem.GetType().Name + " has a different name. This may not be the shape you were expecting."); } } return(blendable.blendableNumber); } return(-1); }
public static bool DrawShapeEditor(this Editor target, BlendSystem blendSystem, string[] blendables, bool useBones, bool allowCreationFromAnimClip, Shape shape, string name, int id, string invalidError = "") { bool markedForDeletion = false; // Add names if missing if (shape.blendableNames == null || shape.blendableNames.Count < shape.blendShapes.Count) { shape.blendableNames = new List <string>(); for (int i = 0; i < shape.blendShapes.Count; i++) { shape.blendableNames.Add(blendables[shape.blendShapes[i]]); } } // Create AnimBool if not defined if (!showBoneOptions.ContainsKey(target)) { showBoneOptions.Add(target, new AnimBool(useBones, target.Repaint)); } showBoneOptions[target].target = useBones; // Create styles if not defined if (lightToolbar == null) { lightToolbar = new GUIStyle(EditorStyles.toolbarDropDown); lightToolbar.normal.background = lightToolbarTexture; miniLabelDark = new GUIStyle(EditorStyles.miniLabel); miniLabelDark.normal.textColor = Color.black; } if (currentToggle == id && currentTarget == target.target) { Undo.RecordObject(target.target, "Change " + name + " Pose"); Rect box = EditorGUILayout.BeginHorizontal(GUILayout.Height(17)); if (shape.verified) { GUI.backgroundColor = new Color(1f, 0.77f, 0f); } else { GUI.backgroundColor = new Color(0.4f, 0.4f, 0.4f); } if (GUI.Button(box, "", lightToolbar)) { currentSearchBlendable = -1; searchString = ""; currentToggle = -1; } GUI.backgroundColor = Color.white; GUILayout.Box(name, miniLabelDark, GUILayout.Width(250)); if (shape.weights.Count == 1) { GUILayout.Box("1 " + blendSystem.blendableDisplayName, miniLabelDark); } else if (shape.weights.Count > 1) { GUILayout.Box(shape.weights.Count.ToString() + " " + blendSystem.blendableDisplayNamePlural, miniLabelDark); } if (shape.bones.Count == 1 && useBones) { GUILayout.Box("1 Bone Transform", miniLabelDark); } else if (shape.bones.Count > 1 && useBones) { GUILayout.Box(shape.bones.Count.ToString() + " Bone Transforms", miniLabelDark); } if (!shape.verified) { GUILayout.FlexibleSpace(); GUILayout.Box("Missing", miniLabelDark); GUILayout.FlexibleSpace(); } EditorGUILayout.EndHorizontal(); GUILayout.Space(8); if (!shape.verified) { if (invalidError != "") { EditorGUILayout.HelpBox(invalidError, MessageType.Warning); } else { EditorGUILayout.HelpBox("There is no matching " + shape.GetType().Name + " in the project settings. It will still function correctly, but it is advised you add it to the project settings for compatibility. Alternatively, you can delete it from here.", MessageType.Warning); } if (GUILayout.Button("Delete Pose")) { markedForDeletion = true; } } box = EditorGUILayout.BeginVertical(); GUI.Box(new Rect(box.x + 4, box.y, box.width - 7, box.height), "", EditorStyles.helpBox); GUILayout.Space(20); for (int b = 0; b < shape.weights.Count; b++) { Rect newBox = EditorGUILayout.BeginHorizontal(); GUI.Box(new Rect(newBox.x + 5, newBox.y, newBox.width - 11, newBox.height), "", EditorStyles.toolbar); GUILayout.Space(5); // Check if blendables have become out-of-sync // (blend system started reporting different blendables) if (blendables[shape.blendShapes[b]] != shape.blendableNames[b] && blendSystem.allowResyncing) { bool matched = false; for (int i = 0; i < blendables.Length; i++) { if (blendables[i] == shape.blendableNames[b]) { shape.blendShapes[b] = i; matched = true; } else if (blendables[i].Remove(blendables[i].Length - 5).Contains(shape.blendableNames[b].Remove(shape.blendableNames[b].Length - 5))) { shape.blendShapes[b] = i; shape.blendableNames[b] = blendables[i]; matched = true; } } if (!matched) { shape.blendableNames[b] = blendables[shape.blendShapes[b]]; } } int oldShape = shape.blendShapes[b]; if (currentSearchBlendable == b) { searchString = EditorGUILayout.TextField("Search", searchString, EditorStyles.toolbarTextField, GUILayout.ExpandWidth(true)); if (GUILayout.Button("Search", EditorStyles.toolbarButton, GUILayout.MaxWidth(45))) { GenericMenu menu = new GenericMenu(); for (int i = 0; i < blendables.Length; i++) { if (blendables[i].ToLowerInvariant().Contains(searchString.ToLowerInvariant())) { int b2 = b; int i2 = i; menu.AddItem(new GUIContent(blendables[i2]), false, () => { if (shape.blendShapes[b2] != i2) { oldShape = shape.blendShapes[b2]; blendSystem.OnBlendableRemovedFromPose(shape.blendShapes[b2]); shape.blendShapes[b2] = i2; blendSystem.OnBlendableAddedToPose(i2); shape.blendableNames[b2] = blendables[b2]; blendSystem.SetBlendableValue(oldShape, 0); blendSystem.SetBlendableValue(i2, shape.weights[b2]); } currentSearchBlendable = -1; searchString = ""; }); } } menu.ShowAsContext(); } } else { int oldBlendable = shape.blendShapes[b]; shape.blendShapes[b] = EditorGUILayout.Popup(blendSystem.blendableDisplayName + " " + b.ToString(), shape.blendShapes[b], blendables, EditorStyles.toolbarPopup); if (oldBlendable != shape.blendShapes[b]) { blendSystem.OnBlendableRemovedFromPose(oldBlendable); blendSystem.OnBlendableAddedToPose(shape.blendShapes[b]); } } if (shape.blendShapes[b] != oldShape) { shape.blendableNames[b] = blendables[b]; blendSystem.SetBlendableValue(oldShape, 0); } if (GUILayout.Button(currentSearchBlendable == b ? list : search, EditorStyles.toolbarButton, GUILayout.MaxWidth(30))) { currentSearchBlendable = currentSearchBlendable == b ? -1 : b; } GUI.backgroundColor = new Color(0.8f, 0.3f, 0.3f); if (GUILayout.Button(delete, EditorStyles.toolbarButton, GUILayout.MaxWidth(50))) { Undo.RecordObject(target.target, "Delete " + blendSystem.blendableDisplayName); shape.blendShapes.RemoveAt(b); blendSystem.SetBlendableValue(oldShape, 0); blendSystem.OnBlendableRemovedFromPose(oldShape); selectedBone = 0; shape.weights.RemoveAt(b); shape.blendableNames.RemoveAt(b); EditorUtility.SetDirty(target.target); break; } GUILayout.Space(4); GUI.backgroundColor = Color.white; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Space(15); shape.weights[b] = EditorGUILayout.Slider(shape.weights[b], blendSystem.blendRangeLow, blendSystem.blendRangeHigh); GUILayout.Space(10); EditorGUILayout.EndHorizontal(); GUILayout.Space(10); } if (FixedBeginFadeGroup(showBoneOptions[target].faded)) { for (int b = 0; b < shape.bones.Count; b++) { Rect newBox = EditorGUILayout.BeginHorizontal(); GUI.Box(new Rect(newBox.x + 5, newBox.y, newBox.width - 11, newBox.height), "", EditorStyles.toolbar); GUILayout.Space(10); bool selected = EditorGUILayout.ToggleLeft(new GUIContent("Bone Transform " + b.ToString(), EditorGUIUtility.FindTexture("Transform Icon"), "Show Transform Handles"), selectedBone == b, GUILayout.Width(170)); selectedBone = selected ? b : selectedBone; Transform oldBone = shape.bones[b].bone; shape.bones[b].bone = (Transform)EditorGUILayout.ObjectField("", shape.bones[b].bone, typeof(Transform), true); if (oldBone != shape.bones[b].bone) { if (shape.bones[b].bone != null) { Transform newbone = shape.bones[b].bone; shape.bones[b].bone = oldBone; if (shape.bones[b].bone != null) { shape.bones[b].bone.localPosition = shape.bones[b].neutralPosition; shape.bones[b].bone.localScale = shape.bones[b].neutralScale; shape.bones[b].bone.localEulerAngles = shape.bones[b].neutralRotation; } shape.bones[b].bone = newbone; shape.bones[b].SetNeutral(); shape.bones[b].endRotation = shape.bones[b].bone.localEulerAngles; shape.bones[b].endPosition = shape.bones[b].bone.localPosition; shape.bones[b].endScale = shape.bones[b].bone.localScale; shape.bones[b].bone.localPosition = shape.bones[b].endPosition; shape.bones[b].bone.localEulerAngles = shape.bones[b].endRotation; shape.bones[b].bone.localScale = shape.bones[b].endScale; } } GUI.backgroundColor = new Color(0.8f, 0.3f, 0.3f); if (GUILayout.Button(delete, EditorStyles.toolbarButton, GUILayout.MaxWidth(50))) { Undo.RecordObject(target.target, "Delete Bone Transform"); if (shape.bones[b].bone != null) { shape.bones[b].bone.localPosition = shape.bones[b].neutralPosition; shape.bones[b].bone.localEulerAngles = shape.bones[b].neutralRotation; shape.bones[b].bone.localScale = shape.bones[b].neutralScale; } shape.bones.RemoveAt(b); if (selectedBone >= shape.bones.Count) { selectedBone -= 1; } EditorUtility.SetDirty(target.target); break; } GUILayout.Space(4); GUI.backgroundColor = Color.white; EditorGUILayout.EndHorizontal(); GUILayout.Space(5); EditorGUILayout.BeginHorizontal(); GUILayout.Space(10); GUILayout.Box("Position", EditorStyles.label, GUILayout.MaxWidth(80)); EditorGUI.BeginDisabledGroup(shape.bones[b].bone == null); EditorGUI.BeginDisabledGroup(shape.bones[b].lockPosition); Vector3 newBonePosition = EditorGUILayout.Vector3Field("", shape.bones[b].endPosition); EditorGUI.EndDisabledGroup(); GUILayout.Space(10); if (GUILayout.Button(shape.bones[b].lockPosition ? locked : unlocked, GUILayout.Width(30), GUILayout.Height(16))) { shape.bones[b].lockPosition = !shape.bones[b].lockPosition; } EditorGUI.EndDisabledGroup(); if (shape.bones[b].bone != null) { if (newBonePosition != shape.bones[b].endPosition) { Undo.RecordObject(shape.bones[b].bone, "Move"); shape.bones[b].endPosition = newBonePosition; shape.bones[b].bone.localPosition = shape.bones[b].endPosition; } else if (shape.bones[b].bone.localPosition != shape.bones[b].endPosition) { shape.bones[b].endPosition = shape.bones[b].bone.localPosition; } } GUILayout.Space(10); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Space(10); GUILayout.Box("Rotation", EditorStyles.label, GUILayout.MaxWidth(80)); EditorGUI.BeginDisabledGroup(shape.bones[b].bone == null); EditorGUI.BeginDisabledGroup(shape.bones[b].lockRotation); Vector3 newBoneRotation = EditorGUILayout.Vector3Field("", shape.bones[b].endRotation); EditorGUI.EndDisabledGroup(); GUILayout.Space(10); if (GUILayout.Button(shape.bones[b].lockRotation ? locked : unlocked, GUILayout.Width(30), GUILayout.Height(16))) { shape.bones[b].lockRotation = !shape.bones[b].lockRotation; } EditorGUI.EndDisabledGroup(); if (shape.bones[b].bone != null) { if (newBoneRotation != shape.bones[b].endRotation) { Undo.RecordObject(shape.bones[b].bone, "Rotate"); shape.bones[b].endRotation = newBoneRotation; shape.bones[b].bone.localEulerAngles = shape.bones[b].endRotation; } else if (shape.bones[b].bone.localEulerAngles != shape.bones[b].endRotation) { shape.bones[b].endRotation = shape.bones[b].bone.localEulerAngles; } } GUILayout.Space(10); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Space(10); GUILayout.Box("Scale", EditorStyles.label, GUILayout.MaxWidth(80)); EditorGUI.BeginDisabledGroup(shape.bones[b].bone == null); EditorGUI.BeginDisabledGroup(shape.bones[b].lockScale); Vector3 newBoneScale = EditorGUILayout.Vector3Field("", shape.bones[b].endScale); EditorGUI.EndDisabledGroup(); GUILayout.Space(10); if (GUILayout.Button(shape.bones[b].lockScale ? locked : unlocked, GUILayout.Width(30), GUILayout.Height(16))) { shape.bones[b].lockScale = !shape.bones[b].lockScale; } EditorGUI.EndDisabledGroup(); if (shape.bones[b].bone != null) { if (newBonePosition != shape.bones[b].endScale) { Undo.RecordObject(shape.bones[b].bone, "Scale"); shape.bones[b].endScale = newBoneScale; shape.bones[b].bone.localScale = shape.bones[b].endScale; } else if (shape.bones[b].bone.localScale != shape.bones[b].endScale) { shape.bones[b].endScale = shape.bones[b].bone.localScale; } } GUILayout.Space(10); EditorGUILayout.EndHorizontal(); GUILayout.Space(10); } } FixedEndFadeGroup(showBoneOptions[target].faded); EditorGUILayout.Space(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (blendSystem.blendableCount > 0) { if (GUILayout.Button("Add " + blendSystem.blendableDisplayName, GUILayout.MaxWidth(200))) { Undo.RecordObject(target.target, "Add " + blendSystem.blendableDisplayName); shape.blendShapes.Add(0); shape.weights.Add(0); shape.blendableNames.Add(blendables[0]); blendSystem.OnBlendableAddedToPose(0); EditorUtility.SetDirty(target.target); } if (useBones) { EditorGUILayout.Space(); } } if (useBones) { if (GUILayout.Button("Add Bone Transform", GUILayout.MaxWidth(240))) { Undo.RecordObject(target.target, "Add Bone Shape"); shape.bones.Add(new BoneShape()); selectedBone = shape.bones.Count - 1; EditorUtility.SetDirty(target.target); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); if (allowCreationFromAnimClip) { GUILayout.Space(5); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Create Pose from AnimationClip", GUILayout.MaxWidth(240))) { PoseExtractorWizard.ShowWindow(blendSystem.transform, shape, name); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } } else { GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } if (blendSystem.blendableCount == 0 && !useBones) { GUILayout.BeginHorizontal(); GUILayout.Space(10); EditorGUILayout.HelpBox(blendSystem.noBlendablesMessage, MessageType.Warning); GUILayout.Space(10); GUILayout.EndHorizontal(); } GUILayout.Space(14); EditorGUILayout.EndVertical(); GUILayout.Space(6); } else { Rect box = EditorGUILayout.BeginHorizontal(GUILayout.Height(17)); if (shape.verified) { if (EditorGUIUtility.isProSkin) { GUI.backgroundColor = new Color(0.22f, 0.22f, 0.22f); } else { GUI.backgroundColor = Color.white; } } else { GUI.backgroundColor = new Color(0.7f, 0.7f, 0.7f); } if (GUI.Button(box, "", lightToolbar)) { currentToggle = id; currentTarget = target.target; selectedBone = 0; searchString = ""; currentSearchBlendable = -1; } GUI.backgroundColor = Color.white; GUILayout.Box(name, EditorStyles.miniLabel, GUILayout.Width(250)); if (shape.weights.Count == 1) { GUILayout.Box("1 " + blendSystem.blendableDisplayName, EditorStyles.miniLabel); } else if (shape.weights.Count > 1) { GUILayout.Box(shape.weights.Count.ToString() + " " + blendSystem.blendableDisplayNamePlural, EditorStyles.miniLabel); } if (shape.bones.Count == 1 && useBones) { GUILayout.Box("1 Bone Transform", EditorStyles.miniLabel); } else if (shape.bones.Count > 1 && useBones) { GUILayout.Box(shape.bones.Count.ToString() + " Bone Transforms", EditorStyles.miniLabel); } if (!shape.verified) { GUILayout.FlexibleSpace(); GUILayout.Box("Missing", EditorStyles.miniLabel); GUILayout.FlexibleSpace(); } EditorGUILayout.EndHorizontal(); GUILayout.Space(1); } return(markedForDeletion); }
public void CreateFromShapes(PhonemeShape[] phonemes, EmotionShape[] emotions, BlendSystem blendSystem, bool relative) { isRelative = relative; phonemeShapes = new PhonemeShapeInfo[phonemes.Length]; emotionShapes = new EmotionShapeInfo[emotions.Length]; for (int s = 0; s < phonemeShapes.Length; s++) { phonemeShapes[s] = new PhonemeShapeInfo(); phonemeShapes[s].phonemeName = phonemes[s].phonemeName; phonemeShapes[s].blendables = new BlendableInfo[phonemes[s].blendShapes.Count]; for (int b = 0; b < phonemeShapes[s].blendables.Length; b++) { phonemeShapes[s].blendables[b].blendableNumber = phonemes[s].blendShapes[b]; phonemeShapes[s].blendables[b].weight = phonemes[s].weights[b]; if (blendSystem != null) { phonemeShapes[s].blendables[b].blendableName = blendSystem.GetBlendables()[phonemes[s].blendShapes[b]]; } } phonemeShapes[s].bones = new BoneInfo[phonemes[s].bones.Count]; for (int b = 0; b < phonemeShapes[s].bones.Length; b++) { phonemeShapes[s].bones[b].name = phonemes[s].bones[b].bone.name; phonemeShapes[s].bones[b].lockPosition = phonemes[s].bones[b].lockPosition; phonemeShapes[s].bones[b].lockRotation = phonemes[s].bones[b].lockRotation; if (relative) { phonemeShapes[s].bones[b].localPosition = phonemes[s].bones[b].neutralPosition - phonemes[s].bones[b].endPosition; phonemeShapes[s].bones[b].localRotation = phonemes[s].bones[b].neutralRotation - phonemes[s].bones[b].endRotation; } else { phonemeShapes[s].bones[b].localPosition = phonemes[s].bones[b].endPosition; phonemeShapes[s].bones[b].localRotation = phonemes[s].bones[b].endRotation; } } } for (int s = 0; s < emotionShapes.Length; s++) { emotionShapes[s] = new EmotionShapeInfo(); emotionShapes[s].emotion = emotions[s].emotion; emotionShapes[s].blendables = new BlendableInfo[emotions[s].blendShapes.Count]; for (int b = 0; b < emotionShapes[s].blendables.Length; b++) { emotionShapes[s].blendables[b].blendableNumber = emotions[s].blendShapes[b]; emotionShapes[s].blendables[b].weight = emotions[s].weights[b]; if (blendSystem != null) { emotionShapes[s].blendables[b].blendableName = blendSystem.GetBlendables()[emotions[s].blendShapes[b]]; } } emotionShapes[s].bones = new BoneInfo[emotions[s].bones.Count]; for (int b = 0; b < emotionShapes[s].bones.Length; b++) { emotionShapes[s].bones[b].name = emotions[s].bones[b].bone.name; emotionShapes[s].bones[b].lockPosition = emotions[s].bones[b].lockPosition; emotionShapes[s].bones[b].lockRotation = emotions[s].bones[b].lockRotation; if (relative) { emotionShapes[s].bones[b].localPosition = emotions[s].bones[b].neutralPosition - phonemes[s].bones[b].endPosition; emotionShapes[s].bones[b].localRotation = emotions[s].bones[b].neutralRotation - phonemes[s].bones[b].endRotation; } else { emotionShapes[s].bones[b].localPosition = emotions[s].bones[b].endPosition; emotionShapes[s].bones[b].localRotation = emotions[s].bones[b].endRotation; } } } }