BACK TO ARCHIVE
qt pyqt python ui ux vfx pipeline nucleus digipro plugin-architecture

Nucleus:面向动画与视效应用的设计系统

07.27.2024 ADUCG RESEARCH

原文页面:https://animallogic.com/technology/publications/nucleus-a-design-system-for-animation-and-vfx-applications/
PDF:https://animallogic.com/wp-content/uploads/2024/08/Nucleus__A_Design_System_for_Animation_and_VFX_Applications.pdf

本文为 Jon‑Patrick Collins、Anno Schachner(Animal Logic,澳大利亚悉尼)的论文《Nucleus: A Design System for Animation and VFX Applications》的中文翻译与整理;在不丢失技术细节的前提下,做了少量语序与术语统一,以便阅读。

图 1:FilmStudio,使用 Nucleus 设计系统开发的基于 USD 的资产制作应用。
图 1:FilmStudio——一个用于创作基于 USD 资产的应用,使用 Nucleus 设计系统开发。

摘要

我们描述了一种用于开发组件化 Qt 应用(面向动画与视觉特效生产场景)的插件式架构,并讨论该方法在代码复用、稳定性与一致性方面的收益。我们还引入了一个“应用成熟度模型”(Application Maturity Model)作为质量度量,用于刻画一组用于开发复杂交互式应用的最佳实践、设计模式与框架集合。

1 引言

开发复杂的交互式软件应用并不容易。在典型的动画或视效工作室语境下,这件事会更难:不同工种(craft groups)往往以去中心化方式协作;制作周期紧、产品化打磨机会有限;且可投入到架构设计的工程师资源可能更少。

过去二十年间,动画与视效社区逐步见证 Qt 成为跨平台 UI 应用框架的事实标准,取代了 wxWidgets、GTK 以及诸多数字内容创作(DCC)软件自带的旧式专有 UI 工具包。

Qt 的行业标准化为我们带来了机会:相比过去 UI 工具链碎片化的时代,工作室可以集中火力在同一个框架上。然而,Qt 应用开发本身也有门槛:它要求开发者对多种设计模式(例如 MVC、事件的广播者/订阅者、应用编排)具备一定掌握。Qt 生态包含 2000+ 类,对缺乏 UI 开发经验的工程师而言很容易“望而生畏”,从而导致设计模式选择不当、Qt 特性使用不足。

此外(至少以我们的经验),由多个自治工种分别开发的 Qt 应用通常会遵循 Conway’s Law(康威定律)[7]:形成一系列高度定制、难以复用的“量身方案”,引发重复劳动、设计割裂,并减少跨团队协作机会。

在 Animal Logic,我们亲身经历了这些挑战,并通过一系列最佳实践、设计模式与框架来更好地发挥 Qt 在快节奏、分布式、多工作室环境中的优势。这条演进路径最终促成了 Nucleus 设计系统:一个在 Animal Logic 内部被广泛使用的框架,也是我们多套 USD 系统的基础,包括 Forge™[2](基于 Maya 的动画系统)、Filament™[1](独立灯光系统)、FilmStudio™[4](独立 USD 资产制作系统)以及 Plasma™[5](基于 Nuke 的合成系统)。

本文将结合“应用成熟度模型”来描述 Nucleus 设计系统以及关键设计决策。该成熟度模型的灵感来自用于描述 Web 服务的 Richardson Maturity Model(理查森成熟度模型)[6]。

2 应用成熟度模型

2.1 Level 0:Qt 基线部署

Animal Logic 早期的 UI 开发基本是临时性、零散且缺少组织的:有些 UI 使用宿主 DCC 的工具包实现,另一些使用 wxWidgets,有的工具甚至完全没有 UI。2010 年我们从 Windows 迁移到 Linux,并借此将(当时规模还不大的)UI 代码库迁移到 Qt。

