mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-08 11:59:26 -05:00
BlendShape thumbnail
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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<Texture2D>();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user