From 0ea5bb338ba8cc36875e747e416f4ac10d9f7022 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 2 Nov 2018 14:55:13 +0900 Subject: [PATCH] Separated BlendShapeClipSelector.cs --- Scripts/BlendShape/BlendShapeAvatar.cs | 18 ++ .../Editor/BlendShapeAvatarEditor.cs | 203 +++++++----------- .../Editor/BlendShapeClipSelector.cs | 86 ++++++++ .../Editor/BlendShapeClipSelector.cs.meta | 12 ++ Scripts/BlendShape/Editor/PreviewEditor.cs | 10 +- 5 files changed, 205 insertions(+), 124 deletions(-) create mode 100644 Scripts/BlendShape/Editor/BlendShapeClipSelector.cs create mode 100644 Scripts/BlendShape/Editor/BlendShapeClipSelector.cs.meta diff --git a/Scripts/BlendShape/BlendShapeAvatar.cs b/Scripts/BlendShape/BlendShapeAvatar.cs index 606dd62ea..f988186e6 100644 --- a/Scripts/BlendShape/BlendShapeAvatar.cs +++ b/Scripts/BlendShape/BlendShapeAvatar.cs @@ -16,6 +16,24 @@ namespace VRM [SerializeField] public List Clips = new List(); + /// + /// NullのClipを削除して詰める + /// + public void RemoveNullClip() + { + if (Clips == null) + { + return; + } + for (int i = Clips.Count - 1; i >= 0; --i) + { + if (Clips[i] == null) + { + Clips.RemoveAt(i); + } + } + } + #if UNITY_EDITOR [ContextMenu("Restore")] void Restore() diff --git a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs index 0e72aba9b..2a01d6201 100644 --- a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs @@ -15,51 +15,22 @@ namespace VRM static String[] Presets = ((BlendShapePreset[])Enum.GetValues(typeof(BlendShapePreset))) .Select(x => x.ToString()).ToArray(); - BlendShapeAvatar m_target; - - BlendShapeClip m_currentClip; - BlendShapeClip CurrentClip - { - get { return m_currentClip; } - set - { - if (m_currentClip == value) return; - - m_currentClip = value; - //ClearBlendShape(); - if (m_currentClip != null) - { - Bake(m_currentClip.Values, m_currentClip.MaterialValues, 1.0f); - } - } - } + BlendShapeClipSelect m_selector; void OnPrefabChanged() { - if (m_currentClip != null) + if (m_selector != null) { - Bake(m_currentClip.Values, m_currentClip.MaterialValues, 1.0f); + Bake(m_selector.Selected, 1.0f); } } protected override void OnEnable() { PrefabChanged += OnPrefabChanged; - base.OnEnable(); - m_target = (BlendShapeAvatar)target; - // remove missing values - foreach(var x in m_target.Clips.Select((x, i) => new { i, x }).Where(x => x.x == null).Reverse()) - { - m_target.Clips.RemoveAt(x.i); - } - - - if(m_target.Clips.Count > 0) - { - CurrentClip = m_target.Clips[0]; - } + m_selector = new BlendShapeClipSelect((BlendShapeAvatar)target, clip => Bake(clip, 1.0f)); } protected override void OnDisable() @@ -74,114 +45,102 @@ namespace VRM { base.OnInspectorGUI(); - // buttons - if (m_target.Clips != null) + m_selector.SelectGUI(); + + ClipGUI(m_selector.Selected); + } + + void ClipGUI(BlendShapeClip clip) + { + if (clip == null) { - EditorGUILayout.Space(); - EditorGUILayout.LabelField("Select BlendShapeClip", EditorStyles.boldLabel); - var array = m_target.Clips - .Select(x => x != null - ? BlendShapeKey.CreateFrom(x).ToString() - : "null" - ).ToArray(); - var preset = GUILayout.SelectionGrid(m_preset, array, 4); - if (preset != m_preset) - { - CurrentClip = m_target.Clips[preset]; - m_preset = preset; - } + Debug.LogWarning("no clip"); + return; } - // Add - if (GUILayout.Button("Add BlendShapeClip")) + EditorGUILayout.Space(); + EditorGUILayout.LabelField("CurrentClip", EditorStyles.boldLabel); + + // ReadonlyのBlendShapeClip参照 + GUI.enabled = false; + EditorGUILayout.ObjectField("Current clip", + clip, typeof(BlendShapeClip), false); + GUI.enabled = true; + + // Preset選択 + clip.Preset = (BlendShapePreset)EditorGUILayout.Popup("Preset", (int)clip.Preset, Presets); + + // Readonlyの名前入力 + GUI.enabled = false; + EditorGUILayout.TextField("BlendShapeName", clip.BlendShapeName); + GUI.enabled = true; + + // Key重複の警告 + m_selector.DuplicateWarn(); + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("BlendShapeValues", EditorStyles.boldLabel); + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Clear")) { - m_target.AddBlendShapeClip(); + ClearBlendShape(); } - if (CurrentClip != null) + if (clip != null && GUILayout.Button("Apply")) { - // clip - EditorGUILayout.Space(); - EditorGUILayout.LabelField("CurrentClip", EditorStyles.boldLabel); + string maxWeightString; + clip.Values = GetBindings(out maxWeightString); + EditorUtility.SetDirty(clip); + } + EditorGUILayout.EndHorizontal(); - /*var loadClip = (BlendShapeClip)*/ - GUI.enabled = false; - EditorGUILayout.ObjectField("Current clip", - CurrentClip, typeof(BlendShapeClip), false); - GUI.enabled = true; - - CurrentClip.Preset = (BlendShapePreset)EditorGUILayout.Popup("Preset", (int)CurrentClip.Preset, Presets); - - GUI.enabled = false; - CurrentClip.BlendShapeName = EditorGUILayout.TextField("BlendShapeName", CurrentClip.BlendShapeName); - GUI.enabled = true; - - var key = BlendShapeKey.CreateFrom(CurrentClip); - if (m_target.Clips.Where(x => key.Match(x)).Count() > 1) + if (PreviewSceneManager != null) + { + if (BlendShapeBindsGUI(clip)) { - EditorGUILayout.HelpBox("duplicate clip", MessageType.Error); + PreviewSceneManager.Bake(); } + } + } - EditorGUILayout.Space(); - EditorGUILayout.LabelField("BlendShapeValues", EditorStyles.boldLabel); - - EditorGUILayout.BeginHorizontal(); - if (GUILayout.Button("Clear")) + bool BlendShapeBindsGUI(BlendShapeClip clip) + { + bool changed = false; + int foldIndex = 0; + // すべてのSkinnedMeshRendererを列挙する + foreach (var item in PreviewSceneManager.EnumRenderItems.Where(x => x.SkinnedMeshRenderer != null)) + { + var mesh = item.SkinnedMeshRenderer.sharedMesh; + if (mesh != null && mesh.blendShapeCount > 0) { - ClearBlendShape(); - } + //var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, m_target.transform); + //EditorGUILayout.LabelField(m_target.name + "/" + item.Path); - if (CurrentClip != null && GUILayout.Button("Apply")) - { - string maxWeightString; - CurrentClip.Values = GetBindings(out maxWeightString); - EditorUtility.SetDirty(CurrentClip); - } - EditorGUILayout.EndHorizontal(); - - // sliders - bool changed = false; - int foldIndex = 0; - if (PreviewSceneManager != null) - { - foreach (var item in PreviewSceneManager.EnumRenderItems.Where(x => x.SkinnedMeshRenderer != null)) + if (foldIndex >= m_meshFolds.Count) { - var mesh = item.SkinnedMeshRenderer.sharedMesh; - if (mesh != null && mesh.blendShapeCount > 0) + m_meshFolds.Add(false); + } + m_meshFolds[foldIndex] = EditorGUILayout.Foldout(m_meshFolds[foldIndex], item.SkinnedMeshRenderer.name); + if (m_meshFolds[foldIndex]) + { + //EditorGUI.indentLevel += 1; + for (int i = 0; i < mesh.blendShapeCount; ++i) { - //var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, m_target.transform); - //EditorGUILayout.LabelField(m_target.name + "/" + item.Path); - - if (foldIndex >= m_meshFolds.Count) + var src = item.SkinnedMeshRenderer.GetBlendShapeWeight(i); + var dst = EditorGUILayout.Slider(mesh.GetBlendShapeName(i), src, 0, 100.0f); + if (dst != src) { - m_meshFolds.Add(false); + item.SkinnedMeshRenderer.SetBlendShapeWeight(i, dst); + changed = true; } - m_meshFolds[foldIndex] = EditorGUILayout.Foldout(m_meshFolds[foldIndex], item.SkinnedMeshRenderer.name); - if (m_meshFolds[foldIndex]) - { - //EditorGUI.indentLevel += 1; - for (int i = 0; i < mesh.blendShapeCount; ++i) - { - var src = item.SkinnedMeshRenderer.GetBlendShapeWeight(i); - var dst = EditorGUILayout.Slider(mesh.GetBlendShapeName(i), src, 0, 100.0f); - if (dst != src) - { - item.SkinnedMeshRenderer.SetBlendShapeWeight(i, dst); - changed = true; - } - } - //EditorGUI.indentLevel -= 1; - } - ++foldIndex; } + //EditorGUI.indentLevel -= 1; } - - if (changed) - { - PreviewSceneManager.Bake(); - } + ++foldIndex; } } + return changed; } BlendShapeBinding[] GetBindings(out string _maxWeightName) @@ -190,7 +149,7 @@ namespace VRM var maxWeightName = ""; // weightのついたblendShapeを集める var values = PreviewSceneManager.EnumRenderItems - .Where(x => x.SkinnedMeshRenderer!=null) + .Where(x => x.SkinnedMeshRenderer != null) .SelectMany(x => { var mesh = x.SkinnedMeshRenderer.sharedMesh; @@ -230,7 +189,7 @@ namespace VRM private void ClearBlendShape() { - foreach (var item in PreviewSceneManager.EnumRenderItems.Where(x => x.SkinnedMeshRenderer!=null)) + foreach (var item in PreviewSceneManager.EnumRenderItems.Where(x => x.SkinnedMeshRenderer != null)) { var renderer = item.SkinnedMeshRenderer; var mesh = renderer.sharedMesh; diff --git a/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs b/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs new file mode 100644 index 000000000..050aa6d85 --- /dev/null +++ b/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs @@ -0,0 +1,86 @@ +using System; +using System.Linq; +using UnityEngine; +using UnityEditor; + + +namespace VRM +{ + class BlendShapeClipSelect + { + BlendShapeAvatar m_avatar; + + public BlendShapeClip Selected + { + get + { + if (m_avatar == null || m_avatar.Clips == null) + { + return null; + } + if (m_selectedIndex < 0 || m_selectedIndex >= m_avatar.Clips.Count) + { + return null; + } + return m_avatar.Clips[m_selectedIndex]; + } + } + + int m_selectedIndex; + int SelectedIndex + { + get { return m_selectedIndex; } + set + { + if (m_selectedIndex == value) return; + m_selectedIndex = value; + if (m_onSelected != null) + { + m_onSelected(Selected); + } + } + } + + Action m_onSelected; + + public BlendShapeClipSelect(BlendShapeAvatar avatar, Action onSelected) + { + avatar.RemoveNullClip(); + + m_avatar = avatar; + m_onSelected = onSelected; + + onSelected(Selected); + } + + public void SelectGUI() + { + if (m_avatar != null && m_avatar.Clips != null) + { + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Select BlendShapeClip", EditorStyles.boldLabel); + var array = m_avatar.Clips + .Select(x => x != null + ? BlendShapeKey.CreateFrom(x).ToString() + : "null" + ).ToArray(); + SelectedIndex = GUILayout.SelectionGrid(SelectedIndex, array, 4); + } + + if (GUILayout.Button("Add BlendShapeClip")) + { + m_avatar.AddBlendShapeClip(); + } + } + + public void DuplicateWarn() + { + var key = BlendShapeKey.CreateFrom(Selected); + if (m_avatar.Clips.Where(x => key.Match(x)).Count() > 1) + { + EditorGUILayout.HelpBox("duplicate clip: " + key, MessageType.Error); + } + } + } + +} \ No newline at end of file diff --git a/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs.meta b/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs.meta new file mode 100644 index 000000000..b5985862a --- /dev/null +++ b/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7842ed7a65c676740aa02678316dd625 +timeCreated: 1541138009 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/BlendShape/Editor/PreviewEditor.cs b/Scripts/BlendShape/Editor/PreviewEditor.cs index 637a70f6c..31465e33e 100644 --- a/Scripts/BlendShape/Editor/PreviewEditor.cs +++ b/Scripts/BlendShape/Editor/PreviewEditor.cs @@ -89,6 +89,11 @@ namespace VRM } } + protected void Bake(BlendShapeClip clip, float weight) + { + Bake(clip.Values, clip.MaterialValues, weight); + } + protected virtual GameObject GetPrefab() { var assetPath = AssetDatabase.GetAssetPath(target); @@ -155,7 +160,7 @@ namespace VRM { if (Event.current.type == EventType.Repaint) { - EditorGUI.DropShadowLabel(new Rect(r.x, r.y, r.width, 40f), + EditorGUI.DropShadowLabel(new Rect(r.x, r.y, r.width, 40f), "Mesh preview requires\nrender texture support"); } return; @@ -196,7 +201,8 @@ namespace VRM case EventType.ScrollWheel: //Debug.LogFormat("wheel: {0}", current.delta); - if (r.Contains(current.mousePosition)){ + if (r.Contains(current.mousePosition)) + { if (current.delta.y > 0) { m_distance *= 1.1f;