增加最后一帧参数
This commit is contained in:
@@ -24,6 +24,11 @@ namespace SpineViewer.Exporter
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float FPS { get; set; } = 60;
|
public float FPS { get; set; } = 60;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否保留最后一帧
|
||||||
|
/// </summary>
|
||||||
|
public bool KeepLast { get; set; } = true;
|
||||||
|
|
||||||
public override string? Validate()
|
public override string? Validate()
|
||||||
{
|
{
|
||||||
if (base.Validate() is string error)
|
if (base.Validate() is string error)
|
||||||
@@ -43,9 +48,21 @@ namespace SpineViewer.Exporter
|
|||||||
if (duration < 0) duration = spine.GetTrackIndices().Select(i => spine.GetAnimationDuration(spine.GetAnimation(i))).Max();
|
if (duration < 0) duration = spine.GetTrackIndices().Select(i => spine.GetAnimationDuration(spine.GetAnimation(i))).Max();
|
||||||
|
|
||||||
float delta = 1f / FPS;
|
float delta = 1f / FPS;
|
||||||
int total = Math.Max(1, (int)(duration * FPS)); // 至少导出 1 帧
|
int total = (int)(duration * FPS); // 完整帧的数量
|
||||||
|
|
||||||
worker?.ReportProgress(0, $"{spine.Name} 已处理 0/{total} 帧");
|
float deltaFinal = duration - delta * total; // 最后一帧时长
|
||||||
|
int final = (KeepLast && (deltaFinal > 1e-3)) ? 1 : 0;
|
||||||
|
|
||||||
|
int frameCount = 1 + total + final; // 所有帧的数量 = 起始帧 + 完整帧 + 最后一帧
|
||||||
|
|
||||||
|
worker?.ReportProgress(0, $"{spine.Name} 已处理 0/{frameCount} 帧");
|
||||||
|
|
||||||
|
// 导出首帧
|
||||||
|
var firstFrame = GetFrame(spine);
|
||||||
|
worker?.ReportProgress(1 * 100 / frameCount, $"{spine.Name} 已处理 1/{frameCount} 帧");
|
||||||
|
yield return firstFrame;
|
||||||
|
|
||||||
|
// 导出完整帧
|
||||||
for (int i = 0; i < total; i++)
|
for (int i = 0; i < total; i++)
|
||||||
{
|
{
|
||||||
if (worker?.CancellationPending == true)
|
if (worker?.CancellationPending == true)
|
||||||
@@ -54,11 +71,20 @@ namespace SpineViewer.Exporter
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var frame = GetFrame(spine);
|
|
||||||
spine.Update(delta);
|
spine.Update(delta);
|
||||||
worker?.ReportProgress((int)((i + 1) * 100.0) / total, $"{spine.Name} 已处理 {i + 1}/{total} 帧");
|
var frame = GetFrame(spine);
|
||||||
|
worker?.ReportProgress((1 + i + 1) * 100 / frameCount, $"{spine.Name} 已处理 {1 + i + 1}/{frameCount} 帧");
|
||||||
yield return frame;
|
yield return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 导出最后一帧
|
||||||
|
if (final > 0)
|
||||||
|
{
|
||||||
|
spine.Update(deltaFinal);
|
||||||
|
var finalFrame = GetFrame(spine);
|
||||||
|
worker?.ReportProgress(100, $"{spine.Name} 已处理 {frameCount}/{frameCount} 帧");
|
||||||
|
yield return finalFrame;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -67,10 +93,24 @@ namespace SpineViewer.Exporter
|
|||||||
protected IEnumerable<SFMLImageVideoFrame> GetFrames(Spine.Spine[] spinesToRender, BackgroundWorker? worker = null)
|
protected IEnumerable<SFMLImageVideoFrame> GetFrames(Spine.Spine[] spinesToRender, BackgroundWorker? worker = null)
|
||||||
{
|
{
|
||||||
// 导出单个时必须根据 Duration 决定导出时长
|
// 导出单个时必须根据 Duration 决定导出时长
|
||||||
float delta = 1f / FPS;
|
var duration = Duration;
|
||||||
int total = Math.Max(1, (int)(Duration * FPS)); // 至少导出 1 帧
|
|
||||||
|
|
||||||
worker?.ReportProgress(0, $"已处理 0/{total} 帧");
|
float delta = 1f / FPS;
|
||||||
|
int total = (int)(duration * FPS); // 完整帧的数量
|
||||||
|
|
||||||
|
float deltaFinal = duration - delta * total; // 最后一帧时长
|
||||||
|
int final = (KeepLast && (deltaFinal > 1e-3)) ? 1 : 0;
|
||||||
|
|
||||||
|
int frameCount = 1 + total + final; // 所有帧的数量 = 起始帧 + 完整帧 + 最后一帧
|
||||||
|
|
||||||
|
worker?.ReportProgress(0, $"已处理 0/{frameCount} 帧");
|
||||||
|
|
||||||
|
// 导出首帧
|
||||||
|
var firstFrame = GetFrame(spinesToRender);
|
||||||
|
worker?.ReportProgress(1 * 100 / frameCount, $"已处理 1/{frameCount} 帧");
|
||||||
|
yield return firstFrame;
|
||||||
|
|
||||||
|
// 导出完整帧
|
||||||
for (int i = 0; i < total; i++)
|
for (int i = 0; i < total; i++)
|
||||||
{
|
{
|
||||||
if (worker?.CancellationPending == true)
|
if (worker?.CancellationPending == true)
|
||||||
@@ -79,11 +119,20 @@ namespace SpineViewer.Exporter
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var frame = GetFrame(spinesToRender);
|
|
||||||
foreach (var spine in spinesToRender) spine.Update(delta);
|
foreach (var spine in spinesToRender) spine.Update(delta);
|
||||||
worker?.ReportProgress((int)((i + 1) * 100.0) / total, $"已处理 {i + 1}/{total} 帧");
|
var frame = GetFrame(spinesToRender);
|
||||||
|
worker?.ReportProgress((1 + i + 1) * 100 / frameCount, $"已处理 {1 + i + 1}/{frameCount} 帧");
|
||||||
yield return frame;
|
yield return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 导出最后一帧
|
||||||
|
if (final > 0)
|
||||||
|
{
|
||||||
|
foreach (var spine in spinesToRender) spine.Update(delta);
|
||||||
|
var finalFrame = GetFrame(spinesToRender);
|
||||||
|
worker?.ReportProgress(100, $"已处理 {frameCount}/{frameCount} 帧");
|
||||||
|
yield return finalFrame;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Export(Spine.Spine[] spines, BackgroundWorker? worker = null)
|
public override void Export(Spine.Spine[] spines, BackgroundWorker? worker = null)
|
||||||
|
|||||||
@@ -24,5 +24,11 @@ namespace SpineViewer.PropertyGridWrappers.Exporter
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Category("[1] 视频参数"), DisplayName("帧率"), Description("每秒画面数")]
|
[Category("[1] 视频参数"), DisplayName("帧率"), Description("每秒画面数")]
|
||||||
public float FPS { get => Exporter.FPS; set => Exporter.FPS = value; }
|
public float FPS { get => Exporter.FPS; set => Exporter.FPS = value; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保留最后一帧
|
||||||
|
/// </summary>
|
||||||
|
[Category("[1] 视频参数"), DisplayName("保留最后一帧"), Description("当设置保留最后一帧时, 动图会更为连贯, 但是帧数可能比预期帧数多 1")]
|
||||||
|
public bool KeepLast { get => Exporter.KeepLast; set => Exporter.KeepLast = value; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user