Separated BlendShapeClipSelector.cs

This commit is contained in:
ousttrue 2018-11-02 14:55:13 +09:00
parent 79e9241ef7
commit 0ea5bb338b
5 changed files with 205 additions and 124 deletions

View File

@ -16,6 +16,24 @@ namespace VRM
[SerializeField]
public List<BlendShapeClip> Clips = new List<BlendShapeClip>();
/// <summary>
/// NullのClipを削除して詰める
/// </summary>
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()

View File

@ -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;

View File

@ -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<BlendShapeClip> m_onSelected;
public BlendShapeClipSelect(BlendShapeAvatar avatar, Action<BlendShapeClip> 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);
}
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7842ed7a65c676740aa02678316dd625
timeCreated: 1541138009
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;