XR一个涵盖虚拟现实 (VR)、增强现实 (AR) 和混合现实 (MR) 应用程序的总称。支持这些交互式应用程序的设备可以称为 XR 设备。更多信息
参见 术语表 SDK 显示子系统提供了一个用于纹理分配、帧生命周期和阻塞以实现节奏的接口。
一些设备 SDK 要求通过 SDK 本身而不是通常的图形 API 来分配纹理。如果您使用 XR SDK 显示子系统,则不再需要依赖外部插件在 Unity 之外创建的一组代码,用于在 Unity 中创建功能。您可以在 Unity 中使用两种类型的插件:托管插件(使用 Visual Studio 等工具创建的托管 .NET 程序集)和原生插件(特定于平台的原生代码库)。更多信息
参见 术语表来blit“位块传输”的简称。blit 操作是将内存中的一块数据传输到另一块内存的过程。
参见 术语表或复制到 SDK 纹理中。
显示子系统使插件提供程序能够分配纹理。在可能的情况下,Unity 会直接渲染到纹理以避免不必要的复制。如果需要,Unity 也可以为您分配纹理。
在以下情况下,Unity 无法直接渲染到纹理,而是渲染到中间纹理,然后 blit 或复制到您的纹理
EXT_multisampled_render_to_texture
扩展。kUnityXRRenderTextureFlagsLockedWidthHeight
标志并且 renderScale 不为 1.0。kUnityXRRenderTextureFlagsWriteOnly
标志并且 Unity 需要从纹理中读取回数据。在 PC 和移动设备上,引擎始终解析到提供程序的纹理。引擎执行隐式解析(在具有多采样渲染到纹理扩展的移动设备上)或显式解析。
在移动设备上,提供程序应启用 kUnityXRRenderTextureFlagsAutoResolve
标志并使用 1 个样本创建其纹理。
使用 UnityXRFrameSetupHints.appSetup.sRGB
检查 Unity 是否期望渲染到 sRGB 纹理格式。提供程序最终从 UnityXRRenderTextureDesc
的 colorFormat
字段中选择输出纹理格式用于处理 3D 图形硬件(如显卡或移动设备)实时渲染期间的纹理的文件格式。更多信息
参见 术语表。如果格式为 sRGB 类型,则 Unity 会根据活动项目选择的颜色空间打开或关闭 sRGB 写入。您应该始终使用 sRGB 到线性转换在合成器中从任何 sRGB 纹理中采样。
如果您的 SDK 需要深度信息,您可以像上面颜色缓冲区一样获取深度缓冲区一个内存存储,用于保存图像中每个像素的 z 值深度,其中 z 值是从投影平面到每个渲染像素的深度。更多信息
参见 术语表。UnityXRRenderTextureDesc
上的 nativeDepthTex
值指定了原生资源。默认情况下,如果 nativeDepthTex
设置为 kUnityXRRenderTextureIdDontCare
,Unity 会尝试在具有类似描述的纹理之间共享深度缓冲区。
如果您的 SDK 不需要深度信息,则应将 UnityXRRenderTextureDesc::depthFormat
设置为 kUnityXRDepthTextureFormatNone
以避免不必要的解析。
在提交期间(请参阅下面的提交正在进行的帧部分),您可以为每一帧指定不同的纹理 ID,以处理 SDK 需要双缓冲或三缓冲 Unity 正在渲染到的图像的情况。提供程序插件负责管理 UnityXRRenderTextureId
的集合。
有两种方法负责帧的生命周期:PopulateNextFrameDesc
,它发生在渲染开始之前,以及 SubmitCurrentFrame
,它发生在渲染完成后立即。这两种方法都在图形线程上调用。
在 PopulateNextFrameDesc
期间,预计显示提供程序将执行以下操作
SubmitCurrentFrame
中完成。nextFrame
参数告诉 Unity 下一次渲染到哪些纹理 ID。在 SubmitCurrentFrame
方法期间,预计显示提供程序将执行以下操作
PopulateNextFrameDesc
期间等待的替代方案。为了在渲染到 HMD 显示器时保持尽可能低的延迟和最大的吞吐量,您需要确保在获取姿势和提交纹理时进行精确的计时。每个 HMD 都有一个其合成器运行的原生刷新率。比该速率快地渲染会导致次优体验,因为计时不匹配或工作冗余。
Unity 期望显示提供程序在帧生命周期期间阻塞或等待帧节奏。Unity 在从阻塞调用“唤醒”后不久开始提交渲染命令。您应该将唤醒时间与特定窗口内的合成器同步。一些 SDK 提供了一个基于启发式的浮动唤醒时间窗口。Meta/Oculus 将其称为“提前排队”(有关更多信息,请参阅Oculus 开发人员文档)。Valve 将其称为“运行开始”(请参阅此演示文稿的幻灯片 18 和 19)。
Unity 等待帧生命周期完成,然后才开始提交依赖于姿势的图形命令。
提供程序可以在 PopulateNextFrameDesc
或 SubmitCurrentFrame
中等待节奏。
当 Unity 在图形线程上提交一帧的图形命令时,下一帧的模拟循环在主线程上运行。它包含物理、脚本逻辑等。PopulateNextFrameDesc
在所有渲染命令都提交后,并且仅在下一帧的模拟以及在其上计划的所有图形作业完成后,在图形线程上被调用。PopulateNextFrameDesc
等待的一个图形作业是当前帧的 SubmitCurrentFrame
。这就是为什么在 SubmitCurrentFrame
中等待节奏是有效的。此外,Unity 只有在 PopulateNextFrameDesc
完成后才会开始渲染。
考虑到这些细节,在 SubmitCurrentFrame
中等待节奏与在 PopulateNextFrameDesc
中等待节奏相比,存在一些权衡。例如,如果应用程序在模拟期间安排了昂贵的图形作业,则在 SubmitCurrentFrame
中等待节奏可能会导致性能问题。因为 SubmitCurrentFrame
计划在渲染之后运行,所以应用程序计划的图形作业将在 SubmitCurrentFrame
之后但在 PopulateNextFrameDesc
之前运行。在这种情况下,提供程序正在 SubmitCurrentFrame
中等待,然后它唤醒并期望 Unity 开始渲染。但是,Unity 在调用 PopulateNextFrameDesc
之前处理应用程序计划的图形作业,这反过来又允许 Unity 开始渲染。唤醒以进行渲染和处理在更新方法中计划的图形作业之间的延迟可能会导致延迟。开发人员可以通过安排其图形作业在渲染之后来优化这一点,以确保图形作业在 SubmitCurrentFrame
之前安排。
虽然提供程序在 SubmitCurrentFrame
中等待节奏允许计算图形作业与主线程并行运行,但在 PopulateNextFrameDesc
中等待节奏会完全阻塞 Unity 主线程。这是可以接受的,因为模拟和其他图形作业已经完成。当模拟或图形线程占用过多的时间并超过设备的目标帧率时,可能会出现问题。这会导致帧率减半,而 PopulateNextFrameDesc
等待节奏中的下一个周期。
当 Unity 调用 SubmitCurrentFrame
时,您在上一次帧中设置的纹理已经渲染到,或者 Unity 已将渲染命令提交到图形驱动程序以渲染它们。Unity 现在已经完成了这些操作,您可以将它们传递给您的合成器。
在阻塞或获取要渲染的下一帧后,您必须告诉 Unity 下一帧要渲染哪些纹理,以及渲染通道的布局是什么(请参阅下面的渲染通道)。
一个UnityXRRenderPass
可能包含一个剔除传递和一个场景场景包含游戏中的环境和菜单。可以将每个唯一的场景文件视为一个独特的关卡。在每个场景中,您放置环境、障碍物和装饰,从本质上讲,将游戏分段设计和构建。 更多信息
参见 术语表图遍历。这是一个资源密集型操作,您应该尝试通过诸如单通道渲染之类的技巧来限制 Unity 执行它的次数。
每个UnityXRRenderPass
包含一个输出纹理(可以是纹理数组)和输出UnityXRRenderParams
,例如视图、投影矩阵以及要渲染到的矩形或纹理数组切片。
对于每一帧,显示提供程序都会设置一个UnityXRRenderPass
并填写 Unity 将渲染到下一帧的UnityXRRenderTextureId
。
UnityXRRenderPass
的用例包括以下内容
API 支持以下其他情况(但 Unity 目前可能无法正确响应)
可以安全地做出以下假设
注意:Unity 项目和 XR SDK 必须对单通道渲染使用相同的设置(启用/禁用),因为此设置会影响用户着色器在 GPU 上运行的程序。 更多信息
参见 术语表。要检查是否启用了单通道渲染,请使用UnityXRFrameSetupHints.appSetup.singlePassRendering
。
如果两个渲染传递的cullingPassIndex
设置为相同的值,则它们可以共享一个剔除传递。cullingPassIndex
选择要使用的UnityXRCullingPass
。必须在UnityXRNextFrameDesc
中填写剔除传递。