using UnityEngine; using UnityEditor; using System.Collections.Generic; using System; /// /// Range-based Keyframe Reduction Utility - Sample code for UMotion integration /// public static class KeyframeReducerUtility { /// /// Reduces keyframes in a specific range of an animation clip based on a step interval. /// /// Target animation clip /// Start frame of the range /// End frame of the range /// How many frames to keep (e.g., keep 1 frame every 5 frames) /// Number of keyframes removed public static int ReduceKeysInRange(AnimationClip clip, int startFrame, int endFrame, int stepValue) { if (clip == null) return 0; int totalKeysRemoved = 0; float frameRate = clip.frameRate; // Validate range int clipEndFrame = Mathf.RoundToInt(clip.length * frameRate); int effectiveEndFrame = Mathf.Min(endFrame, clipEndFrame); // Calculate frames to keep HashSet framesToKeep = new HashSet(); // Always keep start and end frames framesToKeep.Add(startFrame); framesToKeep.Add(effectiveEndFrame); // Add frames based on step value for (int frame = startFrame; frame <= effectiveEndFrame; frame++) { if ((frame - startFrame) % stepValue == 0) { framesToKeep.Add(frame); } } // Convert to time-based values HashSet timesToKeep = new HashSet(); foreach (int frame in framesToKeep) { timesToKeep.Add(frame / frameRate); } // Always preserve special times (0s and clip end) timesToKeep.Add(0f); timesToKeep.Add(clip.length); // Get all curve bindings EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(clip); // Dictionary for curve modifications Dictionary newCurves = new Dictionary(); // Process each curve foreach (var binding in bindings) { AnimationCurve curve = AnimationUtility.GetEditorCurve(clip, binding); if (curve == null || curve.keys.Length <= 2) continue; List keysToKeep = new List(); foreach (var key in curve.keys) { float time = key.time; int frame = Mathf.RoundToInt(time * frameRate); // Check if this key should be kept if (frame < startFrame || frame > effectiveEndFrame || framesToKeep.Contains(frame) || timesToKeep.Contains(time)) { keysToKeep.Add(key); } } // Check if keys were removed int removedKeys = curve.keys.Length - keysToKeep.Count; if (removedKeys > 0) { totalKeysRemoved += removedKeys; newCurves[binding] = new AnimationCurve(keysToKeep.ToArray()); } } // Apply all curve modifications at once for best performance foreach (var kvp in newCurves) { AnimationUtility.SetEditorCurve(clip, kvp.Key, kvp.Value); } return totalKeysRemoved; } }