426 lines
18 KiB
C#
426 lines
18 KiB
C#
|
using System.Collections.Generic;
|
|||
|
using UnityEditor;
|
|||
|
using UnityEditor.Animations;
|
|||
|
using UnityEngine;
|
|||
|
using VRC.SDK3.Avatars.Components;
|
|||
|
using OSCTools.OSCmooth.Animation;
|
|||
|
using OSCTools.OSCmooth.Types;
|
|||
|
using System.Linq;
|
|||
|
|
|||
|
namespace OSCTools.OSCmooth
|
|||
|
{
|
|||
|
public class OSCmoothWindow : EditorWindow
|
|||
|
{
|
|||
|
private VRCAvatarDescriptor _avDescriptor;
|
|||
|
private AnimatorController _animatorController;
|
|||
|
private List<string> layers = new List<string>();
|
|||
|
|
|||
|
private int _layerSelect = 4;
|
|||
|
|
|||
|
private OSCmoothLayer _parameterAsset;
|
|||
|
private OSCmoothParameter _basisConfigurationParameter;
|
|||
|
|
|||
|
private bool _showParameters = true;
|
|||
|
private bool _showGlobalConfiguration = false;
|
|||
|
private bool _writeDefaults = false;
|
|||
|
private Vector2 paramMenuScroll;
|
|||
|
|
|||
|
//readonly private string[] _humanoidLayers = { "Base", "Additive", "Gesture", "Action", "FX" };
|
|||
|
|
|||
|
[MenuItem("Tools/OSCmooth")]
|
|||
|
public static void ShowWindow()
|
|||
|
{
|
|||
|
AssetDatabase.Refresh();
|
|||
|
var window = EditorWindow.GetWindow<OSCmoothWindow>("OSCmooth");
|
|||
|
window.maxSize = new Vector2(512, 1024);
|
|||
|
window.minSize = new Vector2(368, 480);
|
|||
|
window.Show();
|
|||
|
}
|
|||
|
|
|||
|
private void OnGUI()
|
|||
|
{
|
|||
|
DrawGUI();
|
|||
|
}
|
|||
|
void DrawGUI()
|
|||
|
{
|
|||
|
_avDescriptor = (VRCAvatarDescriptor)EditorGUILayout.ObjectField
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Avatar",
|
|||
|
"The VRC Avatar that will have the smoothing animation layers set up on. " +
|
|||
|
"The Avatar must have a VRCAvatarDescriptor to show up in this field."
|
|||
|
),
|
|||
|
_avDescriptor,
|
|||
|
typeof(VRCAvatarDescriptor),
|
|||
|
true
|
|||
|
);
|
|||
|
|
|||
|
if (_avDescriptor != null)
|
|||
|
{
|
|||
|
// Building animation layer selection
|
|||
|
layers.Clear();
|
|||
|
foreach (VRCAvatarDescriptor.CustomAnimLayer animLayer in _avDescriptor.baseAnimationLayers)
|
|||
|
layers.Add(animLayer.type.ToString());
|
|||
|
|
|||
|
// Making sure the selector never goes beyond the length of the selection
|
|||
|
if (_layerSelect > layers.Count)
|
|||
|
_layerSelect = layers.Count - 1;
|
|||
|
|
|||
|
_layerSelect = EditorGUILayout.Popup
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Layer",
|
|||
|
"This selects what VRChat Playable Layer you would like to set up " +
|
|||
|
"the following Binary Animation Layer into. A layer must be populated " +
|
|||
|
"in order for the tool to properly set up an Animation Layer."
|
|||
|
),
|
|||
|
_layerSelect,
|
|||
|
layers.ToArray()
|
|||
|
);
|
|||
|
|
|||
|
EditorGUILayout.Space(10f);
|
|||
|
|
|||
|
_parameterAsset = (OSCmoothLayer)EditorGUILayout.ObjectField
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Config",
|
|||
|
"A preset configuration that stores Parameter Configuration data. " +
|
|||
|
"This is intended for saving configurations for use later or sharing."
|
|||
|
),
|
|||
|
_parameterAsset,
|
|||
|
typeof(OSCmoothLayer),
|
|||
|
false
|
|||
|
);
|
|||
|
|
|||
|
if (_parameterAsset == null)
|
|||
|
_parameterAsset = ScriptableObject.CreateInstance<OSCmoothLayer>();
|
|||
|
|
|||
|
if (_basisConfigurationParameter == null)
|
|||
|
_basisConfigurationParameter = new OSCmoothParameter();
|
|||
|
|
|||
|
EditorGUILayout.BeginHorizontal();
|
|||
|
GUILayout.FlexibleSpace();
|
|||
|
|
|||
|
if (GUILayout.Button
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Save Config",
|
|||
|
"Saves Parameter configuration into a JSON readable text file."
|
|||
|
),
|
|||
|
GUILayout.MaxWidth((float)Screen.width - 159f)
|
|||
|
))
|
|||
|
{
|
|||
|
if (AssetDatabase.GetAssetPath(_parameterAsset) == string.Empty)
|
|||
|
AssetDatabase.CreateAsset(_parameterAsset, EditorUtility.SaveFilePanelInProject("Save OSCmooth Configuration", "OSCmoothConfig", "asset", ""));
|
|||
|
|
|||
|
EditorUtility.SetDirty(_parameterAsset);
|
|||
|
AssetDatabase.SaveAssets();
|
|||
|
}
|
|||
|
|
|||
|
EditorGUILayout.EndHorizontal();
|
|||
|
|
|||
|
_writeDefaults = EditorGUILayout.Toggle
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Write Defaults",
|
|||
|
"Sets whether the generated OSCmooth layer will have write defaults on or off. Set true for WD on, false for WD off"
|
|||
|
),
|
|||
|
_writeDefaults
|
|||
|
);
|
|||
|
|
|||
|
_animatorController = AssetDatabase.LoadAssetAtPath<AnimatorController>(AssetDatabase.GetAssetPath(_avDescriptor.baseAnimationLayers[_layerSelect].animatorController));
|
|||
|
|
|||
|
if (_animatorController == null)
|
|||
|
{
|
|||
|
EditorGUILayout.HelpBox("This Playable Layer must have an Animator Controller in order for OSCmooth to function.", MessageType.Warning, true);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
EditorGUILayout.Space();
|
|||
|
if (GUILayout.Button
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Use Playable Layer Parameters",
|
|||
|
"Populates the parameter list with exising float parameters in the applied Playable Layer controller."
|
|||
|
)
|
|||
|
))
|
|||
|
{
|
|||
|
_parameterAsset = ScriptableObject.CreateInstance<OSCmoothLayer>();
|
|||
|
|
|||
|
foreach (AnimatorControllerParameter parameter in _animatorController.parameters)
|
|||
|
{
|
|||
|
if (parameter.type == AnimatorControllerParameterType.Float && !OSCmoothFilters.BlackList.Any(parameter.name.Contains))
|
|||
|
{
|
|||
|
_parameterAsset.parameters.Add(new OSCmoothParameter
|
|||
|
{
|
|||
|
paramName = parameter.name,
|
|||
|
localSmoothness = _basisConfigurationParameter.localSmoothness,
|
|||
|
remoteSmoothness = _basisConfigurationParameter.remoteSmoothness,
|
|||
|
flipInputOutput = _basisConfigurationParameter.flipInputOutput,
|
|||
|
convertToProxy = _basisConfigurationParameter.convertToProxy
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
EditorUtility.SetDirty(_parameterAsset);
|
|||
|
AssetDatabase.SaveAssets();
|
|||
|
|
|||
|
}
|
|||
|
EditorGUILayout.Space();
|
|||
|
|
|||
|
_showGlobalConfiguration = EditorGUILayout.Foldout(_showGlobalConfiguration, "Default Parameter Values");
|
|||
|
if (_showGlobalConfiguration)
|
|||
|
{
|
|||
|
DrawParameterConfiguration(_basisConfigurationParameter, false);
|
|||
|
}
|
|||
|
|
|||
|
_parameterAsset.configuration = _basisConfigurationParameter;
|
|||
|
|
|||
|
EditorGUI.indentLevel = 0;
|
|||
|
|
|||
|
_showParameters = EditorGUILayout.Foldout(_showParameters, "Parameter Configuration");
|
|||
|
if (_parameterAsset.parameters != null && _parameterAsset.parameters.Count() > 0) {
|
|||
|
if (GUILayout.Button("Remove All")) {
|
|||
|
Undo.RecordObject(_parameterAsset, "Remove All Parameters");
|
|||
|
_parameterAsset.parameters = new List<OSCmoothParameter>();
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
EditorGUI.indentLevel = 0;
|
|||
|
|
|||
|
paramMenuScroll = EditorGUILayout.BeginScrollView(paramMenuScroll);
|
|||
|
if (_showParameters && _parameterAsset != null)
|
|||
|
{
|
|||
|
foreach (OSCmoothParameter parameter in _parameterAsset.parameters)
|
|||
|
{
|
|||
|
if (parameter == null)
|
|||
|
continue;
|
|||
|
|
|||
|
EditorGUI.indentLevel = 0;
|
|||
|
using (new EditorGUILayout.HorizontalScope())
|
|||
|
{
|
|||
|
if (GUILayout.Button(parameter.isVisible ? "v" : ">", GUILayout.Width(20))) {
|
|||
|
Undo.RecordObject(_parameterAsset, "Set Parameter Visible");
|
|||
|
parameter.isVisible = !parameter.isVisible;
|
|||
|
}
|
|||
|
|
|||
|
EditorGUI.BeginChangeCheck();
|
|||
|
string paramName = parameter.paramName;
|
|||
|
paramName = EditorGUILayout.TextField(paramName);
|
|||
|
if (EditorGUI.EndChangeCheck() && parameter != null) {
|
|||
|
Undo.RecordObject(_parameterAsset, "Change Parameter Name");
|
|||
|
parameter.paramName = paramName;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
GUI.color = Color.red;
|
|||
|
if (GUILayout.Button("X", GUILayout.Width(40)))
|
|||
|
{
|
|||
|
Undo.RecordObject(_parameterAsset, "Remove Parameter");
|
|||
|
_parameterAsset.parameters.Remove(parameter);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
GUI.color = Color.white;
|
|||
|
}
|
|||
|
EditorGUI.indentLevel = 2;
|
|||
|
if (parameter.isVisible) {
|
|||
|
DrawParameterConfiguration(parameter);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
EditorGUILayout.Space();
|
|||
|
|
|||
|
if (GUILayout.Button
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Add New Parameter",
|
|||
|
"Adds a new Parameter configuration."
|
|||
|
)
|
|||
|
))
|
|||
|
{
|
|||
|
OSCmoothParameter param = new OSCmoothParameter
|
|||
|
{
|
|||
|
paramName = _basisConfigurationParameter.paramName,
|
|||
|
localSmoothness = _basisConfigurationParameter.localSmoothness,
|
|||
|
remoteSmoothness = _basisConfigurationParameter.remoteSmoothness,
|
|||
|
flipInputOutput = _basisConfigurationParameter.flipInputOutput,
|
|||
|
convertToProxy = _basisConfigurationParameter.convertToProxy
|
|||
|
};
|
|||
|
_parameterAsset.parameters.Add(param);
|
|||
|
|
|||
|
EditorUtility.SetDirty(_parameterAsset);
|
|||
|
AssetDatabase.SaveAssets();
|
|||
|
}
|
|||
|
|
|||
|
EditorGUILayout.EndScrollView();
|
|||
|
|
|||
|
EditorGUILayout.Space(20);
|
|||
|
|
|||
|
if (GUILayout.Button
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Apply OSCmooth to Layer",
|
|||
|
"Creates a new Layer in the selected Animator Controller that will apply smoothing " +
|
|||
|
"to the listed configured parameters."
|
|||
|
)
|
|||
|
))
|
|||
|
{
|
|||
|
string animatorGUID;
|
|||
|
long id;
|
|||
|
|
|||
|
AssetDatabase.TryGetGUIDAndLocalFileIdentifier(_animatorController, out animatorGUID, out id);
|
|||
|
|
|||
|
OSCmoothAnimationHandler._animatorController = _animatorController;
|
|||
|
OSCmoothAnimationHandler._parameters = _parameterAsset.parameters;
|
|||
|
OSCmoothAnimationHandler._writeDefaults = _writeDefaults;
|
|||
|
OSCmoothAnimationHandler._animExportDirectory = "Assets/OSCmooth/Generated/Anims/" + "Animator_" + animatorGUID + "/";
|
|||
|
|
|||
|
Undo.RecordObject(OSCmoothAnimationHandler._animatorController, "Apply OSCmooth to Layer");
|
|||
|
OSCmoothAnimationHandler.CreateSmoothAnimationLayer();
|
|||
|
}
|
|||
|
|
|||
|
EditorGUILayout.Space(20);
|
|||
|
|
|||
|
if (GUILayout.Button
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Revert OSCmooth from Layer",
|
|||
|
"Removes all OSCmooth content from the Animator, and reverts all State Machine parameters back to their original naming." +
|
|||
|
"\n\nWARNING: Will recycle all associated animations to the selected Playable Layer as well, proceed with caution."
|
|||
|
)
|
|||
|
))
|
|||
|
{
|
|||
|
string animatorGUID;
|
|||
|
long id;
|
|||
|
|
|||
|
AssetDatabase.TryGetGUIDAndLocalFileIdentifier(_animatorController, out animatorGUID, out id);
|
|||
|
|
|||
|
OSCmoothAnimationHandler._animatorController = _animatorController;
|
|||
|
OSCmoothAnimationHandler._parameters = _parameterAsset.parameters;
|
|||
|
|
|||
|
Undo.RecordObject(OSCmoothAnimationHandler._animatorController, "Revert OSCmooth in Layer");
|
|||
|
OSCmoothAnimationHandler.RemoveAllOSCmoothFromController();
|
|||
|
|
|||
|
FileUtil.DeleteFileOrDirectory("Assets/OSCmooth/Generated/Anims/" + "Animator_" + animatorGUID);
|
|||
|
FileUtil.DeleteFileOrDirectory("Assets/OSCmooth/Generated/Anims/" + "Animator_" + animatorGUID + ".meta");
|
|||
|
|
|||
|
AssetDatabase.Refresh();
|
|||
|
}
|
|||
|
|
|||
|
EditorGUILayout.Space(20);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void DrawParameterConfiguration(OSCmoothParameter parameter, bool removable = true)
|
|||
|
{
|
|||
|
EditorGUIUtility.labelWidth = 210;
|
|||
|
|
|||
|
EditorGUILayout.LabelField
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Smoothness",
|
|||
|
"How much of a percentage the previous float values influence the current one."
|
|||
|
)
|
|||
|
);
|
|||
|
|
|||
|
EditorGUI.indentLevel = 3;
|
|||
|
EditorGUIUtility.labelWidth = 200;
|
|||
|
|
|||
|
float localSmoothness = parameter.localSmoothness;
|
|||
|
float remoteSmoothness = parameter.remoteSmoothness;
|
|||
|
bool convertToProxy = parameter.convertToProxy;
|
|||
|
bool flipIO = parameter.flipInputOutput;
|
|||
|
|
|||
|
EditorGUI.BeginChangeCheck();
|
|||
|
{
|
|||
|
localSmoothness = EditorGUILayout.FloatField
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Local Smoothness",
|
|||
|
"How much % smoothness you (locally) will see when a parameter " +
|
|||
|
"changes value. Higher values represent more smoothness, and vice versa."
|
|||
|
),
|
|||
|
localSmoothness
|
|||
|
);
|
|||
|
|
|||
|
remoteSmoothness = EditorGUILayout.FloatField
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Remote Smoothness",
|
|||
|
"How much % smoothness remote users will see when a parameter " +
|
|||
|
"changes value. Higher values represent more smoothness, and vice versa."
|
|||
|
),
|
|||
|
remoteSmoothness
|
|||
|
);
|
|||
|
|
|||
|
convertToProxy = EditorGUILayout.Toggle
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Proxy Conversion",
|
|||
|
"Automatically convert existing animations to use the Proxy (output) float."
|
|||
|
),
|
|||
|
convertToProxy
|
|||
|
);
|
|||
|
|
|||
|
flipIO = EditorGUILayout.Toggle
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Flip Input/Output",
|
|||
|
"Sets the Base parameter to be the output parameter from the smoother layer, and " +
|
|||
|
"sets the Proxy parameter as the input driver parameter. Useful for apps that can " +
|
|||
|
"drive the Proxy parameter like VRCFaceTracking binary parameters."
|
|||
|
),
|
|||
|
flipIO
|
|||
|
);
|
|||
|
}
|
|||
|
if (EditorGUI.EndChangeCheck()) {
|
|||
|
Undo.RecordObject(_parameterAsset, "Change Parameter Values");
|
|||
|
parameter.localSmoothness = localSmoothness;
|
|||
|
parameter.remoteSmoothness = remoteSmoothness;
|
|||
|
parameter.convertToProxy = convertToProxy;
|
|||
|
parameter.flipInputOutput = flipIO;
|
|||
|
}
|
|||
|
|
|||
|
EditorGUILayout.BeginHorizontal();
|
|||
|
GUILayout.FlexibleSpace();
|
|||
|
/*
|
|||
|
if (removable)
|
|||
|
{
|
|||
|
if (GUILayout.Button
|
|||
|
(
|
|||
|
new GUIContent
|
|||
|
(
|
|||
|
"Remove Parameter",
|
|||
|
"Removes specified parameter from smoothness creation."
|
|||
|
),
|
|||
|
GUILayout.MaxWidth((float)Screen.width - 248f)
|
|||
|
))
|
|||
|
{
|
|||
|
Undo.RecordObject(_parameterAsset, "Remove Parameter");
|
|||
|
_parameterAsset.parameters.Remove(parameter);
|
|||
|
}
|
|||
|
}
|
|||
|
*/
|
|||
|
|
|||
|
EditorGUILayout.EndHorizontal();
|
|||
|
EditorGUILayout.Space();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|