预渲染:生成式视觉效果与稳定的素材
五条路径,遵循同一套通用规则。代码绘制的作品成为一段素材,作为 video 放置:请先阅读该路径。SVG 静态图成为一张 PNG,作为 image 放置:跳转到 SVG 路径。Lottie 动画也变成一段素材,每一帧使用一个新播放器绘制:跳转到 Lottie 路径。3D 场景变为透明素材或静态 PNG:跳转到 3D 场景路径。源视频稳定会烘焙出一个新剪辑:跳转到 稳定路径。所有操作都在渲染之外进行,因此每个绘制器解码的都是相同的像素。
Montagent 没有着色器或脚本文件(ADR-0017)。effects 列表之外的外观由您自己的代码绘制,一次性编码为素材,并作为普通的 video 放置。格式、模式和绘制器保持不变(ADR-0156 §7,ADR-0233)。
何时使用
优先采用命名路径。查看 montagent://schema/index.json 中的 effects 列表:如果列表中的某个成员(模糊、阴影、色调、blend、键控 mask)能实现所需外观,就使用它。只有当没有成员、绘制或混合模式能合成该外观时,才使用预渲染:例如变形、马赛克、镜头光晕、粒子、程序化图案或外部 3D 模型/场景。
当您拿到 SVG 文件形式的矢量图形(标志、图标、插图),或者静态图最容易用 SVG 绘制时,使用 SVG 路径。没有任何元素接受 SVG 文件(ADR-0171)。带有动画的 SVG(SMIL 或 CSS)不适用此路径:它只会被光栅化为一个静态帧,动画会丢失。请改用已放置图像的 scale、rotation 和 opacity 进行关键帧设置。
当您拿到 3D 资源(.glb、.gltf、.obj、.fbx、.blend、.c4d)或 3D 场景时,使用 3D 场景路径。没有任何元素接受 3D 模型或多通道通行证(ADR-0167,ADR-0233)。无头渲染会在渲染之外生成透明的 ProRes 4444 / PNG 素材,可直接用于 2D 放置。
当您拿到 Lottie JSON 文件(After Effects 导出文件、LottieFiles 动画),或者某个运动最容易从 Lottie 获取时,使用 Lottie 路径。没有任何元素接受 Lottie 文件(ADR-0171)。它有三个代价:固定分辨率:素材是光栅图,大小由渲染尺寸决定。配方工具链:需要安装一个 Lottie 播放器来重现作品(绝不会用于渲染项目)。素材大小:在 1080p 和 25fps 下,MOV 中的 PNG 序列从每秒约 6 MB(平滑的艺术)到每秒约 141 MB(噪点多的艺术)不等,因此请按实际显示尺寸渲染,不要更大。如果运动只涉及几个形状,对原生 rect、ellipse 和 path 元素进行关键帧设置会更小且保持清晰。
预渲染的作品是固定素材。其尺寸、帧率和时长在渲染时确定。更改外观意味着需要重新渲染,因此请先确定简报中的尺寸、帧率和时长,并与项目的 fps 匹配。
通用规则
每条路径都读取这些规则。它们只编写一次。
- 尺寸。 以像素为单位的字面
width和height,在fit、scale以及任何关键帧缩放之后,按作品曾显示的最大尺寸进行光栅化或绘制。绝不要从 SVG 的viewBox推导尺寸:viewBox设置的是绘图的比例,而不是像素,并且不同工具对没有viewBox的文件处理方式不同。在配方中写明尺寸。后续的放大操作会对光栅图进行重采样,因此请重新运行更大的配方,而不是简单地放大。 - 文本。 仅限已供应的字体,或将文本转换为轮廓。切勿使用系统字体:没有该字体的机器会显示其他内容。找不到字体应视为构建失败,而不是忽略的文本段。例如,
usvg会记录缺失并跳过文本,因此build会读取 SVG 的font-family值,对照您在fonts中列出的字体文件,并在光栅化器本身的字体警告处也视为失败。 - 配方。 包括源副本、确切命令、工具版本、尺寸,以及解码后像素的哈希值,该哈希值通过解码器使用的相同读取方式获取。重建报告应显示匹配或第一个差异,并且绝不比较文件字节。配方部分说明了其位置。
步骤
按顺序执行每个步骤。当步骤 5 通过时,作品即被放置。
- 绘制。 使用任何工具编写代码,生成具有固定
width、height和frames数量的 RGBA 帧:未绘制处为透明。代码将原始 RGBA 数据写入标准输出,或将 PNG 文件f00000.png、f00001.png等写入PRERENDER_FRAMES_DIR环境变量指定的文件夹。从PRERENDER_WIDTH、PRERENDER_HEIGHT、PRERENDER_FPS和PRERENDER_FRAMES中读取尺寸。使用整数运算或固定种子,以便第二次运行时绘制相同的字节。示例作品是最小的可行示例。 - 规范。 在代码旁边编写构建规范:
name、out(项目的媒体文件夹)、width、height、fps、frames、render(运行代码的 argv)、files(代码所需的所有文件),以及当代码写入 PNG 时的input设为"png"。运行python3 scripts/prerender.py --help查看所有键。如果任何库的版本变化会影响像素(例如画布库、无头浏览器),请添加versions。 - 构建。 运行
python3 scripts/prerender.py build <spec>。它会运行代码,将输出编码为一个<name>.mov文件,解码它,并在第一个与代码绘制的帧不同的帧处失败。读取最后一行:N frames, decoded = drawn。 - 放置。 将素材作为普通的
video元素添加到项目中(下方),或运行python3 scripts/prerender.py place <project> <placing>,其中<placing>是一个 JSON 文件,包含{"source": "media/<name>.mov"}以及可选的id、at、x、y、origin、width、height、fit、track、layer。该命令会打印添加了元素后的项目,因此请将其重定向到一个新文件。 - 检查。 对项目运行
validate并修复所有错误。然后运行montagent probe检查素材,确认其报告包含 alpha 通道(carries: true)。只有在确认后,才运行frame命令渲染一个包含该作品的图块,并检查透明部分是否显示了背后的内容。
{
"frame": {"width": 640, "height": 360}, "fps": 25, "background": "#101418", "duration": 480, "output": "out/pulse.mp4",
"tracks": [
{"name": "prerender", "layer": 10, "elements": [
{"id": "pulse", "type": "video", "start": 0, "end": 480, "source": "media/pulse.mov", "source_start": 0, "source_end": 480, "volume": 0, "x": 320, "y": 180, "origin": "center", "width": 320, "height": 240, "fit": "contain"}
]}
]
}
该元素是一个普通的 video:可以对 opacity、scale 和 position 进行关键帧设置,添加 effects 和 blend,并将其像任何剪辑一样放置在轨道上。素材没有声音,因此 volume 为 0。其 end 减去 start 等于素材的长度;source_end 也是相同的长度。
SVG 路径
输入: 一个 SVG 文件,以及来自通用规则的像素尺寸。
- 供应字体 SVG 文本所使用的字体,使用
montagent fonts vendor命令,并为每个<text>元素设置其家族的font-family属性。或者在绘图工具中将文本转换为轮廓,不使用任何字体。 - 规范。 在 SVG 旁边编写一个构建规范,设置
"input": "svg":包含name、out、svg、字面值width和height、render(光栅化器的 argv,其中{width}、{height}和{out}是占位符)、files、fonts和versions。不包含 fps 和帧数。 - 光栅化。 运行
python3 scripts/prerender.py build <spec>,在渲染之外执行一次光栅化器。任何能写入单张 RGBA PNG 的工具都可以:如resvg命令行、无头浏览器、Inkscape。跳过系统字体,并使用已供应的字体,如下方规范所示。该命令会写入<name>.png及其配方,并在遇到缺失字体时失败。 - 放置 PNG 文件作为普通的
image元素(下方),或运行python3 scripts/prerender.py place <project> <placing>,设置{"source": "media/<name>.png", "duration": <ms>}以及可选的id、at、x、y、origin、width、height、fit、track、layer。 - 检查。 运行
validate并修复所有错误,然后运行frame命令渲染一个包含该图像的图块,并检查透明部分是否显示了背后的内容。
示例规范,针对示例 SVG(包含形状、渐变和以已供应字体设置的文本),以三倍于其 viewBox 的尺寸进行光栅化:
{
"name": "mark", "out": "media", "input": "svg", "svg": "sample_art.svg", "width": 480, "height": 270,
"render": ["resvg", "--skip-system-fonts", "--use-font-file", "Inter-Bold.ttf", "-w", "{width}", "-h", "{height}", "sample_art.svg", "{out}"],
"files": ["sample_art.svg"], "fonts": ["Inter-Bold.ttf"],
"versions": {"resvg": ["resvg", "--version"]}
}
PNG 具有固有的像素尺寸,因此它作为普通的 image 元素引入,并且 ADR-0015 的 fit 规则适用于任何 PNG:可以是 contain(保持框的宽高比),或 literal。以其自身尺寸放置,并设置 fit 为 contain,即可实现 1:1 绘制。如果以大于光栅化尺寸的方式显示,光栅图将被重采样:请以更大的尺寸重新运行配方。
{
"frame": {"width": 640, "height": 360}, "fps": 25, "background": "#101418", "duration": 2000, "output": "out/mark.mp4",
"tracks": [
{"name": "art", "layer": 10, "elements": [
{"id": "mark", "type": "image", "start": 0, "end": 2000, "source": "media/mark.png", "x": 320, "y": 180, "origin": "center", "width": 480, "height": 270, "fit": "contain"}
]}
]
}
运行 validate。该图像是一个普通元素:可以对 opacity、scale 和 position 进行关键帧设置,添加 effects,并将其放置在轨道上。
Lottie 路径
输入: 一个 Lottie JSON 文件、一个尺寸、一个 fps 和一个帧范围。Lottie 自身的 w、h 和 fr 是可选的输入来源,而非规则:尺寸遵循通用规则(显示的最大尺寸,作为字面值),并且您在规范中写明 fps 和帧数。
- 选择一个播放器 能够写入 RGBA 帧,并在
versions中记录其名称和版本。该技能不指定播放器:预渲染在渲染之外运行一次,绘制器永远不会看到该播放器。示例播放器 是 ThorVG,通过pip install thorvg-python==1.1.3安装。 - 规范。 在 Lottie 文件旁边编写一个构建规范,设置
"input": "lottie":包含name、out、lottie、字面值width和height、fps、frames、render、files、fonts和versions。render是播放器的 argv,其中{width}、{height}、{frame}和{out}是占位符:它绘制一帧作为原始 RGBA 数据写入{out}。可选的start和step设置每个素材帧对应哪个 Lottie 帧(第i帧对应start + i * step;step默认为 Lottie 的fr除以fps)。运行python3 scripts/prerender.py --help查看所有键。 - 构建。 运行
python3 scripts/prerender.py build <spec>,它会首先读取 Lottie 文件,如果 Lottie 使用以下内容,则拒绝并列出每种情况:表达式、播放器被记录为不支持的图层效果(在allow_effects中列出支持的),或者文本的字体既没有嵌入字形路径,也没有在fonts中提供已供应的文件。 播放器会悄无声息地丢弃所有这些内容,因此继续构建将会生成不同的动画。然后,它每帧运行一次render,每次都启动一个新进程,读取播放器自己报告跳过的内容(任何包含 "skipped"、"ignored" 或 "unsupported" 的行都视为构建失败),按照编解码器的规定编码一个<name>.mov文件,并在第一个与播放器绘制结果不同的帧处失败。 - 放置 素材作为普通的
video元素,或使用place命令(如步骤中所述)。运行validate和montagent probe检查 MOV 文件:确认其报告包含 alpha 通道(carries: true)。然后运行frame命令渲染一个包含该作品的图块,并检查透明部分是否显示了背后的内容。
为什么每帧使用一个新播放器。 框架绝不会向前跳转播放器。ThorVG 忽略低于 0.001 的帧变化,因此跳转后的位置取决于之前的跳转,而 Skottie 的跳转会改变其动画对象。在其他帧之后绘制的帧可能与最先绘制的同一帧不同,并且重建将无法匹配。
…
[为翻译截断]