diff --git a/Assets/_Game/Scripts/Editor/AnimationSectionSpeedEditor.cs b/Assets/_Game/Scripts/Editor/AnimationSectionSpeedEditor.cs index 2fc0c12a..0fc8878b 100644 --- a/Assets/_Game/Scripts/Editor/AnimationSectionSpeedEditor.cs +++ b/Assets/_Game/Scripts/Editor/AnimationSectionSpeedEditor.cs @@ -54,18 +54,28 @@ public class AnimationSectionSpeedEditor : EditorWindow // ── 클립 정보 (실제 키프레임 기반) ── float actualLength = GetActualLastKeyframeTime(clip); + bool hasBoneCurves = actualLength > 0f; + + // 본 트랜스폼 곡선이 없으면 m_StopTime을 기준으로 사용 + // (Mixamo export 클립 등 m_FloatCurves만 있는 경우) + float effectiveLength = hasBoneCurves ? actualLength : clip.length; + EditorGUILayout.LabelField("Clip Info", EditorStyles.boldLabel); EditorGUI.indentLevel++; - EditorGUILayout.LabelField("Length (keyframes)", $"{actualLength:F3}s"); - EditorGUILayout.LabelField("m_StopTime", $"{clip.length:F3}s"); + EditorGUILayout.LabelField("Length", $"{effectiveLength:F3}s"); - if (Mathf.Abs(clip.length - actualLength) > 0.01f) + if (hasBoneCurves && Mathf.Abs(clip.length - actualLength) > 0.01f) { + EditorGUILayout.LabelField("m_StopTime", $"{clip.length:F3}s"); EditorGUILayout.HelpBox($"m_StopTime({clip.length:F3}s)이 실제 키프레임 길이({actualLength:F3}s)와 다릅니다.\n" + "스피드 변경 시 실제 키프레임 길이를 기준으로 계산합니다.", MessageType.Warning); } + else if (!hasBoneCurves) + { + EditorGUILayout.LabelField(" (본 곡선 없음, m_StopTime 기준)", EditorStyles.miniLabel); + } - EditorGUILayout.LabelField("Total Frames ({fps}fps)", $"{Mathf.Max(1, Mathf.FloorToInt(actualLength * fps))}"); + EditorGUILayout.LabelField("Total Frames ({fps}fps)", $"{Mathf.Max(1, Mathf.FloorToInt(effectiveLength * fps))}"); EditorGUI.indentLevel--; EditorGUILayout.Space(); @@ -74,7 +84,7 @@ public class AnimationSectionSpeedEditor : EditorWindow fps = EditorGUILayout.IntField("FPS", fps); fps = Mathf.Max(1, fps); - int totalFrames = Mathf.Max(1, Mathf.FloorToInt(actualLength * fps)); + int totalFrames = Mathf.Max(1, Mathf.FloorToInt(effectiveLength * fps)); // ── 프레임 범위 ── EditorGUILayout.LabelField("Target Frame Range", EditorStyles.boldLabel); @@ -108,7 +118,7 @@ public class AnimationSectionSpeedEditor : EditorWindow EditorGUILayout.Space(); // ── 타임라인 시각화 ── - DrawTimeline(startTime, endTime, actualLength); + DrawTimeline(startTime, endTime, effectiveLength); EditorGUILayout.Space(); @@ -133,7 +143,7 @@ public class AnimationSectionSpeedEditor : EditorWindow // ── 미리보기 ── float newDuration = duration / speedMultiplier; float timeDelta = newDuration - duration; - float newLength = actualLength + timeDelta; + float newLength = effectiveLength + timeDelta; EditorGUILayout.LabelField("Preview", EditorStyles.boldLabel); EditorGUI.indentLevel++; @@ -301,6 +311,7 @@ public class AnimationSectionSpeedEditor : EditorWindow float newDuration = duration / speedMultiplier; float timeDelta = newDuration - duration; float actualLength = GetActualLastKeyframeTime(clip); + float effectiveLength = actualLength > 0f ? actualLength : clip.length; Undo.RegisterCompleteObjectUndo(clip, $"Section Speed {speedMultiplier}x (frames {startFrame}~{endFrame})"); @@ -392,7 +403,7 @@ public class AnimationSectionSpeedEditor : EditorWindow } // ── 5. m_StopTime 갱신 (SerializedObject로) ── - float newStopTime = actualLength + timeDelta; + float newStopTime = effectiveLength + timeDelta; var serializedClip = new SerializedObject(clip); SerializedProperty stopTimeProp = serializedClip.FindProperty("m_StopTime"); if (stopTimeProp != null) @@ -433,7 +444,7 @@ public class AnimationSectionSpeedEditor : EditorWindow Debug.Log($"[SectionSpeedEditor] {clip.name}: frames {startFrame}~{endFrame} → {speedMultiplier}x " + $"({duration:F3}s → {newDuration:F3}s) " + - $"| clip: {actualLength:F3}s → {newStopTime:F3}s " + + $"| clip: {effectiveLength:F3}s → {newStopTime:F3}s " + $"| curves: {modifiedCurves}, keyframes: {modifiedKeyframes}, skipped: {skippedCurves}" + $" | events: {(eventsModified ? "modified" : "none")}"); }