From 411bd286dfbc424b8c4f5652697b5246172eee70 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 1 Nov 2018 23:08:01 +0900 Subject: [PATCH 01/25] Separate SerializedBlendShapeClipEditor --- .../BlendShape/Editor/BlendShapeClipEditor.cs | 273 +--------------- .../Editor/SerializedBlendShapeClipEditor.cs | 301 ++++++++++++++++++ .../SerializedBlendShapeClipEditor.cs.meta | 12 + 3 files changed, 320 insertions(+), 266 deletions(-) create mode 100644 Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs create mode 100644 Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs.meta diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs index 701f0553c..50902805d 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs @@ -9,19 +9,9 @@ namespace VRM [CustomEditor(typeof(BlendShapeClip))] public class BlendShapeClipEditor : PreviewEditor { - float m_previewSlider; - - #region for Editor - SerializedProperty m_BlendShapeNameProp; - SerializedProperty m_PresetProp; - SerializedProperty m_ValuesProp; - ReorderableList m_ValuesList; - SerializedProperty m_MaterialValuesProp; - ReorderableList m_MaterialValuesList; - #endregion + SerializedBlendShapeEditor m_serializedEditor; BlendShapeClip m_target; - bool m_changed; protected override GameObject GetPrefab() { @@ -41,42 +31,8 @@ namespace VRM base.OnEnable(); - m_previewSlider = 1.0f; + Bake(m_target.Values, m_target.MaterialValues, 1.0f); - Bake(m_target.Values, m_target.MaterialValues, m_previewSlider); - - m_BlendShapeNameProp = serializedObject.FindProperty("BlendShapeName"); - m_PresetProp = serializedObject.FindProperty("Preset"); - m_ValuesProp = serializedObject.FindProperty("Values"); - - m_ValuesList = new ReorderableList(serializedObject, m_ValuesProp); - m_ValuesList.elementHeight = BlendShapeBindingHeight; - m_ValuesList.drawElementCallback = - (rect, index, isActive, isFocused) => - { - var element = m_ValuesProp.GetArrayElementAtIndex(index); - rect.height -= 4; - rect.y += 2; - if (DrawBlendShapeBinding(rect, element, PreviewSceneManager)) - { - m_changed = true; - } - }; - - m_MaterialValuesProp = serializedObject.FindProperty("MaterialValues"); - m_MaterialValuesList = new ReorderableList(serializedObject, m_MaterialValuesProp); - m_MaterialValuesList.elementHeight = MaterialValueBindingHeight; - m_MaterialValuesList.drawElementCallback = - (rect, index, isActive, isFocused) => - { - var element = m_MaterialValuesProp.GetArrayElementAtIndex(index); - rect.height -= 4; - rect.y += 2; - if (DrawMaterialValueBinding(rect, element, PreviewSceneManager)) - { - m_changed = true; - } - }; } protected override void OnDisable() @@ -88,34 +44,16 @@ namespace VRM public override void OnInspectorGUI() { base.OnInspectorGUI(); - m_changed = false; - EditorGUILayout.Space(); - var previewSlider = EditorGUILayout.Slider("Preview Weight", m_previewSlider, 0, 1.0f); - if (previewSlider != m_previewSlider) + if (m_serializedEditor == null) { - m_previewSlider = previewSlider; - m_changed = true; + m_serializedEditor = new SerializedBlendShapeEditor(serializedObject, PreviewSceneManager); } - EditorGUILayout.Space(); - - serializedObject.Update(); - - EditorGUILayout.PropertyField(m_BlendShapeNameProp, true); - EditorGUILayout.PropertyField(m_PresetProp, true); - - EditorGUILayout.LabelField("BlendShapeBindings", EditorStyles.boldLabel); - m_ValuesList.DoLayoutList(); - - EditorGUILayout.LabelField("MaterialValueBindings", EditorStyles.boldLabel); - m_MaterialValuesList.DoLayoutList(); - - serializedObject.ApplyModifiedProperties(); - - if (m_changed && PreviewSceneManager != null) + var result = m_serializedEditor.Draw(); + if (result.Changed && PreviewSceneManager != null) { - PreviewSceneManager.Bake(m_target.Values, m_target.MaterialValues, m_previewSlider); + PreviewSceneManager.Bake(m_target.Values, m_target.MaterialValues, result.Weight); } } @@ -123,202 +61,5 @@ namespace VRM { return BlendShapeKey.CreateFrom((BlendShapeClip)target).ToString(); } - - public static int BlendShapeBindingHeight = 60; - public static bool DrawBlendShapeBinding(Rect position, SerializedProperty property, - PreviewSceneManager scene) - { - bool changed = false; - if (scene != null) - { - var height = 16; - - var y = position.y; - var rect = new Rect(position.x, y, position.width, height); - int pathIndex; - if (StringPopup(rect, property.FindPropertyRelative("RelativePath"), scene.SkinnedMeshRendererPathList, out pathIndex)) - { - changed = true; - } - - y += height; - rect = new Rect(position.x, y, position.width, height); - int blendShapeIndex; - if (IntPopup(rect, property.FindPropertyRelative("Index"), scene.GetBlendShapeNames(pathIndex), out blendShapeIndex)) - { - changed = true; - } - - y += height; - rect = new Rect(position.x, y, position.width, height); - if (FloatSlider(rect, property.FindPropertyRelative("Weight"), 100)) - { - changed = true; - } - } - return changed; - } - - public static int MaterialValueBindingHeight = 90; - public static bool DrawMaterialValueBinding(Rect position, SerializedProperty property, - PreviewSceneManager scene) - { - bool changed = false; - if (scene != null) - { - var height = 16; - - var y = position.y; - var rect = new Rect(position.x, y, position.width, height); - int materialIndex; - if (StringPopup(rect, property.FindPropertyRelative("MaterialName"), scene.MaterialNames, out materialIndex)) - { - changed = true; - } - - if (materialIndex >= 0) - { - var materialItem = scene.GetMaterialItem(scene.MaterialNames[materialIndex]); - if (materialItem != null) - { - y += height; - rect = new Rect(position.x, y, position.width, height); - - // プロパティ名のポップアップ - int propIndex; - if (StringPopup(rect, property.FindPropertyRelative("ValueName"), materialItem.PropNames, out propIndex)) - { - changed = true; - } - - if (propIndex >= 0) - { - // 有効なプロパティ名が選択された - var propItem = materialItem.PropMap[materialItem.PropNames[propIndex]]; - { - switch (propItem.PropertyType) - { - case ShaderUtil.ShaderPropertyType.Color: - { - property.FindPropertyRelative("BaseValue").vector4Value = propItem.DefaultValues; - - // max - y += height; - rect = new Rect(position.x, y, position.width, height); - if (ColorProp(rect, property.FindPropertyRelative("TargetValue"))) - { - changed = true; - } - } - break; - - case ShaderUtil.ShaderPropertyType.TexEnv: - { - property.FindPropertyRelative("BaseValue").vector4Value = propItem.DefaultValues; - - // max - y += height; - rect = new Rect(position.x, y, position.width, height); - if (OffsetProp(rect, property.FindPropertyRelative("TargetValue"))) - { - changed = true; - } - } - break; - } - } - } - } - } - } - return changed; - } - - static bool StringPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) - { - if (options == null) - { - newIndex = -1; - return false; - } - - var oldIndex = Array.IndexOf(options, prop.stringValue); - newIndex = EditorGUI.Popup(rect, oldIndex, options); - if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) - { - prop.stringValue = options[newIndex]; - return true; - } - else - { - return false; - } - } - - static bool IntPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) - { - if (options == null) - { - newIndex = -1; - return false; - } - - var oldIndex = prop.intValue; - newIndex = EditorGUI.Popup(rect, oldIndex, options); - if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) - { - prop.intValue = newIndex; - return true; - } - else - { - return false; - } - } - - static bool FloatSlider(Rect rect, SerializedProperty prop, float maxValue) - { - var oldValue = prop.floatValue; - var newValue = EditorGUI.Slider(rect, prop.floatValue, 0, 100f); - if (newValue != oldValue) - { - prop.floatValue = newValue; - return true; - } - else - { - return false; - } - } - - static bool ColorProp(Rect rect, SerializedProperty prop) - { - var oldValue = (Color)prop.vector4Value; - var newValue = EditorGUI.ColorField(rect, prop.displayName, oldValue); - if (newValue != oldValue) - { - prop.vector4Value = newValue; - return true; - } - else - { - return false; - } - } - - static bool OffsetProp(Rect rect, SerializedProperty prop) - { - var oldValue = prop.vector4Value; - var newValue = EditorGUI.Vector4Field(rect, prop.displayName, oldValue); - if (newValue != oldValue) - { - prop.vector4Value = newValue; - return true; - } - else - { - return false; - } - } } } diff --git a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs new file mode 100644 index 000000000..3fedaccc7 --- /dev/null +++ b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs @@ -0,0 +1,301 @@ +using System; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + +namespace VRM +{ + public class SerializedBlendShapeEditor + { + public static int BlendShapeBindingHeight = 60; + const int MaterialValueBindingHeight = 90; + + SerializedObject serializedObject; + + SerializedProperty m_BlendShapeNameProp; + SerializedProperty m_PresetProp; + SerializedProperty m_ValuesProp; + ReorderableList m_ValuesList; + SerializedProperty m_MaterialValuesProp; + ReorderableList m_MaterialValuesList; + + float m_previewSlider = 1.0f; + + bool m_changed; + + public SerializedBlendShapeEditor(SerializedObject serializedObject, PreviewSceneManager PreviewSceneManager) + { + this.serializedObject = serializedObject; + + m_BlendShapeNameProp = serializedObject.FindProperty("BlendShapeName"); + m_PresetProp = serializedObject.FindProperty("Preset"); + m_ValuesProp = serializedObject.FindProperty("Values"); + + m_ValuesList = new ReorderableList(serializedObject, m_ValuesProp); + m_ValuesList.elementHeight = BlendShapeBindingHeight; + m_ValuesList.drawElementCallback = + (rect, index, isActive, isFocused) => + { + var element = m_ValuesProp.GetArrayElementAtIndex(index); + rect.height -= 4; + rect.y += 2; + if (DrawBlendShapeBinding(rect, element, PreviewSceneManager)) + { + m_changed = true; + } + }; + + m_MaterialValuesProp = serializedObject.FindProperty("MaterialValues"); + m_MaterialValuesList = new ReorderableList(serializedObject, m_MaterialValuesProp); + m_MaterialValuesList.elementHeight = MaterialValueBindingHeight; + m_MaterialValuesList.drawElementCallback = + (rect, index, isActive, isFocused) => + { + var element = m_MaterialValuesProp.GetArrayElementAtIndex(index); + rect.height -= 4; + rect.y += 2; + if (DrawMaterialValueBinding(rect, element, PreviewSceneManager)) + { + m_changed = true; + } + }; + } + + public static bool DrawBlendShapeBinding(Rect position, SerializedProperty property, + PreviewSceneManager scene) + { + bool changed = false; + if (scene != null) + { + var height = 16; + + var y = position.y; + var rect = new Rect(position.x, y, position.width, height); + int pathIndex; + if (StringPopup(rect, property.FindPropertyRelative("RelativePath"), scene.SkinnedMeshRendererPathList, out pathIndex)) + { + changed = true; + } + + y += height; + rect = new Rect(position.x, y, position.width, height); + int blendShapeIndex; + if (IntPopup(rect, property.FindPropertyRelative("Index"), scene.GetBlendShapeNames(pathIndex), out blendShapeIndex)) + { + changed = true; + } + + y += height; + rect = new Rect(position.x, y, position.width, height); + if (FloatSlider(rect, property.FindPropertyRelative("Weight"), 100)) + { + changed = true; + } + } + return changed; + } + + public static bool DrawMaterialValueBinding(Rect position, SerializedProperty property, + PreviewSceneManager scene) + { + bool changed = false; + if (scene != null) + { + var height = 16; + + var y = position.y; + var rect = new Rect(position.x, y, position.width, height); + int materialIndex; + if (StringPopup(rect, property.FindPropertyRelative("MaterialName"), scene.MaterialNames, out materialIndex)) + { + changed = true; + } + + if (materialIndex >= 0) + { + var materialItem = scene.GetMaterialItem(scene.MaterialNames[materialIndex]); + if (materialItem != null) + { + y += height; + rect = new Rect(position.x, y, position.width, height); + + // プロパティ名のポップアップ + int propIndex; + if (StringPopup(rect, property.FindPropertyRelative("ValueName"), materialItem.PropNames, out propIndex)) + { + changed = true; + } + + if (propIndex >= 0) + { + // 有効なプロパティ名が選択された + var propItem = materialItem.PropMap[materialItem.PropNames[propIndex]]; + { + switch (propItem.PropertyType) + { + case ShaderUtil.ShaderPropertyType.Color: + { + property.FindPropertyRelative("BaseValue").vector4Value = propItem.DefaultValues; + + // max + y += height; + rect = new Rect(position.x, y, position.width, height); + if (ColorProp(rect, property.FindPropertyRelative("TargetValue"))) + { + changed = true; + } + } + break; + + case ShaderUtil.ShaderPropertyType.TexEnv: + { + property.FindPropertyRelative("BaseValue").vector4Value = propItem.DefaultValues; + + // max + y += height; + rect = new Rect(position.x, y, position.width, height); + if (OffsetProp(rect, property.FindPropertyRelative("TargetValue"))) + { + changed = true; + } + } + break; + } + } + } + } + } + } + return changed; + } + + + public struct DrawResult + { + public bool Changed; + public float Weight; + } + + public DrawResult Draw() + { + m_changed = false; + + //EditorGUILayout.Space(); + + var previewSlider = EditorGUILayout.Slider("Preview Weight", m_previewSlider, 0, 1.0f); + if (previewSlider != m_previewSlider) + { + m_previewSlider = previewSlider; + m_changed = true; + } + + EditorGUILayout.Space(); + + serializedObject.Update(); + + EditorGUILayout.PropertyField(m_BlendShapeNameProp, true); + EditorGUILayout.PropertyField(m_PresetProp, true); + + EditorGUILayout.LabelField("BlendShapeBindings", EditorStyles.boldLabel); + m_ValuesList.DoLayoutList(); + + EditorGUILayout.LabelField("MaterialValueBindings", EditorStyles.boldLabel); + m_MaterialValuesList.DoLayoutList(); + + serializedObject.ApplyModifiedProperties(); + + return new DrawResult + { + Changed = m_changed, + Weight = m_previewSlider + }; + } + + static bool StringPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) + { + if (options == null) + { + newIndex = -1; + return false; + } + + var oldIndex = Array.IndexOf(options, prop.stringValue); + newIndex = EditorGUI.Popup(rect, oldIndex, options); + if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) + { + prop.stringValue = options[newIndex]; + return true; + } + else + { + return false; + } + } + + static bool IntPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) + { + if (options == null) + { + newIndex = -1; + return false; + } + + var oldIndex = prop.intValue; + newIndex = EditorGUI.Popup(rect, oldIndex, options); + if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) + { + prop.intValue = newIndex; + return true; + } + else + { + return false; + } + } + + static bool FloatSlider(Rect rect, SerializedProperty prop, float maxValue) + { + var oldValue = prop.floatValue; + var newValue = EditorGUI.Slider(rect, prop.floatValue, 0, 100f); + if (newValue != oldValue) + { + prop.floatValue = newValue; + return true; + } + else + { + return false; + } + } + + static bool ColorProp(Rect rect, SerializedProperty prop) + { + var oldValue = (Color)prop.vector4Value; + var newValue = EditorGUI.ColorField(rect, prop.displayName, oldValue); + if (newValue != oldValue) + { + prop.vector4Value = newValue; + return true; + } + else + { + return false; + } + } + + static bool OffsetProp(Rect rect, SerializedProperty prop) + { + var oldValue = prop.vector4Value; + var newValue = EditorGUI.Vector4Field(rect, prop.displayName, oldValue); + if (newValue != oldValue) + { + prop.vector4Value = newValue; + return true; + } + else + { + return false; + } + } + } +} diff --git a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs.meta b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs.meta new file mode 100644 index 000000000..209e1f5b7 --- /dev/null +++ b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: eaafa3ff7bf991642b922e6af7ecbbc0 +timeCreated: 1541081003 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 79e9241ef70d9a18d17213b5cd9efdf8f89329c0 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 2 Nov 2018 14:18:43 +0900 Subject: [PATCH 02/25] Move BlendShapeAvatar.AddBlendShapeClip --- Scripts/BlendShape/BlendShapeAvatar.cs | 29 +++++++++++++++++++ .../Editor/BlendShapeAvatarEditor.cs | 26 +---------------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/Scripts/BlendShape/BlendShapeAvatar.cs b/Scripts/BlendShape/BlendShapeAvatar.cs index cc2cb36e6..606dd62ea 100644 --- a/Scripts/BlendShape/BlendShapeAvatar.cs +++ b/Scripts/BlendShape/BlendShapeAvatar.cs @@ -3,6 +3,10 @@ using System.Linq; using System; using System.Collections.Generic; using UniGLTF; +using System.IO; +#if UNITY_EDITOR +using UnityEditor; +#endif namespace VRM { @@ -37,6 +41,31 @@ namespace VRM } Clips = Clips.OrderBy(x => BlendShapeKey.CreateFrom(x)).ToList(); } + + public void AddBlendShapeClip() + { + var dir = Path.GetDirectoryName(AssetDatabase.GetAssetPath(this)); + var path = EditorUtility.SaveFilePanel( + "Create BlendShapeClip", + dir, + string.Format("BlendShapeClip#{0}.asset", Clips.Count), + "asset"); + if (string.IsNullOrEmpty(path)) + { + return; + } + path = path.ToUnityRelativePath(); + //Debug.LogFormat("{0}", path); + var clip = ScriptableObject.CreateInstance(); + clip.BlendShapeName = Path.GetFileNameWithoutExtension(path); + clip.Prefab = AssetDatabase.LoadAssetAtPath(AssetDatabase.GetAssetPath(this)); + AssetDatabase.CreateAsset(clip, path); + AssetDatabase.ImportAsset(path); + + Clips.Add(clip); + EditorUtility.SetDirty(this); + AssetDatabase.SaveAssets(); + } #endif /// diff --git a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs index f3657d42f..0e72aba9b 100644 --- a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs @@ -16,30 +16,6 @@ namespace VRM .Select(x => x.ToString()).ToArray(); BlendShapeAvatar m_target; - void AddBlendShapeClip() - { - var dir = Path.GetDirectoryName(AssetDatabase.GetAssetPath(m_target)); - var path = EditorUtility.SaveFilePanel( - "Create BlendShapeClip", - dir, - string.Format("BlendShapeClip#{0}.asset", m_target.Clips.Count), - "asset"); - if (string.IsNullOrEmpty(path)) - { - return; - } - path = path.ToUnityRelativePath(); - //Debug.LogFormat("{0}", path); - var clip = ScriptableObject.CreateInstance(); - clip.BlendShapeName = Path.GetFileNameWithoutExtension(path); - clip.Prefab = AssetDatabase.LoadAssetAtPath(AssetDatabase.GetAssetPath(m_target)); - AssetDatabase.CreateAsset(clip, path); - AssetDatabase.ImportAsset(path); - - m_target.Clips.Add(clip); - EditorUtility.SetDirty(m_target); - AssetDatabase.SaveAssets(); - } BlendShapeClip m_currentClip; BlendShapeClip CurrentClip @@ -119,7 +95,7 @@ namespace VRM // Add if (GUILayout.Button("Add BlendShapeClip")) { - AddBlendShapeClip(); + m_target.AddBlendShapeClip(); } if (CurrentClip != null) From 0ea5bb338ba8cc36875e747e416f4ac10d9f7022 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 2 Nov 2018 14:55:13 +0900 Subject: [PATCH 03/25] 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; From d349197ef693b7077dc135b1309023cb58ded5b2 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 2 Nov 2018 15:50:36 +0900 Subject: [PATCH 04/25] Modify SerializedBlendShapeEditor --- .../BlendShape/Editor/BlendShapeClipEditor.cs | 2 +- .../Editor/SerializedBlendShapeClipEditor.cs | 71 +++++++++++++------ 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs index 50902805d..2967b0b6d 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs @@ -53,7 +53,7 @@ namespace VRM var result = m_serializedEditor.Draw(); if (result.Changed && PreviewSceneManager != null) { - PreviewSceneManager.Bake(m_target.Values, m_target.MaterialValues, result.Weight); + PreviewSceneManager.Bake(result.BlendShapeBindings, result.MaterialValueBindings, result.Weight); } } diff --git a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs index 3fedaccc7..4dcc1de6e 100644 --- a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using UnityEditor; using UnityEditorInternal; using UnityEngine; @@ -7,54 +8,75 @@ namespace VRM { public class SerializedBlendShapeEditor { - public static int BlendShapeBindingHeight = 60; - const int MaterialValueBindingHeight = 90; + BlendShapeClip m_targetObject; - SerializedObject serializedObject; + SerializedObject m_serializedObject; + #region Properties SerializedProperty m_BlendShapeNameProp; SerializedProperty m_PresetProp; - SerializedProperty m_ValuesProp; - ReorderableList m_ValuesList; - SerializedProperty m_MaterialValuesProp; - ReorderableList m_MaterialValuesList; + #endregion + #region BlendShapeBind + public static int BlendShapeBindingHeight = 60; + ReorderableList m_ValuesList; + #endregion + + #region MaterialValueBind + const int MaterialValueBindingHeight = 90; + ReorderableList m_MaterialValuesList; + #endregion + + #region Editor values float m_previewSlider = 1.0f; bool m_changed; + #endregion - public SerializedBlendShapeEditor(SerializedObject serializedObject, PreviewSceneManager PreviewSceneManager) + public SerializedBlendShapeEditor(SerializedObject serializedObject, + PreviewSceneManager previewSceneManager) : this( + serializedObject, (BlendShapeClip)serializedObject.targetObject, previewSceneManager) + { } + + public SerializedBlendShapeEditor(BlendShapeClip blendShapeClip, + PreviewSceneManager previewSceneManager) : this( + new SerializedObject(blendShapeClip), blendShapeClip, previewSceneManager) + { } + + public SerializedBlendShapeEditor(SerializedObject serializedObject, BlendShapeClip targetObject, + PreviewSceneManager previewSceneManager) { - this.serializedObject = serializedObject; + this.m_serializedObject = serializedObject; + this.m_targetObject = targetObject; m_BlendShapeNameProp = serializedObject.FindProperty("BlendShapeName"); m_PresetProp = serializedObject.FindProperty("Preset"); - m_ValuesProp = serializedObject.FindProperty("Values"); + var valuesProp = serializedObject.FindProperty("Values"); - m_ValuesList = new ReorderableList(serializedObject, m_ValuesProp); + m_ValuesList = new ReorderableList(serializedObject, valuesProp); m_ValuesList.elementHeight = BlendShapeBindingHeight; m_ValuesList.drawElementCallback = (rect, index, isActive, isFocused) => { - var element = m_ValuesProp.GetArrayElementAtIndex(index); + var element = valuesProp.GetArrayElementAtIndex(index); rect.height -= 4; rect.y += 2; - if (DrawBlendShapeBinding(rect, element, PreviewSceneManager)) + if (DrawBlendShapeBinding(rect, element, previewSceneManager)) { m_changed = true; } }; - m_MaterialValuesProp = serializedObject.FindProperty("MaterialValues"); - m_MaterialValuesList = new ReorderableList(serializedObject, m_MaterialValuesProp); + var materialValuesProp = serializedObject.FindProperty("MaterialValues"); + m_MaterialValuesList = new ReorderableList(serializedObject, materialValuesProp); m_MaterialValuesList.elementHeight = MaterialValueBindingHeight; m_MaterialValuesList.drawElementCallback = (rect, index, isActive, isFocused) => { - var element = m_MaterialValuesProp.GetArrayElementAtIndex(index); + var element = materialValuesProp.GetArrayElementAtIndex(index); rect.height -= 4; rect.y += 2; - if (DrawMaterialValueBinding(rect, element, PreviewSceneManager)) + if (DrawMaterialValueBinding(rect, element, previewSceneManager)) { m_changed = true; } @@ -174,6 +196,10 @@ namespace VRM { public bool Changed; public float Weight; + + public BlendShapeBinding[] BlendShapeBindings; + + public MaterialValueBinding[] MaterialValueBindings; } public DrawResult Draw() @@ -191,7 +217,7 @@ namespace VRM EditorGUILayout.Space(); - serializedObject.Update(); + m_serializedObject.Update(); EditorGUILayout.PropertyField(m_BlendShapeNameProp, true); EditorGUILayout.PropertyField(m_PresetProp, true); @@ -202,12 +228,17 @@ namespace VRM EditorGUILayout.LabelField("MaterialValueBindings", EditorStyles.boldLabel); m_MaterialValuesList.DoLayoutList(); - serializedObject.ApplyModifiedProperties(); + if (m_changed) + { + m_serializedObject.ApplyModifiedProperties(); + } return new DrawResult { Changed = m_changed, - Weight = m_previewSlider + Weight = m_previewSlider, + BlendShapeBindings = m_targetObject.Values, + MaterialValueBindings = m_targetObject.MaterialValues }; } From c1924a1c4eed39070a6dbce397154a035c653333 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 2 Nov 2018 16:00:49 +0900 Subject: [PATCH 05/25] Tab --- .../Editor/SerializedBlendShapeClipEditor.cs | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs index 4dcc1de6e..515e318f7 100644 --- a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs @@ -31,6 +31,12 @@ namespace VRM float m_previewSlider = 1.0f; bool m_changed; + + int m_mode; + static string[] MODES = new[]{ + "BlendShape", + "Material" + }; #endregion public SerializedBlendShapeEditor(SerializedObject serializedObject, @@ -215,18 +221,31 @@ namespace VRM m_changed = true; } - EditorGUILayout.Space(); - m_serializedObject.Update(); + EditorGUILayout.Space(); EditorGUILayout.PropertyField(m_BlendShapeNameProp, true); EditorGUILayout.PropertyField(m_PresetProp, true); - EditorGUILayout.LabelField("BlendShapeBindings", EditorStyles.boldLabel); - m_ValuesList.DoLayoutList(); + EditorGUILayout.Space(); + //m_mode = EditorGUILayout.Popup("SourceType", m_mode, MODES); + m_mode = GUILayout.Toolbar(m_mode, MODES); + switch (m_mode) + { + case 0: + { + //EditorGUILayout.LabelField("BlendShapeBindings", EditorStyles.boldLabel); + m_ValuesList.DoLayoutList(); + } + break; - EditorGUILayout.LabelField("MaterialValueBindings", EditorStyles.boldLabel); - m_MaterialValuesList.DoLayoutList(); + case 1: + { + //EditorGUILayout.LabelField("MaterialValueBindings", EditorStyles.boldLabel); + m_MaterialValuesList.DoLayoutList(); + } + break; + } if (m_changed) { From 214e0ac3a6363eb696dffc4edc0fb639d440f10a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 2 Nov 2018 16:32:13 +0900 Subject: [PATCH 06/25] BlendShape/Editor/BlendShapeAvatarEditor use SerializedBlendShapeClipEditor --- .../Editor/BlendShapeAvatarEditor.cs | 205 +++++---------- .../Editor/BlendShapeClipSelector.cs | 4 +- Scripts/BlendShape/Editor/PreviewEditor.cs | 16 +- .../Editor/SerializedBlendShapeClipEditor.cs | 243 +++++++++++++----- Scripts/BlendShape/PreviewSceneManager.cs | 10 +- 5 files changed, 261 insertions(+), 217 deletions(-) diff --git a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs index 2a01d6201..9844b7387 100644 --- a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs @@ -15,7 +15,9 @@ namespace VRM static String[] Presets = ((BlendShapePreset[])Enum.GetValues(typeof(BlendShapePreset))) .Select(x => x.ToString()).ToArray(); - BlendShapeClipSelect m_selector; + BlendShapeClipSelector m_selector; + + SerializedBlendShapeEditor m_clipEditor; void OnPrefabChanged() { @@ -25,12 +27,25 @@ namespace VRM } } + void OnSelected(BlendShapeClip clip) + { + Bake(clip, 1.0f); + if (clip != null) + { + m_clipEditor = new SerializedBlendShapeEditor(clip, PreviewSceneManager); + } + else + { + m_clipEditor = null; + } + } + protected override void OnEnable() { PrefabChanged += OnPrefabChanged; base.OnEnable(); - m_selector = new BlendShapeClipSelect((BlendShapeAvatar)target, clip => Bake(clip, 1.0f)); + m_selector = new BlendShapeClipSelector((BlendShapeAvatar)target, OnSelected); } protected override void OnDisable() @@ -39,168 +54,68 @@ namespace VRM PrefabChanged -= OnPrefabChanged; } - List m_meshFolds = new List(); - int m_preset; public override void OnInspectorGUI() { base.OnInspectorGUI(); m_selector.SelectGUI(); - ClipGUI(m_selector.Selected); - } - - void ClipGUI(BlendShapeClip clip) - { - if (clip == null) + if (m_clipEditor != null) { - Debug.LogWarning("no clip"); - return; - } + Separator(); - 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")) - { - ClearBlendShape(); - } - - if (clip != null && GUILayout.Button("Apply")) - { - string maxWeightString; - clip.Values = GetBindings(out maxWeightString); - EditorUtility.SetDirty(clip); - } - EditorGUILayout.EndHorizontal(); - - if (PreviewSceneManager != null) - { - if (BlendShapeBindsGUI(clip)) + var result = m_clipEditor.Draw(); + if (result.Changed) { - PreviewSceneManager.Bake(); + Bake(result.BlendShapeBindings, result.MaterialValueBindings, result.Weight); } } } - 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) + /* + BlendShapeBinding[] GetBindings(out string _maxWeightName) { - //var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, m_target.transform); - //EditorGUILayout.LabelField(m_target.name + "/" + item.Path); + var maxWeight = 0.0f; + var maxWeightName = ""; + // weightのついたblendShapeを集める + var values = PreviewSceneManager.EnumRenderItems + .Where(x => x.SkinnedMeshRenderer != null) + .SelectMany(x => + { + var mesh = x.SkinnedMeshRenderer.sharedMesh; - if (foldIndex >= m_meshFolds.Count) - { - 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 = x.Path; + + var list = new List(); + if (mesh != null) { - var src = item.SkinnedMeshRenderer.GetBlendShapeWeight(i); - var dst = EditorGUILayout.Slider(mesh.GetBlendShapeName(i), src, 0, 100.0f); - if (dst != src) + for (int i = 0; i < mesh.blendShapeCount; ++i) { - item.SkinnedMeshRenderer.SetBlendShapeWeight(i, dst); - changed = true; + var weight = x.SkinnedMeshRenderer.GetBlendShapeWeight(i); + if (weight == 0) + { + continue; + } + var name = mesh.GetBlendShapeName(i); + if (weight > maxWeight) + { + maxWeightName = name; + maxWeight = weight; + } + list.Add(new BlendShapeBinding + { + Index = i, + RelativePath = relativePath, + Weight = weight + }); } } - //EditorGUI.indentLevel -= 1; - } - ++foldIndex; + return list; + }).ToArray() + ; + _maxWeightName = maxWeightName; + return values; } - } - return changed; - } - - BlendShapeBinding[] GetBindings(out string _maxWeightName) - { - var maxWeight = 0.0f; - var maxWeightName = ""; - // weightのついたblendShapeを集める - var values = PreviewSceneManager.EnumRenderItems - .Where(x => x.SkinnedMeshRenderer != null) - .SelectMany(x => - { - var mesh = x.SkinnedMeshRenderer.sharedMesh; - - var relativePath = x.Path; - - var list = new List(); - if (mesh != null) - { - for (int i = 0; i < mesh.blendShapeCount; ++i) - { - var weight = x.SkinnedMeshRenderer.GetBlendShapeWeight(i); - if (weight == 0) - { - continue; - } - var name = mesh.GetBlendShapeName(i); - if (weight > maxWeight) - { - maxWeightName = name; - maxWeight = weight; - } - list.Add(new BlendShapeBinding - { - Index = i, - RelativePath = relativePath, - Weight = weight - }); - } - } - return list; - }).ToArray() - ; - _maxWeightName = maxWeightName; - return values; - } - - private void ClearBlendShape() - { - foreach (var item in PreviewSceneManager.EnumRenderItems.Where(x => x.SkinnedMeshRenderer != null)) - { - var renderer = item.SkinnedMeshRenderer; - var mesh = renderer.sharedMesh; - if (mesh != null) - { - for (int i = 0; i < mesh.blendShapeCount; ++i) - { - renderer.SetBlendShapeWeight(i, 0); - } - } - } - } + */ } } diff --git a/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs b/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs index 050aa6d85..84fd6301d 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs @@ -6,7 +6,7 @@ using UnityEditor; namespace VRM { - class BlendShapeClipSelect + class BlendShapeClipSelector { BlendShapeAvatar m_avatar; @@ -43,7 +43,7 @@ namespace VRM Action m_onSelected; - public BlendShapeClipSelect(BlendShapeAvatar avatar, Action onSelected) + public BlendShapeClipSelector(BlendShapeAvatar avatar, Action onSelected) { avatar.RemoveNullClip(); diff --git a/Scripts/BlendShape/Editor/PreviewEditor.cs b/Scripts/BlendShape/Editor/PreviewEditor.cs index 31465e33e..85bede048 100644 --- a/Scripts/BlendShape/Editor/PreviewEditor.cs +++ b/Scripts/BlendShape/Editor/PreviewEditor.cs @@ -46,6 +46,8 @@ namespace VRM private set { if (m_prefab == value) return; + + //Debug.LogFormat("Prefab = {0}", value); m_prefab = value; if (m_scene != null) @@ -138,11 +140,23 @@ namespace VRM } } + protected static void Separator() + { + EditorGUILayout.Space(); + EditorGUILayout.BeginHorizontal(); + //GUILayout.Space(); + GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1)); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + } + public override void OnInspectorGUI() { //base.OnInspectorGUI(); - Prefab = (GameObject)EditorGUILayout.ObjectField("prefab", Prefab, typeof(GameObject), false); + Prefab = (GameObject)EditorGUILayout.ObjectField("prefab for preview", Prefab, typeof(GameObject), false); + + Separator(); } private static int sliderHash = "Slider".GetHashCode(); diff --git a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs index 515e318f7..16eb6908f 100644 --- a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs @@ -89,7 +89,182 @@ namespace VRM }; } - public static bool DrawBlendShapeBinding(Rect position, SerializedProperty property, + public struct DrawResult + { + public bool Changed; + public float Weight; + + public BlendShapeBinding[] BlendShapeBindings; + + public MaterialValueBinding[] MaterialValueBindings; + } + + public DrawResult Draw() + { + m_changed = false; + + //EditorGUILayout.Space(); + + var previewSlider = EditorGUILayout.Slider("Preview Weight", m_previewSlider, 0, 1.0f); + if (previewSlider != m_previewSlider) + { + m_previewSlider = previewSlider; + m_changed = true; + } + + m_serializedObject.Update(); + + EditorGUILayout.Space(); + EditorGUILayout.PropertyField(m_BlendShapeNameProp, true); + EditorGUILayout.PropertyField(m_PresetProp, true); + + EditorGUILayout.Space(); + //m_mode = EditorGUILayout.Popup("SourceType", m_mode, MODES); + m_mode = GUILayout.Toolbar(m_mode, MODES); + switch (m_mode) + { + case 0: + { + //EditorGUILayout.LabelField("BlendShapeBindings", EditorStyles.boldLabel); + m_ValuesList.DoLayoutList(); + } + break; + + case 1: + { + //EditorGUILayout.LabelField("MaterialValueBindings", EditorStyles.boldLabel); + m_MaterialValuesList.DoLayoutList(); + } + break; + } + + if (m_changed) + { + m_serializedObject.ApplyModifiedProperties(); + } + + return new DrawResult + { + Changed = m_changed, + Weight = m_previewSlider, + BlendShapeBindings = m_targetObject.Values, + MaterialValueBindings = m_targetObject.MaterialValues + }; + } + +#if false + void ClipGUI(BlendShapeClip clip) + { + if (clip == null) + { + Debug.LogWarning("no clip"); + return; + } + + 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")) + { + ClearBlendShape(); + } + + if (clip != null && GUILayout.Button("Apply")) + { + string maxWeightString; + clip.Values = GetBindings(out maxWeightString); + EditorUtility.SetDirty(clip); + } + EditorGUILayout.EndHorizontal(); + + if (PreviewSceneManager != null) + { + if (BlendShapeBindsGUI(clip)) + { + PreviewSceneManager.Bake(); + } + } + } + + List m_meshFolds = new List(); + 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) + { + //var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, m_target.transform); + //EditorGUILayout.LabelField(m_target.name + "/" + item.Path); + + if (foldIndex >= m_meshFolds.Count) + { + 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 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; + } + } + return changed; + } + private void ClearBlendShape() + { + foreach (var item in PreviewSceneManager.EnumRenderItems.Where(x => x.SkinnedMeshRenderer != null)) + { + var renderer = item.SkinnedMeshRenderer; + var mesh = renderer.sharedMesh; + if (mesh != null) + { + for (int i = 0; i < mesh.blendShapeCount; ++i) + { + renderer.SetBlendShapeWeight(i, 0); + } + } + } + } +#endif + + #region private + static bool DrawBlendShapeBinding(Rect position, SerializedProperty property, PreviewSceneManager scene) { bool changed = false; @@ -123,7 +298,7 @@ namespace VRM return changed; } - public static bool DrawMaterialValueBinding(Rect position, SerializedProperty property, + static bool DrawMaterialValueBinding(Rect position, SerializedProperty property, PreviewSceneManager scene) { bool changed = false; @@ -198,69 +373,6 @@ namespace VRM } - public struct DrawResult - { - public bool Changed; - public float Weight; - - public BlendShapeBinding[] BlendShapeBindings; - - public MaterialValueBinding[] MaterialValueBindings; - } - - public DrawResult Draw() - { - m_changed = false; - - //EditorGUILayout.Space(); - - var previewSlider = EditorGUILayout.Slider("Preview Weight", m_previewSlider, 0, 1.0f); - if (previewSlider != m_previewSlider) - { - m_previewSlider = previewSlider; - m_changed = true; - } - - m_serializedObject.Update(); - - EditorGUILayout.Space(); - EditorGUILayout.PropertyField(m_BlendShapeNameProp, true); - EditorGUILayout.PropertyField(m_PresetProp, true); - - EditorGUILayout.Space(); - //m_mode = EditorGUILayout.Popup("SourceType", m_mode, MODES); - m_mode = GUILayout.Toolbar(m_mode, MODES); - switch (m_mode) - { - case 0: - { - //EditorGUILayout.LabelField("BlendShapeBindings", EditorStyles.boldLabel); - m_ValuesList.DoLayoutList(); - } - break; - - case 1: - { - //EditorGUILayout.LabelField("MaterialValueBindings", EditorStyles.boldLabel); - m_MaterialValuesList.DoLayoutList(); - } - break; - } - - if (m_changed) - { - m_serializedObject.ApplyModifiedProperties(); - } - - return new DrawResult - { - Changed = m_changed, - Weight = m_previewSlider, - BlendShapeBindings = m_targetObject.Values, - MaterialValueBindings = m_targetObject.MaterialValues - }; - } - static bool StringPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) { if (options == null) @@ -347,5 +459,6 @@ namespace VRM return false; } } + #endregion } } diff --git a/Scripts/BlendShape/PreviewSceneManager.cs b/Scripts/BlendShape/PreviewSceneManager.cs index 849e1b8a6..4a5928073 100644 --- a/Scripts/BlendShape/PreviewSceneManager.cs +++ b/Scripts/BlendShape/PreviewSceneManager.cs @@ -80,6 +80,7 @@ namespace VRM private void Initialize(GameObject prefab) { + //Debug.LogFormat("[PreviewSceneManager.Initialize] {0}", prefab); Prefab = prefab; var materialNames = new List(); @@ -90,7 +91,7 @@ namespace VRM if (string.IsNullOrEmpty(src.name)) return null; // ! Material dst; - if(!map.TryGetValue(src, out dst)) + if (!map.TryGetValue(src, out dst)) { dst = new Material(src); map.Add(src, dst); @@ -111,7 +112,7 @@ namespace VRM m_blendShapeMeshes = m_meshes .Where(x => x.SkinnedMeshRenderer != null - && x.SkinnedMeshRenderer.sharedMesh.blendShapeCount>0) + && x.SkinnedMeshRenderer.sharedMesh.blendShapeCount > 0) .ToArray(); //Bake(values, materialValues); @@ -183,7 +184,8 @@ namespace VRM public MaterialItem GetMaterialItem(string materialName) { MaterialItem item; - if(!m_materialMap.TryGetValue(materialName, out item)){ + if (!m_materialMap.TryGetValue(materialName, out item)) + { return null; } @@ -205,7 +207,7 @@ namespace VRM #if UNITY_EDITOR Bounds m_bounds; - public void Bake(BlendShapeBinding[] values=null, MaterialValueBinding[] materialValues=null, float weight=1.0f) + public void Bake(BlendShapeBinding[] values = null, MaterialValueBinding[] materialValues = null, float weight = 1.0f) { //Debug.LogFormat("Bake"); m_bounds = default(Bounds); From 62b24dec1e1ee80c147dfc283b6abc6179d68799 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 2 Nov 2018 17:52:17 +0900 Subject: [PATCH 07/25] Implemented ClipGUI using SerializedObject --- .../Editor/BlendShapeAvatarEditor.cs | 48 +-- .../Editor/BlendShapeClipEditorHelper.cs | 207 ++++++++++ .../Editor/BlendShapeClipEditorHelper.cs.meta | 12 + .../Editor/SerializedBlendShapeClipEditor.cs | 360 ++++++------------ 4 files changed, 331 insertions(+), 296 deletions(-) create mode 100644 Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs create mode 100644 Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs.meta diff --git a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs index 9844b7387..ace08a187 100644 --- a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs @@ -64,6 +64,8 @@ namespace VRM { Separator(); + m_selector.DuplicateWarn(); + var result = m_clipEditor.Draw(); if (result.Changed) { @@ -71,51 +73,5 @@ namespace VRM } } } - - /* - BlendShapeBinding[] GetBindings(out string _maxWeightName) - { - var maxWeight = 0.0f; - var maxWeightName = ""; - // weightのついたblendShapeを集める - var values = PreviewSceneManager.EnumRenderItems - .Where(x => x.SkinnedMeshRenderer != null) - .SelectMany(x => - { - var mesh = x.SkinnedMeshRenderer.sharedMesh; - - var relativePath = x.Path; - - var list = new List(); - if (mesh != null) - { - for (int i = 0; i < mesh.blendShapeCount; ++i) - { - var weight = x.SkinnedMeshRenderer.GetBlendShapeWeight(i); - if (weight == 0) - { - continue; - } - var name = mesh.GetBlendShapeName(i); - if (weight > maxWeight) - { - maxWeightName = name; - maxWeight = weight; - } - list.Add(new BlendShapeBinding - { - Index = i, - RelativePath = relativePath, - Weight = weight - }); - } - } - return list; - }).ToArray() - ; - _maxWeightName = maxWeightName; - return values; - } - */ } } diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs new file mode 100644 index 000000000..749c815de --- /dev/null +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs @@ -0,0 +1,207 @@ +using System; +using UnityEditor; +using UnityEngine; + + +namespace VRM +{ + public static class BlendShapeClipEditorHelper + { + public static bool DrawBlendShapeBinding(Rect position, SerializedProperty property, + PreviewSceneManager scene) + { + bool changed = false; + if (scene != null) + { + var height = 16; + + var y = position.y; + var rect = new Rect(position.x, y, position.width, height); + int pathIndex; + if (StringPopup(rect, property.FindPropertyRelative("RelativePath"), scene.SkinnedMeshRendererPathList, out pathIndex)) + { + changed = true; + } + + y += height; + rect = new Rect(position.x, y, position.width, height); + int blendShapeIndex; + if (IntPopup(rect, property.FindPropertyRelative("Index"), scene.GetBlendShapeNames(pathIndex), out blendShapeIndex)) + { + changed = true; + } + + y += height; + rect = new Rect(position.x, y, position.width, height); + if (FloatSlider(rect, property.FindPropertyRelative("Weight"), 100)) + { + changed = true; + } + } + return changed; + } + + public static bool DrawMaterialValueBinding(Rect position, SerializedProperty property, + PreviewSceneManager scene) + { + bool changed = false; + if (scene != null) + { + var height = 16; + + var y = position.y; + var rect = new Rect(position.x, y, position.width, height); + int materialIndex; + if (StringPopup(rect, property.FindPropertyRelative("MaterialName"), scene.MaterialNames, out materialIndex)) + { + changed = true; + } + + if (materialIndex >= 0) + { + var materialItem = scene.GetMaterialItem(scene.MaterialNames[materialIndex]); + if (materialItem != null) + { + y += height; + rect = new Rect(position.x, y, position.width, height); + + // プロパティ名のポップアップ + int propIndex; + if (StringPopup(rect, property.FindPropertyRelative("ValueName"), materialItem.PropNames, out propIndex)) + { + changed = true; + } + + if (propIndex >= 0) + { + // 有効なプロパティ名が選択された + var propItem = materialItem.PropMap[materialItem.PropNames[propIndex]]; + { + switch (propItem.PropertyType) + { + case ShaderUtil.ShaderPropertyType.Color: + { + property.FindPropertyRelative("BaseValue").vector4Value = propItem.DefaultValues; + + // max + y += height; + rect = new Rect(position.x, y, position.width, height); + if (ColorProp(rect, property.FindPropertyRelative("TargetValue"))) + { + changed = true; + } + } + break; + + case ShaderUtil.ShaderPropertyType.TexEnv: + { + property.FindPropertyRelative("BaseValue").vector4Value = propItem.DefaultValues; + + // max + y += height; + rect = new Rect(position.x, y, position.width, height); + if (OffsetProp(rect, property.FindPropertyRelative("TargetValue"))) + { + changed = true; + } + } + break; + } + } + } + } + } + } + return changed; + } + + + static bool StringPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) + { + if (options == null) + { + newIndex = -1; + return false; + } + + var oldIndex = Array.IndexOf(options, prop.stringValue); + newIndex = EditorGUI.Popup(rect, oldIndex, options); + if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) + { + prop.stringValue = options[newIndex]; + return true; + } + else + { + return false; + } + } + + static bool IntPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) + { + if (options == null) + { + newIndex = -1; + return false; + } + + var oldIndex = prop.intValue; + newIndex = EditorGUI.Popup(rect, oldIndex, options); + if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) + { + prop.intValue = newIndex; + return true; + } + else + { + return false; + } + } + + static bool FloatSlider(Rect rect, SerializedProperty prop, float maxValue) + { + var oldValue = prop.floatValue; + var newValue = EditorGUI.Slider(rect, prop.floatValue, 0, 100f); + if (newValue != oldValue) + { + prop.floatValue = newValue; + return true; + } + else + { + return false; + } + } + + static bool ColorProp(Rect rect, SerializedProperty prop) + { + var oldValue = (Color)prop.vector4Value; + var newValue = EditorGUI.ColorField(rect, prop.displayName, oldValue); + if (newValue != oldValue) + { + prop.vector4Value = newValue; + return true; + } + else + { + return false; + } + } + + static bool OffsetProp(Rect rect, SerializedProperty prop) + { + var oldValue = prop.vector4Value; + var newValue = EditorGUI.Vector4Field(rect, prop.displayName, oldValue); + if (newValue != oldValue) + { + prop.vector4Value = newValue; + return true; + } + else + { + return false; + } + } + + } +} diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs.meta b/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs.meta new file mode 100644 index 000000000..173dc5c1c --- /dev/null +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fcb56a7eb1db73c4cb9ea1689635b246 +timeCreated: 1541144400 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs index 16eb6908f..5bd5ddd3f 100644 --- a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEditor; using UnityEditorInternal; using UnityEngine; @@ -20,6 +21,8 @@ namespace VRM #region BlendShapeBind public static int BlendShapeBindingHeight = 60; ReorderableList m_ValuesList; + + SerializedProperty m_valuesProp; #endregion #region MaterialValueBind @@ -35,8 +38,11 @@ namespace VRM int m_mode; static string[] MODES = new[]{ "BlendShape", - "Material" + "BlendShape List", + "Material List" }; + + MeshPreviewItem[] m_items; #endregion public SerializedBlendShapeEditor(SerializedObject serializedObject, @@ -57,17 +63,17 @@ namespace VRM m_BlendShapeNameProp = serializedObject.FindProperty("BlendShapeName"); m_PresetProp = serializedObject.FindProperty("Preset"); - var valuesProp = serializedObject.FindProperty("Values"); + m_valuesProp = serializedObject.FindProperty("Values"); - m_ValuesList = new ReorderableList(serializedObject, valuesProp); + m_ValuesList = new ReorderableList(serializedObject, m_valuesProp); m_ValuesList.elementHeight = BlendShapeBindingHeight; m_ValuesList.drawElementCallback = (rect, index, isActive, isFocused) => { - var element = valuesProp.GetArrayElementAtIndex(index); + var element = m_valuesProp.GetArrayElementAtIndex(index); rect.height -= 4; rect.y += 2; - if (DrawBlendShapeBinding(rect, element, previewSceneManager)) + if (BlendShapeClipEditorHelper.DrawBlendShapeBinding(rect, element, previewSceneManager)) { m_changed = true; } @@ -82,11 +88,15 @@ namespace VRM var element = materialValuesProp.GetArrayElementAtIndex(index); rect.height -= 4; rect.y += 2; - if (DrawMaterialValueBinding(rect, element, previewSceneManager)) + if (BlendShapeClipEditorHelper.DrawMaterialValueBinding(rect, element, previewSceneManager)) { m_changed = true; } }; + + m_items = previewSceneManager.EnumRenderItems + .Where(x => x.SkinnedMeshRenderer != null) + .ToArray(); } public struct DrawResult @@ -115,6 +125,13 @@ namespace VRM m_serializedObject.Update(); EditorGUILayout.Space(); + + // ReadonlyのBlendShapeClip参照 + GUI.enabled = false; + EditorGUILayout.ObjectField("Current clip", + m_targetObject, typeof(BlendShapeClip), false); + GUI.enabled = true; + EditorGUILayout.PropertyField(m_BlendShapeNameProp, true); EditorGUILayout.PropertyField(m_PresetProp, true); @@ -124,13 +141,19 @@ namespace VRM switch (m_mode) { case 0: + { + ClipGUI(); + } + break; + + case 1: { //EditorGUILayout.LabelField("BlendShapeBindings", EditorStyles.boldLabel); m_ValuesList.DoLayoutList(); } break; - case 1: + case 2: { //EditorGUILayout.LabelField("MaterialValueBindings", EditorStyles.boldLabel); m_MaterialValuesList.DoLayoutList(); @@ -152,38 +175,11 @@ namespace VRM }; } -#if false - void ClipGUI(BlendShapeClip clip) + void ClipGUI() { - if (clip == null) - { - Debug.LogWarning("no clip"); - return; - } - - 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")) { @@ -197,25 +193,60 @@ namespace VRM EditorUtility.SetDirty(clip); } EditorGUILayout.EndHorizontal(); + */ - if (PreviewSceneManager != null) + var changed = BlendShapeBindsGUI(); + if (changed) { - if (BlendShapeBindsGUI(clip)) + string maxWeightName; + var bindings = GetBindings(out maxWeightName); + m_valuesProp.ClearArray(); + m_valuesProp.arraySize = bindings.Length; + for (int i = 0; i < bindings.Length; ++i) { - PreviewSceneManager.Bake(); + var item = m_valuesProp.GetArrayElementAtIndex(i); + + var endProperty = item.GetEndProperty(); + while (item.NextVisible(true)) + { + if (SerializedProperty.EqualContents(item, endProperty)) + { + break; + } + + switch (item.name) + { + case "RelativePath": + item.stringValue = bindings[i].RelativePath; + break; + + case "Index": + item.intValue = bindings[i].Index; + break; + + case "Weight": + item.floatValue = bindings[i].Weight; + break; + + default: + throw new Exception(); + } + } } + + m_changed = true; } } List m_meshFolds = new List(); - bool BlendShapeBindsGUI(BlendShapeClip clip) + bool BlendShapeBindsGUI() { bool changed = false; int foldIndex = 0; // すべてのSkinnedMeshRendererを列挙する - foreach (var item in PreviewSceneManager.EnumRenderItems.Where(x => x.SkinnedMeshRenderer != null)) + foreach (var renderer in m_items.Select(x => x.SkinnedMeshRenderer)) { - var mesh = item.SkinnedMeshRenderer.sharedMesh; + var mesh = renderer.sharedMesh; if (mesh != null && mesh.blendShapeCount > 0) { //var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, m_target.transform); @@ -225,17 +256,17 @@ namespace VRM { m_meshFolds.Add(false); } - m_meshFolds[foldIndex] = EditorGUILayout.Foldout(m_meshFolds[foldIndex], item.SkinnedMeshRenderer.name); + m_meshFolds[foldIndex] = EditorGUILayout.Foldout(m_meshFolds[foldIndex], renderer.name); if (m_meshFolds[foldIndex]) { //EditorGUI.indentLevel += 1; for (int i = 0; i < mesh.blendShapeCount; ++i) { - var src = item.SkinnedMeshRenderer.GetBlendShapeWeight(i); + var src = renderer.GetBlendShapeWeight(i); var dst = EditorGUILayout.Slider(mesh.GetBlendShapeName(i), src, 0, 100.0f); if (dst != src) { - item.SkinnedMeshRenderer.SetBlendShapeWeight(i, dst); + renderer.SetBlendShapeWeight(i, dst); changed = true; } } @@ -246,219 +277,48 @@ namespace VRM } return changed; } - private void ClearBlendShape() + + BlendShapeBinding[] GetBindings(out string _maxWeightName) { - foreach (var item in PreviewSceneManager.EnumRenderItems.Where(x => x.SkinnedMeshRenderer != null)) + var maxWeight = 0.0f; + var maxWeightName = ""; + // weightのついたblendShapeを集める + var values = m_items + .SelectMany(x => { - var renderer = item.SkinnedMeshRenderer; - var mesh = renderer.sharedMesh; + var mesh = x.SkinnedMeshRenderer.sharedMesh; + + var relativePath = x.Path; + + var list = new List(); if (mesh != null) { for (int i = 0; i < mesh.blendShapeCount; ++i) { - renderer.SetBlendShapeWeight(i, 0); + var weight = x.SkinnedMeshRenderer.GetBlendShapeWeight(i); + if (weight == 0) + { + continue; + } + var name = mesh.GetBlendShapeName(i); + if (weight > maxWeight) + { + maxWeightName = name; + maxWeight = weight; + } + list.Add(new BlendShapeBinding + { + Index = i, + RelativePath = relativePath, + Weight = weight + }); } } - } + return list; + }).ToArray() + ; + _maxWeightName = maxWeightName; + return values; } -#endif - - #region private - static bool DrawBlendShapeBinding(Rect position, SerializedProperty property, - PreviewSceneManager scene) - { - bool changed = false; - if (scene != null) - { - var height = 16; - - var y = position.y; - var rect = new Rect(position.x, y, position.width, height); - int pathIndex; - if (StringPopup(rect, property.FindPropertyRelative("RelativePath"), scene.SkinnedMeshRendererPathList, out pathIndex)) - { - changed = true; - } - - y += height; - rect = new Rect(position.x, y, position.width, height); - int blendShapeIndex; - if (IntPopup(rect, property.FindPropertyRelative("Index"), scene.GetBlendShapeNames(pathIndex), out blendShapeIndex)) - { - changed = true; - } - - y += height; - rect = new Rect(position.x, y, position.width, height); - if (FloatSlider(rect, property.FindPropertyRelative("Weight"), 100)) - { - changed = true; - } - } - return changed; - } - - static bool DrawMaterialValueBinding(Rect position, SerializedProperty property, - PreviewSceneManager scene) - { - bool changed = false; - if (scene != null) - { - var height = 16; - - var y = position.y; - var rect = new Rect(position.x, y, position.width, height); - int materialIndex; - if (StringPopup(rect, property.FindPropertyRelative("MaterialName"), scene.MaterialNames, out materialIndex)) - { - changed = true; - } - - if (materialIndex >= 0) - { - var materialItem = scene.GetMaterialItem(scene.MaterialNames[materialIndex]); - if (materialItem != null) - { - y += height; - rect = new Rect(position.x, y, position.width, height); - - // プロパティ名のポップアップ - int propIndex; - if (StringPopup(rect, property.FindPropertyRelative("ValueName"), materialItem.PropNames, out propIndex)) - { - changed = true; - } - - if (propIndex >= 0) - { - // 有効なプロパティ名が選択された - var propItem = materialItem.PropMap[materialItem.PropNames[propIndex]]; - { - switch (propItem.PropertyType) - { - case ShaderUtil.ShaderPropertyType.Color: - { - property.FindPropertyRelative("BaseValue").vector4Value = propItem.DefaultValues; - - // max - y += height; - rect = new Rect(position.x, y, position.width, height); - if (ColorProp(rect, property.FindPropertyRelative("TargetValue"))) - { - changed = true; - } - } - break; - - case ShaderUtil.ShaderPropertyType.TexEnv: - { - property.FindPropertyRelative("BaseValue").vector4Value = propItem.DefaultValues; - - // max - y += height; - rect = new Rect(position.x, y, position.width, height); - if (OffsetProp(rect, property.FindPropertyRelative("TargetValue"))) - { - changed = true; - } - } - break; - } - } - } - } - } - } - return changed; - } - - - static bool StringPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) - { - if (options == null) - { - newIndex = -1; - return false; - } - - var oldIndex = Array.IndexOf(options, prop.stringValue); - newIndex = EditorGUI.Popup(rect, oldIndex, options); - if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) - { - prop.stringValue = options[newIndex]; - return true; - } - else - { - return false; - } - } - - static bool IntPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) - { - if (options == null) - { - newIndex = -1; - return false; - } - - var oldIndex = prop.intValue; - newIndex = EditorGUI.Popup(rect, oldIndex, options); - if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) - { - prop.intValue = newIndex; - return true; - } - else - { - return false; - } - } - - static bool FloatSlider(Rect rect, SerializedProperty prop, float maxValue) - { - var oldValue = prop.floatValue; - var newValue = EditorGUI.Slider(rect, prop.floatValue, 0, 100f); - if (newValue != oldValue) - { - prop.floatValue = newValue; - return true; - } - else - { - return false; - } - } - - static bool ColorProp(Rect rect, SerializedProperty prop) - { - var oldValue = (Color)prop.vector4Value; - var newValue = EditorGUI.ColorField(rect, prop.displayName, oldValue); - if (newValue != oldValue) - { - prop.vector4Value = newValue; - return true; - } - else - { - return false; - } - } - - static bool OffsetProp(Rect rect, SerializedProperty prop) - { - var oldValue = prop.vector4Value; - var newValue = EditorGUI.Vector4Field(rect, prop.displayName, oldValue); - if (newValue != oldValue) - { - prop.vector4Value = newValue; - return true; - } - else - { - return false; - } - } - #endregion } } From 537bc707408bdd955fd853d678474de152599e18 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 2 Nov 2018 18:49:53 +0900 Subject: [PATCH 08/25] Implement camera move for preview camera --- Scripts/BlendShape/Editor/PreviewEditor.cs | 48 ++++++++++++------- .../BlendShape/Editor/PreviewFaceRenderer.cs | 9 ++-- Scripts/BlendShape/PreviewSceneManager.cs | 20 ++++---- 3 files changed, 47 insertions(+), 30 deletions(-) diff --git a/Scripts/BlendShape/Editor/PreviewEditor.cs b/Scripts/BlendShape/Editor/PreviewEditor.cs index 85bede048..3a1bc8ace 100644 --- a/Scripts/BlendShape/Editor/PreviewEditor.cs +++ b/Scripts/BlendShape/Editor/PreviewEditor.cs @@ -160,8 +160,9 @@ namespace VRM } private static int sliderHash = "Slider".GetHashCode(); - Vector2 m_previewDir; - float m_distance = 1.0f; + float m_yaw = 180.0f; + float m_pitch; + Vector3 m_position = new Vector3(0, 0, -1f); // very important to override this, it tells Unity to render an ObjectPreview at the bottom of the inspector public override bool HasPreviewGUI() { return true; } @@ -183,14 +184,14 @@ namespace VRM //previewDir = Drag2D(previewDir, r); { int controlId = GUIUtility.GetControlID(sliderHash, FocusType.Passive); - Event current = Event.current; - switch (current.GetTypeForControl(controlId)) + Event e = Event.current; + switch (e.GetTypeForControl(controlId)) { case EventType.MouseDown: - if (r.Contains(current.mousePosition) && (double)r.width > 50.0) + if (r.Contains(e.mousePosition) && (double)r.width > 50.0) { GUIUtility.hotControl = controlId; - current.Use(); + e.Use(); EditorGUIUtility.SetWantsMouseJumping(1); break; } @@ -205,26 +206,41 @@ namespace VRM case EventType.MouseDrag: if (GUIUtility.hotControl == controlId) { - m_previewDir -= current.delta * (!current.shift ? 1f : 3f) / Mathf.Min(r.width, r.height) * 140f; - m_previewDir.y = Mathf.Clamp(m_previewDir.y, -90f, 90f); - current.Use(); - GUI.changed = true; + if (e.button == 2) + { + var shift = e.delta * (!e.shift ? 1f : 3f) / Mathf.Min(r.width, r.height); + m_position.x -= shift.x; + m_position.y += shift.y; + e.Use(); + GUI.changed = true; + } + else if ( + e.button == 0 || + e.button == 1) + { + var shift = e.delta * (!e.shift ? 1f : 3f) / Mathf.Min(r.width, r.height) * 140f; + m_yaw += shift.x; + m_pitch += shift.y; + m_pitch = Mathf.Clamp(m_pitch, -90f, 90f); + e.Use(); + GUI.changed = true; + } break; } break; case EventType.ScrollWheel: //Debug.LogFormat("wheel: {0}", current.delta); - if (r.Contains(current.mousePosition)) + if (r.Contains(e.mousePosition)) { - if (current.delta.y > 0) + if (e.delta.y > 0) { - m_distance *= 1.1f; + m_position.z *= 1.1f; Repaint(); } - else if (current.delta.y < 0) + else if (e.delta.y < 0) { - m_distance *= 0.9f; + m_position.z *= 0.9f; Repaint(); } } @@ -242,7 +258,7 @@ namespace VRM if (m_renderer != null && m_scene != null) { - var texture = m_renderer.Render(r, background, m_scene, m_previewDir, m_distance); + var texture = m_renderer.Render(r, background, m_scene, m_yaw, m_pitch, m_position); if (texture != null) { // draw the RenderTexture in the ObjectPreview pane diff --git a/Scripts/BlendShape/Editor/PreviewFaceRenderer.cs b/Scripts/BlendShape/Editor/PreviewFaceRenderer.cs index 17ad0efc4..504fbcfc0 100644 --- a/Scripts/BlendShape/Editor/PreviewFaceRenderer.cs +++ b/Scripts/BlendShape/Editor/PreviewFaceRenderer.cs @@ -81,7 +81,8 @@ namespace VRM //const float FACTOR = 0.1f; - public Texture Render(Rect r, GUIStyle background, PreviewSceneManager scene, Vector2 drag, float distance) + public Texture Render(Rect r, GUIStyle background, PreviewSceneManager scene, + float yaw, float pitch, Vector3 position) { if (scene == null) return null; @@ -90,7 +91,7 @@ namespace VRM m_previewUtility.BeginPreview(r, background); // set up the PreviewRenderUtility's mini internal scene // setup the ObjectPreview's camera - scene.SetupCamera(PreviewCamera, scene.TargetPosition, -drag.x, drag.y, distance); + scene.SetupCamera(PreviewCamera, scene.TargetPosition, yaw, pitch, position); foreach (var item in scene.EnumRenderItems) { @@ -115,7 +116,7 @@ namespace VRM } } -#region IDisposable Support + #region IDisposable Support private bool disposedValue = false; // 重複する呼び出しを検出するには protected virtual void Dispose(bool disposing) @@ -153,6 +154,6 @@ namespace VRM // TODO: 上のファイナライザーがオーバーライドされる場合は、次の行のコメントを解除してください。 // GC.SuppressFinalize(this); } -#endregion + #endregion } } diff --git a/Scripts/BlendShape/PreviewSceneManager.cs b/Scripts/BlendShape/PreviewSceneManager.cs index 4a5928073..d1025c8d0 100644 --- a/Scripts/BlendShape/PreviewSceneManager.cs +++ b/Scripts/BlendShape/PreviewSceneManager.cs @@ -263,7 +263,7 @@ namespace VRM /// カメラパラメーターを決める /// /// - public void SetupCamera(Camera camera, Vector3 target, float yaw, float pitch, float distance) + public void SetupCamera(Camera camera, Vector3 target, float yaw, float pitch, Vector3 position) { camera.backgroundColor = Color.gray; camera.clearFlags = CameraClearFlags.Color; @@ -275,16 +275,16 @@ namespace VRM camera.fieldOfView = 27f; camera.nearClipPlane = 0.3f; - camera.farClipPlane = distance /*+ magnitude*/ * 2.1f; + camera.farClipPlane = -position.z /*+ magnitude*/ * 2.1f; -#if false - // this used to be "-Vector3.forward * num" but I hardcoded my camera position instead - camera.transform.position = new Vector3(0f, 1.4f, distance); - camera.transform.rotation = Quaternion.Euler(0, 180f, 0); -#else - camera.transform.position = target + Quaternion.Euler(pitch, yaw, 0) * Vector3.forward * distance; - camera.transform.LookAt(target); -#endif + var t = Matrix4x4.Translate(position); + var r = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(pitch, yaw, 0), Vector3.one); + // 回転してから移動 + var m = r * t; + + camera.transform.position = target + m.ExtractPosition(); + camera.transform.rotation = m.ExtractRotation(); + //camera.transform.LookAt(target); //previewLayer のみ表示する //camera.cullingMask = 1 << PreviewLayer; From db4e16b7ab984eec075b60bfed70db76a37f22c4 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 2 Nov 2018 21:24:04 +0900 Subject: [PATCH 09/25] Added SerializedBlendShapeClipEditor.m_isBinaryProp --- .../Editor/SerializedBlendShapeClipEditor.cs | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs index 5bd5ddd3f..4959f74a7 100644 --- a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs @@ -14,8 +14,10 @@ namespace VRM SerializedObject m_serializedObject; #region Properties - SerializedProperty m_BlendShapeNameProp; - SerializedProperty m_PresetProp; + SerializedProperty m_blendShapeNameProp; + SerializedProperty m_presetProp; + + SerializedProperty m_isBinaryProp; #endregion #region BlendShapeBind @@ -61,8 +63,10 @@ namespace VRM this.m_serializedObject = serializedObject; this.m_targetObject = targetObject; - m_BlendShapeNameProp = serializedObject.FindProperty("BlendShapeName"); - m_PresetProp = serializedObject.FindProperty("Preset"); + m_blendShapeNameProp = serializedObject.FindProperty("BlendShapeName"); + m_presetProp = serializedObject.FindProperty("Preset"); + m_isBinaryProp = serializedObject.FindProperty("IsBinary"); + m_valuesProp = serializedObject.FindProperty("Values"); m_ValuesList = new ReorderableList(serializedObject, m_valuesProp); @@ -116,11 +120,6 @@ namespace VRM //EditorGUILayout.Space(); var previewSlider = EditorGUILayout.Slider("Preview Weight", m_previewSlider, 0, 1.0f); - if (previewSlider != m_previewSlider) - { - m_previewSlider = previewSlider; - m_changed = true; - } m_serializedObject.Update(); @@ -132,8 +131,20 @@ namespace VRM m_targetObject, typeof(BlendShapeClip), false); GUI.enabled = true; - EditorGUILayout.PropertyField(m_BlendShapeNameProp, true); - EditorGUILayout.PropertyField(m_PresetProp, true); + EditorGUILayout.PropertyField(m_blendShapeNameProp, true); + EditorGUILayout.PropertyField(m_presetProp, true); + + // v0.45 Added. Binary flag + EditorGUILayout.PropertyField(m_isBinaryProp, true); + if (m_isBinaryProp.boolValue) + { + previewSlider = Mathf.Round(previewSlider); + } + if (previewSlider != m_previewSlider) + { + m_previewSlider = previewSlider; + m_changed = true; + } EditorGUILayout.Space(); //m_mode = EditorGUILayout.Popup("SourceType", m_mode, MODES); @@ -161,10 +172,7 @@ namespace VRM break; } - if (m_changed) - { - m_serializedObject.ApplyModifiedProperties(); - } + m_serializedObject.ApplyModifiedProperties(); return new DrawResult { From 74ab2683e56801c9758cedd66d16c5a558669632 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 2 Nov 2018 22:07:40 +0900 Subject: [PATCH 10/25] Implement _ST, ST_S, ST_T --- .../Editor/BlendShapeClipEditorHelper.cs | 39 +++++++++++++++-- Scripts/BlendShape/MeshPreviewItem.cs | 43 ++++++++++++++----- 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs index 749c815de..1935395d8 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs @@ -115,7 +115,7 @@ namespace VRM return changed; } - + #region Private static bool StringPopup(Rect rect, SerializedProperty prop, string[] options, out int newIndex) { if (options == null) @@ -188,10 +188,43 @@ namespace VRM } } + static Rect AdvanceRect(ref float x, float y, float w, float h) + { + var rect = new Rect(x, y, w, h); + x += w; + return rect; + } + + static Vector4 TilingOffset(Rect rect, string label, Vector4 src) + { + var style = new GUIStyle() + { + alignment = TextAnchor.MiddleRight, + }; + + var quad = rect.width / 10; + var x = rect.x; + + EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad * 2, rect.height), "Tiling X", style); + src.x = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), src.x); + + EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", style); + src.y = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), src.y); + + EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad * 2, rect.height), "Offset X", style); + src.z = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), src.z); + + EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", style); + src.w = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), src.w); + + return src; + } + static bool OffsetProp(Rect rect, SerializedProperty prop) { var oldValue = prop.vector4Value; - var newValue = EditorGUI.Vector4Field(rect, prop.displayName, oldValue); + //var newValue = EditorGUI.Vector4Field(rect, prop.displayName, oldValue); + var newValue = TilingOffset(rect, prop.displayName, oldValue); if (newValue != oldValue) { prop.vector4Value = newValue; @@ -202,6 +235,6 @@ namespace VRM return false; } } - + #endregion } } diff --git a/Scripts/BlendShape/MeshPreviewItem.cs b/Scripts/BlendShape/MeshPreviewItem.cs index be9293aa1..8f5c0316c 100644 --- a/Scripts/BlendShape/MeshPreviewItem.cs +++ b/Scripts/BlendShape/MeshPreviewItem.cs @@ -50,6 +50,7 @@ namespace VRM switch (propType) { case ShaderUtil.ShaderPropertyType.Color: + // 色 item.PropMap.Add(name, new PropItem { PropertyType = propType, @@ -59,13 +60,35 @@ namespace VRM break; case ShaderUtil.ShaderPropertyType.TexEnv: - name += "_ST"; - item.PropMap.Add(name, new PropItem + // テクスチャ { - PropertyType = propType, - DefaultValues = material.GetVector(name), - }); - propNames.Add(name); + name += "_ST"; + item.PropMap.Add(name, new PropItem + { + PropertyType = propType, + DefaultValues = material.GetVector(name), + }); + propNames.Add(name); + } + // 縦横分離用 + { + var st_name = name + "_S"; + item.PropMap.Add(st_name, new PropItem + { + PropertyType = propType, + DefaultValues = material.GetVector(name), + }); + propNames.Add(st_name); + } + { + var st_name = name + "_T"; + item.PropMap.Add(st_name, new PropItem + { + PropertyType = propType, + DefaultValues = material.GetVector(name), + }); + propNames.Add(st_name); + } break; } } @@ -147,15 +170,15 @@ namespace VRM { if (x.RelativePath == Path) { - if(x.Index>=0 && x.Index < SkinnedMeshRenderer.sharedMesh.blendShapeCount) + if (x.Index >= 0 && x.Index < SkinnedMeshRenderer.sharedMesh.blendShapeCount) { SkinnedMeshRenderer.SetBlendShapeWeight(x.Index, x.Weight * weight); } else { - Debug.LogWarningFormat("Out of range {0}: 0 <= {1} < {2}", - SkinnedMeshRenderer.name, - x.Index, + Debug.LogWarningFormat("Out of range {0}: 0 <= {1} < {2}", + SkinnedMeshRenderer.name, + x.Index, SkinnedMeshRenderer.sharedMesh.blendShapeCount); } } From 5a31c777bbec55c057f52a266fc332cf110b847a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 2 Nov 2018 22:17:13 +0900 Subject: [PATCH 11/25] IsBinary read/write --- Scripts/Format/VRMImporterContext.cs | 5 +++-- Scripts/Format/glTF_VRM_BlendShape.cs | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Scripts/Format/VRMImporterContext.cs b/Scripts/Format/VRMImporterContext.cs index 4be74a047..e73bcb11f 100644 --- a/Scripts/Format/VRMImporterContext.cs +++ b/Scripts/Format/VRMImporterContext.cs @@ -152,6 +152,7 @@ namespace VRM { asset.BlendShapeName = groupName; asset.Preset = EnumUtil.TryParseOrDefault(group.presetName); + asset.IsBinary = group.isBinary; if (asset.Preset == BlendShapePreset.Unknown) { // fallback @@ -250,7 +251,7 @@ namespace VRM AvatarDescription = GLTF.extensions.VRM.humanoid.ToDescription(Nodes); AvatarDescription.name = "AvatarDescription"; HumanoidAvatar = AvatarDescription.CreateAvatar(Root.transform); - if(!HumanoidAvatar.isValid || !HumanoidAvatar.isHuman) + if (!HumanoidAvatar.isValid || !HumanoidAvatar.isHuman) { throw new Exception("fail to create avatar"); } @@ -289,7 +290,7 @@ namespace VRM meta.Title = gltfMeta.title; var thumbnail = GetTexture(gltfMeta.texture); - if (thumbnail!=null) + if (thumbnail != null) { // ロード済み meta.Thumbnail = thumbnail.Texture; diff --git a/Scripts/Format/glTF_VRM_BlendShape.cs b/Scripts/Format/glTF_VRM_BlendShape.cs index 522051d6a..7338872c2 100644 --- a/Scripts/Format/glTF_VRM_BlendShape.cs +++ b/Scripts/Format/glTF_VRM_BlendShape.cs @@ -91,7 +91,7 @@ namespace VRM [JsonSchema(Description = "Expression name")] public string name; - [JsonSchema(Description = "Predefined Expression name", EnumValues =new object[] { + [JsonSchema(Description = "Predefined Expression name", EnumValues = new object[] { "unknown", "neutral", "a", @@ -119,10 +119,14 @@ namespace VRM [JsonSchema(Description = "Material animation references.")] public List materialValues = new List(); + [JsonSchema(Description = "0 or 1. Do not allow an intermediate value. Value should rounded")] + public bool isBinary; + protected override void SerializeMembers(GLTFJsonFormatter f) { f.KeyValue(() => name); f.KeyValue(() => presetName); + f.KeyValue(() => isBinary); f.KeyValue(() => binds); f.KeyValue(() => materialValues); } @@ -157,6 +161,7 @@ namespace VRM { name = clip.BlendShapeName, presetName = clip.Preset.ToString().ToLower(), + isBinary = clip.IsBinary, binds = list, materialValues = materialList, }; From 2b41df1d0bd49f3a27e2e6cd933aa0c61f85e474 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 2 Nov 2018 23:11:38 +0900 Subject: [PATCH 12/25] Implemented BlendShapeClip.IsBinary for BlendShapeMerger --- Scripts/BlendShape/BlendShapeMerger.cs | 149 ++++++++++++++++++------- 1 file changed, 110 insertions(+), 39 deletions(-) diff --git a/Scripts/BlendShape/BlendShapeMerger.cs b/Scripts/BlendShape/BlendShapeMerger.cs index 8a8c514a3..8c88b41fe 100644 --- a/Scripts/BlendShape/BlendShapeMerger.cs +++ b/Scripts/BlendShape/BlendShapeMerger.cs @@ -12,15 +12,43 @@ namespace VRM /// class BlendShapeMerger { + /// + /// KeyからBlendShapeClipを得る + /// Dictionary m_clipMap; + + /// + /// BlendShapeのWeightを蓄積する + /// Dictionary m_valueMap; + /// + /// 名前とmaterialのマッピング + /// Dictionary m_materialMap; + /// + /// BlendShapeの適用値を蓄積する + /// + /// + /// + /// Dictionary m_blendShapeValueMap = new Dictionary(); + + /// + /// + /// + /// Dictionary> m_blendShapeSetterMap = new Dictionary>(); + /// + /// MaterialValueの適用値を蓄積する + /// + /// + /// + /// Dictionary m_materialValueMap = new Dictionary(); + Dictionary> m_materialSetterMap = new Dictionary>(); public BlendShapeMerger(IEnumerable clips, Transform root) @@ -102,7 +130,7 @@ namespace VRM }; m_materialSetterMap.Add(binding, setter); } - else if(binding.ValueName.EndsWith("_ST_T")) + else if (binding.ValueName.EndsWith("_ST_T")) { var valueName = binding.ValueName.Substring(0, binding.ValueName.Length - 2); Action setter = value => @@ -143,6 +171,9 @@ namespace VRM Apply(); } + /// + /// 蓄積した値を適用する + /// public void Apply() { foreach (var kv in m_blendShapeValueMap) @@ -166,16 +197,25 @@ namespace VRM m_materialValueMap.Clear(); } + /// + /// まとめて反映する。1フレームに1回呼び出されることを想定 + /// + /// public void SetValues(IEnumerable> values) { foreach (var kv in values) { - SetValue(kv.Key, kv.Value, false); + AccumulateValue(kv.Key, kv.Value); } Apply(); } - public void SetValue(BlendShapeKey key, float value, bool replace) + /// + /// 即時に反映しない。後にApplyによって反映する + /// + /// + /// + public void AccumulateValue(BlendShapeKey key, float value) { m_valueMap[key] = value; @@ -185,60 +225,91 @@ namespace VRM return; } + if (clip.IsBinary) + { + value = Mathf.Round(value); + } + foreach (var binding in clip.Values) { - if (replace) + // 積算 + float acc; + if (m_blendShapeValueMap.TryGetValue(binding, out acc)) { - // 値置き換え - Action setter; - if (m_blendShapeSetterMap.TryGetValue(binding, out setter)) - { - setter(binding.Weight * value); - } + m_blendShapeValueMap[binding] = acc + binding.Weight * value; } else { - // 積算 - float acc; - if (m_blendShapeValueMap.TryGetValue(binding, out acc)) - { - m_blendShapeValueMap[binding] = acc + binding.Weight * value; - } - else - { - m_blendShapeValueMap[binding] = binding.Weight * value; - } + m_blendShapeValueMap[binding] = binding.Weight * value; } } - // materialの更新 foreach (var binding in clip.MaterialValues) { - if (replace) + // 積算 + float acc; + if (m_materialValueMap.TryGetValue(binding, out acc)) { - // 値置き換え - Action setter; - if (m_materialSetterMap.TryGetValue(binding, out setter)) - { - setter(value); - } + m_materialValueMap[binding] = acc + value; } else { - // 積算 - float acc; - if (m_materialValueMap.TryGetValue(binding, out acc)) - { - m_materialValueMap[binding] = acc + value; - } - else - { - m_materialValueMap[binding] = value; - } + m_materialValueMap[binding] = value; } } } + /// + /// 即時に反映する + /// + /// + /// + public void ImmediatelySetValue(BlendShapeKey key, float value) + { + m_valueMap[key] = value; + + BlendShapeClip clip; + if (!m_clipMap.TryGetValue(key, out clip)) + { + return; + } + + if (clip.IsBinary) + { + value = Mathf.Round(value); + } + + foreach (var binding in clip.Values) + { + Action setter; + if (m_blendShapeSetterMap.TryGetValue(binding, out setter)) + { + setter(binding.Weight * value); + } + } + + foreach (var binding in clip.MaterialValues) + { + Action setter; + if (m_materialSetterMap.TryGetValue(binding, out setter)) + { + setter(value); + } + } + } + + public void SetValue(BlendShapeKey key, float value, bool replace) + { + if (replace) + { + ImmediatelySetValue(key, value); + } + else + { + AccumulateValue(key, value); + } + } + public float GetValue(BlendShapeKey key) { float value; @@ -259,7 +330,7 @@ namespace VRM { // restore values Material material; - if(m_materialMap.TryGetValue(y.MaterialName, out material)) + if (m_materialMap.TryGetValue(y.MaterialName, out material)) { material.SetColor(y.ValueName, y.BaseValue); } From f0064a287970997158f661aaff7e27322b3ca9ce Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 3 Nov 2018 01:40:15 +0900 Subject: [PATCH 13/25] PreviewSceneManager.Bake IEnumerable --- Scripts/BlendShape/Editor/PreviewEditor.cs | 6 ++++-- Scripts/BlendShape/MeshPreviewItem.cs | 2 +- Scripts/BlendShape/PreviewSceneManager.cs | 12 ++++-------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Scripts/BlendShape/Editor/PreviewEditor.cs b/Scripts/BlendShape/Editor/PreviewEditor.cs index 3a1bc8ace..7c451d222 100644 --- a/Scripts/BlendShape/Editor/PreviewEditor.cs +++ b/Scripts/BlendShape/Editor/PreviewEditor.cs @@ -2,6 +2,8 @@ using UnityEngine; using UnityEditorInternal; using System; +using System.Linq; +using System.Collections.Generic; namespace VRM { @@ -82,7 +84,7 @@ namespace VRM /// /// /// - protected void Bake(BlendShapeBinding[] values, MaterialValueBinding[] materialValues, float weight) + protected void Bake(IEnumerable values, IEnumerable materialValues, float weight) { if (m_scene != null) { @@ -93,7 +95,7 @@ namespace VRM protected void Bake(BlendShapeClip clip, float weight) { - Bake(clip.Values, clip.MaterialValues, weight); + Bake(Enumerable.Empty(), Enumerable.Empty(), weight); } protected virtual GameObject GetPrefab() diff --git a/Scripts/BlendShape/MeshPreviewItem.cs b/Scripts/BlendShape/MeshPreviewItem.cs index 8f5c0316c..0280f185b 100644 --- a/Scripts/BlendShape/MeshPreviewItem.cs +++ b/Scripts/BlendShape/MeshPreviewItem.cs @@ -153,7 +153,7 @@ namespace VRM Materials = materials; } - public void Bake(BlendShapeBinding[] values, float weight) + public void Bake(IEnumerable values, float weight) { if (SkinnedMeshRenderer == null) return; diff --git a/Scripts/BlendShape/PreviewSceneManager.cs b/Scripts/BlendShape/PreviewSceneManager.cs index d1025c8d0..2703b35e0 100644 --- a/Scripts/BlendShape/PreviewSceneManager.cs +++ b/Scripts/BlendShape/PreviewSceneManager.cs @@ -207,7 +207,10 @@ namespace VRM #if UNITY_EDITOR Bounds m_bounds; - public void Bake(BlendShapeBinding[] values = null, MaterialValueBinding[] materialValues = null, float weight = 1.0f) + public void Bake( + IEnumerable values = null, + IEnumerable materialValues = null, + float weight = 1.0f) { //Debug.LogFormat("Bake"); m_bounds = default(Bounds); @@ -251,13 +254,6 @@ namespace VRM } #endif - /* - int PreviewLayer - { - get; - set; - } - */ /// /// カメラパラメーターを決める From 91306f4a8343e209c71f171bee8b09a501cc7ff8 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 3 Nov 2018 03:21:45 +0900 Subject: [PATCH 14/25] Added BlendShapeClipDrawer --- Scripts/BlendShape/BlendShapeAvatar.cs | 22 +---- Scripts/BlendShape/BlendShapeClip.cs | 5 +- .../Editor/BlendShapeAvatarEditor.cs | 99 +++++++++---------- .../BlendShape/Editor/BlendShapeClipDrawer.cs | 56 +++++++++++ .../Editor/BlendShapeClipDrawer.cs.meta | 12 +++ .../Editor/BlendShapeClipSelector.cs | 2 +- .../Editor/SerializedBlendShapeClipEditor.cs | 4 + 7 files changed, 130 insertions(+), 70 deletions(-) create mode 100644 Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs create mode 100644 Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs.meta diff --git a/Scripts/BlendShape/BlendShapeAvatar.cs b/Scripts/BlendShape/BlendShapeAvatar.cs index f988186e6..5606b0fce 100644 --- a/Scripts/BlendShape/BlendShapeAvatar.cs +++ b/Scripts/BlendShape/BlendShapeAvatar.cs @@ -60,29 +60,17 @@ namespace VRM Clips = Clips.OrderBy(x => BlendShapeKey.CreateFrom(x)).ToList(); } - public void AddBlendShapeClip() + static public BlendShapeClip CreateBlendShapeClip(string path) { - var dir = Path.GetDirectoryName(AssetDatabase.GetAssetPath(this)); - var path = EditorUtility.SaveFilePanel( - "Create BlendShapeClip", - dir, - string.Format("BlendShapeClip#{0}.asset", Clips.Count), - "asset"); - if (string.IsNullOrEmpty(path)) - { - return; - } - path = path.ToUnityRelativePath(); //Debug.LogFormat("{0}", path); var clip = ScriptableObject.CreateInstance(); clip.BlendShapeName = Path.GetFileNameWithoutExtension(path); - clip.Prefab = AssetDatabase.LoadAssetAtPath(AssetDatabase.GetAssetPath(this)); AssetDatabase.CreateAsset(clip, path); AssetDatabase.ImportAsset(path); - - Clips.Add(clip); - EditorUtility.SetDirty(this); - AssetDatabase.SaveAssets(); + return clip; + //Clips.Add(clip); + //EditorUtility.SetDirty(this); + //AssetDatabase.SaveAssets(); } #endif diff --git a/Scripts/BlendShape/BlendShapeClip.cs b/Scripts/BlendShape/BlendShapeClip.cs index 99b28f35c..96253b651 100644 --- a/Scripts/BlendShape/BlendShapeClip.cs +++ b/Scripts/BlendShape/BlendShapeClip.cs @@ -73,7 +73,7 @@ namespace VRM public BlendShapePreset Preset; /// - /// BlendShapeに対する参照(indexベース) + /// BlendShapeに対する参照(index ベース) /// /// [SerializeField] @@ -91,5 +91,8 @@ namespace VRM /// [SerializeField] public bool IsBinary; + + [SerializeField] + public Texture2D Thumbnail; } } diff --git a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs index ace08a187..e87e43682 100644 --- a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs @@ -4,74 +4,71 @@ using System.IO; using System.Linq; using UniGLTF; using UnityEditor; +using UnityEditorInternal; using UnityEngine; namespace VRM { [CustomEditor(typeof(BlendShapeAvatar))] - public class BlendShapeAvatarEditor : PreviewEditor + public class BlendShapeAvatarEditor : Editor { - static String[] Presets = ((BlendShapePreset[])Enum.GetValues(typeof(BlendShapePreset))) - .Select(x => x.ToString()).ToArray(); + ReorderableList m_clipList; - BlendShapeClipSelector m_selector; - - SerializedBlendShapeEditor m_clipEditor; - - void OnPrefabChanged() + void OnEnable() { - if (m_selector != null) + var prop = serializedObject.FindProperty("Clips"); + m_clipList = new ReorderableList(serializedObject, prop); + + m_clipList.drawHeaderCallback = (rect) => + EditorGUI.LabelField(rect, "BlendShapeClips"); + + m_clipList.elementHeight = BlendShapeClipDrawer.Height; + m_clipList.drawElementCallback = (rect, index, isActive, isFocused) => { - Bake(m_selector.Selected, 1.0f); - } + var element = prop.GetArrayElementAtIndex(index); + rect.height -= 4; + rect.y += 2; + EditorGUI.PropertyField(rect, element); + }; + + m_clipList.onAddCallback += (list) => + { + // Add slot + prop.arraySize++; + // select last item + list.index = prop.arraySize - 1; + // get last item + var element = prop.GetArrayElementAtIndex(list.index); + element.objectReferenceValue = null; + + var dir = Path.GetDirectoryName(AssetDatabase.GetAssetPath(target)); + var path = EditorUtility.SaveFilePanel( + "Create BlendShapeClip", + dir, + string.Format("BlendShapeClip#{0}.asset", list.count), + "asset"); + if (!string.IsNullOrEmpty(path)) + { + var clip = BlendShapeAvatar.CreateBlendShapeClip(path.ToUnityRelativePath()); + //clip.Prefab = AssetDatabase.LoadAssetAtPath(AssetDatabase.GetAssetPath(target)); + + element.objectReferenceValue = clip; + } + }; + + m_clipList.onCanRemoveCallback += list => true; } - void OnSelected(BlendShapeClip clip) + void OnDisable() { - Bake(clip, 1.0f); - if (clip != null) - { - m_clipEditor = new SerializedBlendShapeEditor(clip, PreviewSceneManager); - } - else - { - m_clipEditor = null; - } - } - - protected override void OnEnable() - { - PrefabChanged += OnPrefabChanged; - base.OnEnable(); - - m_selector = new BlendShapeClipSelector((BlendShapeAvatar)target, OnSelected); - } - - protected override void OnDisable() - { - base.OnDisable(); - PrefabChanged -= OnPrefabChanged; } public override void OnInspectorGUI() { - base.OnInspectorGUI(); - - m_selector.SelectGUI(); - - if (m_clipEditor != null) - { - Separator(); - - m_selector.DuplicateWarn(); - - var result = m_clipEditor.Draw(); - if (result.Changed) - { - Bake(result.BlendShapeBindings, result.MaterialValueBindings, result.Weight); - } - } + serializedObject.Update(); + m_clipList.DoLayoutList(); + serializedObject.ApplyModifiedProperties(); } } } diff --git a/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs b/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs new file mode 100644 index 000000000..5a432cecb --- /dev/null +++ b/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs @@ -0,0 +1,56 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + + +namespace VRM +{ + + [CustomPropertyDrawer(typeof(BlendShapeClip))] + public class BlendShapeClipDrawer : PropertyDrawer + { + public const int Height = 72; + + public override void OnGUI(Rect position, + SerializedProperty property, GUIContent label) + { + using (new EditorGUI.PropertyScope(position, label, property)) + { + EditorGUIUtility.labelWidth = 80; + + position.height = EditorGUIUtility.singleLineHeight; + + var halfWidth = position.width * 0.5f; + + var rect = new Rect(position.x + 64, position.y, position.width - 64, position.height); + EditorGUI.PropertyField(rect, property); + + var clip = property.objectReferenceValue as BlendShapeClip; + if (clip != null) + { + var clipObj = new SerializedObject(clip); + var thumbnail = clipObj.FindProperty("Thumbnail"); + var blendShapeName = clipObj.FindProperty("BlendShapeName"); + var preset = clipObj.FindProperty("Preset"); + var isBinary = clipObj.FindProperty("IsBinary"); + + EditorGUI.ObjectField(new Rect(position) + { + width = 64, + height = 64 + }, thumbnail.objectReferenceValue, typeof(Texture), false); + + rect.y += (EditorGUIUtility.singleLineHeight + 2); + EditorGUI.PropertyField(rect, blendShapeName); + rect.y += (EditorGUIUtility.singleLineHeight + 2); + EditorGUI.PropertyField(rect, preset); + rect.y += (EditorGUIUtility.singleLineHeight + 2); + EditorGUI.PropertyField(rect, isBinary); + + clipObj.ApplyModifiedProperties(); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs.meta b/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs.meta new file mode 100644 index 000000000..b5ef0081e --- /dev/null +++ b/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6a31667cfcf461c47b3b384211e2d9ff +timeCreated: 1541179390 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs b/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs index 84fd6301d..b37d7c21d 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs @@ -69,7 +69,7 @@ namespace VRM if (GUILayout.Button("Add BlendShapeClip")) { - m_avatar.AddBlendShapeClip(); + //m_avatar.AddBlendShapeClip(); } } diff --git a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs index 4959f74a7..ebeb4c894 100644 --- a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs @@ -14,6 +14,7 @@ namespace VRM SerializedObject m_serializedObject; #region Properties + SerializedProperty m_thumbnail; SerializedProperty m_blendShapeNameProp; SerializedProperty m_presetProp; @@ -63,6 +64,7 @@ namespace VRM this.m_serializedObject = serializedObject; this.m_targetObject = targetObject; + m_thumbnail = serializedObject.FindProperty("Thumbnail"); m_blendShapeNameProp = serializedObject.FindProperty("BlendShapeName"); m_presetProp = serializedObject.FindProperty("Preset"); m_isBinaryProp = serializedObject.FindProperty("IsBinary"); @@ -131,6 +133,8 @@ namespace VRM m_targetObject, typeof(BlendShapeClip), false); GUI.enabled = true; + m_thumbnail.objectReferenceValue = EditorGUILayout.ObjectField(m_thumbnail.objectReferenceValue, typeof(Texture), false); + EditorGUILayout.PropertyField(m_thumbnail, true); EditorGUILayout.PropertyField(m_blendShapeNameProp, true); EditorGUILayout.PropertyField(m_presetProp, true); From 183ec644ba7f64e8caea3c74fe096d7b573b891f Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 3 Nov 2018 14:26:15 +0900 Subject: [PATCH 15/25] BlendShape thumbnail --- .../BlendShape/Editor/BlendShapeClipDrawer.cs | 10 +- .../BlendShape/Editor/BlendShapeClipEditor.cs | 99 ++++++++++++++++++- .../Editor/BlendShapeClipEditorHelper.cs | 74 ++++++++++++++ Scripts/BlendShape/Editor/PreviewEditor.cs | 18 +++- .../Editor/SerializedBlendShapeClipEditor.cs | 19 ---- 5 files changed, 190 insertions(+), 30 deletions(-) diff --git a/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs b/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs index 5a432cecb..6b1da8820 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs @@ -10,7 +10,9 @@ namespace VRM [CustomPropertyDrawer(typeof(BlendShapeClip))] public class BlendShapeClipDrawer : PropertyDrawer { - public const int Height = 72; + public const int Height = 132; + + public const int ThumbnailSize = 128; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) @@ -23,7 +25,7 @@ namespace VRM var halfWidth = position.width * 0.5f; - var rect = new Rect(position.x + 64, position.y, position.width - 64, position.height); + var rect = new Rect(position.x + ThumbnailSize, position.y, position.width - ThumbnailSize, position.height); EditorGUI.PropertyField(rect, property); var clip = property.objectReferenceValue as BlendShapeClip; @@ -37,8 +39,8 @@ namespace VRM EditorGUI.ObjectField(new Rect(position) { - width = 64, - height = 64 + width = ThumbnailSize, + height = ThumbnailSize }, thumbnail.objectReferenceValue, typeof(Texture), false); rect.y += (EditorGUIUtility.singleLineHeight + 2); diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs index 2967b0b6d..8cd8bbad6 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs @@ -1,4 +1,6 @@ using System; +using System.IO; +using UniGLTF; using UnityEditor; using UnityEditorInternal; using UnityEngine; @@ -13,6 +15,9 @@ namespace VRM BlendShapeClip m_target; + SerializedProperty m_thumbnailProp; + SerializedProperty m_isBinaryProp; + protected override GameObject GetPrefab() { return m_target.Prefab; @@ -41,6 +46,49 @@ namespace VRM PrefabChanged -= OnPrefabChanged; } + float m_previewSlider = 1.0f; + + + + static Texture2D SaveResizedImage(RenderTexture rt, UnityPath path, int size) + { + var tex = new Texture2D(rt.width, rt.height, TextureFormat.RGB24, false); + RenderTexture.active = rt; + tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); + tex.Apply(); + + //TextureScale.Scale(tex, size, size); + tex = TextureScale.GetResized(tex, size, size); + + byte[] bytes; + switch (path.Extension.ToLower()) + { + case ".png": + bytes = tex.EncodeToPNG(); + break; + + case ".jpg": + bytes = tex.EncodeToJPG(); + break; + + default: + throw new Exception(); + } + + if (Application.isPlaying) + { + UnityEngine.Object.Destroy(tex); + } + else + { + UnityEngine.Object.DestroyImmediate(tex); + } + File.WriteAllBytes(path.FullPath, bytes); + + path.ImportAsset(); + return path.LoadAsset(); + } + public override void OnInspectorGUI() { base.OnInspectorGUI(); @@ -48,12 +96,57 @@ namespace VRM if (m_serializedEditor == null) { m_serializedEditor = new SerializedBlendShapeEditor(serializedObject, PreviewSceneManager); + m_thumbnailProp = serializedObject.FindProperty("Thumbnail"); + m_isBinaryProp = serializedObject.FindProperty("IsBinary"); } - var result = m_serializedEditor.Draw(); - if (result.Changed && PreviewSceneManager != null) + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.ObjectField(m_thumbnailProp.objectReferenceValue, typeof(Texture), false, + GUILayout.Width(64), GUILayout.Height(64)); + + var changed = false; + EditorGUILayout.BeginVertical(); + EditorGUILayout.LabelField("Preview Weight"); + var previewSlider = EditorGUILayout.Slider(m_previewSlider, 0, 1.0f); + GUI.enabled = PreviewTexture != null; + if (GUILayout.Button("save thumbnail")) { - PreviewSceneManager.Bake(result.BlendShapeBindings, result.MaterialValueBindings, result.Weight); + //var ext = "jpg"; + var ext = "png"; + var asset = UnityPath.FromAsset(target); + var path = EditorUtility.SaveFilePanel( + "save thumbnail", + asset.Parent.FullPath, + string.Format("{0}.{1}", asset.FileNameWithoutExtension, ext), + ext); + if (!string.IsNullOrEmpty(path)) + { + var thumbnail = SaveResizedImage(PreviewTexture, UnityPath.FromFullpath(path), + BlendShapeClipDrawer.ThumbnailSize); + m_thumbnailProp.objectReferenceValue = thumbnail; + serializedObject.ApplyModifiedProperties(); + } + } + GUI.enabled = true; + EditorGUILayout.EndVertical(); + + if (m_isBinaryProp.boolValue) + { + previewSlider = Mathf.Round(previewSlider); + } + if (previewSlider != m_previewSlider) + { + m_previewSlider = previewSlider; + changed = true; + } + + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + + var result = m_serializedEditor.Draw(); + if ((changed || result.Changed) && PreviewSceneManager != null) + { + PreviewSceneManager.Bake(result.BlendShapeBindings, result.MaterialValueBindings, m_previewSlider); } } diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs index 1935395d8..57627ba75 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs @@ -237,4 +237,78 @@ namespace VRM } #endregion } + + /// https://gist.github.com/gszauer/7799899 + public class TextureScale + { + private static Color[] texColors; + private static Color[] newColors; + private static int w; + private static float ratioX; + private static float ratioY; + private static int w2; + + public static void Scale(Texture2D tex, int newWidth, int newHeight) + { + texColors = tex.GetPixels(); + newColors = new Color[newWidth * newHeight]; + ratioX = 1.0f / ((float)newWidth / (tex.width - 1)); + ratioY = 1.0f / ((float)newHeight / (tex.height - 1)); + w = tex.width; + w2 = newWidth; + + BilinearScale(0, newHeight); + + tex.Resize(newWidth, newHeight); + tex.SetPixels(newColors); + tex.Apply(); + } + + private static void BilinearScale(int start, int end) + { + for (var y = start; y < end; y++) + { + int yFloor = (int)Mathf.Floor(y * ratioY); + var y1 = yFloor * w; + var y2 = (yFloor + 1) * w; + var yw = y * w2; + + for (var x = 0; x < w2; x++) + { + int xFloor = (int)Mathf.Floor(x * ratioX); + var xLerp = x * ratioX - xFloor; + newColors[yw + x] = ColorLerpUnclamped(ColorLerpUnclamped(texColors[y1 + xFloor], texColors[y1 + xFloor + 1], xLerp), + ColorLerpUnclamped(texColors[y2 + xFloor], texColors[y2 + xFloor + 1], xLerp), + y * ratioY - yFloor); + } + } + } + + private static Color ColorLerpUnclamped(Color c1, Color c2, float value) + { + return new Color(c1.r + (c2.r - c1.r) * value, + c1.g + (c2.g - c1.g) * value, + c1.b + (c2.b - c1.b) * value, + c1.a + (c2.a - c1.a) * value); + } + + /// http://light11.hatenadiary.com/entry/2018/04/19/194015 + public static Texture2D GetResized(Texture2D texture, int width, int height) + { + // リサイズ後のサイズを持つRenderTextureを作成して書き込む + var rt = RenderTexture.GetTemporary(width, height); + Graphics.Blit(texture, rt); + + // リサイズ後のサイズを持つTexture2Dを作成してRenderTextureから書き込む + var preRT = RenderTexture.active; + RenderTexture.active = rt; + var ret = new Texture2D(width, height); + ret.ReadPixels(new Rect(0, 0, width, height), 0, 0); + ret.Apply(); + RenderTexture.active = preRT; + + RenderTexture.ReleaseTemporary(rt); + return ret; + } + } } diff --git a/Scripts/BlendShape/Editor/PreviewEditor.cs b/Scripts/BlendShape/Editor/PreviewEditor.cs index 7c451d222..dd4bd9b1b 100644 --- a/Scripts/BlendShape/Editor/PreviewEditor.cs +++ b/Scripts/BlendShape/Editor/PreviewEditor.cs @@ -164,11 +164,13 @@ namespace VRM private static int sliderHash = "Slider".GetHashCode(); float m_yaw = 180.0f; float m_pitch; - Vector3 m_position = new Vector3(0, 0, -1f); + Vector3 m_position = new Vector3(0, 0, -0.8f); // very important to override this, it tells Unity to render an ObjectPreview at the bottom of the inspector public override bool HasPreviewGUI() { return true; } + public RenderTexture PreviewTexture; + // the main ObjectPreview function... it's called constantly, like other IMGUI On*GUI() functions public override void OnPreviewGUI(Rect r, GUIStyle background) { @@ -183,6 +185,14 @@ namespace VRM return; } + var src = r; + + var min = Mathf.Min(r.width, r.height); + r.width = min; + r.height = min; + r.x = src.x + (src.width - min) / 2; + r.y = src.y + (src.height - min) / 2; + //previewDir = Drag2D(previewDir, r); { int controlId = GUIUtility.GetControlID(sliderHash, FocusType.Passive); @@ -260,11 +270,11 @@ namespace VRM if (m_renderer != null && m_scene != null) { - var texture = m_renderer.Render(r, background, m_scene, m_yaw, m_pitch, m_position); - if (texture != null) + PreviewTexture = m_renderer.Render(r, background, m_scene, m_yaw, m_pitch, m_position) as RenderTexture; + if (PreviewTexture != null) { // draw the RenderTexture in the ObjectPreview pane - GUI.DrawTexture(r, texture, ScaleMode.StretchToFill, false); + GUI.DrawTexture(r, PreviewTexture, ScaleMode.StretchToFill, false); } } } diff --git a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs index ebeb4c894..bda504b6e 100644 --- a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs @@ -108,7 +108,6 @@ namespace VRM public struct DrawResult { public bool Changed; - public float Weight; public BlendShapeBinding[] BlendShapeBindings; @@ -119,36 +118,19 @@ namespace VRM { m_changed = false; - //EditorGUILayout.Space(); - - var previewSlider = EditorGUILayout.Slider("Preview Weight", m_previewSlider, 0, 1.0f); - m_serializedObject.Update(); - EditorGUILayout.Space(); - // ReadonlyのBlendShapeClip参照 GUI.enabled = false; EditorGUILayout.ObjectField("Current clip", m_targetObject, typeof(BlendShapeClip), false); GUI.enabled = true; - m_thumbnail.objectReferenceValue = EditorGUILayout.ObjectField(m_thumbnail.objectReferenceValue, typeof(Texture), false); - EditorGUILayout.PropertyField(m_thumbnail, true); EditorGUILayout.PropertyField(m_blendShapeNameProp, true); EditorGUILayout.PropertyField(m_presetProp, true); // v0.45 Added. Binary flag EditorGUILayout.PropertyField(m_isBinaryProp, true); - if (m_isBinaryProp.boolValue) - { - previewSlider = Mathf.Round(previewSlider); - } - if (previewSlider != m_previewSlider) - { - m_previewSlider = previewSlider; - m_changed = true; - } EditorGUILayout.Space(); //m_mode = EditorGUILayout.Popup("SourceType", m_mode, MODES); @@ -181,7 +163,6 @@ namespace VRM return new DrawResult { Changed = m_changed, - Weight = m_previewSlider, BlendShapeBindings = m_targetObject.Values, MaterialValueBindings = m_targetObject.MaterialValues }; From caf215ca2ad06f8083850b150185699ab98caab0 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 3 Nov 2018 15:16:37 +0900 Subject: [PATCH 16/25] Modify BlendShapeClipEditor --- Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs | 2 +- Scripts/BlendShape/Editor/BlendShapeClipEditor.cs | 10 ++++++++-- Scripts/BlendShape/Editor/PreviewEditor.cs | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs index e87e43682..7f76f52f0 100644 --- a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs @@ -57,7 +57,7 @@ namespace VRM } }; - m_clipList.onCanRemoveCallback += list => true; + //m_clipList.onCanRemoveCallback += list => true; } void OnDisable() diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs index 8cd8bbad6..440076e86 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs @@ -91,7 +91,10 @@ namespace VRM public override void OnInspectorGUI() { - base.OnInspectorGUI(); + if (PreviewSceneManager == null) + { + return; + } if (m_serializedEditor == null) { @@ -100,12 +103,14 @@ namespace VRM m_isBinaryProp = serializedObject.FindProperty("IsBinary"); } + int thumbnailSize = 96; EditorGUILayout.BeginHorizontal(); EditorGUILayout.ObjectField(m_thumbnailProp.objectReferenceValue, typeof(Texture), false, - GUILayout.Width(64), GUILayout.Height(64)); + GUILayout.Width(thumbnailSize), GUILayout.Height(thumbnailSize)); var changed = false; EditorGUILayout.BeginVertical(); + base.OnInspectorGUI(); EditorGUILayout.LabelField("Preview Weight"); var previewSlider = EditorGUILayout.Slider(m_previewSlider, 0, 1.0f); GUI.enabled = PreviewTexture != null; @@ -141,6 +146,7 @@ namespace VRM } EditorGUILayout.EndHorizontal(); + Separator(); EditorGUILayout.Space(); var result = m_serializedEditor.Draw(); diff --git a/Scripts/BlendShape/Editor/PreviewEditor.cs b/Scripts/BlendShape/Editor/PreviewEditor.cs index dd4bd9b1b..b00967fed 100644 --- a/Scripts/BlendShape/Editor/PreviewEditor.cs +++ b/Scripts/BlendShape/Editor/PreviewEditor.cs @@ -156,9 +156,9 @@ namespace VRM { //base.OnInspectorGUI(); - Prefab = (GameObject)EditorGUILayout.ObjectField("prefab for preview", Prefab, typeof(GameObject), false); + Prefab = (GameObject)EditorGUILayout.ObjectField("Preview Prefab", Prefab, typeof(GameObject), false); - Separator(); + //Separator(); } private static int sliderHash = "Slider".GetHashCode(); From 7a95cd07ab9952777e2b9b1151035fc7f758c818 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 3 Nov 2018 16:14:13 +0900 Subject: [PATCH 17/25] Cleanup BlendShapeMerger. Removed BlendShapeMerger.Clear --- Scripts/BlendShape/BlendShapeBindingMerger.cs | 105 ++++++++ .../BlendShapeBindingMerger.cs.meta | 12 + Scripts/BlendShape/BlendShapeMerger.cs | 229 ++---------------- .../Editor/BlendShapeClipEditorHelper.cs | 6 + .../BlendShape/MaterialValueBindingMerger.cs | 169 +++++++++++++ .../MaterialValueBindingMerger.cs.meta | 12 + Scripts/BlendShape/VRMBlendShapeProxy.cs | 2 + 7 files changed, 322 insertions(+), 213 deletions(-) create mode 100644 Scripts/BlendShape/BlendShapeBindingMerger.cs create mode 100644 Scripts/BlendShape/BlendShapeBindingMerger.cs.meta create mode 100644 Scripts/BlendShape/MaterialValueBindingMerger.cs create mode 100644 Scripts/BlendShape/MaterialValueBindingMerger.cs.meta diff --git a/Scripts/BlendShape/BlendShapeBindingMerger.cs b/Scripts/BlendShape/BlendShapeBindingMerger.cs new file mode 100644 index 000000000..e2126878d --- /dev/null +++ b/Scripts/BlendShape/BlendShapeBindingMerger.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace VRM +{ + /// + /// A.Value * A.Weight + B.Value * B.Weight ... + /// + class BlendShapeBindingMerger + { + /// + /// BlendShapeの適用値を蓄積する + /// + /// + /// + /// + Dictionary m_blendShapeValueMap = new Dictionary(); + + /// + /// + /// + /// + Dictionary> m_blendShapeSetterMap = new Dictionary>(); + + public BlendShapeBindingMerger(Dictionary clipMap, Transform root) + { + foreach (var kv in clipMap) + { + foreach (var binding in kv.Value.Values) + { + if (!m_blendShapeSetterMap.ContainsKey(binding)) + { + var _target = root.Find(binding.RelativePath); + SkinnedMeshRenderer target = null; + if (_target != null) + { + target = _target.GetComponent(); + } + if (target != null) + { + if (binding.Index >= 0 && binding.Index < target.sharedMesh.blendShapeCount) + { + m_blendShapeSetterMap.Add(binding, x => + { + target.SetBlendShapeWeight(binding.Index, x); + }); + } + else + { + Debug.LogWarningFormat("Invalid blendshape binding: {0}: {1}", target.name, binding); + } + + } + else + { + Debug.LogWarningFormat("SkinnedMeshRenderer: {0} not found", binding.RelativePath); + } + } + } + } + } + + public void ImmediatelySetValue(BlendShapeClip clip, float value) + { + foreach (var binding in clip.Values) + { + Action setter; + if (m_blendShapeSetterMap.TryGetValue(binding, out setter)) + { + setter(binding.Weight * value); + } + } + } + + public void AccumulateValue(BlendShapeClip clip, float value) + { + foreach (var binding in clip.Values) + { + float acc; + if (m_blendShapeValueMap.TryGetValue(binding, out acc)) + { + m_blendShapeValueMap[binding] = acc + binding.Weight * value; + } + else + { + m_blendShapeValueMap[binding] = binding.Weight * value; + } + } + } + + public void Apply() + { + foreach (var kv in m_blendShapeValueMap) + { + Action setter; + if (m_blendShapeSetterMap.TryGetValue(kv.Key, out setter)) + { + setter(kv.Value); + } + } + m_blendShapeValueMap.Clear(); + } + } +} \ No newline at end of file diff --git a/Scripts/BlendShape/BlendShapeBindingMerger.cs.meta b/Scripts/BlendShape/BlendShapeBindingMerger.cs.meta new file mode 100644 index 000000000..29c3d8446 --- /dev/null +++ b/Scripts/BlendShape/BlendShapeBindingMerger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ca4c8446451eeed46b1598db9e08bb73 +timeCreated: 1541229189 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/BlendShape/BlendShapeMerger.cs b/Scripts/BlendShape/BlendShapeMerger.cs index 8c88b41fe..5949751db 100644 --- a/Scripts/BlendShape/BlendShapeMerger.cs +++ b/Scripts/BlendShape/BlendShapeMerger.cs @@ -7,161 +7,38 @@ using UnityEngine; namespace VRM { + /// /// ブレンドシェイプを蓄えてまとめて適用するクラス /// class BlendShapeMerger { /// - /// KeyからBlendShapeClipを得る + /// Key からBlendShapeClipを得る /// Dictionary m_clipMap; /// - /// BlendShapeのWeightを蓄積する + /// BlendShape のWeightを記録する /// Dictionary m_valueMap; - /// - /// 名前とmaterialのマッピング - /// - Dictionary m_materialMap; + BlendShapeBindingMerger m_blendShapeBindingMerger; - /// - /// BlendShapeの適用値を蓄積する - /// - /// - /// - /// - Dictionary m_blendShapeValueMap = new Dictionary(); + MaterialValueBindingMerger m_materialValueBindingMerger; - /// - /// - /// - /// - Dictionary> m_blendShapeSetterMap = new Dictionary>(); - - /// - /// MaterialValueの適用値を蓄積する - /// - /// - /// - /// - Dictionary m_materialValueMap = new Dictionary(); - - Dictionary> m_materialSetterMap = new Dictionary>(); public BlendShapeMerger(IEnumerable clips, Transform root) { - m_materialMap = new Dictionary(); - foreach (var x in root.Traverse()) - { - var renderer = x.GetComponent(); - if (renderer != null) - { - foreach (var y in renderer.sharedMaterials.Where(y => y != null)) - { - if (!string.IsNullOrEmpty(y.name)) - { - if (!m_materialMap.ContainsKey(y.name)) - { - m_materialMap.Add(y.name, y); - } - } - } - } - } - m_clipMap = clips.ToDictionary(x => BlendShapeKey.CreateFrom(x), x => x); m_valueMap = new Dictionary(); - foreach (var kv in m_clipMap) - { - foreach (var binding in kv.Value.Values) - { - if (!m_blendShapeSetterMap.ContainsKey(binding)) - { - var _target = root.Find(binding.RelativePath); - SkinnedMeshRenderer target = null; - if (_target != null) - { - target = _target.GetComponent(); - } - if (target != null) - { - if (binding.Index >= 0 && binding.Index < target.sharedMesh.blendShapeCount) - { - m_blendShapeSetterMap.Add(binding, x => - { - target.SetBlendShapeWeight(binding.Index, x); - }); - } - else - { - Debug.LogWarningFormat("Invalid blendshape binding: {0}: {1}", target.name, binding); - } - - } - else - { - Debug.LogWarningFormat("SkinnedMeshRenderer: {0} not found", binding.RelativePath); - } - } - } - - foreach (var binding in kv.Value.MaterialValues) - { - if (!m_materialSetterMap.ContainsKey(binding)) - { - Material target; - if (m_materialMap.TryGetValue(binding.MaterialName, out target)) - { - if (binding.ValueName.EndsWith("_ST_S")) - { - var valueName = binding.ValueName.Substring(0, binding.ValueName.Length - 2); - Action setter = value => - { - var propValue = binding.BaseValue + (binding.TargetValue - binding.BaseValue) * value; - var src = target.GetVector(valueName); - src.x = propValue.x; // horizontal only - src.z = propValue.z; // horizontal only - target.SetVector(valueName, src); - }; - m_materialSetterMap.Add(binding, setter); - } - else if (binding.ValueName.EndsWith("_ST_T")) - { - var valueName = binding.ValueName.Substring(0, binding.ValueName.Length - 2); - Action setter = value => - { - var propValue = binding.BaseValue + (binding.TargetValue - binding.BaseValue) * value; - var src = target.GetVector(valueName); - src.y = propValue.y; // vertical only - src.w = propValue.w; // vertical only - target.SetVector(valueName, src); - }; - m_materialSetterMap.Add(binding, setter); - } - else - { - Action vec4Setter = x => - { - var propValue = binding.BaseValue + (binding.TargetValue - binding.BaseValue) * x; - target.SetColor(binding.ValueName, propValue); - }; - m_materialSetterMap.Add(binding, vec4Setter); - } - } - else - { - Debug.LogWarningFormat("material: {0} not found", binding.MaterialName); - } - } - } - } + m_blendShapeBindingMerger = new BlendShapeBindingMerger(m_clipMap, root); + m_materialValueBindingMerger = new MaterialValueBindingMerger(m_clipMap, root); } + /* public void Clear() { foreach (var kv in m_valueMap.ToArray()) @@ -170,31 +47,15 @@ namespace VRM } Apply(); } + */ /// /// 蓄積した値を適用する /// public void Apply() { - foreach (var kv in m_blendShapeValueMap) - { - Action setter; - if (m_blendShapeSetterMap.TryGetValue(kv.Key, out setter)) - { - setter(kv.Value); - } - } - m_blendShapeValueMap.Clear(); - - foreach (var kv in m_materialValueMap) - { - Action setter; - if (m_materialSetterMap.TryGetValue(kv.Key, out setter)) - { - setter(kv.Value); - } - } - m_materialValueMap.Clear(); + m_blendShapeBindingMerger.Apply(); + m_materialValueBindingMerger.Apply(); } /// @@ -230,33 +91,8 @@ namespace VRM value = Mathf.Round(value); } - foreach (var binding in clip.Values) - { - // 積算 - float acc; - if (m_blendShapeValueMap.TryGetValue(binding, out acc)) - { - m_blendShapeValueMap[binding] = acc + binding.Weight * value; - } - else - { - m_blendShapeValueMap[binding] = binding.Weight * value; - } - } - - foreach (var binding in clip.MaterialValues) - { - // 積算 - float acc; - if (m_materialValueMap.TryGetValue(binding, out acc)) - { - m_materialValueMap[binding] = acc + value; - } - else - { - m_materialValueMap[binding] = value; - } - } + m_blendShapeBindingMerger.AccumulateValue(clip, value); + m_materialValueBindingMerger.AccumulateValue(clip, value); } /// @@ -279,23 +115,8 @@ namespace VRM value = Mathf.Round(value); } - foreach (var binding in clip.Values) - { - Action setter; - if (m_blendShapeSetterMap.TryGetValue(binding, out setter)) - { - setter(binding.Weight * value); - } - } - - foreach (var binding in clip.MaterialValues) - { - Action setter; - if (m_materialSetterMap.TryGetValue(binding, out setter)) - { - setter(value); - } - } + m_blendShapeBindingMerger.ImmediatelySetValue(clip, value); + m_materialValueBindingMerger.ImmediatelySetValue(clip, value); } public void SetValue(BlendShapeKey key, float value, bool replace) @@ -322,25 +143,7 @@ namespace VRM public void RestoreMaterialInitialValues(IEnumerable clips) { - if (m_materialMap != null) - { - foreach (var x in clips) - { - foreach (var y in x.MaterialValues) - { - // restore values - Material material; - if (m_materialMap.TryGetValue(y.MaterialName, out material)) - { - material.SetColor(y.ValueName, y.BaseValue); - } - else - { - Debug.LogWarningFormat("{0} not found", y.MaterialName); - } - } - } - } + m_materialValueBindingMerger.RestoreMaterialInitialValues(clips); } } } diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs index 57627ba75..9b5010968 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs @@ -7,6 +7,9 @@ namespace VRM { public static class BlendShapeClipEditorHelper { + /// + /// BlendShape List のElement描画 + /// public static bool DrawBlendShapeBinding(Rect position, SerializedProperty property, PreviewSceneManager scene) { @@ -41,6 +44,9 @@ namespace VRM return changed; } + /// + /// Material List のElement描画 + /// public static bool DrawMaterialValueBinding(Rect position, SerializedProperty property, PreviewSceneManager scene) { diff --git a/Scripts/BlendShape/MaterialValueBindingMerger.cs b/Scripts/BlendShape/MaterialValueBindingMerger.cs new file mode 100644 index 000000000..31c2559a4 --- /dev/null +++ b/Scripts/BlendShape/MaterialValueBindingMerger.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UniGLTF; + +namespace VRM +{ + /// + /// Base + (A.Target - Base) * A.Weight + (B.Target - Base) * B.Weight ... + /// + class MaterialValueBindingMerger + { + /// + /// 名前とmaterialのマッピング + /// + Dictionary m_materialMap; + + /// + /// MaterialValueの適用値を蓄積する + /// + /// + /// + /// + Dictionary m_materialValueMap = new Dictionary(); + + Dictionary> m_materialSetterMap = new Dictionary>(); + + public MaterialValueBindingMerger(Dictionary clipMap, Transform root) + { + m_materialMap = new Dictionary(); + foreach (var x in root.Traverse()) + { + var renderer = x.GetComponent(); + if (renderer != null) + { + foreach (var y in renderer.sharedMaterials.Where(y => y != null)) + { + if (!string.IsNullOrEmpty(y.name)) + { + if (!m_materialMap.ContainsKey(y.name)) + { + m_materialMap.Add(y.name, y); + } + } + } + } + } + + foreach (var kv in clipMap) + { + foreach (var binding in kv.Value.MaterialValues) + { + if (!m_materialSetterMap.ContainsKey(binding)) + { + Material target; + if (m_materialMap.TryGetValue(binding.MaterialName, out target)) + { + if (binding.ValueName.EndsWith("_ST_S")) + { + var valueName = binding.ValueName.Substring(0, binding.ValueName.Length - 2); + Action setter = value => + { + var propValue = binding.BaseValue + (binding.TargetValue - binding.BaseValue) * value; + var src = target.GetVector(valueName); + src.x = propValue.x; // horizontal only + src.z = propValue.z; // horizontal only + target.SetVector(valueName, src); + }; + m_materialSetterMap.Add(binding, setter); + } + else if (binding.ValueName.EndsWith("_ST_T")) + { + var valueName = binding.ValueName.Substring(0, binding.ValueName.Length - 2); + Action setter = value => + { + var propValue = binding.BaseValue + (binding.TargetValue - binding.BaseValue) * value; + var src = target.GetVector(valueName); + src.y = propValue.y; // vertical only + src.w = propValue.w; // vertical only + target.SetVector(valueName, src); + }; + m_materialSetterMap.Add(binding, setter); + } + else + { + Action vec4Setter = x => + { + var propValue = binding.BaseValue + (binding.TargetValue - binding.BaseValue) * x; + target.SetColor(binding.ValueName, propValue); + }; + m_materialSetterMap.Add(binding, vec4Setter); + } + } + else + { + Debug.LogWarningFormat("material: {0} not found", binding.MaterialName); + } + } + } + } + } + + public void RestoreMaterialInitialValues(IEnumerable clips) + { + if (m_materialMap != null) + { + foreach (var x in clips) + { + foreach (var y in x.MaterialValues) + { + // restore values + Material material; + if (m_materialMap.TryGetValue(y.MaterialName, out material)) + { + material.SetColor(y.ValueName, y.BaseValue); + } + else + { + Debug.LogWarningFormat("{0} not found", y.MaterialName); + } + } + } + } + } + + public void ImmediatelySetValue(BlendShapeClip clip, float value) + { + foreach (var binding in clip.MaterialValues) + { + Action setter; + if (m_materialSetterMap.TryGetValue(binding, out setter)) + { + setter(value); + } + } + } + + public void AccumulateValue(BlendShapeClip clip, float value) + { + foreach (var binding in clip.MaterialValues) + { + // 積算 + float acc; + if (m_materialValueMap.TryGetValue(binding, out acc)) + { + m_materialValueMap[binding] = acc + value; + } + else + { + m_materialValueMap[binding] = value; + } + } + } + + public void Apply() + { + foreach (var kv in m_materialValueMap) + { + Action setter; + if (m_materialSetterMap.TryGetValue(kv.Key, out setter)) + { + setter(kv.Value); + } + } + m_materialValueMap.Clear(); + } + } +} diff --git a/Scripts/BlendShape/MaterialValueBindingMerger.cs.meta b/Scripts/BlendShape/MaterialValueBindingMerger.cs.meta new file mode 100644 index 000000000..53929f073 --- /dev/null +++ b/Scripts/BlendShape/MaterialValueBindingMerger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4ccc88d77d5d1e74499d053083ade08d +timeCreated: 1541229189 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/BlendShape/VRMBlendShapeProxy.cs b/Scripts/BlendShape/VRMBlendShapeProxy.cs index 9d07bd519..9725b0347 100644 --- a/Scripts/BlendShape/VRMBlendShapeProxy.cs +++ b/Scripts/BlendShape/VRMBlendShapeProxy.cs @@ -159,6 +159,7 @@ namespace VRM } } + /* /// /// Clear all blendShape values /// @@ -169,6 +170,7 @@ namespace VRM m_merger.Clear(); } } + */ /// /// Apply blendShape values that use SetValue apply=false From 6d05fb44b7fcf757ee041a4f21e3d0e13c35632e Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 3 Nov 2018 16:58:02 +0900 Subject: [PATCH 18/25] Renamed --- Scripts/BlendShape/BlendShapeMerger.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/BlendShape/BlendShapeMerger.cs b/Scripts/BlendShape/BlendShapeMerger.cs index 5949751db..9a7738cc8 100644 --- a/Scripts/BlendShape/BlendShapeMerger.cs +++ b/Scripts/BlendShape/BlendShapeMerger.cs @@ -119,9 +119,9 @@ namespace VRM m_materialValueBindingMerger.ImmediatelySetValue(clip, value); } - public void SetValue(BlendShapeKey key, float value, bool replace) + public void SetValue(BlendShapeKey key, float value, bool immediately) { - if (replace) + if (immediately) { ImmediatelySetValue(key, value); } From 7733b896ea9f1ea576a5a958f1f173b64304091b Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 3 Nov 2018 16:58:56 +0900 Subject: [PATCH 19/25] Modified MaterialValueBindingMerger.Setter --- .../Editor/VRMBlnedShapeProxyEditor.cs | 22 +++----- .../BlendShape/MaterialValueBindingMerger.cs | 51 ++++++++++++++----- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/Scripts/BlendShape/Editor/VRMBlnedShapeProxyEditor.cs b/Scripts/BlendShape/Editor/VRMBlnedShapeProxyEditor.cs index 622d67328..153ddaff6 100644 --- a/Scripts/BlendShape/Editor/VRMBlnedShapeProxyEditor.cs +++ b/Scripts/BlendShape/Editor/VRMBlnedShapeProxyEditor.cs @@ -23,22 +23,14 @@ namespace VRM m_key = key; } - public void Slider() + public KeyValuePair Slider() { - if (m_target.BlendShapeAvatar == null) - { - return; - } - var oldValue = m_target.GetValue(m_key); var enable = GUI.enabled; GUI.enabled = Application.isPlaying; var newValue = EditorGUILayout.Slider(m_key.ToString(), oldValue, 0, 1.0f); GUI.enabled = enable; - if (Application.isPlaying && oldValue != newValue) - { - m_target.SetValue(m_key, newValue); - } + return new KeyValuePair(m_key, newValue); } } List m_sliders; @@ -65,12 +57,14 @@ namespace VRM EditorGUILayout.HelpBox("Enable when playing", MessageType.Info); } + if (m_target.BlendShapeAvatar == null) + { + return; + } + if (m_sliders != null) { - foreach (var slider in m_sliders) - { - slider.Slider(); - } + m_target.SetValues(m_sliders.Select(x => x.Slider())); } } } diff --git a/Scripts/BlendShape/MaterialValueBindingMerger.cs b/Scripts/BlendShape/MaterialValueBindingMerger.cs index 31c2559a4..447795bb2 100644 --- a/Scripts/BlendShape/MaterialValueBindingMerger.cs +++ b/Scripts/BlendShape/MaterialValueBindingMerger.cs @@ -14,7 +14,9 @@ namespace VRM /// /// 名前とmaterialのマッピング /// - Dictionary m_materialMap; + Dictionary m_materialMap = new Dictionary(); + + delegate void Setter(float value, bool firstValue); /// /// MaterialValueの適用値を蓄積する @@ -24,11 +26,10 @@ namespace VRM /// Dictionary m_materialValueMap = new Dictionary(); - Dictionary> m_materialSetterMap = new Dictionary>(); + Dictionary m_materialSetterMap = new Dictionary(); public MaterialValueBindingMerger(Dictionary clipMap, Transform root) { - m_materialMap = new Dictionary(); foreach (var x in root.Traverse()) { var renderer = x.GetComponent(); @@ -59,9 +60,12 @@ namespace VRM if (binding.ValueName.EndsWith("_ST_S")) { var valueName = binding.ValueName.Substring(0, binding.ValueName.Length - 2); - Action setter = value => + Setter setter = (value, firstValue) => { - var propValue = binding.BaseValue + (binding.TargetValue - binding.BaseValue) * value; + var propValue = firstValue + ? (binding.BaseValue + (binding.TargetValue - binding.BaseValue) * value) + : (target.GetVector(binding.ValueName) + (binding.TargetValue - binding.BaseValue) * value) + ; var src = target.GetVector(valueName); src.x = propValue.x; // horizontal only src.z = propValue.z; // horizontal only @@ -72,9 +76,12 @@ namespace VRM else if (binding.ValueName.EndsWith("_ST_T")) { var valueName = binding.ValueName.Substring(0, binding.ValueName.Length - 2); - Action setter = value => + Setter setter = (value, firstValue) => { - var propValue = binding.BaseValue + (binding.TargetValue - binding.BaseValue) * value; + var propValue = firstValue + ? (binding.BaseValue + (binding.TargetValue - binding.BaseValue) * value) + : (target.GetVector(binding.ValueName) + (binding.TargetValue - binding.BaseValue) * value) + ; var src = target.GetVector(valueName); src.y = propValue.y; // vertical only src.w = propValue.w; // vertical only @@ -84,9 +91,12 @@ namespace VRM } else { - Action vec4Setter = x => + Setter vec4Setter = (value, firstValue) => { - var propValue = binding.BaseValue + (binding.TargetValue - binding.BaseValue) * x; + var propValue = firstValue + ? (binding.BaseValue + (binding.TargetValue - binding.BaseValue) * value) + : (target.GetVector(binding.ValueName) + (binding.TargetValue - binding.BaseValue) * value) + ; target.SetColor(binding.ValueName, propValue); }; m_materialSetterMap.Add(binding, vec4Setter); @@ -128,10 +138,10 @@ namespace VRM { foreach (var binding in clip.MaterialValues) { - Action setter; + Setter setter; if (m_materialSetterMap.TryGetValue(binding, out setter)) { - setter(value); + setter(value, true); } } } @@ -153,14 +163,29 @@ namespace VRM } } + Dictionary m_used = new Dictionary(); + public void Apply() { + m_used.Clear(); + + // (binding.Value-Base) * weight を足す foreach (var kv in m_materialValueMap) { - Action setter; + Setter setter; if (m_materialSetterMap.TryGetValue(kv.Key, out setter)) { - setter(kv.Value); + int count; + if (m_used.TryGetValue(kv.Key.MaterialName, out count)) + { + m_used[kv.Key.MaterialName] += 1; + } + else + { + m_used.Add(kv.Key.MaterialName, 1); + } + + setter(kv.Value, count == 0); } } m_materialValueMap.Clear(); From 965b81564dcce6d00c99e35dcb71dd7127d992c8 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 3 Nov 2018 19:06:37 +0900 Subject: [PATCH 20/25] Restore BlendShapeAvatarEditor.BlendShapeClipSelector --- .../Editor/BlendShapeAvatarEditor.cs | 75 +++++++++++++++++-- .../BlendShape/Editor/BlendShapeClipEditor.cs | 34 ++++----- .../Editor/BlendShapeClipSelector.cs | 4 +- Scripts/BlendShape/Editor/PreviewEditor.cs | 29 +++---- .../Editor/SerializedBlendShapeClipEditor.cs | 40 ++++------ Scripts/BlendShape/PreviewSceneManager.cs | 32 +++++--- 6 files changed, 132 insertions(+), 82 deletions(-) diff --git a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs index 7f76f52f0..afbf100d0 100644 --- a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs @@ -11,12 +11,48 @@ using UnityEngine; namespace VRM { [CustomEditor(typeof(BlendShapeAvatar))] - public class BlendShapeAvatarEditor : Editor + public class BlendShapeAvatarEditor : PreviewEditor { ReorderableList m_clipList; - void OnEnable() + BlendShapeClipSelector m_selector; + + SerializedBlendShapeEditor m_clipEditor; + + protected override PreviewSceneManager.BakeValue GetBakeValue() { + var clip = m_selector.Selected; + var value = new PreviewSceneManager.BakeValue(); + if (clip != null) + { + value.BlendShapeBindings = clip.Values; + value.MaterialValueBindings = clip.MaterialValues; + value.Weight = 1.0f; + } + return value; + } + + void OnSelected(BlendShapeClip clip) + { + if (PreviewSceneManager == null) + { + m_clipEditor = null; + } + else if (clip != null) + { + m_clipEditor = new SerializedBlendShapeEditor(clip, PreviewSceneManager); + } + else + { + m_clipEditor = null; + } + Bake(); + } + + protected override void OnEnable() + { + m_selector = new BlendShapeClipSelector((BlendShapeAvatar)target, OnSelected); + var prop = serializedObject.FindProperty("Clips"); m_clipList = new ReorderableList(serializedObject, prop); @@ -58,16 +94,43 @@ namespace VRM }; //m_clipList.onCanRemoveCallback += list => true; + base.OnEnable(); + + OnSelected(m_selector.Selected); } - void OnDisable() - { - } + int m_mode; + static readonly string[] MODES = new string[]{ + "Editor", + "List" + }; public override void OnInspectorGUI() { serializedObject.Update(); - m_clipList.DoLayoutList(); + + base.OnInspectorGUI(); + + m_mode = GUILayout.Toolbar(m_mode, MODES); + switch (m_mode) + { + case 0: + m_selector.SelectGUI(); + if (m_clipEditor != null) + { + Separator(); + m_clipEditor.Draw(); + } + break; + + case 1: + m_clipList.DoLayoutList(); + break; + + default: + throw new NotImplementedException(); + } + serializedObject.ApplyModifiedProperties(); } } diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs index 440076e86..8b0f67b70 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs @@ -14,6 +14,15 @@ namespace VRM SerializedBlendShapeEditor m_serializedEditor; BlendShapeClip m_target; + protected override PreviewSceneManager.BakeValue GetBakeValue() + { + return new PreviewSceneManager.BakeValue + { + BlendShapeBindings = m_target.Values, + MaterialValueBindings = m_target.MaterialValues, + Weight = 1.0f, + }; + } SerializedProperty m_thumbnailProp; SerializedProperty m_isBinaryProp; @@ -23,33 +32,15 @@ namespace VRM return m_target.Prefab; } - void OnPrefabChanged() - { - m_target.Prefab = Prefab; - Bake(m_target.Values, m_target.MaterialValues, 1.0f); - } - protected override void OnEnable() { m_target = (BlendShapeClip)target; - PrefabChanged += OnPrefabChanged; base.OnEnable(); - - Bake(m_target.Values, m_target.MaterialValues, 1.0f); - - } - - protected override void OnDisable() - { - base.OnDisable(); - PrefabChanged -= OnPrefabChanged; } float m_previewSlider = 1.0f; - - static Texture2D SaveResizedImage(RenderTexture rt, UnityPath path, int size) { var tex = new Texture2D(rt.width, rt.height, TextureFormat.RGB24, false); @@ -152,7 +143,12 @@ namespace VRM var result = m_serializedEditor.Draw(); if ((changed || result.Changed) && PreviewSceneManager != null) { - PreviewSceneManager.Bake(result.BlendShapeBindings, result.MaterialValueBindings, m_previewSlider); + PreviewSceneManager.Bake(new PreviewSceneManager.BakeValue + { + BlendShapeBindings = result.BlendShapeBindings, + MaterialValueBindings = result.MaterialValueBindings, + Weight = m_previewSlider + }); } } diff --git a/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs b/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs index b37d7c21d..d8ce3beb3 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs @@ -67,10 +67,12 @@ namespace VRM SelectedIndex = GUILayout.SelectionGrid(SelectedIndex, array, 4); } + /* if (GUILayout.Button("Add BlendShapeClip")) { - //m_avatar.AddBlendShapeClip(); + m_avatar.AddBlendShapeClip(); } + */ } public void DuplicateWarn() diff --git a/Scripts/BlendShape/Editor/PreviewEditor.cs b/Scripts/BlendShape/Editor/PreviewEditor.cs index b00967fed..b1615a1cb 100644 --- a/Scripts/BlendShape/Editor/PreviewEditor.cs +++ b/Scripts/BlendShape/Editor/PreviewEditor.cs @@ -13,7 +13,7 @@ namespace VRM /// * https://github.com/Unity-Technologies/UnityCsReference/blob/11bcfd801fccd2a52b09bb6fd636c1ddcc9f1705/Editor/Mono/Inspector/ModelInspector.cs /// /// - public class PreviewEditor : Editor + public abstract class PreviewEditor : Editor { /// /// PreviewRenderUtilityを管理する。 @@ -66,38 +66,26 @@ namespace VRM { m_scene.gameObject.SetActive(false); } - RaisePrefabChanged(); + + Bake(); } } } - protected event Action PrefabChanged; - void RaisePrefabChanged() - { - var handler = PrefabChanged; - if (handler == null) return; - handler(); - } + + protected abstract PreviewSceneManager.BakeValue GetBakeValue(); /// - /// シーンにBlendShapeとMaterialMorphを適用する + /// Preview シーンに BlendShape と MaterialValue を適用する /// - /// - /// - /// - protected void Bake(IEnumerable values, IEnumerable materialValues, float weight) + protected void Bake() { if (m_scene != null) { //Debug.Log("Bake"); - m_scene.Bake(values, materialValues, weight); + m_scene.Bake(GetBakeValue()); } } - protected void Bake(BlendShapeClip clip, float weight) - { - Bake(Enumerable.Empty(), Enumerable.Empty(), weight); - } - protected virtual GameObject GetPrefab() { var assetPath = AssetDatabase.GetAssetPath(target); @@ -119,6 +107,7 @@ namespace VRM protected virtual void OnEnable() { m_renderer = new PreviewFaceRenderer(); + Prefab = GetPrefab(); } diff --git a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs index bda504b6e..0390b5c3d 100644 --- a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs @@ -31,6 +31,8 @@ namespace VRM #region MaterialValueBind const int MaterialValueBindingHeight = 90; ReorderableList m_MaterialValuesList; + + SerializedProperty m_materialsProp; #endregion #region Editor values @@ -85,13 +87,13 @@ namespace VRM } }; - var materialValuesProp = serializedObject.FindProperty("MaterialValues"); - m_MaterialValuesList = new ReorderableList(serializedObject, materialValuesProp); + m_materialsProp = serializedObject.FindProperty("MaterialValues"); + m_MaterialValuesList = new ReorderableList(serializedObject, m_materialsProp); m_MaterialValuesList.elementHeight = MaterialValueBindingHeight; m_MaterialValuesList.drawElementCallback = (rect, index, isActive, isFocused) => { - var element = materialValuesProp.GetArrayElementAtIndex(index); + var element = m_materialsProp.GetArrayElementAtIndex(index); rect.height -= 4; rect.y += 2; if (BlendShapeClipEditorHelper.DrawMaterialValueBinding(rect, element, previewSceneManager)) @@ -120,7 +122,7 @@ namespace VRM m_serializedObject.Update(); - // ReadonlyのBlendShapeClip参照 + // Readonly のBlendShapeClip参照 GUI.enabled = false; EditorGUILayout.ObjectField("Current clip", m_targetObject, typeof(BlendShapeClip), false); @@ -145,14 +147,22 @@ namespace VRM case 1: { - //EditorGUILayout.LabelField("BlendShapeBindings", EditorStyles.boldLabel); + if (GUILayout.Button("Clear")) + { + m_changed = true; + m_valuesProp.arraySize = 0; + } m_ValuesList.DoLayoutList(); } break; case 2: { - //EditorGUILayout.LabelField("MaterialValueBindings", EditorStyles.boldLabel); + if (GUILayout.Button("Clear")) + { + m_changed = true; + m_materialsProp.arraySize = 0; + } m_MaterialValuesList.DoLayoutList(); } break; @@ -170,24 +180,6 @@ namespace VRM void ClipGUI() { - // Key重複の警告 - - /* - EditorGUILayout.BeginHorizontal(); - if (GUILayout.Button("Clear")) - { - ClearBlendShape(); - } - - if (clip != null && GUILayout.Button("Apply")) - { - string maxWeightString; - clip.Values = GetBindings(out maxWeightString); - EditorUtility.SetDirty(clip); - } - EditorGUILayout.EndHorizontal(); - */ - var changed = BlendShapeBindsGUI(); if (changed) { diff --git a/Scripts/BlendShape/PreviewSceneManager.cs b/Scripts/BlendShape/PreviewSceneManager.cs index 2703b35e0..0bf80978f 100644 --- a/Scripts/BlendShape/PreviewSceneManager.cs +++ b/Scripts/BlendShape/PreviewSceneManager.cs @@ -206,25 +206,34 @@ namespace VRM } #if UNITY_EDITOR - Bounds m_bounds; - public void Bake( - IEnumerable values = null, - IEnumerable materialValues = null, - float weight = 1.0f) + + public struct BakeValue { - //Debug.LogFormat("Bake"); + public IEnumerable BlendShapeBindings; + public IEnumerable MaterialValueBindings; + public float Weight; + } + + Bounds m_bounds; + public void Bake(BakeValue bake) + { + // + // Bake BlendShape + // m_bounds = default(Bounds); if (m_meshes != null) { foreach (var x in m_meshes) { - x.Bake(values, weight); + x.Bake(bake.BlendShapeBindings, bake.Weight); m_bounds.Expand(x.Mesh.bounds.size); } } - // Udpate Material - if (materialValues != null && m_materialMap != null) + // + // Update Material + // + if (bake.MaterialValueBindings != null && m_materialMap != null) { // clear //Debug.LogFormat("clear material"); @@ -236,7 +245,7 @@ namespace VRM } } - foreach (var x in materialValues) + foreach (var x in bake.MaterialValueBindings) { MaterialItem item; if (m_materialMap.TryGetValue(x.MaterialName, out item)) @@ -245,13 +254,12 @@ namespace VRM PropItem prop; if (item.PropMap.TryGetValue(x.ValueName, out prop)) { - var value = x.BaseValue + (x.TargetValue - x.BaseValue) * weight; + var value = x.BaseValue + (x.TargetValue - x.BaseValue) * bake.Weight; item.Material.SetColor(x.ValueName, value); } } } } - } #endif From 3e3e4070cf10cb6ac66c26d7ec20ed21d56a7722 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 3 Nov 2018 19:25:16 +0900 Subject: [PATCH 21/25] Restore Clear, Add --- .../Editor/BlendShapeAvatarEditor.cs | 11 ++++++++++- .../BlendShape/Editor/BlendShapeClipEditor.cs | 8 +++++++- .../Editor/BlendShapeClipSelector.cs | 19 +++++++++++++++---- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs index afbf100d0..762f5deae 100644 --- a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs @@ -119,7 +119,16 @@ namespace VRM if (m_clipEditor != null) { Separator(); - m_clipEditor.Draw(); + var result = m_clipEditor.Draw(); + if (result.Changed) + { + PreviewSceneManager.Bake(new PreviewSceneManager.BakeValue + { + BlendShapeBindings = result.BlendShapeBindings, + MaterialValueBindings = result.MaterialValueBindings, + Weight = 1.0f, + }); + } } break; diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs index 8b0f67b70..125f625d6 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs @@ -86,6 +86,7 @@ namespace VRM { return; } + serializedObject.Update(); if (m_serializedEditor == null) { @@ -96,8 +97,13 @@ namespace VRM int thumbnailSize = 96; EditorGUILayout.BeginHorizontal(); - EditorGUILayout.ObjectField(m_thumbnailProp.objectReferenceValue, typeof(Texture), false, + var objectReferenceValue = EditorGUILayout.ObjectField(m_thumbnailProp.objectReferenceValue, typeof(Texture), false, GUILayout.Width(thumbnailSize), GUILayout.Height(thumbnailSize)); + if (m_thumbnailProp.objectReferenceValue != objectReferenceValue) + { + m_thumbnailProp.objectReferenceValue = objectReferenceValue; + serializedObject.ApplyModifiedProperties(); + } var changed = false; EditorGUILayout.BeginVertical(); diff --git a/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs b/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs index d8ce3beb3..c3853c35e 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipSelector.cs @@ -2,7 +2,8 @@ using System.Linq; using UnityEngine; using UnityEditor; - +using System.IO; +using UniGLTF; namespace VRM { @@ -67,12 +68,22 @@ namespace VRM SelectedIndex = GUILayout.SelectionGrid(SelectedIndex, array, 4); } - /* if (GUILayout.Button("Add BlendShapeClip")) { - m_avatar.AddBlendShapeClip(); + var dir = Path.GetDirectoryName(AssetDatabase.GetAssetPath(m_avatar)); + var path = EditorUtility.SaveFilePanel( + "Create BlendShapeClip", + dir, + string.Format("BlendShapeClip#{0}.asset", m_avatar.Clips.Count), + "asset"); + if (!string.IsNullOrEmpty(path)) + { + var clip = BlendShapeAvatar.CreateBlendShapeClip(path.ToUnityRelativePath()); + //clip.Prefab = AssetDatabase.LoadAssetAtPath(AssetDatabase.GetAssetPath(target)); + + m_avatar.Clips.Add(clip); + } } - */ } public void DuplicateWarn() From b879ce8a4a19df07a41a2731c677bb04407c478e Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 3 Nov 2018 19:32:25 +0900 Subject: [PATCH 22/25] Remove thumbnail --- Scripts/BlendShape/BlendShapeClip.cs | 4 ++-- Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs | 11 ++++++++--- Scripts/BlendShape/Editor/BlendShapeClipEditor.cs | 8 ++++++-- .../Editor/SerializedBlendShapeClipEditor.cs | 2 +- Scripts/Meta/Editor/VRMMetaEditor.cs | 12 ++++++------ 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Scripts/BlendShape/BlendShapeClip.cs b/Scripts/BlendShape/BlendShapeClip.cs index 96253b651..4b883fdc4 100644 --- a/Scripts/BlendShape/BlendShapeClip.cs +++ b/Scripts/BlendShape/BlendShapeClip.cs @@ -92,7 +92,7 @@ namespace VRM [SerializeField] public bool IsBinary; - [SerializeField] - public Texture2D Thumbnail; + // [SerializeField] + // public Texture2D Thumbnail; } } diff --git a/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs b/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs index 6b1da8820..a8dec2adb 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs @@ -10,9 +10,12 @@ namespace VRM [CustomPropertyDrawer(typeof(BlendShapeClip))] public class BlendShapeClipDrawer : PropertyDrawer { - public const int Height = 132; + //public const int Height = 132; - public const int ThumbnailSize = 128; + //public const int ThumbnailSize = 128; + + public const int Height = 80; + public const int ThumbnailSize = 0; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) @@ -32,16 +35,18 @@ namespace VRM if (clip != null) { var clipObj = new SerializedObject(clip); - var thumbnail = clipObj.FindProperty("Thumbnail"); + //var thumbnail = clipObj.FindProperty("Thumbnail"); var blendShapeName = clipObj.FindProperty("BlendShapeName"); var preset = clipObj.FindProperty("Preset"); var isBinary = clipObj.FindProperty("IsBinary"); + /* EditorGUI.ObjectField(new Rect(position) { width = ThumbnailSize, height = ThumbnailSize }, thumbnail.objectReferenceValue, typeof(Texture), false); + */ rect.y += (EditorGUIUtility.singleLineHeight + 2); EditorGUI.PropertyField(rect, blendShapeName); diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs index 125f625d6..5af9097f5 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs @@ -24,7 +24,7 @@ namespace VRM }; } - SerializedProperty m_thumbnailProp; + //SerializedProperty m_thumbnailProp; SerializedProperty m_isBinaryProp; protected override GameObject GetPrefab() @@ -91,12 +91,13 @@ namespace VRM if (m_serializedEditor == null) { m_serializedEditor = new SerializedBlendShapeEditor(serializedObject, PreviewSceneManager); - m_thumbnailProp = serializedObject.FindProperty("Thumbnail"); + //m_thumbnailProp = serializedObject.FindProperty("Thumbnail"); m_isBinaryProp = serializedObject.FindProperty("IsBinary"); } int thumbnailSize = 96; EditorGUILayout.BeginHorizontal(); + /* var objectReferenceValue = EditorGUILayout.ObjectField(m_thumbnailProp.objectReferenceValue, typeof(Texture), false, GUILayout.Width(thumbnailSize), GUILayout.Height(thumbnailSize)); if (m_thumbnailProp.objectReferenceValue != objectReferenceValue) @@ -104,6 +105,7 @@ namespace VRM m_thumbnailProp.objectReferenceValue = objectReferenceValue; serializedObject.ApplyModifiedProperties(); } + */ var changed = false; EditorGUILayout.BeginVertical(); @@ -111,6 +113,7 @@ namespace VRM EditorGUILayout.LabelField("Preview Weight"); var previewSlider = EditorGUILayout.Slider(m_previewSlider, 0, 1.0f); GUI.enabled = PreviewTexture != null; + /* if (GUILayout.Button("save thumbnail")) { //var ext = "jpg"; @@ -129,6 +132,7 @@ namespace VRM serializedObject.ApplyModifiedProperties(); } } + */ GUI.enabled = true; EditorGUILayout.EndVertical(); diff --git a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs index 0390b5c3d..7d21c8341 100644 --- a/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/SerializedBlendShapeClipEditor.cs @@ -66,7 +66,7 @@ namespace VRM this.m_serializedObject = serializedObject; this.m_targetObject = targetObject; - m_thumbnail = serializedObject.FindProperty("Thumbnail"); + //m_thumbnail = serializedObject.FindProperty("Thumbnail"); m_blendShapeNameProp = serializedObject.FindProperty("BlendShapeName"); m_presetProp = serializedObject.FindProperty("Preset"); m_isBinaryProp = serializedObject.FindProperty("IsBinary"); diff --git a/Scripts/Meta/Editor/VRMMetaEditor.cs b/Scripts/Meta/Editor/VRMMetaEditor.cs index b5e861d22..6e90bb5db 100644 --- a/Scripts/Meta/Editor/VRMMetaEditor.cs +++ b/Scripts/Meta/Editor/VRMMetaEditor.cs @@ -70,12 +70,12 @@ namespace VRM } bool m_foldoutInfo = true; - bool m_foldoutPersmission=true; - bool m_foldoutDistribution=true; + bool m_foldoutPersmission = true; + bool m_foldoutDistribution = true; void VRMMetaObjectGUI(SerializedObject so) { InitMap(so); - if (m_propMap == null || m_propMap.Count==0) return; + if (m_propMap == null || m_propMap.Count == 0) return; so.Update(); @@ -95,8 +95,8 @@ namespace VRM EditorGUILayout.PropertyField(m_propMap["Author"]); EditorGUILayout.PropertyField(m_propMap["ContactInformation"]); EditorGUILayout.PropertyField(m_propMap["Reference"]); - var thumbnail = m_propMap["Thumbnail"]; - thumbnail.objectReferenceValue = TextureField("", (Texture2D)thumbnail.objectReferenceValue, 100); + //var thumbnail = m_propMap["Thumbnail"]; + //thumbnail.objectReferenceValue = TextureField("", (Texture2D)thumbnail.objectReferenceValue, 100); } EditorGUILayout.LabelField("License ", EditorStyles.boldLabel); @@ -121,7 +121,7 @@ namespace VRM EditorGUILayout.PropertyField(m_propMap["OtherLicenseUrl"]); } } - + so.ApplyModifiedProperties(); } From 9f98b1cc70d03e244b94ecdcda9fd797e40b9328 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 3 Nov 2018 19:46:13 +0900 Subject: [PATCH 23/25] ListSelect --- .../BlendShape/Editor/BlendShapeAvatarEditor.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs index 762f5deae..bc1054254 100644 --- a/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeAvatarEditor.cs @@ -41,12 +41,18 @@ namespace VRM else if (clip != null) { m_clipEditor = new SerializedBlendShapeEditor(clip, PreviewSceneManager); + PreviewSceneManager.Bake(new PreviewSceneManager.BakeValue + { + BlendShapeBindings = clip.Values, + MaterialValueBindings = clip.MaterialValues, + Weight = 1.0f + }); } else { m_clipEditor = null; + PreviewSceneManager.Bake(new PreviewSceneManager.BakeValue()); } - Bake(); } protected override void OnEnable() @@ -93,6 +99,13 @@ namespace VRM } }; + m_clipList.onSelectCallback += (list) => + { + var a = list.serializedProperty; + var selected = a.GetArrayElementAtIndex(list.index); + OnSelected((BlendShapeClip)selected.objectReferenceValue); + }; + //m_clipList.onCanRemoveCallback += list => true; base.OnEnable(); From c7212d16d45ef641660e39e903095ff575de50a7 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 5 Nov 2018 14:21:16 +0900 Subject: [PATCH 24/25] Updated MToon --- MToon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MToon b/MToon index 15dd8816d..bf08610b3 160000 --- a/MToon +++ b/MToon @@ -1 +1 @@ -Subproject commit 15dd8816dc1775871e5ca02802a561e6448e5792 +Subproject commit bf08610b38e27ae915b0613ee4dfb574bc8e381b From d63517babe31a9a383e0df06d02c76a00a1e3d97 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 5 Nov 2018 15:45:29 +0900 Subject: [PATCH 25/25] Fixed preview for ST_S and ST_T --- .../BlendShape/Editor/BlendShapeClipDrawer.cs | 2 +- .../Editor/BlendShapeClipEditorHelper.cs | 39 ++++++++++++++----- Scripts/BlendShape/PreviewSceneManager.cs | 13 ++++++- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs b/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs index a8dec2adb..822a5a09f 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipDrawer.cs @@ -22,7 +22,7 @@ namespace VRM { using (new EditorGUI.PropertyScope(position, label, property)) { - EditorGUIUtility.labelWidth = 80; + //EditorGUIUtility.labelWidth = 80; position.height = EditorGUIUtility.singleLineHeight; diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs index 9b5010968..cc7eec3dc 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditorHelper.cs @@ -201,27 +201,48 @@ namespace VRM return rect; } + static float[] v2 = new float[2]; + static GUIContent[] l2 = new GUIContent[]{ + new GUIContent("x"), + new GUIContent("y") + }; static Vector4 TilingOffset(Rect rect, string label, Vector4 src) { + /* var style = new GUIStyle() { alignment = TextAnchor.MiddleRight, }; + */ - var quad = rect.width / 10; + var quad = (rect.width - 56); var x = rect.x; + //EditorGUIUtility.labelWidth = 18; - EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad * 2, rect.height), "Tiling X", style); - src.x = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), src.x); + EditorGUI.LabelField(AdvanceRect(ref x, rect.y, 40, rect.height), "Tiling"); + v2[0] = src.x; + v2[1] = src.y; + EditorGUI.MultiFloatField(AdvanceRect(ref x, rect.y, quad, rect.height), l2, v2); + src.x = v2[0]; + src.y = v2[1]; - EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", style); - src.y = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), src.y); + //EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", style); + //src.y = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", src.y); - EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad * 2, rect.height), "Offset X", style); - src.z = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), src.z); + rect.y += EditorGUIUtility.singleLineHeight; + x = rect.x; + EditorGUI.LabelField(AdvanceRect(ref x, rect.y, 40, rect.height), "Offset"); + v2[0] = src.z; + v2[1] = src.w; + EditorGUI.MultiFloatField(AdvanceRect(ref x, rect.y, quad, rect.height), l2, v2); + src.z = v2[0]; + src.w = v2[1]; - EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", style); - src.w = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), src.w); + //EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad * 2, rect.height), "Offset X", style); + //src.z = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), "X", src.z); + + //EditorGUI.LabelField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", style); + //src.w = EditorGUI.FloatField(AdvanceRect(ref x, rect.y, quad, rect.height), "Y", src.w); return src; } diff --git a/Scripts/BlendShape/PreviewSceneManager.cs b/Scripts/BlendShape/PreviewSceneManager.cs index 0bf80978f..0ed21272f 100644 --- a/Scripts/BlendShape/PreviewSceneManager.cs +++ b/Scripts/BlendShape/PreviewSceneManager.cs @@ -254,8 +254,17 @@ namespace VRM PropItem prop; if (item.PropMap.TryGetValue(x.ValueName, out prop)) { - var value = x.BaseValue + (x.TargetValue - x.BaseValue) * bake.Weight; - item.Material.SetColor(x.ValueName, value); + var valueName = x.ValueName; + if (valueName.EndsWith("_ST_S") + || valueName.EndsWith("_ST_T")) + { + valueName = valueName.Substring(0, valueName.Length - 2); + } + + var value = item.Material.GetVector(valueName); + Debug.LogFormat("{0} => {1}", valueName, x.TargetValue); + value += ((x.TargetValue - x.BaseValue) * bake.Weight); + item.Material.SetColor(valueName, value); } } }