尽可能优先使用 PyQt。 由于工作室内部对 Python 的广泛使用,我们主要采用 Python 的 PyQt 绑定,以便让尽可能多的开发者参与 Qt 应用建设。我们也在少数场景使用 C++ Qt 库,通常发生在代码本就以 C++ 为主或性能至关重要的地方。在当时,我们选择 PyQt 而非 PySide,原因是其生态与产品支持更活跃。我们也倾向 PyQt 而非 QML(QtQuick)标记语言,因为 QWidget 体系的控件库更完整,尤其是树/列表/表格等数据密集型控件,当时 QtQuick 缺少同等成熟的替代品。

优先手写代码而非 Qt Designer。 我们刻意避免使用 Qt Designer 来构建界面,因为视觉设计阶段通过 RAD 工具带来的少量短期收益,往往会被后续无法维护、难以重构的 .ui 文件所抵消。Qt Designer 也会阻碍我们以自定义 Qt Widget 替换默认控件的部署策略。Qt 在代码库中完成铺开后,我们认为该代码库达到了应用成熟度 Level 0。我们大约在 2010 年达到这一门槛。

2.2 Level 1:统一的视觉设计

当应用迁移到 Qt 后,一个自然的下一步是基于这一统一底座去进一步推动一致性——尤其是确保各类 Qt 工具之间的外观与交互风格一致。

引入 UI 专用的软件包。 Animal Logic 使用 Rez 作为软件包管理系统。我们较早引入了一个新的 Rez 包用于承载 UI 相关能力。这是关键的第一步:它降低了各团队“选择加入”共享 UI 库的成本。

定义共享的 Qt 样式表(QSS)。 Qt 的样式表系统允许使用 QSS 文件定义控件外观,类似 Web 的 CSS。随着时间推移,我们逐步微调一套内部定制风格,主要动机之一是将 Qt 默认的“浅底深字”主题切换为更适合动画与视效应用的“深底浅字”。完成后,我们通过 UI 包将该样式表分发到所有 Qt 工具,以形成可识别的 Animal Logic 品牌。这几乎是“最低成本”的选择,却带来了很大收益:软件集合在视觉上变得高度一致。

自动化 QSS 生成。 QSS 往往大量依赖硬编码常量(颜色、字体等)。我们很快发现,把这些常量集中到单独的 Python 模块,并从模板自动生成 QSS,可以减少重复、避免不一致,还能生成一整族(family)的 QSS 变体:既保持统一品牌,又能在某些上下文(例如特定宿主 DCC 的视觉约束、不同显示分辨率)做适配。

引入通用图标库。 我们希望建立强一致性的视觉语言,使得“shot”“character”等工作室级概念在不同 UI 中拥有一致的视觉表达。最初,各应用要么自带图标资源(风格不统一),要么干脆不用图标。我们引入了一个包含 16×16 PNG 与 SVG 的图标库,并提供 Python API 在运行时以 QImageQPixmapQIcon 形式访问,同时支持缓存与多种变换(缩放、灰度、着色)。我们主要采用“图形符号化”(iconographic)的风格,以便许多开发者都能贡献;图标多以“白色图形 + 透明背景”的 PNG 形式存储,从而可以在运行时进行颜色化处理。

图 2:Icon Gallery,展示 500+ 共享图标,可程序化着色/高亮/置灰。
图 2:Icon Gallery 浏览器展示了 500+ 的共享图标库;图标可在运行时进行着色、高亮与禁用态处理。

完成视觉设计在整个 Qt 代码库中的统一后,我们认为该代码库达到了应用成熟度 Level 1。我们大约在 2012 年达到这一门槛。

2.3 Level 2:统一的 QWidget 生态

当 UI 包在代码库中被广泛采用后,它自然成为自定义控件的归宿。随着时间推移,我们在该库中加入了数百个自定义 Widget。更进一步,通过使用外观模式(Facade)[8],它也成为访问 Qt 类的主要入口。

