TiXL 输出设置(Output Settings)详解:0×0 魔法分辨率、继承规则与输出取景
【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3
TiXL 的输出设置(Output Settings)控制着当前活动输出(active output)如何被尺寸化(sized)与取景(framed),并最终决定最终图像以什么分辨率被渲染。这篇指南将以官方参考文档 OutputSettings.md 为核心骨架,结合 TiXL/t3 仓库源码深入讲解 0×0 "魔法"分辨率(magic resolution)的继承优先级、宽高比保持的实现原理、固定分辨率的适用场景,以及分辨率从输出窗口一路传递到渲染管线的完整链路。读完本文,你将能够准确理解 TiXL 的分辨率体系,并能在实时演出与视频导出场景中正确选择输出分辨率策略。
一、Output Settings 是什么:输出的尺寸化与取景控制
TiXL 的 Output Settings 本质上是针对当前活动输出的一组分辨率与取景控制,它回答了两个问题:
- 最终图像以多大分辨率渲染?——这决定了 3D 场景的投影矩阵、纹理分配与最终画面清晰度。
- 画面如何在输出窗口中呈现?——是铺满、按比例适配,还是固定形状不被拉伸。
官方文档 OutputSettings.md 开篇即说明:"Controls how the active output is sized and framed, including the resolution the final image is rendered at."(控制活动输出如何被尺寸化与取景,包括最终图像渲染时的分辨率)。
在实际界面中,这一设置体现为输出窗口工具栏上的分辨率下拉框(Output Resolution 选择器)。它在源码中的实现位于 Editor/Gui/Windows/Output/OutputWindow.cs 的DrawContent()中:第 326 行通过ResolutionHandling.DrawSelector(ref _selectedResolution, _resolutionDialog)绘制选择器,选择器中的 Tooltip 也明确写道:"Adjust requested output resolution — This can either be an aspect ratio or a fixed resolution. This is used by all Image operators if their resolution is set to 0 or -1."(调整请求的输出分辨率——它可以是宽高比或固定分辨率;所有 Image 算子在分辨率为 0 或 -1 时都会使用它)。
从这句话可以看出,Output Settings 不仅是输出窗口自身的显示设置,更是整个 TiXL 渲染图中"请求分辨率"(Requested Resolution)的全局来源。
二、0×0 "魔法"分辨率:inherit 继承模式
官方文档最核心的概念是默认的 0×0 "魔法"分辨率:
The default "magic" 0×0 resolution means "inherit": it takes the size of an incoming image if one is connected, otherwise the current output window's size, cropping left and right to keep the aspect ratio rather than squashing the picture.
0×0 分辨率代表inherit(继承)模式,其取值遵循以下优先级:
- 有输入图像连接时:直接采用所连接输入图像(incoming image)的尺寸;
- 没有输入图像时:采用当前输出窗口(OutputWindow)的尺寸;
- 无论哪种情况,都保持宽高比——对画面左右进行适配(原文为 cropping left and right),而不是把图片压扁(squashing)。
这种设计的工程意义在于:当你的合成图没有固定输出需求时,TiXL 会自适应地跟随画面内容或窗口大小,让用户专注于构图而不是手工维护分辨率。
源码印证:ComputeResolution() 的继承逻辑
0×0 继承模式的底层实现位于 Editor/Gui/Windows/Output/ResolutionHandling.cs 的Resolution.ComputeResolution()方法(第 116–137 行):
public Int2 ComputeResolution() { if (!UseAsAspectRatio) return Size; var windowSize = ImGui.GetWindowSize(); var paddingForFocusBorder = LayoutHandling.FocusMode ? 0 : 1; // 0×0(Fill):直接返回窗口尺寸 if (Size.Width <= 0 || Size.Height <= 0) { return new Int2((int)windowSize.X - paddingForFocusBorder * 2, (int)windowSize.Y - paddingForFocusBorder * 2); } // 固定宽高比:按窗口大小推导出保持比例的尺寸 var windowAspectRatio = windowSize.X / windowSize.Y; var requestedAspectRatio = (float)Size.Width / Size.Height; return (requestedAspectRatio > windowAspectRatio) ? new Int2((int)windowSize.X, (int)(windowSize.X / requestedAspectRatio)) : new Int2((int)(windowSize.Y * requestedAspectRatio), (int)windowSize.Y); }该实现与文档描述一一对应:
UseAsAspectRatio为false(即选择的是 480p/720p/1080p 这类固定分辨率)时,直接返回Size,不随窗口变化;- 尺寸为 0 或负数(0×0 "Fill" 模式)时,返回窗口的像素尺寸——这就是"魔法分辨率"继承窗口大小的实现;
- 其余情况(如 16:9、4:3 等比模式)按窗口实际宽高比推导:请求宽高比大于窗口宽高比时宽度取窗口宽度、高度按比例缩小,反之高度取窗口高度、宽度按比例缩小。无论哪种分支,画面都不会被拉伸变形,这与文档中 "rather than squashing the picture"(不压扁画面)的表述完全一致。
需要说明的是,源码中的这种适配本质上是"letterbox/pillarbox"式的等比缩放:画面始终完整可见,多余空间留空(在输出窗口中以背景色呈现)。这与关联文档 OutputWindow.md 中对填充模式(fill mode)的描述互相印证:"In fill mode the view matches the panel's height and pads the sides to your set aspect ratio, so resizing the panel reflows the image without distorting it."(填充模式下视图匹配面板高度并向两侧留白以保持设定宽高比,因此拖拽面板时画面会重新排布而不会失真)。
三、固定分辨率:纹理需要保持特定形状时
官方文档紧接着给出了继承模式的反例与选择依据:
Set a real fixed resolution instead when a texture must stay a specific shape — for example a square shadow sprite — regardless of how you drag the window.
也就是说,当纹理必须保持特定形状时(例如一个方形阴影精灵square shadow sprite),无论你怎么拖拽输出窗口,都应该设置一个真实的固定分辨率,而不是使用 0×0 继承模式。
为什么阴影精灵需要固定分辨率?
阴影贴图(shadow sprite)这类资源往往被后续算子(如投影、合成、粒子系统)以"固定尺寸采样"的方式消费。如果分辨率跟随窗口大小或输入图像变化,阴影的采样密度和覆盖范围会随窗口拖拽而改变,导致渲染结果不稳定。固定分辨率能保证:
- 纹理形状恒定(例如始终为正方形),下游算子对纹理解释一致;
- 渲染分辨率与窗口交互解耦,窗口怎么拖都不影响实际输出纹理;
- 在实时演出中,输出给投影仪 / Spout / NDI 的信号形状可预期。
如何设置固定分辨率
在输出窗口工具栏的分辨率下拉框中:
- 选择内置的固定分辨率项(480p / 720p / 1080p / 4k / 8k 等);
- 或者点击Add添加自定义分辨率,通过弹出的编辑对话框(
EditResolutionDialog)指定宽高。
源码中,新增分辨率会先以 256×256 的默认值进入列表(见 ResolutionHandling.cs 第 45–50 行的 "Add" 菜单项处理),随后你可以在对话框中修改标题与宽高。分辨率对象必须通过IsValid校验(第 139–148 行)才会被真正使用:标题非空、标题在列表中唯一、宽高均大于 0 且小于 16384。
四、分辨率下拉框:内置列表与 resolutions.json 持久化
内置分辨率列表
ResolutionHandling.cs 第 65–79 行定义了 TiXL 出厂默认的分辨率列表:
| 标题 | 尺寸(宽×高) | 模式 |
|---|---|---|
| Fill | 0×0 | 宽高比(0×0 继承窗口) |
| 1:1 | 1×1 | 宽高比 |
| 16:9 | 16×9 | 宽高比 |
| 4:3 | 4×3 | 宽高比 |
| 480p | 850×480 | 固定分辨率 |
| 720p | 1280×720 | 固定分辨率 |
| 1080p | 1920×1080 | 固定分辨率 |
| 4k | 3840×2160 | 固定分辨率 |
| 8k | 7680×4320 | 固定分辨率 |
| 4k Portrait | 2160×3840 | 固定分辨率(竖屏) |
需要注意:
- Fill(0×0)是
DefaultResolution(第 83 行Resolutions[0]),即默认选中项,也就是文档中所说的"魔法"分辨率; - 宽高比模式(1:1、16:9、4:3)在
Resolution构造时通过useAsAspectRatio: true标记,它们提供的是比例约束而非具体像素值,最终像素尺寸由ComputeResolution()结合窗口大小实时推导; - 固定分辨率(480p 及以上)则直接给出确切像素,其中 480p 采用 850×480 这一 TiXL 特有的非标准宽度(而非标准 854),使用时需注意。
resolutions.json:自定义列表的持久化
用户新增或删除的分辨率条目会被持久化到配置文件resolutions.json,其路径由FileLocations.SettingsDirectory决定(见 ResolutionHandling.cs 第 82 行):
private static readonly string _filePath = System.IO.Path.Combine(FileLocations.SettingsDirectory, "resolutions.json");Save()方法(第 60–63 行)在每次增删条目后通过JsonUtils.TrySaveJson(_resolutions, _filePath)落盘;程序启动时通过JsonUtils.TryLoadingJson<List<Resolution>>(_filePath)加载,加载失败则回退到内置默认列表。这意味着你为某台演出机器定制好的分辨率集合(例如舞台 LED 屏的异形分辨率)可以跨项目复用。
五、分辨率的传递链路:从窗口 UI 到渲染管线
输出设置不只是窗口的显示偏好,它最终会写入EvaluationContext.RequestedResolution,成为整张算子图求值时的全局"请求分辨率"。完整的传递链路如下:
第 1 步:输出窗口计算请求分辨率
在 OutputWindow.cs 第 489–492 行,每次绘制窗口内容时都会刷新请求分辨率:
RequestedResolution = RenderProcess.TryGetActiveExportResolution(out var overrideResolution) ? overrideResolution : _selectedResolution.ComputeResolution(); EvaluationContext.RequestedResolution = RequestedResolution;逻辑是:
- 如果当前正在进行导出(
RenderProcess处于活跃状态),则优先使用导出会话的分辨率覆盖(TryGetActiveExportResolution),保证实时预览与导出文件分辨率一致; - 否则使用用户在下拉框中选择的分辨率经
ComputeResolution()计算后的结果。
第 2 步:写入 EvaluationContext
EvaluationContext.RequestedResolution是类型为Int2的公共属性,定义在 Core/Operator/EvaluationContext.cs 第 121 行。它是所有 Image 算子(在分辨率参数为 0 或 -1 时)以及相机投影共同依赖的全局量。
第 3 步:影响相机投影(宽高比)
RequestedResolution最直接的影响体现在相机投影矩阵上。在 EvaluationContext.cs 的SetViewFromCamera()(第 75–87 行)与SetDefaultCamera()(第 89–96 行)中:
var aspectRatio = (float)RequestedResolution.Width / RequestedResolution.Height; CameraToClipSpace = GraphicsMath.PerspectiveFovRH(fov, aspectRatio, 0.01f, 1000);也就是说,请求分辨率的宽高比直接决定了透视相机的视野纵横比。如果分辨率设置不当(例如选择了与画面内容不匹配的宽高比),即使纹理没有被拉伸,3D 场景的取景(framing)也会发生改变——这正是文档标题中 "sized and framed"(尺寸化与取景)两个词的完整含义:sized决定像素尺寸,framed决定宽高比与取景。
第 4 步:Image 算子的分辨率回退
如前文 Tooltip 所述,所有 Image 算子在自身分辨率设置为 0 或 -1 时会回退使用EvaluationContext.RequestedResolution。这保证了"输出设置"成为整个合成图的统一分辨率基准:你只需要在输出窗口设置一次,所有遵循约定的算子都会随之工作。
六、输出窗口状态持久化:每个窗口记住自己的分辨率
Output Settings 的每次选择都会作为输出窗口状态的一部分被保存。其数据结构定义在 Editor/Gui/Windows/Output/OutputWindowState.cs(第 39–43 行):
// Resolution public string? ResolutionTitle; public int ResolutionWidth; public int ResolutionHeight; public bool ResolutionUseAsAspectRatio;这些字段通过OutputWindow.SyncCopyFieldsToState()每帧同步,并在保存项目时以OutputWindows数组的形式写入.t3ui文件的 Settings 块(见 OutputWindowState.cs 第 74–80 行的WriteAllToJson)。重新打开项目时,OutputWindow会通过ResolutionHandling.FindByTitle()(ResolutionHandling.cs 第 85–97 行)按标题找回对应的分辨率对象,标题找不到则按存储的宽高与宽高比标志重建(见 OutputWindow.cs 第 699–705 行)。
实用含义:分辨率选择是按窗口实例、随项目保存的。你可以为预览窗口选 1080p、为输出窗口选 4k,并且这些偏好会随着.t3ui文件被版本管理、被团队成员共享。
七、渲染/视频导出时的分辨率规则
输出设置的分辨率规则同样作用于视频与图像序列导出。官方文档 RenderSettings.md 明确指出:
Keep an eye on the output resolution, which follows the same rules as the output window unless you set a fixed size.
(注意输出分辨率——除非你设置了固定尺寸,否则它遵循与输出窗口相同的规则。)
在源码 Editor/Gui/Windows/RenderExport/RenderProcess.cs 中可以验证这一规则:
- 第 93 行:实时抓取(realtime grabs)时
settings.ResolutionFactor = 1f,即以原生尺寸捕获实时纹理; - 第 117 行:
TryGetRenderResolution(settings, out var requestedResolution)解析出导出请求分辨率; - 第 125 行:将其写入
RenderToFileResolution,随后传递给视频编码器(第 148 行记录renderedSize=宽x高)。
同时,导出时会通过TryGetActiveExportResolution()(被 OutputWindow.cs 第 489 行调用)把导出分辨率反向覆盖到输出窗口的请求分辨率上,确保你在渲染的同时看到的就是最终导出的画面。如果你在渲染设置面板中为导出指定了固定尺寸,导出将使用该尺寸;否则导出分辨率跟随输出窗口的当前设置(包括 0×0 继承模式下的窗口尺寸)。
八、程序化控制分辨率:SetRequestedResolution 算子
除了在输出窗口手动选择,TiXL 还提供算子级的分辨率控制——SetRequestedResolution。其官方文档位于 .help/docs/operators/lib/render/shading/SetRequestedResolution.md,它属于Lib.render.shading分组,功能是"设置请求的分辨率(类似输出窗口的分辨率下拉框)"。
该算子提供三个输入参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| Texture | Texture2D | 输入的纹理数据 |
| Resolution | Int2 | 当宽高两个值都大于 1 时,强制设定新的分辨率 |
| ScaleResolution | Single | 可选的缩放因子,作用于原始分辨率或新设定的分辨率 |
它的工程意义在于:分辨率不再只是窗口级的手动设置,而是可以成为算子图中的一个数据流。例如你可以根据输入视频的实际尺寸、或者根据舞台输出的动态需求,在图中实时调整请求分辨率,而无需人工干预窗口设置。文档同时建议使用者先充分理解 TiXL 的分辨率体系(即本文所讲的内容)再使用该算子,因为它会影响所有以 0 或 -1 回退的 Image 算子。
九、实践建议与常见陷阱
综合官方文档与源码,以下是关于 Output Settings 的实践要点:
默认就用 0×0 Fill(继承)模式:当你的合成以窗口预览为主、没有固定输出需求时,
Fill是最省心的选择——它跟随输入图像或窗口尺寸,自动保持宽高比,不压扁画面。固定分辨率用于形状敏感的内容:凡是下游需要"固定形状纹理"的场合——如方形阴影精灵、需要精确像素对齐的 UI/文字合成、输出给硬件设备(LED 屏、投影映射)的信号——务必切换到明确的固定分辨率(1080p、4k 等),避免窗口拖拽引发渲染变化。
注意宽高比会改变 3D 取景:由于
RequestedResolution直接参与相机投影矩阵的宽高比计算(见 EvaluationContext.cs),切换分辨率宽高比(如从 16:9 切到 4:3)会改变 3D 场景的视野范围,而不只是纹理形状。理解 480p 的非标准宽度:内置 480p 是 850×480 而非标准 854×480,如需严格标准尺寸请用 Add 自定义。
自定义分辨率会持久化到 resolutions.json:位置在
FileLocations.SettingsDirectory下(ResolutionHandling.cs),可在多项目间复用,但注意它是全局设置而非项目设置。导出与预览共享分辨率规则:渲染设置面板默认跟随输出窗口的分辨率(除非你显式设置固定尺寸,见 RenderSettings.md);导出进行中,输出窗口会显示导出分辨率,便于所见即所得。
动态分辨率需求交给 SetRequestedResolution 算子:当分辨率需要在演出中随数据流变化时,使用 SetRequestedResolution 算子以参数驱动,注意其 Resolution 参数需两个分量都大于 1 才生效。
十、延伸阅读
- 输出窗口本体:OutputWindow.md —— 查看 1:1/Fit 视图模式与 fill mode 的呈现行为;
- 渲染导出面板:RenderSettings.md —— 时间范围、格式、自动递增版本号与分辨率规则;
- 当前合成(Composition)概念:Composition.md —— 理解"活动输出"由当前 Composition 的输出驱动;
- 核心实现:ResolutionHandling.cs、OutputWindow.cs、EvaluationContext.cs;
- 分辨率持久化:OutputWindowState.cs;
- 导出链路:RenderProcess.cs。
【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考