Streamingle_URP/Assets/External/VRM/Editor/BlendShape/SerializedBlendShapeClipEditor.cs

314 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace VRM
{
public class SerializedBlendShapeEditor
{
BlendShapeClip m_targetObject;
SerializedObject m_serializedObject;
#region Properties
SerializedProperty m_thumbnail;
SerializedProperty m_blendShapeNameProp;
SerializedProperty m_presetProp;
SerializedProperty m_isBinaryProp;
#endregion
#region BlendShapeBind
public static int BlendShapeBindingHeight = 60;
ReorderableList m_ValuesList;
SerializedProperty m_valuesProp;
#endregion
#region MaterialValueBind
const int MaterialValueBindingHeight = 90;
ReorderableList m_MaterialValuesList;
SerializedProperty m_materialsProp;
#endregion
#region Editor values
//float m_previewSlider = 1.0f;
bool m_changed;
int m_mode;
static string[] MODES = new[]{
"BlendShape",
"BlendShape List",
"Material List"
};
MeshPreviewItem[] m_items;
#endregion
public SerializedBlendShapeEditor(SerializedObject serializedObject,
PreviewSceneManager previewSceneManager) : this(
serializedObject, (BlendShapeClip)serializedObject.targetObject, previewSceneManager)
{ }
public SerializedBlendShapeEditor(BlendShapeClip blendShapeClip,
PreviewSceneManager previewSceneManager) : this(
new SerializedObject(blendShapeClip), blendShapeClip, previewSceneManager)
{ }
public SerializedBlendShapeEditor(SerializedObject serializedObject, BlendShapeClip targetObject,
PreviewSceneManager previewSceneManager)
{
this.m_serializedObject = serializedObject;
this.m_targetObject = targetObject;
//m_thumbnail = serializedObject.FindProperty("Thumbnail");
m_blendShapeNameProp = serializedObject.FindProperty("BlendShapeName");
m_presetProp = serializedObject.FindProperty("Preset");
m_isBinaryProp = serializedObject.FindProperty("IsBinary");
m_valuesProp = serializedObject.FindProperty("Values");
m_ValuesList = new ReorderableList(serializedObject, m_valuesProp);
m_ValuesList.elementHeight = BlendShapeBindingHeight;
m_ValuesList.drawElementCallback =
(rect, index, isActive, isFocused) =>
{
var element = m_valuesProp.GetArrayElementAtIndex(index);
rect.height -= 4;
rect.y += 2;
if (BlendShapeClipEditorHelper.DrawBlendShapeBinding(rect, element, previewSceneManager))
{
m_changed = true;
}
};
m_materialsProp = serializedObject.FindProperty("MaterialValues");
m_MaterialValuesList = new ReorderableList(serializedObject, m_materialsProp);
m_MaterialValuesList.elementHeight = MaterialValueBindingHeight;
m_MaterialValuesList.drawElementCallback =
(rect, index, isActive, isFocused) =>
{
var element = m_materialsProp.GetArrayElementAtIndex(index);
rect.height -= 4;
rect.y += 2;
if (BlendShapeClipEditorHelper.DrawMaterialValueBinding(rect, element, previewSceneManager))
{
m_changed = true;
}
};
m_items = previewSceneManager.EnumRenderItems
.Where(x => x.SkinnedMeshRenderer != null)
.ToArray();
}
public struct DrawResult
{
public bool Changed;
public BlendShapeBinding[] BlendShapeBindings;
public MaterialValueBinding[] MaterialValueBindings;
}
public DrawResult Draw()
{
m_changed = false;
m_serializedObject.Update();
// Readonly のBlendShapeClip参照
GUI.enabled = false;
EditorGUILayout.ObjectField("Current clip",
m_targetObject, typeof(BlendShapeClip), false);
GUI.enabled = true;
EditorGUILayout.PropertyField(m_blendShapeNameProp, true);
EditorGUILayout.PropertyField(m_presetProp, true);
// v0.45 Added. Binary flag
EditorGUILayout.PropertyField(m_isBinaryProp, true);
EditorGUILayout.Space();
//m_mode = EditorGUILayout.Popup("SourceType", m_mode, MODES);
m_mode = GUILayout.Toolbar(m_mode, MODES);
switch (m_mode)
{
case 0:
{
ClipGUI();
}
break;
case 1:
{
if (GUILayout.Button("Clear"))
{
m_changed = true;
m_valuesProp.arraySize = 0;
}
m_ValuesList.DoLayoutList();
}
break;
case 2:
{
if (GUILayout.Button("Clear"))
{
m_changed = true;
m_materialsProp.arraySize = 0;
}
m_MaterialValuesList.DoLayoutList();
}
break;
}
m_serializedObject.ApplyModifiedProperties();
return new DrawResult
{
Changed = m_changed,
BlendShapeBindings = m_targetObject.Values,
MaterialValueBindings = m_targetObject.MaterialValues
};
}
void ClipGUI()
{
var changed = BlendShapeBindsGUI();
if (changed)
{
string maxWeightName;
var bindings = GetBindings(out maxWeightName);
m_valuesProp.ClearArray();
m_valuesProp.arraySize = bindings.Length;
for (int i = 0; i < bindings.Length; ++i)
{
var item = m_valuesProp.GetArrayElementAtIndex(i);
var endProperty = item.GetEndProperty();
while (item.NextVisible(true))
{
if (SerializedProperty.EqualContents(item, endProperty))
{
break;
}
switch (item.name)
{
case "RelativePath":
item.stringValue = bindings[i].RelativePath;
break;
case "Index":
item.intValue = bindings[i].Index;
break;
case "Weight":
item.floatValue = bindings[i].Weight;
break;
default:
throw new Exception();
}
}
}
m_changed = true;
}
}
List<bool> m_meshFolds = new List<bool>();
bool BlendShapeBindsGUI()
{
bool changed = false;
int foldIndex = 0;
// すべてのSkinnedMeshRendererを列挙する
foreach (var renderer in m_items.Select(x => x.SkinnedMeshRenderer))
{
if (renderer == null)
{
continue;
}
var mesh = renderer.sharedMesh;
if (mesh != null && mesh.blendShapeCount > 0)
{
//var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(renderer.transform, m_target.transform);
//EditorGUILayout.LabelField(m_target.name + "/" + item.Path);
if (foldIndex >= m_meshFolds.Count)
{
m_meshFolds.Add(false);
}
m_meshFolds[foldIndex] = EditorGUILayout.Foldout(m_meshFolds[foldIndex], renderer.name);
if (m_meshFolds[foldIndex])
{
//EditorGUI.indentLevel += 1;
for (int i = 0; i < mesh.blendShapeCount; ++i)
{
var src = renderer.GetBlendShapeWeight(i);
var dst = EditorGUILayout.Slider(mesh.GetBlendShapeName(i), src, 0, 100.0f);
if (dst != src)
{
renderer.SetBlendShapeWeight(i, dst);
changed = true;
}
}
//EditorGUI.indentLevel -= 1;
}
++foldIndex;
}
}
return changed;
}
BlendShapeBinding[] GetBindings(out string _maxWeightName)
{
var maxWeight = 0.0f;
var maxWeightName = "";
// weightのついたblendShapeを集める
var values = m_items
.SelectMany(x =>
{
var mesh = x.SkinnedMeshRenderer.sharedMesh;
var relativePath = x.Path;
var list = new List<BlendShapeBinding>();
if (mesh != null)
{
for (int i = 0; i < mesh.blendShapeCount; ++i)
{
var weight = x.SkinnedMeshRenderer.GetBlendShapeWeight(i);
if (weight == 0)
{
continue;
}
var name = mesh.GetBlendShapeName(i);
if (weight > maxWeight)
{
maxWeightName = name;
maxWeight = weight;
}
list.Add(new BlendShapeBinding
{
Index = i,
RelativePath = relativePath,
Weight = weight
});
}
}
return list;
}).ToArray()
;
_maxWeightName = maxWeightName;
return values;
}
}
}