策划(curate)共享的自定义控件库。 起初,需要自定义控件的应用会在各自仓库中直接定义这些控件:有的是带额外/重载方法、信号或槽的子类,有的是由多个控件组合而成的复合控件。我们持续将这些控件迁移到 UI 包,使它们成为可复用 Widget,并提供简洁的实例化模式(例如 myObj = ui.AdvancedSearchBar())。当 QWidget 类“易发现、易实例化、易开发”后,共享控件库便具备了正向开发势能。我们鼓励开发者贡献控件库,即使某个控件短期内看似只有一个应用会使用。

统一内置控件与自定义控件。 当 UI 包成功铺开后,我们进一步要求:所有内置 Qt 类也通过同一个中央模块导入,并按内部规范去掉 Q 前缀重映射名称。于是 myObj = ui.ComboBox() 成为创建我们版本的 QComboBox 的首选方式。有了这层间接(indirection),我们可以在不破坏客户端代码的情况下逐步引入/修改标准控件的子类(在完成一次性的代码转换之后)。更重要的是,它抹平了“标准 Qt 控件”和“自定义控件”的使用差异:创建方式完全一致。同时,它也把可能很深的 Python 包路径“拍扁”为统一的调用约定,使所有控件都能从 UI facade 模块直接访问。

图 3:UI Testbed 展示 100+ 共享控件与示例界面。
图 3:UI Testbed 浏览器展示了 100+ 共享控件库;示例为 New Entity 对话框。两者都使用共享的 QSS、颜色与字体体系。

在统一了 QWidget 生态与视觉语言后,我们认为代码库达到了应用成熟度 Level 2。我们大约在 2014 年达到这一门槛。

2.4 Level 3:依赖倒置(Dependency Inversion)模式

Widget 可以粗分为“轻数据”和“重数据”:诸如 QComboBox 之类的轻量控件通常可以在创建时一次性填充;而诸如 QTreeWidget 之类的重量控件,其数据集可能变化且规模很大,若在创建时预填充全部数据会导致明显的卡顿。

为缓解这一问题,Qt 提供了一套数据驱动的 Model‑View 控件(例如 QTreeViewQTableView),它们采用依赖倒置原则(Dependency Inversion Principle)[10]:常被口语化地概括为“别来调用我——我会来调用你”(Don’t call us—we’ll call you)。该模式通过一个中间的数据模型(Model)按需访问数据。然而,尽管强大,这类控件也极其难用,现实中往往导致它们的使用受限。我们在代码库里发现,对这些关键控件的“正确使用”几乎为零。

为 Model‑View 控件提供更简单的编程模型。 我们认为 QTreeViewQListViewQTableView 对内部 Qt 应用至关重要,于是开发了自定义子类(例如 ui.TreeViewPlusui.ListViewPlus),并提供一种强大且简单的模式来注册行/列数据源(datasource)。这显著降低了客户端使用门槛,同时避免了旧实现中围绕 QModelIndex 的复杂性。该编程模式在内部获得了广泛采用,并对我们的应用生态非常关键——因为大型层级数据在动画与视效场景无处不在。

推动依赖倒置的普及与“数据源”抽象。 我们发现,这一模式(尤其是用独立的数据源类来管理“特定业务上下文的数据”与“通用 QWidget”的数据流)是非常有价值的抽象。随后我们开发了更多复杂控件,包括通用且可复用的 ui.GraphViewui.PropertiesView。借助数据源模式,这些通用控件可以被不同工种以截然不同的目的复用:只需注入不同的 datasource 即可。我们也强烈鼓励开发者将“为特定需求写的控件”重构为数据源模式,以提升复用性并实现清晰的关注点分离。

图 4:PropertiesView 通过注入不同 datasource 在不同场景复用。
图 4:PropertiesView——一个支持检查与修改对象属性的复杂自定义 QWidget。通过注入不同 datasource,该控件可在多个业务场景复用(示例包含 USD 与数据库对象等数据源)。

