From 08b1e3d95ae7ed47046a1d68f652c483764fb25d Mon Sep 17 00:00:00 2001 From: dal4segno Date: Thu, 2 Apr 2026 13:45:06 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20Section=20Speed=20Editor=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=B3=B8=20=EA=B3=A1=EC=84=A0=20=EC=97=86=EB=8A=94?= =?UTF-8?q?=20=ED=81=B4=EB=A6=BD=20length=200=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=ED=91=9C=EC=8B=9C=EB=90=98=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Mixamo export 클립 등 m_FloatCurves만 있는 경우 bone transform 곡선이 없어 length가 0으로 계산되던 문제 수정 - bone 곡선이 없으면 m_StopTime을 기준으로 폴백하도록 effectiveLength 로직 추가 --- .../Editor/AnimationSectionSpeedEditor.cs | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) 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")}"); }