您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
281 行
10 KiB
281 行
10 KiB
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
namespace UniVRM10
|
|
{
|
|
/// <summary>
|
|
/// Expression カスタムエディタの実装
|
|
/// </summary>
|
|
public class SerializedExpressionEditor
|
|
{
|
|
VRM10Expression m_targetObject;
|
|
|
|
SerializedObject m_serializedObject;
|
|
|
|
#region Properties
|
|
SerializedProperty m_thumbnail;
|
|
SerializedProperty m_isBinaryProp;
|
|
|
|
public bool IsBinary => m_isBinaryProp.boolValue;
|
|
|
|
SerializedProperty m_ignoreBlinkProp;
|
|
SerializedProperty m_ignoreLookAtProp;
|
|
SerializedProperty m_ignoreMouthProp;
|
|
#endregion
|
|
|
|
ReorderableMorphTargetBindingList m_morphTargetBindings;
|
|
ReorderableMaterialColorBindingList m_materialColorBindings;
|
|
ReorderableMaterialUVBindingList m_materialUVBindings;
|
|
|
|
#region Editor values
|
|
|
|
bool m_changed;
|
|
|
|
static int s_Mode;
|
|
static bool s_MorphTargetFoldout = true;
|
|
static bool s_OptionFoldout;
|
|
static bool s_ListFoldout;
|
|
|
|
static string[] MODES = new[]{
|
|
"MorphTarget",
|
|
"Material Color",
|
|
"Texture Transform"
|
|
};
|
|
|
|
PreviewMeshItem[] m_items;
|
|
#endregion
|
|
|
|
public SerializedExpressionEditor(SerializedObject serializedObject,
|
|
PreviewSceneManager previewSceneManager) : this(
|
|
serializedObject, (VRM10Expression)serializedObject.targetObject, previewSceneManager)
|
|
{ }
|
|
|
|
public SerializedExpressionEditor(VRM10Expression expression,
|
|
PreviewSceneManager previewSceneManager) : this(
|
|
new SerializedObject(expression), expression, previewSceneManager)
|
|
{ }
|
|
|
|
public SerializedExpressionEditor(SerializedObject serializedObject, VRM10Expression targetObject,
|
|
PreviewSceneManager previewSceneManager)
|
|
{
|
|
this.m_serializedObject = serializedObject;
|
|
this.m_targetObject = targetObject;
|
|
|
|
m_isBinaryProp = serializedObject.FindProperty(nameof(targetObject.IsBinary));
|
|
m_ignoreBlinkProp = serializedObject.FindProperty(nameof(targetObject.OverrideBlink));
|
|
m_ignoreLookAtProp = serializedObject.FindProperty(nameof(targetObject.OverrideLookAt));
|
|
m_ignoreMouthProp = serializedObject.FindProperty(nameof(targetObject.OverrideMouth));
|
|
|
|
m_morphTargetBindings = new ReorderableMorphTargetBindingList(serializedObject, previewSceneManager, 20);
|
|
m_materialColorBindings = new ReorderableMaterialColorBindingList(serializedObject, previewSceneManager?.MaterialNames, 20);
|
|
m_materialUVBindings = new ReorderableMaterialUVBindingList(serializedObject, previewSceneManager?.MaterialNames, 20);
|
|
|
|
m_items = previewSceneManager.EnumRenderItems
|
|
.Where(x => x.SkinnedMeshRenderer != null)
|
|
.ToArray();
|
|
}
|
|
|
|
public bool Draw(out VRM10Expression bakeValue)
|
|
{
|
|
m_changed = false;
|
|
|
|
m_serializedObject.Update();
|
|
|
|
// Readonly の Expression 参照
|
|
GUI.enabled = false;
|
|
EditorGUILayout.ObjectField("Current clip",
|
|
m_targetObject, typeof(VRM10Expression), false);
|
|
GUI.enabled = true;
|
|
|
|
s_MorphTargetFoldout = CustomUI.Foldout(s_MorphTargetFoldout, "MorphTarget");
|
|
if (s_MorphTargetFoldout)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
var changed = MorphTargetBindsGUI();
|
|
if (changed)
|
|
{
|
|
string maxWeightName;
|
|
var bindings = GetBindings(out maxWeightName);
|
|
m_morphTargetBindings.SetValues(bindings);
|
|
|
|
m_changed = true;
|
|
}
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
s_ListFoldout = CustomUI.Foldout(s_ListFoldout, "List");
|
|
if (s_ListFoldout)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
s_Mode = GUILayout.Toolbar(s_Mode, MODES);
|
|
switch (s_Mode)
|
|
{
|
|
case 0:
|
|
// MorphTarget
|
|
{
|
|
if (m_morphTargetBindings.Draw("MorphTarget"))
|
|
{
|
|
m_changed = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
// Material
|
|
{
|
|
if (m_materialColorBindings.Draw("MaterialColor"))
|
|
{
|
|
m_changed = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
// TextureTransform
|
|
{
|
|
if (m_materialUVBindings.Draw("TextureTransform"))
|
|
{
|
|
m_changed = true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
s_OptionFoldout = CustomUI.Foldout(s_OptionFoldout, "Option");
|
|
if (s_OptionFoldout)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
|
|
// v0.45 Added. Binary flag
|
|
EditorGUILayout.PropertyField(m_isBinaryProp, true);
|
|
|
|
// v1.0 Ignore State
|
|
EditorGUILayout.PropertyField(m_ignoreBlinkProp, true);
|
|
EditorGUILayout.PropertyField(m_ignoreLookAtProp, true);
|
|
EditorGUILayout.PropertyField(m_ignoreMouthProp, true);
|
|
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
m_serializedObject.ApplyModifiedProperties();
|
|
|
|
bakeValue = m_targetObject;
|
|
return m_changed;
|
|
}
|
|
|
|
static List<bool> m_meshFolds = new List<bool>();
|
|
bool MorphTargetBindsGUI()
|
|
{
|
|
bool changed = false;
|
|
int foldIndex = 0;
|
|
// すべてのSkinnedMeshRendererを列挙する
|
|
foreach (var renderer in m_items.Select(x => x.SkinnedMeshRenderer))
|
|
{
|
|
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) * MorphTargetBinding.UNITY_TO_VRM;
|
|
var dst = EditorGUILayout.Slider(mesh.GetBlendShapeName(i), src, 0, MorphTargetBinding.MAX_WEIGHT);
|
|
if (dst != src)
|
|
{
|
|
renderer.SetBlendShapeWeight(i, dst * MorphTargetBinding.VRM_TO_UNITY);
|
|
changed = true;
|
|
}
|
|
}
|
|
//EditorGUI.indentLevel -= 1;
|
|
}
|
|
++foldIndex;
|
|
}
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
MorphTargetBinding[] GetBindings(out string _maxWeightName)
|
|
{
|
|
var maxUnityWeight = 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<MorphTargetBinding>();
|
|
if (mesh != null)
|
|
{
|
|
for (int i = 0; i < mesh.blendShapeCount; ++i)
|
|
{
|
|
var unityWeight = x.SkinnedMeshRenderer.GetBlendShapeWeight(i);
|
|
if (unityWeight == 0)
|
|
{
|
|
continue;
|
|
}
|
|
var name = mesh.GetBlendShapeName(i);
|
|
if (unityWeight > maxUnityWeight)
|
|
{
|
|
maxWeightName = name;
|
|
maxUnityWeight = unityWeight;
|
|
}
|
|
list.Add(new MorphTargetBinding(relativePath, i, unityWeight * MorphTargetBinding.UNITY_TO_VRM));
|
|
}
|
|
}
|
|
return list;
|
|
}).ToArray()
|
|
;
|
|
_maxWeightName = maxWeightName;
|
|
return values;
|
|
}
|
|
}
|
|
|
|
/// http://tips.hecomi.com/entry/2016/10/15/004144
|
|
public static class CustomUI
|
|
{
|
|
public static bool Foldout(bool display, string title)
|
|
{
|
|
var style = new GUIStyle("ShurikenModuleTitle");
|
|
style.font = new GUIStyle(EditorStyles.label).font;
|
|
style.border = new RectOffset(15, 7, 4, 4);
|
|
style.fixedHeight = 22;
|
|
style.contentOffset = new Vector2(20f, -2f);
|
|
|
|
var rect = GUILayoutUtility.GetRect(16f, 22f, style);
|
|
GUI.Box(rect, title, style);
|
|
|
|
var e = Event.current;
|
|
|
|
var toggleRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f);
|
|
if (e.type == EventType.Repaint)
|
|
{
|
|
EditorStyles.foldout.Draw(toggleRect, false, false, display, false);
|
|
}
|
|
|
|
if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition))
|
|
{
|
|
display = !display;
|
|
e.Use();
|
|
}
|
|
|
|
return display;
|
|
}
|
|
}
|
|
}
|