fix: Section Speed Editor에서 본 곡선 없는 클립 length 0으로 표시되는 문제 수정
- Mixamo export 클립 등 m_FloatCurves만 있는 경우 bone transform 곡선이 없어 length가 0으로 계산되던 문제 수정 - bone 곡선이 없으면 m_StopTime을 기준으로 폴백하도록 effectiveLength 로직 추가
This commit is contained in:
@@ -54,18 +54,28 @@ public class AnimationSectionSpeedEditor : EditorWindow
|
|||||||
|
|
||||||
// ── 클립 정보 (실제 키프레임 기반) ──
|
// ── 클립 정보 (실제 키프레임 기반) ──
|
||||||
float actualLength = GetActualLastKeyframeTime(clip);
|
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);
|
EditorGUILayout.LabelField("Clip Info", EditorStyles.boldLabel);
|
||||||
EditorGUI.indentLevel++;
|
EditorGUI.indentLevel++;
|
||||||
EditorGUILayout.LabelField("Length (keyframes)", $"{actualLength:F3}s");
|
EditorGUILayout.LabelField("Length", $"{effectiveLength:F3}s");
|
||||||
EditorGUILayout.LabelField("m_StopTime", $"{clip.length: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" +
|
EditorGUILayout.HelpBox($"m_StopTime({clip.length:F3}s)이 실제 키프레임 길이({actualLength:F3}s)와 다릅니다.\n" +
|
||||||
"스피드 변경 시 실제 키프레임 길이를 기준으로 계산합니다.", MessageType.Warning);
|
"스피드 변경 시 실제 키프레임 길이를 기준으로 계산합니다.", 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--;
|
EditorGUI.indentLevel--;
|
||||||
|
|
||||||
EditorGUILayout.Space();
|
EditorGUILayout.Space();
|
||||||
@@ -74,7 +84,7 @@ public class AnimationSectionSpeedEditor : EditorWindow
|
|||||||
fps = EditorGUILayout.IntField("FPS", fps);
|
fps = EditorGUILayout.IntField("FPS", fps);
|
||||||
fps = Mathf.Max(1, 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);
|
EditorGUILayout.LabelField("Target Frame Range", EditorStyles.boldLabel);
|
||||||
@@ -108,7 +118,7 @@ public class AnimationSectionSpeedEditor : EditorWindow
|
|||||||
EditorGUILayout.Space();
|
EditorGUILayout.Space();
|
||||||
|
|
||||||
// ── 타임라인 시각화 ──
|
// ── 타임라인 시각화 ──
|
||||||
DrawTimeline(startTime, endTime, actualLength);
|
DrawTimeline(startTime, endTime, effectiveLength);
|
||||||
|
|
||||||
EditorGUILayout.Space();
|
EditorGUILayout.Space();
|
||||||
|
|
||||||
@@ -133,7 +143,7 @@ public class AnimationSectionSpeedEditor : EditorWindow
|
|||||||
// ── 미리보기 ──
|
// ── 미리보기 ──
|
||||||
float newDuration = duration / speedMultiplier;
|
float newDuration = duration / speedMultiplier;
|
||||||
float timeDelta = newDuration - duration;
|
float timeDelta = newDuration - duration;
|
||||||
float newLength = actualLength + timeDelta;
|
float newLength = effectiveLength + timeDelta;
|
||||||
|
|
||||||
EditorGUILayout.LabelField("Preview", EditorStyles.boldLabel);
|
EditorGUILayout.LabelField("Preview", EditorStyles.boldLabel);
|
||||||
EditorGUI.indentLevel++;
|
EditorGUI.indentLevel++;
|
||||||
@@ -301,6 +311,7 @@ public class AnimationSectionSpeedEditor : EditorWindow
|
|||||||
float newDuration = duration / speedMultiplier;
|
float newDuration = duration / speedMultiplier;
|
||||||
float timeDelta = newDuration - duration;
|
float timeDelta = newDuration - duration;
|
||||||
float actualLength = GetActualLastKeyframeTime(clip);
|
float actualLength = GetActualLastKeyframeTime(clip);
|
||||||
|
float effectiveLength = actualLength > 0f ? actualLength : clip.length;
|
||||||
|
|
||||||
Undo.RegisterCompleteObjectUndo(clip, $"Section Speed {speedMultiplier}x (frames {startFrame}~{endFrame})");
|
Undo.RegisterCompleteObjectUndo(clip, $"Section Speed {speedMultiplier}x (frames {startFrame}~{endFrame})");
|
||||||
|
|
||||||
@@ -392,7 +403,7 @@ public class AnimationSectionSpeedEditor : EditorWindow
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── 5. m_StopTime 갱신 (SerializedObject로) ──
|
// ── 5. m_StopTime 갱신 (SerializedObject로) ──
|
||||||
float newStopTime = actualLength + timeDelta;
|
float newStopTime = effectiveLength + timeDelta;
|
||||||
var serializedClip = new SerializedObject(clip);
|
var serializedClip = new SerializedObject(clip);
|
||||||
SerializedProperty stopTimeProp = serializedClip.FindProperty("m_StopTime");
|
SerializedProperty stopTimeProp = serializedClip.FindProperty("m_StopTime");
|
||||||
if (stopTimeProp != null)
|
if (stopTimeProp != null)
|
||||||
@@ -433,7 +444,7 @@ public class AnimationSectionSpeedEditor : EditorWindow
|
|||||||
|
|
||||||
Debug.Log($"[SectionSpeedEditor] {clip.name}: frames {startFrame}~{endFrame} → {speedMultiplier}x " +
|
Debug.Log($"[SectionSpeedEditor] {clip.name}: frames {startFrame}~{endFrame} → {speedMultiplier}x " +
|
||||||
$"({duration:F3}s → {newDuration:F3}s) " +
|
$"({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}" +
|
$"| curves: {modifiedCurves}, keyframes: {modifiedKeyframes}, skipped: {skippedCurves}" +
|
||||||
$" | events: {(eventsModified ? "modified" : "none")}");
|
$" | events: {(eventsModified ? "modified" : "none")}");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user