mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-04-26 22:44:00 +08:00
Improve support for multiple objects in BlendshapeSync editor
This commit is contained in:
parent
232d0c43bc
commit
61b04fb1e5
@ -1,5 +1,6 @@
|
|||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
|
||||||
namespace net.fushizen.modular_avatar.core.editor
|
namespace net.fushizen.modular_avatar.core.editor
|
||||||
{
|
{
|
||||||
@ -34,15 +35,7 @@ namespace net.fushizen.modular_avatar.core.editor
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Find containing object, and from that the avatar
|
var avatar = findContainingAvatar(property);
|
||||||
if (property.serializedObject == null || property.serializedObject.targetObjects.Length != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var obj = property.serializedObject.targetObject as Component;
|
|
||||||
if (obj == null) return false;
|
|
||||||
|
|
||||||
var transform = obj.transform;
|
|
||||||
var avatar = RuntimeUtil.FindAvatarInParents(transform);
|
|
||||||
if (avatar == null) return false;
|
if (avatar == null) return false;
|
||||||
|
|
||||||
bool isRoot = property.stringValue == AvatarObjectReference.AVATAR_ROOT;
|
bool isRoot = property.stringValue == AvatarObjectReference.AVATAR_ROOT;
|
||||||
@ -129,5 +122,31 @@ namespace net.fushizen.modular_avatar.core.editor
|
|||||||
GUI.contentColor = color;
|
GUI.contentColor = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static VRCAvatarDescriptor findContainingAvatar(SerializedProperty property)
|
||||||
|
{
|
||||||
|
// Find containing object, and from that the avatar
|
||||||
|
if (property.serializedObject == null) return null;
|
||||||
|
|
||||||
|
VRCAvatarDescriptor commonAvatar = null;
|
||||||
|
var targets = property.serializedObject.targetObjects;
|
||||||
|
for (int i = 0; i < targets.Length; i++)
|
||||||
|
{
|
||||||
|
var obj = targets[i] as Component;
|
||||||
|
if (obj == null) return null;
|
||||||
|
|
||||||
|
var transform = obj.transform;
|
||||||
|
var avatar = RuntimeUtil.FindAvatarInParents(transform);
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
if (avatar == null) return null;
|
||||||
|
commonAvatar = avatar;
|
||||||
|
}
|
||||||
|
else if (commonAvatar != avatar) return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return commonAvatar;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,26 +1,118 @@
|
|||||||
using UnityEditor;
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditorInternal;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.PlayerLoop;
|
||||||
|
|
||||||
namespace net.fushizen.modular_avatar.core.editor
|
namespace net.fushizen.modular_avatar.core.editor
|
||||||
{
|
{
|
||||||
[CustomEditor(typeof(ModularAvatarBlendshapeSync))]
|
[CustomEditor(typeof(ModularAvatarBlendshapeSync))]
|
||||||
|
[CanEditMultipleObjects]
|
||||||
internal class BlendshapeSyncEditor : Editor
|
internal class BlendshapeSyncEditor : Editor
|
||||||
{
|
{
|
||||||
|
private static FieldInfo f_m_SerializedObject;
|
||||||
private BlendshapeSelectWindow _window;
|
private BlendshapeSelectWindow _window;
|
||||||
|
private ReorderableList _list;
|
||||||
|
private SerializedProperty _bindings;
|
||||||
|
|
||||||
|
static BlendshapeSyncEditor()
|
||||||
|
{
|
||||||
|
f_m_SerializedObject =
|
||||||
|
typeof(Editor).GetField("m_SerializedObject", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround unity bug: When we modify the number of array elements via the underlying objects, the serialized
|
||||||
|
// object will throw exceptions trying to access the new element, even after calling Update() and recreating all
|
||||||
|
// serialized properties. So force the serialized object to be recreated as a workaround.
|
||||||
|
private void ClearSerializedObject()
|
||||||
|
{
|
||||||
|
f_m_SerializedObject.SetValue(this, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
if (_window != null) DestroyImmediate(_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
if (_window != null) DestroyImmediate(_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
InitList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitList()
|
||||||
|
{
|
||||||
|
_bindings = serializedObject.FindProperty(nameof(ModularAvatarBlendshapeSync.Bindings));
|
||||||
|
_list = new ReorderableList(serializedObject,
|
||||||
|
_bindings,
|
||||||
|
true, true, true, true
|
||||||
|
);
|
||||||
|
_list.drawHeaderCallback = DrawHeader;
|
||||||
|
_list.drawElementCallback = DrawElement;
|
||||||
|
_list.onAddCallback = list => OpenAddWindow();
|
||||||
|
_list.elementHeight += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawHeader(Rect rect)
|
||||||
|
{
|
||||||
|
var leftHalf = rect;
|
||||||
|
leftHalf.width /= 2;
|
||||||
|
|
||||||
|
var rightHalf = rect;
|
||||||
|
rightHalf.width /= 2;
|
||||||
|
rightHalf.x += rightHalf.width;
|
||||||
|
|
||||||
|
EditorGUI.LabelField(leftHalf, "Mesh");
|
||||||
|
EditorGUI.LabelField(rightHalf, "Blendshape");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawElement(Rect rect, int index, bool isactive, bool isfocused)
|
||||||
|
{
|
||||||
|
rect.height -= 2;
|
||||||
|
rect.y += 1;
|
||||||
|
|
||||||
|
var leftHalf = rect;
|
||||||
|
leftHalf.width /= 2;
|
||||||
|
leftHalf.width -= 12;
|
||||||
|
|
||||||
|
var rightHalf = rect;
|
||||||
|
rightHalf.width /= 2;
|
||||||
|
rightHalf.x += rightHalf.width;
|
||||||
|
|
||||||
|
var item = _bindings.GetArrayElementAtIndex(index);
|
||||||
|
var mesh = item.FindPropertyRelative(nameof(BlendshapeBinding.ReferenceMesh));
|
||||||
|
var blendshape = item.FindPropertyRelative(nameof(BlendshapeBinding.Blendshape));
|
||||||
|
|
||||||
|
using (var scope = new ZeroIndentScope())
|
||||||
|
{
|
||||||
|
EditorGUI.PropertyField(leftHalf, mesh, GUIContent.none);
|
||||||
|
EditorGUI.PropertyField(rightHalf, blendshape, GUIContent.none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnInspectorGUI()
|
public override void OnInspectorGUI()
|
||||||
{
|
{
|
||||||
base.OnInspectorGUI();
|
serializedObject.Update();
|
||||||
|
|
||||||
if (GUILayout.Button("Add blendshape"))
|
_list.DoLayoutList();
|
||||||
{
|
|
||||||
if (_window != null) DestroyImmediate(_window);
|
serializedObject.ApplyModifiedProperties();
|
||||||
_window = ScriptableObject.CreateInstance<BlendshapeSelectWindow>();
|
}
|
||||||
_window.AvatarRoot = RuntimeUtil.FindAvatarInParents(((ModularAvatarBlendshapeSync) target).transform)
|
|
||||||
.gameObject;
|
private void OpenAddWindow()
|
||||||
_window.OfferBinding += OfferBinding;
|
{
|
||||||
_window.Show();
|
if (_window != null) DestroyImmediate(_window);
|
||||||
}
|
_window = ScriptableObject.CreateInstance<BlendshapeSelectWindow>();
|
||||||
|
_window.AvatarRoot = RuntimeUtil.FindAvatarInParents(((ModularAvatarBlendshapeSync) target).transform)
|
||||||
|
.gameObject;
|
||||||
|
_window.OfferBinding += OfferBinding;
|
||||||
|
_window.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OfferBinding(BlendshapeBinding binding)
|
private void OfferBinding(BlendshapeBinding binding)
|
||||||
@ -32,6 +124,9 @@ namespace net.fushizen.modular_avatar.core.editor
|
|||||||
if (!sync.Bindings.Contains(binding)) sync.Bindings.Add(binding);
|
if (!sync.Bindings.Contains(binding)) sync.Bindings.Add(binding);
|
||||||
EditorUtility.SetDirty(sync);
|
EditorUtility.SetDirty(sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClearSerializedObject();
|
||||||
|
InitList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user