在完成依赖倒置部署,并已具备统一控件库与统一视觉设计后,我们认为代码库达到了应用成熟度 Level 3。我们大约在 2016 年达到这一门槛。

2.5 Level 4:命令(Command)模式

动画与视效工作室通常会积累大量分散的脚本、函数与系统:它们难以发现、使用门槛高,也不易与其他系统集成。我们发现,把这些功能用命令模式(Command Pattern)[9] 重新表达,是一个关键且早期的决策,为后续的 Nucleus 设计系统铺平了道路。

引入 Command。 我们引入了一个 Command 基类,提供诸如 doIt()undoIt() 方法,并为每个命令分配唯一的 Command ID。随后,我们将所有面向艺术家的工具与脚本逐步重构为命令,将实现迁移到 doIt() 方法中。我们还扩展了命令能力:支持可选的强类型参数、参数预设(presets),以及执行前的参数解析(pre‑execution argument resolution)。这一过程将数百个既有工具“正规化/标准化”,对代码库帮助巨大。命令执行也因此变得简单:调用方只需知道相关的 Command ID 即可调用。

引入可发现性与注册(registration)。 我们为命令系统加入了自动发现与自动注册机制,并在构建阶段生成命令清单(manifest)以优化运行时性能。Rez 包系统非常适配这项工作:Rez 包可以扩展环境变量(如系统目录列表),使得某个包被解析(resolved)后,其命令会自动注入到 command registry(命令注册表)中。

引入 UI 元数据与提示(hinting)。 我们为命令添加了可选的 UI 元数据,包括显示名、tooltip、icon。结合可发现性,这让我们可以构建诸如“Artist Tools Palette(艺术家工具面板)”这类应用:它可以根据当前环境自动发现命令并生成一个工具架(shelf)。该面板非常成功,取代了大量需要人工维护、且风格不一致的工具架。我们还为命令加入了可选的 isVisible()isEnabled() 方法,使命令能够自主判断自己在特定上下文中是否可用/可执行。

用 Command ID 替代硬编码 QAction。 该命令模式最初是为了实现自治的 Artist Tools Palette,但很快我们意识到:命令是一种极其干净、可扩展的代码组织方式。一个关键洞察是,我们可以让命令成为所有 Qt 应用的基石:不再硬编码工具栏、菜单栏与上下文菜单及其静态 QAction,而是让客户端只声明一组 Command ID 列表。运行时系统从 command registry 中找到对应命令,并使用其 UI hint 动态创建 QAction。这在“应用开发者”和“命令开发者”之间建立了优雅的关注点分离。作为自描述的功能单元,命令可以轻松在不同应用间共享复用;调用代码也无需知道具体模块导入路径,只需通过 Command ID 调用。另一个副作用是:若运行时某个命令不可用,对应的 QAction 就不会被创建,使应用能够在更多环境中运行,并以“优雅降级”的方式工作。

图 5:Artist Tools Palette,通过发现与注册的命令插件自动生成。
图 5:Artist Tools Palette——基于当前环境中自动发现/注册的命令插件(Command Plugins)生成的工具集合;其上下文菜单动作也由同一命令系统实现。

在已具备统一视觉、统一控件库、依赖倒置之后引入命令模式,我们认为代码库达到了应用成熟度 Level 4。我们大约在 2018 年达到这一门槛。

3 Nucleus 设计系统

尽管我们成功实现了成熟度 Level 4,但随着应用规模增长,不可避免的复杂性仍带来反复出现的问题:构建大型交互应用需要大量重复逻辑来管理 UI 元素创建与运行时状态;复杂 signal‑slot 链的编排容易出错且难以推理;共享控件生态本身也无法阻止代码的重复与分裂,因为更偏业务的高阶控件仍会被反复“再造”。

3.1 Level 5:组件化插件架构

