Unity 中的 QR 码
HoloLens 2 头戴显示设备可以跟踪和检测可用于提供全息影像和其他 AR 功能的 QR 码。 本文将指导你完成开始在 Unity 应用中开始使用 QR 码所需的一切,包括:
- 将 QR 码检测添加到 Unity 应用。
- 了解需要使用的重要概念和 Unity 组件。
- 提供涵盖常见 QR 码用法的教程。
- 介绍 AR 标记示例方案,演示启用了 QR 码的场景和示例脚本。
在继续本文之前,建议先浏览 QR 码概述。
配置 Unity 项目和应用
必须正确设置和配置 Unity 项目和应用才能启用 QR 码功能,这需要:
- OpenXR for Windows 混合现实版本 113.2403.5001 或更高版本。
注意
这附带 OS,可通过 Windows 应用商店进行更新。 请注意,用户可能已安装早期版本,并且其设备将无法使用 AR 标记(如 QR 码),直到更新到版本 113.2403.5001 或更高版本。
- 与受支持的 Unity 版本兼容的项目:
- Unity 2022.3 LTS (建议)
- Unity 2021.3 LTS
- 混合现实 OpenXR 插件。
- 为 Unity 项目启用的网络摄像头功能。
- 授予应用的相机权限。
以下部分将指导你配置 Unity 项目和应用以启用 QR 码检测。
获取 混合现实 OpenXR 插件
混合现实 OpenXR 插件包包含可用于访问 QR 码功能的 C# API。
导入包:
混合现实功能工具还简化了包管理,可用于查找、更新和添加应用所需的混合现实功能。 有关如何使用该工具的详细说明,请参阅欢迎使用 混合现实 功能工具。
启用 WebCam 功能
若要检测和跟踪 QR 码,Unity 项目需要 启用 WebCam 功能。
启用 WebCam 功能:
- 打开 Unity 项目。
- 在 Unity 编辑器的应用菜单中单击“ 编辑 ”。
- 转到 “项目设置 > 播放器 ”并选择 “UWP ”选项卡,如下所示:
- 在“功能”列表中启用 WebCam。
- 退出 项目设置。
现已为 Unity 应用启用 WebCam 功能。 但是,你的应用仍必须被授予访问设备相机的权限。
授予应用相机访问权限
如果应用启用了 WebCam 功能,权限对话框会提示用户授予应用对设备相机的访问权限。
此对话框仅向用户显示一次,通常在输入包含已启用 QR 码标记支持的场景ARMarkerManager
时显示。 如果拒绝相机访问,用户可以转到“设置应用”>,并通过应用的高级选项启用它。
将 QR 码检测构建到场景中
QR 码检测必须内置到想要在其中使用 QR 码的每个场景中,这需要:
- 附加的
ARMarkerManager
AGameObject
。ARMarkerManager
只负责创建、更新和删除检测到的 QR 码的每一个GameObject
。 - 附加的
ARMarker
prefab。 ARMarkerManager
配置为在创建GameObject
QR 码时使用 prefab。
为 QR 码创建 prefab
若要在场景中使用 QR 码,需要为 QR 码创建预制。 ARMarkerManager
使用此 prefab 在检测到 QR 码时创建一个 GameObject
。
若要为 QR 码创建 prefab,请执行:
- 为项目创建新的 prefab 。
- 将
ARMarker
组件添加到 prefab,位于 Script > Microsoft.MixedReality.OpenXR > ARMarker 下。
你现在有一个基本的 prefab 来处理。 你可能希望应用直观地表示环境中检测到的 QR 码。 下一部分将指导你如何添加 QR 码的视觉表示形式。
添加视觉对象
在上一部分中,添加到 ARMarker
prefab 也会自动添加 ARMarkerScale
组件。 此组件用于将 QR 码的视觉表示比例与其物理对应组件匹配。
为此,请执行以下操作:
- 将空
GameObject
添加到在上一节中创建的 prefab。 它将表示所有视觉 标记内容。 - 将子 3D
GameObject
(如 aQuad
)添加到标记内容GameObject
。 - 在 prefab 的
ARMarkerScale
组件中,将标记刻度转换设置为标记内容GameObject
。 设置此字段可确保正确缩放所选的 3DGameObject
,以匹配实际 QR 码。
添加到 ARMarkerManager
场景
ARMarkerManager
只负责创建、更新和删除检测到的 QR 码的每一个 GameObject
。
若要添加到 ARMarkerManager
场景,
- 将一个
GameObject
放置到场景中。 - 将
ARMarkerManager
组件添加到GameObject
位于 Script > Microsoft.MixedReality.OpenXR > ARMarkerManager 下的组件。
- 将
ARMarkerManager
“标记 Prefab”字段设置为在上一节中创建的 prefab。 - 展开 “启用标记类型”,然后选择一个元素并将其设置为 QR 码。
跟踪 QR 码更改
ARMarkerManager
包含 markersChanged
向订阅者提供 ARMarkersChangedEventArgs
的事件。 使用这些事件参数跟踪在检测或更新的姿势数据中添加或删除了哪些 QR 码。
以下代码演示如何订阅 ARMarkerManager.markersChanged
事件,使用事件参数循环访问 ARMarker
对象 ARMarkerManager
正在处理和写入调试,无论它们是添加、删除还是更新。
using System;
using Microsoft.MixedReality.OpenXR;
// ...
private void Awake()
{
m_arMarkerManager = GetComponent<ARMarkerManager>();
m_arMarkerManager.markersChanged += OnQRCodesChanged;
}
void OnQRCodesChanged(ARMarkersChangedEventArgs args)
{
foreach (ARMarker qrCode in args.added)
Debug.Log($"QR code with the ID {qrCode.trackableId} added.");
foreach (ARMarker qrCode in args.removed)
Debug.Log($"QR code with the ID {qrCode.trackableId} removed.");
foreach (ARMarker qrCode in args.updated)
{
Debug.Log($"QR code with the ID {qrCode.trackableId} updated.");
Debug.Log($"Pos:{qrCode.transform.position} Rot:{qrCode.transform.rotation} Size:{qrCode.size}");
}
}
获取上次检测到 QR 码的时间
使用该 ARMarker.lastSeenTime
属性来确定设备上次跟踪检测到的 QR 码的时间以及丢失跟踪的时间量(如果有)。 时间以自 Unity 启动应用程序以来的秒数进行度量,类似于 UnityEngine.Time.realtimeSinceStartup
。
使用 QR 码的可跟踪 ID
QR 码是 可跟踪的,这是 AR 设备可以在物理环境中检测和跟踪的任何内容。 可跟踪对象派生自提供 ID、跟踪状态、姿势和其他数据的类型 ARTrackable<TSessionRelativeData, TTrackable>
。
QR 码的可跟踪 ID 可以传递到 ARMarkerManager
方法中,以获取 QR 码的属性、原始字节数据和字符串表示形式,以及设置 QR 码的转换模式。 这些方法允许检索 QR 码的数据,而无需保留 ARMarker
对象引用。
可以将 QR 码的 ID 传递到以下 ARMarkerManager
方法中:
GetDecodedString(UnityEngine.XR.ARSubsystems.TrackableId trackableId)
GetMarker(UnityEngine.XR.ARSubsystems.TrackableId trackableId)
GetQRCodeProperties(UnityEngine.XR.ARSubsystems.TrackableId)
GetRawData(UnityEngine.XR.ARSubsystems.TrackableId, Unity.Collections.Allocator)
SetTransformMode(UnityEngine.XR.ARSubsystems.TrackableId, Microsoft.MixedReality.OpenXR.TransformMode)
注意
GetRawData
对于方法参数allocator
,传递Unity.Collections.Allocator.Temp
足以满足大多数方案。
遵循 QR 码的跟踪状态
由于可跟踪, ARMarker
因此它将继承属性 trackingState
,并设置为以下三 UnityEngine.XR.ARSubsystems.TrackingState
个之一:
Limited
:指示正在跟踪 QR 码,但信息有限,或者质量不佳。Tracking
:指定正在完全跟踪 QR 码。None
:指示未跟踪 QR 码。
若要监视 QR 码的跟踪状态,请 ARMarkerManager.markersChanged
订阅并循环访问 ARMarker
传递给事件处理程序的事件参数中提供的标记集合。
以下代码演示如何使用 ARMarkerManager.markersChanged
事件循环访问 ARMarker
新检测到的 QR 码的对象,并将其可跟踪 ID 写入“调试”窗口。
using System;
using Microsoft.MixedReality.OpenXR;
// ...
private void Awake()
{
m_arMarkerManager = GetComponent<ARMarkerManager>();
m_arMarkerManager.markersChanged += OnQRCodesChanged;
}
void OnQRCodesChanged(ARMarkersChangedEventArgs args)
{
foreach (ARMarker qrCode in args.added)
{
if (qrCode.trackingState == UnityEngine.XR.ARSubsystems.TrackingState.Tracking)
Debug.Log($"Fully tracked QR code with the ID {qrCode.trackableId} was added.");
}
}
获取 QR 码的版本和 QR 码类型
获取检测到的 QR 码的版本和类型:
- 调用
ARMarker.GetQRCodeProperties()
,返回实例QRCodeProperties
。 - 访问返回值中的字段
QRCodeProperties
以获取 QR 码的类型。 该值为QRCodeType.QRCode
或QRCodeType.MicroQRCode
。 - 访问返回值的
QRCodeProperties.version
字段以获取 QR 码的版本。 如果类型为QRCodeType.QRCode
,则该值范围为 1 到 40,如果类型为QRCodeType.MicroQRCode
,则范围为 1 到 4。
或者,传递 ARMarker
对象的可跟踪 ID 以获取 ARMarkerManager.GetQRCodeProperties(TrackableId)
QR 码的类型和版本。
警告
QR 码是当前唯一支持的标记类型,尽管将来的版本中可能会添加对其他标记类型的支持。 如果 markerType
不是 ARMarkerType.QRCode
,则调用 GetQRCodeProperties(TrackableId)
将 System.InvalidOperationException
引发。 如果这可能会导致应用以后出现问题,请考虑在 try-catch 块中包装调用 GetQRCodeProperties(TrackableId)
。
读取 QR 数据
该ARMarker
组件附加到创建的每个GameObject
ARMarkerManager
组件。 ARMarker
提供两种返回 QR 码数据的方法:
GetDecodedString()
:此方法获取 QR 码的字符串表示形式,例如 URL。GetRawData(Unity.Collections.Allocator allocator)
:此方法将 QR 码内容作为字节数组返回,从而对数组的分配方式进行精细优化。 在热路径和其他性能至关重要的情况下使用此方法。
以下代码演示了基本用法 GetDecodedString()
和 GetRawData(Unity.Collections.Allocator allocator)
:
using System;
using Microsoft.MixedReality.OpenXR;
// ...
void OnQRCodesChanged(ARMarkersChangedEventArgs args)
{
foreach (ARMarker qrCode in args.added)
{
var text = qrCode.GetDecodedString();
Debug.Log($"QR code text: {text}");
var bytes = qrCode.GetRawData(Unity.Collections.Allocator.Temp);
Debug.Log($"QR code bytes: {bytes.Length}");
bytes.Dispose();
}
}
获取 QR 码大小、位置、旋转和居中
对象 ARMarker
提供它所表示的 QR 码的大小、位置、旋转和中心。
若要获取 QR 码的大小(以米为单位),请使用属性 ARMarker.size
。
使用该 ARMarker.transform
属性获取 QR 码转换的旋转和世界空间位置,以及 ARMarker.center
QR 码相对于 QR 码转换的 2D 坐标。 转换本身根据ARMarker.transformMode
(转换模式)设置为TransformMode.MostStable
(最稳定、QR 码的左上角)或TransformMode.Center
(居中,QR 码的几何中心)居中。
使用 ARMarkerManager.defaultTransformMode
字段设置转换模式 ARMarkerManager
可创建包含的新 ARMarker
对象。 该字段使用 Default Transform Mode
该字段设置为在 Unity 检查器中初始化,如下所示:
作为使用替代方法 ARMarker.transformMode
,传递 ARMarker
对象的可跟踪 ID 以 ARMarkerManager.SetTransformMode(TrackableId, TransformMode)
设置其转换模式。
以下代码演示如何获取新的 QR 码的大小和中心、转换的位置和旋转,以及更改转换模式后更新的转换位置。
using System;
using Microsoft.MixedReality.OpenXR;
// ...
void OnMarkersChanged(ARMarkersChangedEventArgs args)
{
Debug.Log($"Default transform mode is {ARMarkerManager.Instance.defaultTransformMode}./n");
if (e.added.Count > 0)
{
ARMarker qrCode = args.added[0];
Debug.Log($"Position: {qrCode.transform.position}");
Debug.Log($"Rotation: {qrCode.transform.rotation}");
Debug.Log($"Center: {qrCode.center}");
if (qrCode.transformMode == TransformMode.Center)
qrCode.transformMode = TransformMode.MostStable;
else
qrCode.transformMode = TransformMode.Center;
Debug.Log($"QR code's transform mode is now set to {qrCode.transformMode}. /n");
Debug.Log($"New position: {qrCode.transform.position}");
}
}
AR 标记示例方案
随 OpenXR 插件包一起提供的示例包含启用了 QR 码的场景,该场景提供了如何使用 ARMarkerManager
和 ARMarker
用法的示例。
场景位于 Assets > ARMarker 中,如下所示:
可以在 GitHub 上的 OpenXR Unity 混合现实示例存储库中找到场景中使用的 C# 脚本:/OpenXR-Unity-MixedReality-Samples/tree/main/SampleScenarios/Scenarios/MarkerSample/Scripts