diff --git a/Scripts/BlendShape/Editor/BlendShapeBindingPropertyDrawer.cs b/Scripts/BlendShape/Editor/BlendShapeBindingPropertyDrawer.cs deleted file mode 100644 index 0ddd37000..000000000 --- a/Scripts/BlendShape/Editor/BlendShapeBindingPropertyDrawer.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using UnityEditor; -using UnityEngine; - - -namespace VRM -{ - [CustomPropertyDrawer(typeof(BlendShapeBinding))] - public class BlendShapeBindingPropertyDrawer : PropertyDrawer - { - public static int GUIElementHeight = 60; - - public override void OnGUI(Rect position, - SerializedProperty property, GUIContent label) - { - using (new EditorGUI.PropertyScope(position, label, property)) - { - var y = position.y; - for (var depth = property.depth; - property.NextVisible(true) && property.depth > depth; - ) - { - { - var height = EditorGUI.GetPropertyHeight(property); - EditorGUI.PropertyField(new Rect(position.x, y, position.width, height), property, false); - y += height; - } - } - } - } - - public static void DrawElement(Rect position, SerializedProperty property, - PreviewSceneManager scene) - { - if (scene == null) return; - var height = 16; - - var y = position.y; - var rect = new Rect(position.x, y, position.width, height); - var index=StringPopup(rect, property.FindPropertyRelative("RelativePath"), scene.SkinnedMeshRendererPathList); - - y += height; - rect = new Rect(position.x, y, position.width, height); - IntPopup(rect, property.FindPropertyRelative("Index"), scene.GetBlendShapeNames(index)); - - y += height; - rect = new Rect(position.x, y, position.width, height); - FloatSlider(rect, property.FindPropertyRelative("Weight"), 100); - } - - static int StringPopup(Rect rect, SerializedProperty prop, string[] options) - { - if (options == null) { return -1; } - - var oldIndex = Array.IndexOf(options, prop.stringValue); - var newIndex = EditorGUI.Popup(rect, oldIndex, options); - if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) - { - prop.stringValue = options[newIndex]; - } - return newIndex; - } - - static int IntPopup(Rect rect, SerializedProperty prop, string[] options) - { - if (options == null){ return -1; } - - var oldIndex = prop.intValue; - var newIndex = EditorGUI.Popup(rect, oldIndex, options); - if (newIndex != oldIndex && newIndex >= 0 && newIndex < options.Length) - { - prop.intValue = newIndex; - } - return newIndex; - } - - static void 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; - } - } - } -} diff --git a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs index 16f0e0d94..8c816b6db 100644 --- a/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs +++ b/Scripts/BlendShape/Editor/BlendShapeClipEditor.cs @@ -1,4 +1,5 @@ -using UnityEditor; +using System; +using UnityEditor; using UnityEditorInternal; using UnityEngine; @@ -30,7 +31,7 @@ namespace VRM if (m_prefab != null) { - m_scene = PreviewSceneManager.GetOrCreate(m_prefab); + m_scene = PreviewSceneManager.GetOrCreate(m_prefab, m_target.Values); if (m_scene != null) { m_scene.gameObject.SetActive(false); @@ -48,32 +49,42 @@ namespace VRM ReorderableList m_MaterialValuesList; #endregion + BlendShapeClip m_target; + bool m_changed; + private void OnEnable() { + m_target = (BlendShapeClip)target; + 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 = BlendShapeBindingPropertyDrawer.GUIElementHeight; + m_ValuesList.elementHeight = BlendShapeBindingHeight; m_ValuesList.drawElementCallback = (rect, index, isActive, isFocused) => { var element = m_ValuesProp.GetArrayElementAtIndex(index); rect.height -= 4; rect.y += 2; - //EditorGUI.PropertyField(rect, element); - BlendShapeBindingPropertyDrawer.DrawElement(rect, element, m_scene); + if(DrawBlendShapeBinding(rect, element, m_scene)) + { + m_changed = true; + } }; m_MaterialValuesProp = serializedObject.FindProperty("MaterialValues"); m_MaterialValuesList = new ReorderableList(serializedObject, m_MaterialValuesProp); - m_MaterialValuesList.elementHeight = MaterialValueBindingPropertyDrawer.GUIElementHeight; + m_MaterialValuesList.elementHeight = MaterialValueBindingHeight; m_MaterialValuesList.drawElementCallback = (rect, index, isActive, isFocused) => { var element = m_MaterialValuesProp.GetArrayElementAtIndex(index); rect.height -= 4; rect.y += 2; - EditorGUI.PropertyField(rect, element); + if(DrawMaterialValueBinding(rect, element, m_scene)) + { + m_changed = true; + } }; m_renderer = new PreviewFaceRenderer(); @@ -106,6 +117,8 @@ namespace VRM public override void OnInspectorGUI() { + m_changed = false; + Prefab = (GameObject)EditorGUILayout.ObjectField("prefab", Prefab, typeof(GameObject), false); serializedObject.Update(); @@ -122,6 +135,11 @@ namespace VRM m_MaterialValuesList.DoLayoutList(); serializedObject.ApplyModifiedProperties(); + + if (m_changed && m_scene!=null) + { + m_scene.Bake(m_target.Values); + } } // very important to override this, it tells Unity to render an ObjectPreview at the bottom of the inspector @@ -160,5 +178,135 @@ 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 = 60; + 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 pathIndex; + if (StringPopup(rect, property.FindPropertyRelative("RelativePath"), scene.RendererPathList, out pathIndex)) + { + changed = true; + } + + y += height; + rect = new Rect(position.x, y, position.width, height); + int blendShapeIndex; + if (IntPopup(rect, property.FindPropertyRelative("Index"), scene.GetMaterialNames(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 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; + } + } + } } diff --git a/Scripts/BlendShape/Editor/MaterialValueBindingPropertyDrawer.cs b/Scripts/BlendShape/Editor/MaterialValueBindingPropertyDrawer.cs deleted file mode 100644 index e668d9d90..000000000 --- a/Scripts/BlendShape/Editor/MaterialValueBindingPropertyDrawer.cs +++ /dev/null @@ -1,31 +0,0 @@ -using UnityEditor; -using UnityEngine; - - -namespace VRM -{ - [CustomPropertyDrawer(typeof(MaterialValueBinding))] - public class MaterialValueBindingPropertyDrawer : PropertyDrawer - { - public static int GUIElementHeight = 90; - - public override void OnGUI(Rect position, - SerializedProperty property, GUIContent label) - { - using (new EditorGUI.PropertyScope(position, label, property)) - { - var y = position.y; - for (var depth = property.depth; - property.NextVisible(true) && property.depth > depth; - ) - { - { - var height = EditorGUI.GetPropertyHeight(property); - EditorGUI.PropertyField(new Rect(position.x, y, position.width, height), property, false); - y += height; - } - } - } - } - } -} diff --git a/Scripts/BlendShape/Editor/MaterialValueBindingPropertyDrawer.cs.meta b/Scripts/BlendShape/Editor/MaterialValueBindingPropertyDrawer.cs.meta deleted file mode 100644 index e4c120c50..000000000 --- a/Scripts/BlendShape/Editor/MaterialValueBindingPropertyDrawer.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 06e4436c683663e40abfdce36b92e11d -timeCreated: 1522997334 -licenseType: Free -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Scripts/BlendShape/MeshPreviewItem.cs b/Scripts/BlendShape/MeshPreviewItem.cs new file mode 100644 index 000000000..50840a224 --- /dev/null +++ b/Scripts/BlendShape/MeshPreviewItem.cs @@ -0,0 +1,131 @@ +using System.Linq; +using UnityEngine; +using UniGLTF; + + +namespace VRM +{ + public class MeshPreviewItem + { + public string Path + { + get; + private set; + } + + public SkinnedMeshRenderer SkinnedMeshRenderer + { + get; + private set; + } + + public Mesh Mesh + { + get; + private set; + } + + public int BlendShapeCount + { + get; + private set; + } + + Material[] m_materials; + public Material[] Materials + { + get { return m_materials; } + private set + { + m_materials = value; + m_MaterialNames = value.Select(x => x.name).ToArray(); + } + } + + string[] m_MaterialNames; + public string[] MaterialsNames + { + get { return m_MaterialNames; } + } + + Transform m_transform; + public Vector3 Position + { + get { return m_transform.position; } + } + public Quaternion Rotation + { + get { return m_transform.rotation; } + } + + MeshPreviewItem(string path, Transform transform) + { + Path = path; + m_transform = transform; + } + + public void Bake(BlendShapeBinding[] values) + { + if (SkinnedMeshRenderer == null) return; + + // clear + for (int i = 0; i < BlendShapeCount; ++i) + { + SkinnedMeshRenderer.SetBlendShapeWeight(i, 0); + } + + if (values != null) + { + foreach (var x in values) + { + if (x.RelativePath == Path) + { + SkinnedMeshRenderer.SetBlendShapeWeight(x.Index, x.Weight); + } + } + } + SkinnedMeshRenderer.BakeMesh(Mesh); + } + + public static MeshPreviewItem Create(Transform t, Transform root) + { + var meshFilter = t.GetComponent(); + var meshRenderer = t.GetComponent(); + var skinnedMeshRenderer = t.GetComponent(); + if (meshFilter != null && meshRenderer != null) + { + return new MeshPreviewItem(t.RelativePathFrom(root), t) + { + Mesh = meshFilter.sharedMesh, + Materials = meshRenderer.sharedMaterials + }; + } + else if (skinnedMeshRenderer != null) + { + if (skinnedMeshRenderer.sharedMesh.blendShapeCount > 0) + { + // bake required + return new MeshPreviewItem(t.RelativePathFrom(root), t) + { + SkinnedMeshRenderer = skinnedMeshRenderer, + Mesh = new Mesh(), // for bake + BlendShapeCount = skinnedMeshRenderer.sharedMesh.blendShapeCount, + Materials = skinnedMeshRenderer.sharedMaterials + }; + } + else + { + return new MeshPreviewItem(t.RelativePathFrom(root), t) + { + Mesh = skinnedMeshRenderer.sharedMesh, + Materials = skinnedMeshRenderer.sharedMaterials + }; + } + } + else + { + return null; + } + } + } +} diff --git a/Scripts/BlendShape/Editor/BlendShapeBindingPropertyDrawer.cs.meta b/Scripts/BlendShape/MeshPreviewItem.cs.meta similarity index 70% rename from Scripts/BlendShape/Editor/BlendShapeBindingPropertyDrawer.cs.meta rename to Scripts/BlendShape/MeshPreviewItem.cs.meta index a5bc5a740..fb8fb8dd1 100644 --- a/Scripts/BlendShape/Editor/BlendShapeBindingPropertyDrawer.cs.meta +++ b/Scripts/BlendShape/MeshPreviewItem.cs.meta @@ -1,8 +1,9 @@ fileFormatVersion: 2 -guid: 128cbb6916bbc7b4f89deb96d22af39e -timeCreated: 1522997334 +guid: 7a8f34605a43f30459f50399149f5929 +timeCreated: 1523145842 licenseType: Free MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/Scripts/BlendShape/PreviewSceneManager.cs b/Scripts/BlendShape/PreviewSceneManager.cs index 0f3bc5065..e85211a91 100644 --- a/Scripts/BlendShape/PreviewSceneManager.cs +++ b/Scripts/BlendShape/PreviewSceneManager.cs @@ -20,7 +20,7 @@ namespace VRM public GameObject Prefab; #if UNITY_EDITOR - public static PreviewSceneManager GetOrCreate(GameObject prefab) + public static PreviewSceneManager GetOrCreate(GameObject prefab, BlendShapeBinding[] values) { if (prefab == null) { @@ -50,7 +50,7 @@ namespace VRM ); go.name = "__PREVIEW_SCENE_MANGER__"; manager = go.AddComponent(); - manager.Initialize(prefab); + manager.Initialize(prefab, values); // HideFlags are special editor-only settings that let you have *secret* GameObjects in a scene, or to tell Unity not to save that temporary GameObject as part of the scene go.hideFlags |= HideFlags.DontSaveInEditor; @@ -60,13 +60,13 @@ namespace VRM go.hideFlags |= HideFlags.HideAndDontSave; ; // you could also hide it from the hierarchy or inspector, but personally I like knowing everything that's there #endif - Debug.LogFormat("Create {0}", manager); + //Debug.LogFormat("Create {0}", manager); return manager; } #endif - private void Initialize(GameObject prefab) + private void Initialize(GameObject prefab, BlendShapeBinding[] values) { Prefab = prefab; @@ -97,96 +97,15 @@ namespace VRM } } - Bake(); + Bake(values); m_rendererPathList = m_meshes.Select(x => x.Path).ToArray(); - m_skinnedMeshRendererPathList = m_meshes.Where(x => x.SkinnedMeshRenderer != null).Select(x => x.Path).ToArray(); + m_skinnedMeshRendererPathList = m_meshes + .Where(x => x.SkinnedMeshRenderer != null) + .Select(x => x.Path) + .ToArray(); } - public class MeshPreviewItem - { - public string Path - { - get; - private set; - } - - public SkinnedMeshRenderer SkinnedMeshRenderer - { - get; - private set; - } - - public Mesh Mesh - { - get; - private set; - } - - public int BlendShapeCount - { - get; - private set; - } - - public Material[] Materials - { - get; - private set; - } - - - Transform m_transform; - public Vector3 Position - { - get { return m_transform.position; } - } - public Quaternion Rotation - { - get { return m_transform.rotation; } - } - - MeshPreviewItem(string path, Transform transform) - { - Path = path; - m_transform = transform; - } - - public void Bake() - { - if (SkinnedMeshRenderer == null) return; - SkinnedMeshRenderer.BakeMesh(Mesh); - } - - public static MeshPreviewItem Create(Transform t, Transform root) - { - var meshFilter = t.GetComponent(); - var meshRenderer = t.GetComponent(); - var skinnedMeshRenderer = t.GetComponent(); - if (meshFilter != null && meshRenderer != null) - { - return new MeshPreviewItem(t.RelativePathFrom(root), t) - { - Mesh = meshFilter.sharedMesh, - Materials = meshRenderer.sharedMaterials - }; - } - else if (skinnedMeshRenderer != null) - { - return new MeshPreviewItem(t.RelativePathFrom(root), t) - { - SkinnedMeshRenderer = skinnedMeshRenderer, - Mesh = new Mesh(), // for bake - BlendShapeCount = skinnedMeshRenderer.sharedMesh.blendShapeCount, - Materials = skinnedMeshRenderer.sharedMaterials - }; - } - else - { - return null; - } - } - } MeshPreviewItem[] m_meshes; public IEnumerable EnumRenderItems { @@ -225,15 +144,27 @@ namespace VRM return null; } - Bounds m_bounds; - public void Bake() + public string[] GetMaterialNames(int rendererIndex) { - Debug.LogFormat("Bake"); - m_bounds = default(Bounds); - foreach (var x in m_meshes) + if (rendererIndex >= 0 && rendererIndex < m_meshes.Length) { - x.Bake(); - m_bounds.Expand(x.Mesh.bounds.size); + return m_meshes[rendererIndex].MaterialsNames; + } + return null; + } + + Bounds m_bounds; + public void Bake(BlendShapeBinding[] values) + { + //Debug.LogFormat("Bake"); + m_bounds = default(Bounds); + if (m_meshes != null) + { + foreach (var x in m_meshes) + { + x.Bake(values); + m_bounds.Expand(x.Mesh.bounds.size); + } } }