本文内容
通道系统概述
本页概述了 Atom Renderer 的 pass system,它指的是定义如何构建和管理通道的高级系统。
通道系统旨在高度灵活地满足开发人员的不同需求和工作流程。为了让不同类型的开发人员和技术美术师可以使用通道,O3DE 允许将通道创作为数据驱动 (JSON) 和/或硬编码 (C++) 或两者的组合。在决定如何创作通道时,每个选项都有优点和缺点,需要考虑这些优点和缺点。
数据驱动 (JSON)
以数据驱动的方式进行创作可以简化原型制作工作流程并缩短迭代时间。由于仅对数据进行了更改,因此无需在每次更改后重新编译渲染器。使用数据驱动的通道还可以使它们与核心引擎分离。这允许将通道作为资源共享,从而减轻将通道集成到引擎中的负担。在 JSON 中创作传递的主要成本是性能以及管道中缺乏灵活性。建议将 JSON 格式主要用于原型设计、小型共享传递和简单的实现。
硬编码 (C++)
创作通过 C++ 编程并直接与 Atom 集成,让您可以更好地控制渲染管道并提供更高的性能。在 C++ 中创作传递更为复杂,并且需要 O3DE Gem 来分发共享传递。两者组合
在某些情况下,开发人员可能希望在 C++ 中创建具有复杂功能的通道,同时还能够在 JSON 中调整其高级属性。例如,在创建复杂的视觉效果时,一部分可以用 C++ 完成实现以提高性能,另一部分可以用 JSON 实现,以便对效果进行快速迭代。组合方法增加了 pass 体系结构的一些复杂性,但复杂性对用户仍然是透明的。
建筑
pass 系统架构有两个方面:代码端 (C++) 和数据端 (JSON)。代码端定义通道的结构(例如其属性和功能),并实现管理通道的系统,例如通道的创建和注册。数据端序列化 C++ 传递结构,允许您使用 JSON 文件创作传递。
通道可以是包含其他通道的 父通道,也可以是执行 GPU 工作的渲染通道。过程还定义它们自己的过程行为,或者它们在渲染帧期间的行为方式。
代码端:Pass 的结构
以下类定义传递的结构。
Pass
相关: Pass API
Pass
类是每个 Pass 类派生自的基类。它定义通道的属性和功能。
通道附件
通道使用 RHI 附件,如纹理、缓冲区和渲染目标。有三种类型的附件:Input、Output 和 InputOutput。
附件 | 说明 |
---|---|
Input | 如果 pass 读取 attachment 但不写入它,则 attachment 插槽应为 Input。例如,在 SSAO 中,深度缓冲区被绑定为 Input,因为只需要读取内容。 |
Output | 如果通道写入附件,并且不需要附件的先前状态,则附件槽应为 Output。Output 的先前状态可能被清除或覆盖。例如,在深度预通道中,深度缓冲区被绑定为 Output,因为它只需要写入。另一个示例是,对于渲染到目标的全屏通道,目标将绑定为 Output。 |
InputOutput | 如果传递写入附件,但需要附件的先前状态,则附件槽应为 InputOutput。保留 InputOutput 的先前状态。例如,在前向透明传递中,渲染目标是 InputOutput,因为渲染目标已经包含在不透明传递中渲染的像素。 |
通道行为
通道的行为在虚拟函数中定义,可以覆盖这些虚拟函数。这些虚拟函数的名称末尾有后缀 Internal
。它们不包含任何默认行为,并且只需要在需要时由派生类实现。
每个虚拟函数都有一个非虚拟对应项,它们具有相同的名称,但没有Internal
。非 virtual 函数调用 virtual 对应函数并实现所有通道通用的核心功能。
在 C++ 中编写新通道时,用户会创建一个派生自 Pass
的类,并覆盖他们需要的任何函数,以获得所需的行为。
以下函数用于定义传递行为。
函数 | 行为 |
---|---|
Reset , ResetInternal | 这是传递重置其内部状态的地方,例如连接和指向邻居上连接连接的指针。 |
BuildAttachments , BuildAttachmentsInternal | 这是通道构建附件、连接到其他通道并设置任何必要状态的地方。 |
Validate | 此函数允许传递验证其内部状态。例如,您可以检查附件是否有效,内部数据是否已正确配置,或者通道层次结构是否有效。这是一个虚拟函数,但不遵循Internal 命名模式。相反,派生类应覆盖虚拟的 Validate 方法,如果成功,则调用其基类 Validate 方法。 |
FrameBegin , FrameBeginInternal | 这可以看作是通道的 “render” 函数。它调用每一帧,并允许通道使用 RHI 的FrameGraph 设置其渲染逻辑。 对于叶通道,这通常涉及使用RHI::ScopeProducer 并在 FrameGraph 上调用ImportScopeProducer 。 这将向 FrameGraph 注册通道范围生成器,以便它可以接收必要的回调。 |
FrameEnd , FrameEndInternal | 在执行帧的渲染逻辑后,每帧调用此函数。 它主要用作通道的同步点,以清理不再需要的任何每帧状态或资源。 |
父通道
相关: ParentPass API
父通道 是由其他通道组成的通道。例如,Bloom 通道由多个下采样通道、模糊通道和上采样通道组成。
父通道继承自Pass
并实现复合模式,允许通道的树状层次结构。所有刀路都保留指向其父刀路的指针。如果传递指针为 null,则传递是层次结构的根或孤立项,这意味着它不属于传递层次结构。在执行过程中,将按深度优先顺序遍历子传递的层次结构,并执行每个传递的行为函数。
Render Pass
相关: RenderPass API
渲染通道 负责执行某种形式的 GPU 工作。
Atom 提供了以下渲染通道,用于实现最常见的渲染用例。
名称 | 说明 | API |
---|---|---|
Raster Pass | 将场景中的对象转换为由单个像素组成的图像。 | RasterPass |
Compute Pass | 激活计算着色器以调度渲染命令。 | ComputePass |
Full Screen Triangle Pass | 渲染覆盖整个屏幕的单个三角形。此通道可以调整为全屏呈现其他视觉对象。 | FullScreenTrianglePass |
Copy Pass | 在 GPU 上复制图像和缓冲区。 | CopyPass |
代码端:创建路径
在通道创建过程中,涉及四个组件:Pass
, Pass System
, Pass Template
, 和 Pass Request
。创建通道时,通道系统使用通道模板中定义的信息来创建通道的实例。pass 请求可用于告知 pass 系统创建通道。本节详细介绍了每个组件的角色。
Pass
要创建通道,涉及两个属性:Name 和 Pass Descriptor。(Pass 在前面定义 此处.)
- Name
- 引用全局名称字典中的条目的字符串 ID。名称的内存效率更高,并且比字符串提供更快的相等性检查。
- Pass Descriptor
- 相关: PassDescriptor API
用作传递构造函数的输入的类。它包含要创建的通道的名称。如果它从PassTemplate
或 PassRequest
创建传递,它还包含传递模板或传递请求的指针;否则,指针指向 nullptr
。
通道系统
相关: PassSystem API
通道系统 是监督和管理通道的中心枢纽。它负责创建、重建和删除通道。它还保存通道层次结构的根。
要在渲染管道中使用通道,必须首先向通道系统注册关联的通道模板。然后,通道系统可以从已注册的通道模板列表中查询,并创建该通道的实例。
通道模板
相关: PassTemplate API, Pass Template File Specification
通道模板 提供允许通道系统创建通道实例的数据。 Pass 模板可以用 C++ 或通过 JSON 文件创作。
Pass Request
相关: PassRequest API
pass 请求是从 pass 模板创建传递的查询。它使用 PassTemplate
的 Name
属性从 PassSystem
查询 PassTemplate
并创建一个 Pass
。它还包含有关如何将通道的输入和输出与通道树层次结构中的相邻通道相关联的信息。
数据端:序列化通道
可以使用 JSON 以数据驱动的方式创作通行证。Pass 文件使用.pass
扩展名。通过在 JSON 中创作通道,您可以配置通道和编辑渲染管道,而无需重新编译任何二进制文件。
Pass Asset
相关: PassAsset API
pass 资产 是围绕 PassTemplate
类的序列化包装器.pass
文件由通道资产处理和序列化,以创建通道模板。从磁盘加载时,Asset Processor 会向PassSystem
类注册通道模板,因此可以在代码或其他通道资产中按名称引用通道模板。序列化的传递模板中的任何传递请求都将用于创建子传递。