Last active
July 29, 2024 21:23
-
-
Save 8chan-co/b288d25ab92ba9981db3bb01ad69a3b5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
NOTE: to use this Unity Editor utility, make a folder (Create > Folder) inside of Unity, and name it "Editor", | |
in that folder, make a C# script (Create > C# Script) and preferably name it (MirrorAnimationEditor), | |
open the C# script file in a File Editor (such as Note Pad) to paste the below C# code inside of it, | |
save the file, then head back to Unity; wait a sec or 2 until Unity finishes compiling the script, | |
once Unity is done compiling; you should be able to see a Button called "Mirror Animation" on the | |
Inspector Window when you select an Animation Clip in the Project Window, clicking the button will make a | |
new Animation Clip with the same name and path as the one inspected suffixed with "Mirrored", this newly | |
created Animation Clip will reflect all properties of the original, with the exception where humanoid rig | |
properties that animate a given side of the avatar will now oppose that side to mirror the Animation Clip. | |
*/ | |
using System.IO; | |
using System.Linq; | |
using UnityEditor; | |
using UnityEngine; | |
using UnityEngine.UIElements; | |
[CustomEditor(typeof(AnimationClip))] | |
internal sealed class MirroredAnimationVariantEditor : Editor | |
{ | |
private static readonly System.Type s_NativeEditorType = | |
typeof(Editor).Assembly.GetType("UnityEditor.AnimationClipEditor"); | |
private EditorCurveBinding[] m_Bindings; | |
private AnimationCurve[] m_Curves; | |
private Editor m_NativeEditor; | |
private Button m_CreationButton; | |
private void OnEnable() | |
{ | |
var animation = target as AnimationClip; | |
m_NativeEditor = CreateEditor(animation, s_NativeEditorType); | |
m_CreationButton = new(CreateMirroredVariant) | |
{ | |
text = ObjectNames.NicifyVariableName(nameof(CreateMirroredVariant)) | |
}; | |
m_Bindings = AnimationUtility.GetCurveBindings(animation); | |
m_Curves = System.Array.ConvertAll(AnimationUtility.GetCurveBindings(animation), | |
binding => AnimationUtility.GetEditorCurve(animation, binding) | |
); | |
const string Left = nameof(Left), Right = nameof(Right); | |
for (var i = 0; i < m_Bindings.Length; ++i) | |
{ | |
if (m_Bindings[i].type != typeof(Animator)) continue; | |
if (m_Bindings[i].propertyName.StartsWith(Left)) | |
m_Bindings[i].propertyName = m_Bindings[i].propertyName.Replace(Left, Right); | |
else if (m_Bindings[i].propertyName.StartsWith(Right)) | |
m_Bindings[i].propertyName = m_Bindings[i].propertyName.Replace(Right, Left); | |
} | |
m_CreationButton.visible = m_Bindings.Any(binding => | |
binding.propertyName.StartsWith(Left) | binding.propertyName.StartsWith(Right) | |
); | |
if (m_CreationButton.visible is false) return; | |
var width = System.MathF.Min( | |
m_CreationButton.MeasureTextSize(m_CreationButton.text, | |
float.NaN, VisualElement.MeasureMode.Undefined, | |
float.NaN, VisualElement.MeasureMode.Undefined | |
).x, EditorWindow.focusedWindow.position.width | |
); | |
m_CreationButton.style.width = System.MathF.Round(width += width * 0.25F); | |
m_CreationButton.style.alignSelf = Align.Center; | |
} | |
public override VisualElement CreateInspectorGUI() | |
{ | |
VisualElement inspector = new(); | |
inspector.Add(new IMGUIContainer(m_NativeEditor.OnInspectorGUI)); | |
inspector.Add(m_CreationButton); | |
return inspector; | |
} | |
private void OnDestroy() => DestroyImmediate(m_NativeEditor); | |
private void CreateMirroredVariant() | |
{ | |
AnimationClip animation = new(); | |
AnimationUtility.SetEditorCurves(animation, m_Bindings, m_Curves); | |
var pathname = AssetDatabase.GetAssetPath(target); | |
var destination = Path.Join(Path.GetDirectoryName(pathname), | |
string.Concat(Path.GetFileNameWithoutExtension(pathname), | |
"Mirrored", Path.GetExtension(pathname) | |
) | |
); | |
AssetDatabase.CreateAsset(animation, AssetDatabase.GenerateUniqueAssetPath(destination)); | |
Selection.SetActiveObjectWithContext(animation, EditorWindow.focusedWindow); | |
EditorGUIUtility.PingObject(animation); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment