From 183ec644ba7f64e8caea3c74fe096d7b573b891f Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 3 Nov 2018 14:26:15 +0900 Subject: [PATCH] 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 };