2018 年,我们在成熟度模型上进入下一阶段:引入 Nucleus 设计系统。简言之,Nucleus 用“插件式架构 + 应用级配置(configuration)”重新想象应用:以配置替代应用级代码。

泛化的 MVC 插件系统。 我们的核心洞察是:一个应用与另一个应用的差异究竟是什么?我们的答案是:一组特定的模型(Model)、视图(View)、命令(Command),以及它们的编排方式。基于这一点,我们决定将插件化的命令系统泛化,并扩展为覆盖完整 MVC 框架所需组件的插件系统:Models、Views、Commands,以及额外的插件(例如 ToolbarControlsMenuBuilders)。所有 Nucleus 插件都有唯一的 Nucleus ID,例如 Nucleus.Model.Maya.SelectionNucleus.View.Properties

单一、可配置的应用。 与其反复开发多个 Qt 应用(并承受不可避免的代码重复、不一致与冗余投入),我们选择实现一个单一的、规范的 Qt 应用(“Nucleus 核心应用”),并在启动时向其注入不同的应用配置对象,以满足不同目标应用的需求。应用配置主要是一组静态 key‑value:它会(除其他内容外)声明所需的 Model ID 与 View ID;核心应用负责正确地发现(discovery)、实例化(instantiation)并组织这些插件。其他配置同样可定义工具栏控件、菜单、启动闪屏、窗口图标等基础设施。

集中式事件系统与事件‑命令映射。 Nucleus 应用实现了一个事件系统,用来封装并泛化底层 Qt signal‑slot。模型与视图可以选择将某个 QSignal “提升”为 Nucleus 事件:通过重新广播一个带唯一 Event ID(可选参数)的事件。随后,Nucleus 的应用配置通过声明“当某个 Event ID 发生时要执行的一组 Command ID”来管理控制流。例如,一个数据模型在内部数据重载时发出事件;该事件会触发一串命令,用于重载那些对更新后数据感兴趣的视图。该机制使得通用而模块化、彼此无关的组件可以对彼此做出反应,却无需彼此了解对方的存在(也无需硬编码导入依赖)。

图 6:Filament 应用,由 Nucleus 配置驱动,配置文件仅 1890 行。
图 6:Filament——Animal Logic 的旗舰灯光系统,完全基于 Nucleus 设计系统开发。该应用由 17 个 Nucleus Model 与 25 个 Nucleus View 构成,并观察 112 个 Nucleus Event;定义模型/视图/事件交互(含快捷键与右键菜单)的配置仅为一个 1890 行的 Python 模块。

在一个已具备命令、依赖倒置、共享控件与共享视觉设计的 Qt 代码库之上,引入“基于配置的 MVC 插件架构”后,我们认为其达到了应用成熟度 Level 5。我们大约在 2020 年达到这一门槛。

3.2 灵感、结果与讨论

Nucleus 的主要动机,是希望能够独立于任何具体应用去设计与开发可用的功能组件,并让应用能够以几乎零成本声明并使用所需组件。一个关键灵感来自 Eclipse IDE [3]:它采用类似的架构,使得所有功能都以插件形式表达。据我们所知,Nucleus 是首次将这一模式用于 Qt 应用创建。

Nucleus 被证明是成功的设计模式,使一个小团队得以构建并维护大量复杂的交互式应用。并且,在实际落地过程中,还获得了若干起初并不明显的收益。

丰富的组件生态。 组件化的应用设计极大提升复用性:为某个工种开发一个 Nucleus 组件(例如一个 View)这一行为本身,就使它能被其他工种轻松复用。久而久之,我们形成了一个丰富的可复用组件生态。例如,现在我们会为所有 Nucleus 应用默认提供一些通用视图(如脚本编辑器视图、性能剖析视图)。

