增强现实( AR )与透视

增强现实的支持方式因硬件不同而有所差异。

诸如 Magic Leap、TiltFive 等设备通过使用`“透视显示屏” <https://en.wikipedia.org/wiki/See-through_display>`__ 显示渲染结果,使得用户能同时看到虚拟与现实世界。

而另一方面, Quest、HTC Elite 和 Lynx R1 等设备通过一种称为视频透视(Video Passthrough)的技术实现这一功能:摄像头记录现实世界的画面作为渲染背景,在上面显示渲染结果。

备注

透视功能在不同平台上的实现方式也不尽相同。

在 Godot 4.3 中,我们实现了一种统一的方法,因此你无需担心这些差异,XRInterface 实现现在负责应用正确的平台依赖方法。

而对于 Meta Quest 和 HTC Elite 等头戴设备,你需要使用 `OpenXR vendors plugin v3.0.0 或更高版本插件<https://github.com/GodotVR/godot_openxr_vendors/releases>`__ 来启用视频透视功能。

为保证向后兼容,旧的透视 API 仍然可用,但推荐按照以下新说明进行操作。

环境混合模式

我们通过设置环境混合模式来配置 VR 或 AR 功能。该模式决定了(现实世界)环境与虚拟世界的融合方式。

混合模式一览

混合模式

描述

XR_ENV_BLEND_MODE_OPAQUE

渲染的图像将是不透明的,我们看不到现实世界,只能看到 VR 世界。视频透视功能同样会被关闭。

XR_ENV_BLEND_MODE_ADDITIVE

渲染的图像将以半透明的形式被添加到现实世界中。该模式通常用于无法遮挡现实世界的透视设备。如果同时在使用视频透视功能,透视会被启用。

XR_ENV_BLEND_MODE_ALPHA_BLEND

渲染的图像将与现实世界进行 alpha 混合。在支持此功能的透视设备上,alpha 值将控制光学元件的透明度。在视频透视设备上,alpha 混合将应用于视频图像,并在适用时启用透视。

你可以通过 XRInterface 实例的 environment_blend_mode 属性来设置应用程序的环境混合模式。

同时,可以使用同一实例上的 get_supported_environment_blend_modes 属性来查询硬件支持的混合模式。

配置背景

当环境混合模式为 XR_ENV_BLEND_MODE_ALPHA_BLEND 时,必须将 Viewporttransparent_bg 属性设置为 true。而使用 XR_ENV_BLEND_MODE_ADDITIVE 混合模式时,应将背景颜色设置为黑色。

这两种解决方案都会导致背景渲染不再提供环境照明。因此,建议相应地调整环境设置,确保有足够的环境光来照亮场景。

备注

部分增强现实 SDK 确实会提供环境光信息——甚至是完整的辐射图——以允许在虚拟对象中模拟真实世界的反射。不过,目前 Godot XR 的核心尚不支持此功能,但可以通过插件来实现。

OpenXR 特定功能

在 OpenXR 选项卡中,你可以配置想要使用的默认混合模式。如果该模式可用,Godot 将在启动时选择此混合模式。如果不可用,Godot 将默认选择 XR 运行时提供的第一个支持的混合模式。

../../_images/openxr_default_blend_mode.webp

对于透视设备,OpenXR 需要配置额外的设置。这些设置依赖于平台,并通过 OpenXR 供应商插件提供。

举个例子,以下是 Meta Quest 所需的设置:

../../_images/openxr_export_passthrough.webp

Passthrough 设置定义了是否支持或者需要启动视频透视功能。

The Boundary Mode allows you to define whether the guardian is needed, disabling this fully requires passthrough to be enabled at all times.

Putting it together

综合以上内容,我们可以使用以下代码作为基础:

  1. @onready var viewport : Viewport = get_viewport()
  2. @onready var environment : Environment = $WorldEnvironment.environment
  3. func switch_to_ar() -> bool:
  4. var xr_interface: XRInterface = XRServer.primary_interface
  5. if xr_interface:
  6. var modes = xr_interface.get_supported_environment_blend_modes()
  7. if XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND in modes:
  8. xr_interface.environment_blend_mode = XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND
  9. viewport.transparent_bg = true
  10. elif XRInterface.XR_ENV_BLEND_MODE_ADDITIVE in modes:
  11. xr_interface.environment_blend_mode = XRInterface.XR_ENV_BLEND_MODE_ADDITIVE
  12. viewport.transparent_bg = false
  13. else:
  14. return false
  15. environment.background_mode = Environment.BG_COLOR
  16. environment.background_color = Color(0.0, 0.0, 0.0, 0.0)
  17. environment.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
  18. return true
  19. func switch_to_vr() -> bool:
  20. var xr_interface: XRInterface = XRServer.primary_interface
  21. if xr_interface:
  22. var modes = xr_interface.get_supported_environment_blend_modes()
  23. if XRInterface.XR_ENV_BLEND_MODE_OPAQUE in modes:
  24. xr_interface.environment_blend_mode = XRInterface.XR_ENV_BLEND_MODE_OPAQUE
  25. else:
  26. return false
  27. viewport.transparent_bg = false
  28. environment.background_mode = Environment.BG_SKY
  29. environment.ambient_light_source = Environment.AMBIENT_SOURCE_BG
  30. return true

阴影转不透明模式

阴影转不透明( Shadow to opacity )是 Godot 空间着色器的一种渲染模式,在 Godot 3 中专门为 AR 引入。这种特殊的渲染模式会根据表面阴影决定其透明程度:当表面越多地处于阴影中,表面就变得越不透明。而表面完全被照亮时,表面会变得完全透明,从而显示出真实世界。

但是,表面实际上是在不透明状态下渲染的。使用该模式会导致两个后果:

  • 由于深度缓冲区和颜色缓冲区都被写入,即使表面完全透明,我们仍会遮挡其后方的几何体。

  • 由于我们将表面在阴影中变得不透明,因此虚拟物体可以在现实世界的物体上投射阴影。

“阴影到不透明”效果在用户桌面上的应用。

“阴影到不透明”效果在用户桌面上的应用。

这使得以下应用场景成为可能:

  • 你可以在现实世界的桌子周围渲染一个盒子网格,这样即使有虚拟物体放在桌子下面,桌子也能保持可见。虚拟物体会被正确地遮挡。当将虚拟物体放在现实世界的桌子上时,会在桌子上投下阴影。

  • 在使用手部追踪功能渲染手部网格时,你可以使用这种渲染模式的着色器,以确保你的手能正确地遮挡虚拟物体。

以下着色器代码可以作为实现该功能的良好基础:

  1. shader_type spatial;
  2. render_mode blend_mix, depth_draw_opaque, cull_back, shadow_to_opacity;
  3. void fragment() {
  4. ALBEDO = vec3(0.0, 0.0, 0.0);
  5. }

1

相关限制可能因 XR 接口的实现而有所不同。

2

该功能仍在完善中。