Hololens 2 Unity QR扫描应用无法识别二维码求助
问题:Hololens 2 Unity二维码扫描应用无法识别二维码
我正在开发Hololens 2平台的二维码扫描Unity应用,因不熟悉AR开发,直接采用微软官方二维码追踪示例。但部署到Hololens 2后无法识别二维码:官方示例本应在识别到二维码后生成矩形框,实际完全无效果;已尝试纸质和屏幕显示的二维码(设备自带扫描器可正常识别),也安装了Microsoft.MixedReality.QR NuGet包、集成了MRTK,Visual Studio也安装了UWP和Unity开发包,但应用仅显示白色调试线。
两个脚本(QRCodesManager和QRCodesVisualizer)已挂载到Unity空对象,且已关联QR Code Prefab,求解决方法。
QRCodesManager代码
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Microsoft.MixedReality.QR; using System; using System.Collections.Generic; using UnityEngine; namespace Microsoft.MixedReality.SampleQRCodes { public static class QRCodeEventArgs { public static QRCodeEventArgs<TData> Create<TData>(TData data) { return new QRCodeEventArgs<TData>(data); } } [Serializable] public class QRCodeEventArgs<TData> : EventArgs { public TData Data { get; private set; } public QRCodeEventArgs(TData data) { Data = data; } } public class QRCodesManager : Singleton<QRCodesManager> { [Tooltip("Determines if the QR codes scanner should be automatically started.")] public bool AutoStartQRTracking = true; public bool IsTrackerRunning { get; private set; } public bool IsSupported { get; private set; } public event EventHandler<bool> QRCodesTrackingStateChanged; public event EventHandler<QRCodeEventArgs<Microsoft.MixedReality.QR.QRCode>> QRCodeAdded; public event EventHandler<QRCodeEventArgs<Microsoft.MixedReality.QR.QRCode>> QRCodeUpdated; public event EventHandler<QRCodeEventArgs<Microsoft.MixedReality.QR.QRCode>> QRCodeRemoved; private System.Collections.Generic.SortedDictionary<System.Guid, Microsoft.MixedReality.QR.QRCode> qrCodesList = new SortedDictionary<System.Guid, Microsoft.MixedReality.QR.QRCode>(); private QRCodeWatcher qrTracker; private bool capabilityInitialized = false; private QRCodeWatcherAccessStatus accessStatus; private System.Threading.Tasks.Task<QRCodeWatcherAccessStatus> capabilityTask; public System.Guid GetIdForQRCode(string qrCodeData) { lock (qrCodesList) { foreach (var ite in qrCodesList) { if (ite.Value.Data == qrCodeData) { return ite.Key; } } } return new System.Guid(); } public System.Collections.Generic.IList<Microsoft.MixedReality.QR.QRCode> GetList() { lock (qrCodesList) { return new List<Microsoft.MixedReality.QR.QRCode>(qrCodesList.Values); } } protected void Awake() { } // Use this for initialization async protected virtual void Start() { IsSupported = QRCodeWatcher.IsSupported(); capabilityTask = QRCodeWatcher.RequestAccessAsync(); accessStatus = await capabilityTask; capabilityInitialized = true; } private void SetupQRTracking() { try { qrTracker = new QRCodeWatcher(); IsTrackerRunning = false; qrTracker.Added += QRCodeWatcher_Added; qrTracker.Updated += QRCodeWatcher_Updated; qrTracker.Removed += QRCodeWatcher_Removed; qrTracker.EnumerationCompleted += QRCodeWatcher_EnumerationCompleted; } catch (Exception ex) { Debug.Log("QRCodesManager : exception starting the tracker " + ex.ToString()); } if (AutoStartQRTracking) { StartQRTracking(); } } public void StartQRTracking() { if (qrTracker != null && !IsTrackerRunning) { Debug.Log("QRCodesManager starting QRCodeWatcher"); try { qrTracker.Start(); IsTrackerRunning = true; Debug.Log("QRCodeManager started!"); QRCodesTrackingStateChanged?.Invoke(this, true); } catch (Exception ex) { Debug.Log("QRCodesManager starting QRCodeWatcher Exception:" + ex.ToString()); } } } public void StopQRTracking() { if (IsTrackerRunning) { IsTrackerRunning = false; if (qrTracker != null) { qrTracker.Stop(); qrCodesList.Clear(); } var handlers = QRCodesTrackingStateChanged; if (handlers != null) { handlers(this, false); } } } private void QRCodeWatcher_Removed(object sender, QRCodeRemovedEventArgs args) { Debug.Log("QRCodesManager QRCodeWatcher_Removed"); bool found = false; lock (qrCodesList) { if (qrCodesList.ContainsKey(args.Code.Id)) { qrCodesList.Remove(args.Code.Id); found = true; } } if (found) { var handlers = QRCodeRemoved; if (handlers != null) { handlers(this, QRCodeEventArgs.Create(args.Code)); } } } private void QRCodeWatcher_Updated(object sender, QRCodeUpdatedEventArgs args) { Debug.Log("QRCodesManager QRCodeWatcher_Updated"); bool found = false; lock (qrCodesList) { if (qrCodesList.ContainsKey(args.Code.Id)) { found = true; qrCodesList[args.Code.Id] = args.Code; } } if (found) { var handlers = QRCodeUpdated; if (handlers != null) { handlers(this, QRCodeEventArgs.Create(args.Code)); } } } private void QRCodeWatcher_Added(object sender, QRCodeAddedEventArgs args) { Debug.Log("QRCodesManager QRCodeWatcher_Added"); lock (qrCodesList) { qrCodesList[args.Code.Id] = args.Code; } var handlers = QRCodeAdded; if (handlers != null) { handlers(this, QRCodeEventArgs.Create(args.Code)); } } private void QRCodeWatcher_EnumerationCompleted(object sender, object e) { Debug.Log("QRCodesManager QrTracker_EnumerationCompleted"); } private void Update() { if (qrTracker == null && capabilityInitialized && IsSupported) { if (accessStatus == QRCodeWatcherAccessStatus.Allowed) { SetupQRTracking(); } else { Debug.Log("Capability access status : " + accessStatus); } } } } }
QRCodesVisualizer代码
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Collections.Generic; using UnityEngine; namespace Microsoft.MixedReality.SampleQRCodes { public class QRCodesVisualizer : MonoBehaviour { public GameObject qrCodePrefab; private SortedDictionary<System.Guid, GameObject> qrCodesObjectsList; private bool clearExisting = false; struct ActionData { public enum Type { Added, Updated, Removed }; public Type type; public Microsoft.MixedReality.QR.QRCode qrCode; public ActionData(Type type, Microsoft.MixedReality.QR.QRCode qRCode) : this() { this.type = type; qrCode = qRCode; } } private Queue<ActionData> pendingActions = new Queue<ActionData>(); // Use this for initialization void Start() { Debug.Log("QRCodesVisualizer start"); qrCodesObjectsList = new SortedDictionary<System.Guid, GameObject>(); QRCodesManager.Instance.QRCodesTrackingStateChanged += Instance_QRCodesTrackingStateChanged; QRCodesManager.Instance.QRCodeAdded += Instance_QRCodeAdded; QRCodesManager.Instance.QRCodeUpdated += Instance_QRCodeUpdated; QRCodesManager.Instance.QRCodeRemoved += Instance_QRCodeRemoved; if (qrCodePrefab == null) { throw new System.Exception("Prefab not assigned"); } } private void Instance_QRCodesTrackingStateChanged(object sender, bool status) { if (!status) { clearExisting = true; } } private void Instance_QRCodeAdded(object sender, QRCodeEventArgs<Microsoft.MixedReality.QR.QRCode> e) { Debug.Log("QRCodesVisualizer Instance_QRCodeAdded"); lock (pendingActions) { pendingActions.Enqueue(new ActionData(ActionData.Type.Added, e.Data)); } } private void Instance_QRCodeUpdated(object sender, QRCodeEventArgs<Microsoft.MixedReality.QR.QRCode> e) { Debug.Log("QRCodesVisualizer Instance_QRCodeUpdated"); lock (pendingActions) { pendingActions.Enqueue(new ActionData(ActionData.Type.Updated, e.Data)); } } private void Instance_QRCodeRemoved(object sender, QRCodeEventArgs<Microsoft.MixedReality.QR.QRCode> e) { Debug.Log("QRCodesVisualizer Instance_QRCodeRemoved"); lock (pendingActions) { pendingActions.Enqueue(new ActionData(ActionData.Type.Removed, e.Data)); } } private void HandleEvents() { lock (pendingActions) { while (pendingActions.Count > 0) { var action = pendingActions.Dequeue(); if (action.type == ActionData.Type.Added) { GameObject qrCodeObject = Instantiate(qrCodePrefab, new Vector3(0, 0, 0), Quaternion.identity); qrCodeObject.GetComponent<SpatialGraphNodeTracker>().Id = action.qrCode.SpatialGraphNodeId; qrCodeObject.GetComponent<QRCode>().qrCode = action.qrCode; qrCodesObjectsList.Add(action.qrCode.Id, qrCodeObject); } else if (action.type == ActionData.Type.Updated) { if (!qrCodesObjectsList.ContainsKey(action.qrCode.Id)) { GameObject qrCodeObject = Instantiate(qrCodePrefab, new Vector3(0, 0, 0), Quaternion.identity); qrCodeObject.GetComponent<SpatialGraphNodeTracker>().Id = action.qrCode.SpatialGraphNodeId; qrCodeObject.GetComponent<QRCode>().qrCode = action.qrCode; qrCodesObjectsList.Add(action.qrCode.Id, qrCodeObject); } } else if (action.type == ActionData.Type.Removed) { if (qrCodesObjectsList.ContainsKey(action.qrCode.Id)) { Destroy(qrCodesObjectsList[action.qrCode.Id]); qrCodesObjectsList.Remove(action.qrCode.Id); } } } } if (clearExisting) { clearExisting = false; foreach (var obj in qrCodesObjectsList) { Destroy(obj.Value); } qrCodesObjectsList.Clear(); } } // Update is called once per frame void Update() { HandleEvents(); } } }
排查与解决步骤
检查权限配置
- 在Unity的Player Settings中,确保UWP平台的WebCam权限和Spatial Perception权限已开启。QR扫描依赖摄像头权限,空间感知用于定位二维码空间位置。
- 打包后检查AppxManifest.xml,确认包含
<DeviceCapability Name="webcam"/>和<DeviceCapability Name="spatialPerception"/>两项。
验证设备QR服务状态
- 在Hololens 2设备设置的系统>开发者中,确认QR代码追踪功能已开启。该功能关闭时第三方应用无法调用系统QR扫描服务。
- 在
QRCodesManager的Start方法中添加调试日志,输出IsSupported和accessStatus的值,确认设备支持QR追踪且权限已获取:async protected virtual void Start() { IsSupported = QRCodeWatcher.IsSupported(); Debug.Log($"QR追踪是否支持: {IsSupported}"); capabilityTask = QRCodeWatcher.RequestAccessAsync(); accessStatus = await capabilityTask; Debug.Log($"权限状态: {accessStatus}"); capabilityInitialized = true; } - 若
accessStatus为Denied,需在设备上为应用授予摄像头权限。
检查Prefab与组件配置
- 确认QR Code Prefab上的
SpatialGraphNodeTracker组件配置正确,该组件负责同步二维码空间坐标到Unity对象。 - 检查Prefab中的
QRCode组件是否正确引用,确保能接收二维码数据并渲染矩形框。 - 确认Prefab的渲染层级正确,避免被其他UI或模型遮挡。
- 确认QR Code Prefab上的
版本兼容性检查
- 确认Microsoft.MixedReality.QR NuGet包版本与MRTK、Unity版本兼容,建议使用与官方示例一致的版本,避免版本冲突。
- 检查Unity的UWP目标版本与Hololens 2系统版本匹配,推荐使用Windows 10 20H2或更高版本。
调试日志分析
- 查看应用运行时的调试日志,确认
QRCodesManager中的QRCodeWatcher_Added、QRCodeWatcher_Updated等事件是否触发:- 若未触发,问题出在权限或服务配置;
- 若触发但未生成矩形框,问题出在可视化逻辑或Prefab配置。
- 查看应用运行时的调试日志,确认
内容的提问来源于stack exchange,提问作者koto pes ESQ
相关产品推荐
相关产品推荐