稳定性与一致性。 有了单一的规范 Nucleus 核心应用,我们可以在核心代码库中集中实现并持续改进许多 Qt 应用层面的细节,而无需由每个应用团队各自“重复造轮子”。以视图管理为例,我们可以在 Nucleus 核心中统一处理布局持久化、用户自定义命名布局、视图菜单同步等;以前这些都需要各应用团队分别实现。新的范式让一个核心团队对应用与 UI 管理负责,从而显著提升生产力,并大幅提高各产品的稳定性与一致性。

事件编排(orchestration)。 Nucleus 事件系统是将各个组件串联成完整应用的关键:它提供了事件广播与处理之间的单一接触点。所有关键事件都流经配置中的一个函数,使开发、测试与调试更简单。对我们的旗舰级应用而言,这种集中式方法在追踪控制流问题、理解组件间复杂依赖时尤其有帮助。

图 7:应用配置声明模型/视图与事件-命令关系,核心应用据此组装 Qt 主窗口与 Dock 视图。
图 7:应用配置(浅蓝)声明所需模型、视图与事件‑命令关系;应用实例(深蓝)以此配置初始化;最终组装出包含三个 Dock 视图的 Qt 主窗口。

通过配置生成应用。 当我们强制应用以“插件组件的配置聚合”方式表达时,实质上就形成了“无代码应用”(code‑free applications):所有功能都由可复用组件提供,并且组件编写与应用编写之间有清晰边界。当某个应用需要对现有组件做特定风味或变体时,正确做法是把能力沉淀到共享组件中,而不是写应用专属扩展。长期来看,这让任何团队的投入都能惠及所有团队。

低门槛。 更一般地说,集中式、字符串化(string‑based)的应用配置非常易读、易改,使缺乏经验的用户也能相对容易地创建 Nucleus 应用。

3.3 独立(Standalone)与托管(Hosted)模式

在 Nucleus 1.x 中,我们提供了两种相关的实例化模式:独立模式与托管模式。

独立模式(Standalone Mode)。 这是传统的独立应用形态:应用不依附于任何 DCC 独立运行。Filament、FilmStudio、RigStudio 等内部应用使用该模式。

托管模式(Hosted Mode)。 我们也支持在 Maya 或 Houdini 等 DCC 的进程空间内运行 Nucleus 应用:与宿主共享同一内存空间,但拥有独立于宿主主窗口的自有主窗口。AnimationStudio、Artist Tools Palette、EnvironmentStudio、Forge、ModellingStudio、MultiShot、QCStation 等应用以托管方式在 Maya 中运行。

为支持托管模式下与宿主 DCC 的紧密集成,我们引入了一些 Nucleus Model,用于封装宿主 DCC 的事件与选择(selection)系统等能力。除此以外,无论独立还是托管,都使用相同的 Nucleus 配置模式。

4 Nucleus 2.0

Nucleus 1.x 的客户反馈中反复出现一个诉求:希望 Nucleus 应用与宿主 DCC 更紧密地整合。具体而言,希望 Nucleus 应用不再带自己的主窗口,而是把各个 View 直接 dock 到宿主 DCC 的主窗口中;同时,菜单、工具栏等 UI 也应注入到宿主主窗口。动机是获得更统一的 UI/UX、更充分的屏幕空间利用,以及与用户预期更贴合的工作流。

4.1 早期工作

为实现更紧密的宿主整合,我们探索了多种“嵌入(embedding)”原型,重点覆盖建模/布局/动画(Autodesk Maya™)、材质与程序化特效(SideFX Houdini™)、影像与合成(Foundry Nuke™)、审片(Autodesk RV™)以及 USD 资产检视(Pixar Animation USDView™)。一个核心挑战是:不同 DCC 对 Qt 的集成程度差异很大。

原生 Qt(Native Qt)。 RV、USDView 等应用原生就是 Qt 开发的,因此最容易支持 Nucleus 的嵌入模式:我们可以直接访问其 QMainWindow 并将 QDockWidget 注入其中。

