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;
}
}