using UnityEngine; using UnityEditor; using System.Collections.Generic; /// /// 선택한 AnimationClip의 키프레임 순서를 반전합니다. /// FBX 임포트 클립에는 적용 불가 — 우선 Extract 후 사용하세요. /// public static class ReverseAnimation { public static AnimationClip GetSelectedClip() { var clips = Selection.GetFiltered(typeof(AnimationClip), SelectionMode.Assets); if (clips.Length > 0) return clips[0] as AnimationClip; return null; } [MenuItem("Tools/ReverseAnimation")] public static void Reverse() { var clip = GetSelectedClip(); if (clip == null) return; float clipLength = clip.length; List curves = new List(); EditorCurveBinding[] editorCurveBindings = AnimationUtility.GetCurveBindings(clip); foreach (EditorCurveBinding i in editorCurveBindings) { var curve = AnimationUtility.GetEditorCurve(clip, i); curves.Add(curve); } clip.ClearCurves(); for (int i = 0; i < curves.Count; i++) { var curve = curves[i]; var binding = editorCurveBindings[i]; var keys = curve.keys; int keyCount = keys.Length; var postWrapmode = curve.postWrapMode; curve.postWrapMode = curve.preWrapMode; curve.preWrapMode = postWrapmode; for (int j = 0; j < keyCount; j++) { Keyframe K = keys[j]; K.time = clipLength - K.time; var tmp = -K.inTangent; K.inTangent = -K.outTangent; K.outTangent = tmp; keys[j] = K; } curve.keys = keys; clip.SetCurve(binding.path, binding.type, binding.propertyName, curve); } // AnimationEvent 시간도 반전 var events = AnimationUtility.GetAnimationEvents(clip); if (events.Length > 0) { for (int i = 0; i < events.Length; i++) { events[i].time = clipLength - events[i].time; } AnimationUtility.SetAnimationEvents(clip, events); } Debug.Log("[ReverseAnimation] Animation reversed: " + clip.name); EditorUtility.SetDirty(clip); } }