后移植到 Qt(Backports to Qt)。 Maya、Nuke 等并非最初以 Qt 开发,但近年来重写为 Qt。它们仍带有自研的布局管理系统,这为集成 Nucleus 组件带来额外复杂性:客户端代码与 DCC UI 的 Qt 对象之间存在一层间接。

非 Qt(Non‑Qt)。 Houdini 等应用并非 Qt 编写,但仍提供部分可扩展性:例如可以注册封装 Nucleus View 的 Houdini pane,但 Houdini UI 的其他部分对运行时修改开放程度更低。

为了覆盖这类异构平台,我们首先实现了一个 Layout Engine(布局引擎) 系统,并为不同 DCC 提供特定扩展,以优雅处理它们各自能力边界。例如:某个 Nucleus 应用在配置中声明的 toolbar command,在 RV 中可以被实例化为真正的 QToolButton,但在 Houdini 中可能需要落地为 shelf script;同样,一个 Nucleus View 在 Maya 中可能通过 MayaQWidgetDockableMixin 进行 docking,而在 Houdini 中则通过等价的 hou.Pane 实现。需要注意的是,Nucleus 提供的许多能力并非所有宿主都支持;在某些情况下,我们必须提供缩减功能范围的“优雅降级”。

图 8:Nucleus 运行时生态:插件 registry、命令 registry、应用实例与事件-命令映射。
图 8:Nucleus 运行时生态:包含模型/视图等插件 registry、命令 registry,以及中心化的应用实例。模型与视图广播 Event ID;应用截获事件并根据配置映射到一串 Command ID,同步或异步执行;命令反过来更新模型/视图状态。

4.2 Level 6:嵌入(Embedded)模式

2024 年初,我们发布 Nucleus 2.0:在目标 DCC 中全面支持嵌入模式,并在内部使用 Layout Engine 系统实现跨 DCC 的差异化注入。此次更新的一个关键特性是:Nucleus 配置作者仍可按以往方式编写配置,而无需关心将应用注入宿主 DCC 所需的具体机制;这些被视为框架的私有实现细节。

这种关注点分离再次带来多项收益。例如,为独立模式编写的 Nucleus 应用可以无需重构便自动在嵌入模式下工作。并且,通过把某个 DCC 的集成逻辑集中在 Layout Engine 中,我们可以随时升级这部分逻辑,而不需要重新发布任何客户端代码。

在一个具备“基于配置的 MVC 插件架构”,并支持独立/托管/嵌入三种模式,同时拥有命令、依赖倒置、共享控件与共享视觉设计的 Qt 代码库中,我们认为其达到了成熟度模型的顶级:应用成熟度 Level 6。我们(暂时)认为截至 2024 年已达到这一门槛。

图 9:Nucleus 2.0 应用以嵌入模式运行在宿主 DCC 内(Nuke/RV)。
图 9:Nucleus 2.0 的多个应用以嵌入模式运行在宿主 DCC 中:左为 Nuke 内的 Plasma,右为 RV 内的 RVWorkshop。我们还对标准 QSS 做了微调以融入宿主的部分视觉元素(例如 Plasma 使用的橙色选中颜色)。

4.3 结果与讨论

Nucleus 2.0 的开发并非没有挑战:Nucleus 已是被广泛使用的框架,必须避免回归(regressions)或干扰制作。我们最初把嵌入模式当作“特殊情况”,导致代码库出现显著分叉,并产生多套并行类层级。经过几轮试错,我们得到一个关键洞察:把嵌入模式重新定义为标准情况,而把独立与托管模式视为特殊情况——其嵌入目标只是我们自己创建的一个 QMainWindow。这种更优雅的重述方式解开了问题,并为 Nucleus 2.0 的发布打开通路。

