基于Vuforia/Unity实现条码扫描动态模型叠加的问题排查
问题分析
你的核心问题在于错误依赖InstanceData是否为null来判断条码是否在视野内。Vuforia的BarcodeBehaviour中,InstanceData不会在条码移出视野后立刻置空,而是会保留上一次扫描的数据,导致你的else if分支永远不会触发,模型也就不会隐藏。
解决方案
改用TrackableBehaviour(BarcodeBehaviour的父类)的跟踪状态来判断条码是否被有效识别/跟踪,这是Vuforia官方推荐的判断方式。同时优化模型切换逻辑,确保扫描新条码时自动隐藏旧模型。
修改后的完整脚本
using UnityEngine; using Vuforia; using TMPro; public class SimpleBarcodeScanner : MonoBehaviour { public TextMeshProUGUI barcodeAsText; private BarcodeBehaviour _barcodeBehaviour; public DictionarySerializer dictionarySerializer; private GameObject _activeModel; void Start() { _barcodeBehaviour = GetComponent<BarcodeBehaviour>(); _activeModel = null; // 注册跟踪状态变化事件,替代Update轮询(更高效) _barcodeBehaviour.OnTrackableStatusChanged += OnBarcodeTrackableStatusChanged; } // 使用事件监听处理跟踪状态变化(推荐,性能更好) private void OnBarcodeTrackableStatusChanged(TrackableBehaviour.Status previousStatus, TrackableBehaviour.Status newStatus) { switch (newStatus) { case TrackableBehaviour.Status.TRACKED: case TrackableBehaviour.Status.EXTENDED_TRACKED: HandleBarcodeDetected(); break; case TrackableBehaviour.Status.NO_POSE: case TrackableBehaviour.Status.NOT_FOUND: HandleBarcodeLost(); break; } } // 兼容旧版本Vuforia的Update轮询方式(可选) // void Update() // { // if (_barcodeBehaviour == null) return; // // var status = _barcodeBehaviour.CurrentStatus; // if (status == TrackableBehaviour.Status.TRACKED || status == TrackableBehaviour.Status.EXTENDED_TRACKED) // { // HandleBarcodeDetected(); // } // else // { // HandleBarcodeLost(); // } // } private void HandleBarcodeDetected() { if (_barcodeBehaviour.InstanceData == null) return; string barcodeText = _barcodeBehaviour.InstanceData.Text; barcodeAsText.text = barcodeText; Debug.Log($"Scanned Barcode ID: {barcodeText}"); if (dictionarySerializer.GetObjectsDictionary() == null || !dictionarySerializer.GetObjectsDictionary().ContainsKey(barcodeText)) { Debug.LogWarning($"No model mapped to barcode: {barcodeText}"); return; } GameObject targetModel = dictionarySerializer.GetObjectsDictionary()[barcodeText]; // 切换模型:如果当前有激活的模型且不是目标模型,先隐藏它 if (_activeModel != null && _activeModel != targetModel) { _activeModel.SetActive(false); } // 激活目标模型 targetModel.SetActive(true); _activeModel = targetModel; } private void HandleBarcodeLost() { Debug.Log("Barcode lost from view"); if (_activeModel != null) { _activeModel.SetActive(false); _activeModel = null; } barcodeAsText.text = ""; // 可选:清空显示的条码文本 } void OnDestroy() { // 移除事件监听,避免内存泄漏 if (_barcodeBehaviour != null) { _barcodeBehaviour.OnTrackableStatusChanged -= OnBarcodeTrackableStatusChanged; } } }
关键修改点说明
- 跟踪状态判断:用
TrackableBehaviour.Status的枚举值替代InstanceData是否为空,准确识别条码状态:TRACKED/EXTENDED_TRACKED:条码在视野内且被稳定跟踪NO_POSE/NOT_FOUND:条码移出视野或无法识别
- 模型切换优化:扫描新条码时自动隐藏旧模型,实现无缝切换
- 事件监听替代Update轮询:使用
OnTrackableStatusChanged事件代替每帧轮询,提升性能(也保留了Update方式作为兼容选项) - 内存泄漏防护:在脚本销毁时移除事件监听
额外注意事项
- 确保所有3D模型初始状态为非激活状态(
SetActive(false)),避免一开始就显示 - 模型的位置应该绑定到条码跟踪对象(即挂载
BarcodeBehaviour的GameObject),这样模型才能跟随条码位置叠加显示 - 检查
DictionarySerializer返回的字典是否正确映射了条码ID和模型对象
内容的提问来源于stack exchange,提问作者anya
相关产品推荐
相关产品推荐

