1
05 导出动画
ww-rm edited this page 2025-08-30 21:21:36 +08:00

导出动画

预览图

image2

本页面介绍如何导出需要的动画素材.

使用导出功能

导入模型之后, 选中需要导出的模型项, 右键单击, 在弹出菜单中选择需要的导出格式, 目前支持 4 类导出格式:

  • 单帧画面. 该格式类似截图功能, 点击导出后会截取点击时的那一帧画面, 并且支持设置导出格式和质量参数 (如果指定的格式可以设置). 如果需要导出某个确切的画面可以暂停预览画面后逐帧调整.
  • 帧序列. 导出图像格式为 png 的帧序列.
  • 动图/视频. 基于 FFmpeg 工具的视频导出, 在内部会将帧序列送入 FFmpeg 的输入, 并合并成指定的动图/视频格式.
  • 自定义导出. 适用于更复杂的需求, 同样基于 FFmpeg 工具, 但是可以定制输入的命令行参数, 程序只起到了提供帧序列的功能.

一般情况下, 导出的内容与预览画面一致, 并且悬停导出参数面板可以得到大部分参数的提示文本, 但是在此说明一些特殊参数的效果.

  • 导出单个. 这个参数用于指定在选择了多项进行导出时, 是将它们合并导出在一个文件上还是分别独立导出, 如果未选择导出单个, 则选中的模型将逐个导出在各自的资源文件夹内, 否则将所有模型在一个画面上导出到指定的输出文件夹内.
  • 背景颜色. 导出内容允许使用带半透明效果的背景色, 前提是导出的格式本身支持半透明背景, 例如 Gif/Webm 格式, 否则在本身不支持半透明背景的格式下使用半透明背景色可能导致画面边缘异常.
  • 四周边距. 也可以理解为 "出血位", 是在原本像素大小上的外部扩充大小, 对应英语术语的 "Margin", 目前支持四周边距取同一个像素值.
  • 自动分辨率 & 最大分辨率. 启用自动分辨率可以忽略画面的参数, 直接计算模型的真实大小, 并按模型的大小来得到一个刚好放得下模型的矩形画布大小进行导出. 但是某些情况下自动计算的画布大小会非常大, 例如达到 4k+, 极易导致导出时资源耗尽卡死, 因此可以使用最大分辨率来限制画布边长的最大值, 当超过最大值时会自动将画布大小等比例缩放至最大分辨率之下.

值得一提的是, 受限于某些像素格式, 导出的内容分辨率一定会被就近调整为偶数值.

  • 时长. 当时长取负数时, 将会自动使用模型的动画时长最大值, 如果是合并导出单个文件则使用所有模型所有动画的时长最大值. 当时长不足一帧时, 至少导出一帧起始帧.
  • 导出速度. 修改导出速度不影响时长, 仅在时长内调整速度.
  • 保留最后一帧. 此处指的是是否保留最后一个不完整帧 (如果存在), 对于恰好能整除帧间隔的时长, 总是导出 n + 1 个帧 (包含首尾帧), 当时长无法整除, 最后一个帧间隔不足一帧时长时, 可以通过该参数控制是否保留不完整的帧. 这个参数在生成循环动图时可以控制动图的循环是否流畅.

在使用基于 FFmpeg 的导出时, 针对不同格式提供了各自的关键参数, 这些参数仅在对应的格式下生效, 具体可以通过悬停鼠标获取提示文本查看说明.

基于 FFmpeg 的导出

基于 FFmpeg 的导出分为两种, 一种是提供了预设格式的导出, 另一种是完全自定义命令行参数的导出.

前者可以在 Spine.Exporters.FFmpegVideoExporter 类下查看不同格式使用的预设参数, 这里简单贴一下代码片段.

private void SetGifOptions(FFMpegArgumentOptions options)
{
    // Gif 固定使用 256 调色板和 128 透明度阈值
    var v = "split [s0][s1]";
    var s0 = "[s0] palettegen=max_colors=256 [p]";
    var s1 = "[s1][p] paletteuse=alpha_threshold=128";
    var customArgs = $"-vf \"unpremultiply=inplace=1, {v};{s0};{s1}\" -loop {(_loop ? 0 : -1)}";
    options.ForceFormat("gif")
        .WithCustomArgument(customArgs);
}

private void SetWebpOptions(FFMpegArgumentOptions options)
{
    var customArgs = $"-vf unpremultiply=inplace=1 -quality {_quality} -loop {(_loop ? 0 : 1)} -lossless {(_lossless ? 1 : 0)}";
    options.ForceFormat("webp").WithVideoCodec("libwebp_anim").ForcePixelFormat("yuva420p")
        .WithCustomArgument(customArgs);
}

private void SetMp4Options(FFMpegArgumentOptions options)
{
    // XXX: windows 默认播放器在播放 MP4 格式时对于 libx264 编码器只支持 yuv420p 的像素格式
    // 但是如果是 libx265 则没有该限制
    var customArgs = "-vf unpremultiply=inplace=1";
    options.ForceFormat("mp4").WithVideoCodec("libx264").ForcePixelFormat("yuv420p")
        .WithFastStart()
        .WithConstantRateFactor(_crf)
        .WithCustomArgument(customArgs);
}

private void SetWebmOptions(FFMpegArgumentOptions options)
{
    var customArgs = "-vf unpremultiply=inplace=1";
    options.ForceFormat("webm").WithVideoCodec("libvpx-vp9").ForcePixelFormat("yuva420p")
        .WithConstantRateFactor(_crf)
        .WithCustomArgument(customArgs);
}

private void SetMkvOptions(FFMpegArgumentOptions options)
{
    var customArgs = "-vf unpremultiply=inplace=1";
    options.ForceFormat("matroska").WithVideoCodec("libx265").ForcePixelFormat("yuv444p")
        .WithConstantRateFactor(_crf)
        .WithCustomArgument(customArgs);
}

private void SetMovOptions(FFMpegArgumentOptions options)
{
    var customArgs = "-vf unpremultiply=inplace=1";
    options.ForceFormat("mov").WithVideoCodec("prores_ks").ForcePixelFormat("yuva444p10le")
        .WithFastStart()
        .WithCustomArgument($"-profile {_profile}")
        .WithCustomArgument(customArgs);
}

其中 "-vf unpremultiply=inplace=1"必需参数, 已经为所有预设格式增加, 在自定义格式内也已增加.