嵌入模式已被许多工种快速采用。在框架就绪后,我们与 Imaging 团队合作为 Nuke 开发 Plasma,也为 RV 开发 RVWorkshop;同时与 Procedural Assets & FX 团队合作为 Houdini 开发 Alchemy,并与 Assets 团队合作为 USDView 开发 USDWorkshop。迁移到嵌入式 Nucleus 往往能简化并现代化既有代码库,尤其是那些以多个 DCC 插件为基础构建功能的系统。例如,USDWorkshop 能以单个插件替换掉多达十二个 USDView 插件,从而获得(可认为)更好的用户体验;更显著的是,RVWorkshop 甚至以一个插件替换了四十多个 RV 插件。

5 未来工作

随着 Nucleus 2.0 近期部署落地,我们当前与未来的工作重点,是与各工种密切协作,确保在所有目标平台上成功完成嵌入模式集成。我们将继续关注稳定性与性能,并推进额外特性:例如命令行变体(command‑line variant)、更好的异步启动支持、迁移到可缩放的 SVG 图标、改进面向终端用户的文档,以及协助开发更广泛的 Nucleus 组件生态。

我们也可能在未来迁移到 PySide(它往往被视为更常用的 Qt Python 绑定标准)。目前,相比 PyQt 的 SIP 绑定参考指南,PySide 的 Shiboken 相关文档缺乏仍是一个限制因素,但这在未来可能会发生变化。

参考文献(References)

[1] Steve Agland, Jakub Jeziorski, Manuel Macha, Simon Bunker, Francesco Sansoni, and Eoin Murphy. 2020. Grip and Filament: A USD-Based Lighting Workflow. In ACM SIGGRAPH 2020 Talks (Virtual Event, USA) (SIGGRAPH ’20). Association for Computing Machinery, New York, NY, USA, Article 33, 2 pages. doi:10.1145/3388767.3407350

[2] Aloys Baillet, Eoin Murphy, Oliver Dunn, and Miguel Gao. 2018. Forging a new animation pipeline with USD. In ACM SIGGRAPH 2018 Talks (Vancouver, British Columbia, Canada) (SIGGRAPH ’18). Association for Computing Machinery, New York, NY, USA, Article 54, 2 pages. doi:10.1145/3214745.3214779

[3] Azad Bolour. 2003. Notes on the Eclipse Plug-in Architecture. (2003). Retrieved May 7, 2024 from https://www.eclipse.org/articles/Article-Plug-in-architecture/

[4] Jon-Patrick Collins, Romain Maurer, Fabrice Macagno, and Christian Lopez Barron. 2022. USD at Scale. In The Digital Production Symposium (Vancouver, BC, Canada) (DigiPro ’22). Association for Computing Machinery, New York, NY, USA, Article 11, 6 pages. doi:10.1145/3543664.3543677

[5] Michael De Caria, Prethish Bhasuran, Mitja Müller-Jend, and Manuel Macha. 2023. Matte Painting a Brighter Future: A USD-Based Toolset in Nuke. In Proceedings of the Digital Production Symposium (Los Angeles, CA, USA) (DigiPro ’23). Association for Computing Machinery, New York, NY, USA, Article 10, 5 pages. doi:10.1145/3603521.3604294

[6] Martin Fowler. 2010. Richardson Maturity Model. (2010). Retrieved May 10, 2024 from https://martinfowler.com/articles/richardsonMaturityModel.html

[7] Martin Fowler. 2022. Conway’s Law. (2022). Retrieved May 6, 2024 from https://martinfowler.com/bliki/ConwaysLaw.html

[8] Wikipedia. 2023. Facade pattern. (2023). Retrieved May 6, 2024 from https://en.wikipedia.org/wiki/Facade_pattern

[9] Wikipedia. 2024. Command pattern. (2024). Retrieved May 6, 2024 from https://en.wikipedia.org/wiki/Command_pattern

[10] Wikipedia. 2024. Dependency inversion principle. (2024). Retrieved May 6, 2024 from https://en.wikipedia.org/wiki/Dependency_inversion_principle

本文采用 Creative Commons BY-NC-ND 4.0 协议进行授权。

BY-NC-ND: 署名-非商业性使用-禁止演绎

End of Article