mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-20 09:47:56 -05:00
Separated BlendShapeClipSelector.cs
This commit is contained in:
parent
79e9241ef7
commit
0ea5bb338b
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
86
Scripts/BlendShape/Editor/BlendShapeClipSelector.cs
Normal file
86
Scripts/BlendShape/Editor/BlendShapeClipSelector.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
12
Scripts/BlendShape/Editor/BlendShapeClipSelector.cs.meta
Normal file
12
Scripts/BlendShape/Editor/BlendShapeClipSelector.cs.meta
Normal 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:
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user