最近在做一个MR(混合现实)应用的项目,用的是HoloLens 2和Unity开发。
这个项目看起来很酷,把虚拟物体叠加到真实世界中,用手势和眼神交互,听起来很有未来感。但实际开发起来,坑多得让人怀疑人生。很多问题在文档里找不到答案,在网上也搜不到解决方案,只能自己一点点摸索,熬了好几个通宵。
这篇文章就来记录一下我在MR开发中遇到的那些坑,以及最终是怎么解决的。希望能给正在做MR开发的朋友一些参考,少走一些弯路。
坑一:开发环境配置
第一个坑就是开发环境的配置,这是最基础但也最容易出问题的地方。
MR开发需要安装的东西很多:Visual Studio、Unity、Windows SDK、Mixed Reality Toolkit(MRTK)、HoloLens模拟器、设备驱动等等。而且这些工具的版本必须匹配,差一个版本都可能出问题。
我第一次配置环境的时候,用的是最新版的Unity 2022 LTS,结果发现MRTK 2.x不支持这个版本的Unity,各种报错。后来查了文档才知道,MRTK 2.x最高支持Unity 2021 LTS,MRTK 3才支持Unity 2022。
我又换成了Unity 2021,结果Visual Studio的版本又不对,UWP构建工具没装全,打包的时候各种报错。又花了半天时间装Visual Studio的组件,才终于能正常打包。
还有一个坑是HoloLens模拟器。模拟器需要启用Hyper-V,而Hyper-V和VMware、Docker Desktop有冲突。我电脑上装了Docker,启用Hyper-V之后Docker就用不了了,只能二选一。最后我在BIOS里开了嵌套虚拟化,才让两者共存,但性能打了折扣。
建议:开发之前一定要仔细看官方文档,确认各个工具的版本兼容性。不要盲目用最新版,MR开发的工具链更新比较慢,最新版往往不兼容。最好按照官方推荐的版本来装,能省很多麻烦。
坑二:空间锚点丢失
空间锚点(Spatial Anchor)是MR应用的核心,它能让虚拟物体固定在真实世界的位置上,你走动的时候虚拟物体不会跟着跑。
但空间锚点是我遇到的最头疼的问题之一。
第一个问题是锚点保存之后,下次打开应用找不到了。HoloLens的空间锚点是保存在设备上的,但有时候设备会清理空间数据,或者环境变化太大,锚点就找不到了。我们的应用需要用户把虚拟物体放在固定位置,下次打开还在那里,但经常出现锚点丢失的情况。
解决方案是用Azure Spatial Anchors(Azure空间锚点),把锚点保存在云端,而不是本地。这样即使本地锚点丢了,也能从云端恢复。但Azure Spatial Anchors需要联网,而且配置比较复杂,还要收费。我们最后用了混合方案:本地锚点为主,云端锚点为备份,本地找不到的时候再从云端恢复。
第二个问题是锚点漂移。有时候虚拟物体放好了,过一会儿就慢慢偏移了,特别是在环境特征少的地方(比如白墙、空旷的房间)。这是因为HoloLens的空间映射在不断更新,锚点的位置会随着空间理解的变化而微调。
解决方案是在放置锚点的时候,选择环境特征丰富的位置(比如有纹理的墙面、角落、家具旁边),避免放在空旷的地方。同时,应用启动的时候做一次空间扫描,让设备充分理解环境,再恢复锚点。
第三个问题是多设备共享锚点。多个HoloLens设备需要看到同一个虚拟物体在同一个位置,这就需要共享空间锚点。用Azure Spatial Anchors可以实现,但延迟比较高,而且有时候不同设备恢复的锚点位置有偏差。我们最后用了一个折中方案:一个设备创建锚点并分享坐标,其他设备根据相对位置来放置虚拟物体,虽然不是完全精确,但对于我们的应用场景来说够用了。
坑三:手势交互
HoloLens的主要交互方式是手势,比如隔空点击、手势导航、手势操作。听起来很自然,但实际开发起来,手势交互的坑很多。
第一个问题是手势识别不稳定。用户的手在摄像头视野里的时候,识别还可以;但手移到视野边缘,或者光线不好,或者手的姿势不标准,识别就会出问题。用户经常反映"点了没反应""手势不灵敏"。
解决方案是:第一,在UI上给用户明确的提示,告诉用户手应该放在什么位置、做什么手势;第二,增加视觉反馈,手被识别到的时候显示一个手的模型,点击的时候有反馈效果;第三,提供多种交互方式,除了手势,还可以用语音、凝视、蓝牙遥控器,让用户选择最适合自己的方式。
第二个问题是手势的精度不够。隔空点击的精度不如鼠标和触摸屏,用户经常点错按钮,特别是按钮比较小或者靠得比较近的时候。
解决方案是:把UI元素做大一点,按钮之间留足够的间距。MR界面的设计原则和2D界面不一样,不能按照手机或电脑的尺寸来设计。一般来说,按钮的最小尺寸是3到4厘米,间距至少1厘米。而且要把常用的按钮放在用户容易操作的位置(胸前偏下的区域),不要放太高或太低。
第三个问题是手势疲劳。长时间抬手做手势,用户会觉得手臂酸。这是MR交互的通病,被称为"哥斯拉手臂"(Gorilla Arm)。
解决方案是:设计交互的时候,尽量减少需要抬手的操作。比如用凝视+点击的方式,用户只需要看着按钮,然后用手指轻轻一捏就行,不需要抬手去点。还可以设计一些不需要手势的交互,比如语音控制、头部姿态控制。同时,给用户休息的时间,不要让用户一直抬着手操作。
坑四:性能优化
MR应用对性能的要求很高,因为需要实时渲染立体画面,还要处理空间映射、手势识别、眼动追踪等。HoloLens 2的性能虽然比第一代强了不少,但和电脑比起来还是差很多,性能优化是MR开发的重中之重。
我遇到的性能问题主要有这几个。
第一个问题是帧率低。HoloLens 2的目标帧率是60fps,但我们的应用刚开始只有30到40fps,画面卡顿,用户体验很差,还会导致头晕。
排查之后发现,主要原因是模型面数太高、材质太复杂、draw call太多。我们做了这几个优化:把3D模型的面数减到最低(能用低模就不用高模),合并材质和纹理,减少draw call;用简单的shader,避免复杂的光照计算;关闭不必要的后处理效果(比如抗锯齿、景深);用遮挡剔除,只渲染可见的物体。
优化之后,帧率稳定在了60fps,画面流畅了很多。
第二个问题是内存不足。HoloLens 2的内存只有4GB,而且系统占用了一部分,应用能用的内存不多。我们的应用加载了几个大的3D模型之后,就出现了内存不足的情况,应用崩溃。
解决方案是:模型用压缩格式,减少内存占用;不要一次性加载所有模型,用的时候再加载,不用的时候卸载;纹理用压缩格式,尺寸不要太大(最大1024x1024);及时释放不用的资源,避免内存泄漏。
第三个问题是发热和降频。长时间运行之后,HoloLens 2会发热,然后CPU和GPU降频,性能下降,帧率降低。特别是在夏天或者环境温度高的时候,更明显。
解决方案是:不要让应用一直满负荷运行,在不需要的时候降低渲染质量或者帧率;优化应用的功耗,减少不必要的计算;提醒用户适时休息,不要连续使用太长时间。
坑五:空间映射和碰撞
MR应用需要把虚拟物体和真实世界融合,这就需要空间映射(Spatial Mapping)——用设备的深度摄像头扫描真实环境,生成一个3D网格。
空间映射的坑也不少。
第一个问题是空间映射不完整。HoloLens的深度摄像头有一定的范围和精度,对于黑色的、反光的、透明的物体,扫描效果不好。比如黑色的显示器、玻璃桌面、镜面,经常扫描不出来,导致虚拟物体穿过这些物体,或者落在错误的位置。
解决方案是:在应用中提示用户扫描环境,特别是要扫描到关键的物体;对于扫描不到的物体,可以让用户手动标记位置;在放置虚拟物体的时候,做一些合理性检查,避免放在明显不合理的位置。
第二个问题是碰撞检测不准确。我们希望虚拟物体能和真实世界碰撞,比如放在桌子上不会掉下去,撞到墙会停下来。但空间映射的网格是不完美的,有很多噪点和漏洞,碰撞检测经常出问题,虚拟物体会掉下去或者穿墙。
解决方案是:不要完全依赖空间映射的网格做碰撞,可以用平面检测(Plane Detection)来识别桌面、地面、墙面,用平面来做碰撞,更稳定。同时,给虚拟物体加一些物理约束,比如最大下落距离、位置限制,避免出现太离谱的情况。
第三个问题是空间映射更新导致的抖动。HoloLens的空间映射在不断更新,当用户走动或者环境变化的时候,网格会变化,导致虚拟物体的位置出现抖动或者偏移。
解决方案是:虚拟物体一旦放置好,就锁定位置,不要随着空间映射的更新而变化。用空间锚点来固定虚拟物体的位置,而不是每帧根据空间映射重新计算。
坑六:语音交互
HoloLens支持语音交互,这是一个很重要的交互方式,特别是在手不方便的时候。
但语音交互的坑也不少。
第一个问题是语音识别率低。在嘈杂的环境下,或者用户有口音,语音识别的准确率会下降。用户经常反映"说了好几遍都识别不出来"。
解决方案是:用关键词识别而不是连续语音识别,关键词的识别率更高;给用户明确的语音指令提示,让用户知道可以说什么;提供语音反馈,识别到指令之后重复一遍,让用户确认;除了语音,提供其他交互方式作为备选。
第二个问题是语音指令冲突。我们定义了很多语音指令,有些发音相似,导致识别错误。比如"打开设置"和"打开摄像头",经常被混淆。
解决方案是:指令之间的发音差异要大,避免用发音相似的词;指令不要太长,2到4个字最好;给每个指令加一个前缀,比如"你好小助手,打开设置",减少误识别。
第三个问题是多语言支持。我们的应用需要支持中文和英文,但不同语言的语音识别需要不同的配置,而且切换语言的时候需要重新加载语音模型,有延迟。
解决方案是:在应用设置里让用户选择语言,根据语言加载对应的语音识别配置;切换语言的时候给用户提示,让用户等待加载完成;对于关键指令,可以同时支持多种语言,不需要切换。
坑七:部署和更新
MR应用的部署和更新,和普通的手机、电脑应用不太一样,也有一些坑。
第一个问题是部署麻烦。HoloLens的应用部署,可以通过Visual Studio远程部署,也可以打包成appx文件通过设备门户安装。但远程部署经常失败,特别是网络不稳定的时候;设备门户安装需要先配对设备,操作也比较繁琐。
解决方案是:用Visual Studio远程部署的时候,确保电脑和HoloLens在同一个网络,而且网络稳定;打包成appx之后,可以用U盘安装,比设备门户更方便;对于企业用户,可以用设备管理平台批量部署。
第二个问题是更新不及时。HoloLens的应用更新,需要用户手动在商店里更新,或者管理员通过设备管理平台推送。如果用户不主动更新,就会一直用旧版本,出现兼容性问题。
解决方案是:在应用里加版本检测,有新版本的时候提示用户更新;对于企业应用,用设备管理平台强制更新;重要更新可以在服务端做兼容,同时支持多个版本的客户端。
第三个问题是设备差异。不同的HoloLens设备,系统版本、硬件状态、空间数据都不一样,同样的应用在不同设备上表现可能不一样。比如有的设备空间锚点保存得好,有的就经常丢;有的设备摄像头校准得好,手势识别就准,有的就差一些。
解决方案是:应用要做容错处理,不要假设设备的状态一定是完美的;在应用启动的时候做设备状态检测,有问题的时候给用户提示;提供详细的日志,方便排查问题。
一些经验和建议
踩了这么多坑之后,我总结了一些MR开发的经验和建议。
第一,先做原型再做完整应用。MR开发的不确定性很大,很多问题只有在真实设备上才能发现。先做一个简单的原型,验证核心交互和技术可行性,再逐步完善,不要一开始就做复杂的功能。
第二,多用真机测试。模拟器虽然方便,但和真机的体验差很多。手势、空间映射、性能这些,只有在真机上才能准确测试。尽量每天都在真机上测试,不要等到最后才上真机。
第三,关注用户体验。MR是一个新的交互方式,用户没有使用经验,很多在手机上理所当然的操作,在MR里用户可能不知道怎么做。要多做用户测试,观察用户怎么用你的应用,根据反馈优化交互。
第四,性能优化从一开始就做。不要等功能做完了再优化性能,那时候可能架构已经定了,改起来很麻烦。从项目一开始就关注性能,定期做性能测试,发现问题及时解决。
第五,文档和社区很重要。MR开发的资料相对较少,官方文档有时候也不够详细。要多关注官方文档、论坛、GitHub,遇到问题多搜多问。很多坑已经有人踩过了,能找到解决方案。
第六,保持耐心。MR开发确实比普通应用开发难,坑多,资料少,很多问题需要自己摸索。遇到问题不要急,一步步排查,总会找到解决方案的。
写在最后
MR混合现实开发,是一个充满挑战但也充满乐趣的领域。
当你第一次看到自己做的虚拟物体出现在真实世界中,能用手去触摸、去交互的时候,那种成就感是很难用语言形容的。但在这之前,你可能需要熬过无数个调试的夜晚,踩过无数个莫名其妙的坑。
这篇文章记录了我在MR开发中遇到的主要问题和解决方案,包括环境配置、空间锚点、手势交互、性能优化、空间映射、语音交互、部署更新等方面。希望能给正在做MR开发的朋友一些参考,少走一些弯路。
MR技术还在快速发展中,很多现在的坑,未来可能会被更好的工具和框架解决。但在那之前,我们只能自己摸索,在踩坑中成长。
如果你也在做MR开发,或者对MR感兴趣,欢迎交流讨论。让我们一起在这个充满未来感的领域里,探索更多的可能性。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录