首页 / 资讯中心 / 文章详情

ARFoundation集成SenseAR:桥接方案解决AR平面检测稳定性实践

ARFoundation集成SenseAR:桥接方案解决AR平面检测稳定性实践 ★ FEATURED ARTICLE
ARFoundation集成SenseAR这件事最早是我们组里的一次“被迫尝试”。当时手头有一套AR试鞋应用一直跑在ARFoundation上跨平台抽象确实省心iOS端和Android端一套代码就能出包。但问题出在部分中低端安卓机型上地面平面的识别结果不稳定3D鞋模放上去之后会轻微悬空或歪斜用户拿手机转两圈就明显感觉“模型没站在地上”。我试过调置信度阈值、换识别模式收效都有限。后来拿到SenseAR的Unity集成包在同样的真机上做了对比同一个房间、同一个地面SenseAR的平面检测稳定性明显好一截。当时的直接想法是把整套AR能力换成SenseAR——但真动手评估之后发现上层的交互逻辑、生命周期管理、资源加载都是按ARFoundation接口写的推倒重来不仅工作量巨大后续维护也是双份成本。所以最后选了一条折中路保留ARFoundation做上层框架把SenseAR作为底层算法引擎接进来。这篇是第一篇重点讲清楚三件事为什么值得做这种集成、环境准备阶段要注意什么、以及第一版桥接架构怎么搭、怎么跑通第一个AR场景。如果你也在做类似的事——手里有一套ARFoundation项目又拿到一个第三方AR引擎要融进去——这篇应该能帮你省不少试错时间。1. 这个集成的真实动机两个引擎各有各的“主场”1.1 我们的场景与真正的痛点AR试鞋这个场景听起来简单实际对上层的稳定性要求很高。用户把手机对准地面系统需要快速识别出水平平面然后把鞋模稳定地“放”上去。这里有两个硬指标识别速度要够快基本一秒内要出结果位置要够稳手机轻微移动时鞋模不能跟着乱跳。ARFoundation默认提供了一整套统一的AR工作流从会话生命周期到平面检测、相机画面渲染都是封装好的。优点是开发效率高缺点也很明显底层能力完全依赖系统级AR服务不同机型、不同系统版本的算法表现差异很大。我们在测试机上梳理过大概有15%左右的机型会出现平面识别不稳定的情况模型悬空、识别失败、掉跟踪是主要问题集中在中低端设备上。这个痛点不是靠调UI层能解决的属于算法层的差距。SenseAR在平面检测上采用的是另一套算法管线在某些设备上确实能补上这个短板。1.2 为什么舍不得丢掉ARFoundation可能有人会问既然SenseAR效果好为什么不整个换掉我的回答是方案选型不能只看单点效果要看整个工程的开销。ARFoundation的好处在于它把所有AR概念统一成了同一个对象模型——ARSession、ARCameraManager、ARPlaneManager、ARTrackable。这些接口不区分你用的是哪家底层能力切换底层的时候上层代码基本不用动。这个价值在做多端版本的时候特别明显。我们的AR试鞋应用不只在Android端跑iOS端也要同步发版。如果全部迁到SenseAR意味着iOS端也要重新找一套对应能力否则两端代码就分叉了。而桥接方案可以让两端继续共用上层的交互和业务逻辑只是底层能力各自适配维护成本要低得多。1.3 集成的边界到底画在哪里说得直白一点这次集成不是“用SenseAR替换ARFoundation”而是在ARFoundation的工作流里把底层算法换源。ARFoundation负责的还是那几件事摄像头权限管理、AR Session生命周期、Unity侧的渲染管线。SenseAR负责的是它更强的那块底层SLAM、平面识别、位姿估计。我们需要做的是写一层翻译代码把SenseAR给出的结果映射成ARFoundation上层能直接消费的数据。判断你这个项目适不适合做类似集成我有一个简单清单当前默认AR框架在目标机型上是否真的有明显短板第三方引擎的能力是否能覆盖这块短板且差距值得投入开发成本上层业务是否已经大量依赖现有框架的接口导致整体替换成本不可接受是否有足够的真机测试资源能支撑双引擎长时间的稳定性验证如果这四条里能对上三条那这条集成路线基本是值得试的。2. 环境准备阶段最容易翻车的三件事2.1 Unity、ARFoundation、SenseAR的版本对应关系这个坑我替你们踩过了版本不匹配是绝大多数编译报错和运行崩溃的来源。我先说明一下我们最终定下来的版本组合供参考组件版本说明Unity2021.3 LTS建议用LTS版本稳定优先ARFoundation4.2.x与Unity 2021.3兼容性较好SenseAR SDK当时最新发布版需向厂商技术支持确认与ARF 4.2的兼容性构建平台AndroidSenseAR侧重点在Android端能力这里要特别提醒一点ARFoundation的不同小版本底层接口会有微调。比如某些版本中ARPlaneManager的事件回调时机变化了某些版本对自定义渲染纹理的支持方式不同。另外SenseAR SDK通常是通过相机纹理和位姿数据来对接Unity渲染层的如果ARFoundation版本太新可能会出现渲染纹理获取方式对不上的问题。还有一个小细节Unity的Package Manager有时候会自动把ARFoundation解析成和你预期不同的版本建议在项目里加一个packages-lock.json的版本固定并且把不需要的ARFoundation扩展包比如ARCore/ARKit的specific package暂时都关掉排除干扰项。2.2 插件包冲突最常见的隐性地雷同时导入多套AR相关SDK容易出现符号冲突。我们第一次集成时导入SenseAR的Unity包之后编译直接报了大量重复定义错误主要集中在AndroidX库上——ARFoundation及其底层依赖会引入一个版本的AndroidXSenseAR包又带了一套Gradle合并时直接打起来。解决思路分三步实际操作下来很有效先建一个干净的Unity工程只导入ARFoundation和SenseAR排除业务代码干扰确认基础编译能过。比对两个SDK的依赖关系把重复的AndroidX库统一保留一个版本一般以官方较新的版本为准。如果SenseAR提供的是Android模块AAR优先手动放到Assets/Plugins/Android下并在Player Settings里关掉默认的AndroidX自动解析改成手动管理依赖。另外不要忽略Manifest合并问题。SenseAR通常需要在AndroidManifest里声明自己的Activity或Service两个SDK的Manifest节点偶尔会产生冲突建议用合并后的最终Manifest检查一遍关键节点是否都在。2.3 权限、机型适配与初始化前置条件SenseAR这类第三方AR引擎有一个特点它对机型有明确的适配列表不是所有Android设备都能跑。这一点在上项目前必须确认。我们做的最小权限配置如下CAMERA必须AR功能的基础INTERNET部分引擎用于联网验证授权ACCESS_NETWORK_STATE检查网络状态WAKE_LOCK防止识别过程中屏幕休眠除了权限机型适配校验也很关键。SenseAR一般会提供一个设备能力检测接口需要在初始化前先调用根据返回值判断当前设备是否支持。根据我们的经验这个检测结果不能单看Unity日志——某些型号在引擎内部校验失败后日志是静默的建议在真机上专门写一个UI页面展示检测结果方便测试阶段快速排查。最后是Gradle配置。建议把minSdkVersion设到23以上targetSdkVersion跟随Unity默认版本即可。SenseAR某些算法对CPU指令集有要求部分老机型是armeabi-v7a架构需要在Player Settings里确认CPU架构勾选是否包含了目标真机的指令集。3. 架构选择为什么我建议“桥接”而不是“替换”3.1 三种可行方案对比在决定具体实现前我把可行方案列了一遍最后选定了方案B。这里把三种方案整理成表格方便对比方案核心思路改造量主要风险A. 完全替换底层去掉ARFoundation所有AR能力走SenseAR大上层全部要改两端工程分叉iOS无对应方案B. 桥接层方案ARFoundation管生命周期和渲染SenseAR管算法中主要加一个翻译层双引擎共存时相机和位姿的冲突C. 原生双栈方案完全绕开Unity的AR封装自己写Android原生调用极大需要从Unity底层做起需要自己接渲染管线坑太多方案B胜在改动可控——我们不需要动任何业务层的ARFoundation调用只需要把底层的数据来源换掉。代价是多加一层桥接代码以及可能要处理双引擎同时活动时的资源冲突。3.2 桥接层的核心职责做“翻译官”桥接层要做的事本质上是一个翻译过程。SenseAR给出的底层结果和ARFoundation上层需要的结构并不一致。比如SenseAR识别出一个平面可能返回的是引擎自己定义的坐标系统、平面参数矩阵而ARFoundation的ARPlaneManager需要的是它自己定义的BoundedPlane。桥接层就要完成这个映射把引擎的平面数据转换成ARFoundation的ARTrackable结构再交给上层业务使用。我用一个生活化的类比来说明ARFoundation像是一个只讲普通话的经理SenseAR只讲方言。桥接层就是那个翻译——经理该指挥还是指挥方言那边干活的效率还是一样高但双方的信息能流畅互通。这个翻译层还有一个重要职责位姿数据的同步。ARFoundation自身的ARSession会维护一套Unity世界坐标下的相机位姿SenseAR也有自己引擎内部的相机位姿。如果不做校准两套坐标系会打架最典型的表现就是画面里模型在漂移或者相机转动时追踪结果不对。3.3 桥接层的代码骨架一个示例结构下面是我在工程里实际使用的桥接层结构类名是我自己封装的不代表SenseAR官方API你接入时要以自己拿到的SDK为准public sealed class ARFoundBridgeManager : MonoBehaviour { [SerializeField] private ARSession arSession; [SerializeField] private ARCameraManager arCameraManager; [SerializeField] private ARPlaneManager arPlaneManager; private ISenseARClient senseClient; private bool isBridging; private void Start() { // 1. 先初始化SenseAR客户端自定义封装 senseClient.Init(); // 2. 订阅SenseAR的帧数据和平面结果 senseClient.OnPlaneDetected OnSensePlaneDetected; senseClient.OnFramePose OnSenseFramePose; // 3. 等待初始化回调后再启动ARFoundation senseClient.OnReady OnSenseReady; } private void OnSenseReady() { arSession.enabled true; arCameraManager.enabled true; arPlaneManager.enabled true; isBridging true; } private void OnSensePlaneDetected(SensePlaneResult plane) { // 将SenseAR的平面结果转换为ARFoundation的BoundedPlane结构 ARPersistenceBridge.TranslatePlane(plane, out var translatedPlane); arPlaneManager.UpdatePlaneData(translatedPlane); } private void OnSenseFramePose(SensePose pose) { // 将SenseAR的相机位姿同步到ARFoundation的跟踪数据中 if (isBridging) { arCameraManager.UpdateExternalPose(pose.ToUnityPose()); } } }这段代码的核心思想是ARFoundation的ARSession正常启动但底层位姿和平面数据不来自系统AR服务而是来自SenseAR。代码里我并没有去接管Unity的渲染管线只是把数据源替换了这样对业务层是透明的。要提醒的是这段代码只是一个结构示范。实际对接的时候你需要仔细查阅SenseAR SDK里关于“外部位姿注入”“平面数据上报”的接口文档不同版本的接口差异确实比较大。4. 从零跑通首个AR场景的实操记录4.1 导入与工程配置的分步清单实际动手的第一步是搭一个干净的Demo工程。这个步骤看起来基础但很关键不要直接在原有大型工程里试否则分不清报错是业务引入的还是集成引入的。我的操作步骤是这样新建Unity工程选择3D模板版本固定在我们定好的2021.3 LTS。通过Package Manager安装ARFoundation 4.2.x同时勾选对应的XR Plugin Management模块。手动导入SenseAR的UnityPackage这里注意只勾选核心运行时模块不要勾Demo场景和示例资源。示例场景里通常会自带相机Rig和旧版本依赖导入后会和ARFoundation的新建场景冲突。把SDK自带的Android依赖包AAR或JAR复制到Assets/Plugins/Android目录下。检查AndroidManifest合并结果确认权限和SDK组件声明都已经合入。在Player Settings中设置Minimum API Level为23以上并将Graphics API保持为OpenGLES 3.0或更高版本。这几步做完之后建议先做一个最简单的编译验证确认工程能正常出包。别急着写桥接逻辑先跑一次空包。4.2 初始化时序先SenseAR后ARFoundation初始化顺序这个事当初差点把整个项目带偏。最开始的写法是让SenseAR和ARFoundation的ARSession在同一个帧里同时启动结果出现了两个问题一是摄像头权限竞争两个模块抢相机会话画面出现黑帧二是位姿数据冲突两套坐标系同时向Unity汇报渲染结果随机抖动。后面整理出的标准时序是这样的请求相机权限必须等用户授权回调成功。调用SenseAR的设备能力检测接口判断当前真机是否支持。初始化SenseAR引擎等待其内部完成SLAM初始化。收到SenseAR的Ready回调后再启用ARFoundation的ARSession。ARSession启动后再依次启用ARCameraManager和ARPlaneManager。这里最核心的一点是SenseAR必须作为“主时钟”先启动ARFoundation作为辅助方后启动。因为SenseAR的算法管线一旦启动就会开始跟踪相机位姿并按帧回调ARFoundation启动后直接消费这些已有数据而不是自己再另起一套跟踪逻辑。这个顺序还有一个额外的好处方便降级。如果设备不满足SenseAR的适配要求初始化会提前失败这时可以退回到ARFoundation默认能力保证应用不会直接黑屏或崩溃。4.3 背景纹理挂接与首个平面验证初始化跑通之后下一个要解决的问题是让他能看见SenseAR的画面。ARFoundation默认的ARCameraBackground会去系统AR能力那边拿相机纹理但既然底层能力已经换成了SenseARARCameraBackground默认那套逻辑就拿不到数据了。解决办法是把SenseAR输出的相机纹理绑定到CameraBackground使用的材质上。这个步骤在不同SDK里差异比较大我只说通用思路SenseAR通常会提供相机纹理接口拿到的是一个Unity纹理对象然后你需要把ARCameraBackground的目标材质替换成能消费这个纹理的着色器。注意纹理格式要匹配我遇到过SenseAR输出YUV格式而默认材质只认RGBA直接显示出来就是灰绿色的异常画面。第一次验证成功是在一个很朴素的场景里完成的镜头对准地面Code里监听ARPlaneManager的planesChanged事件检测到平面后在平面中心点实例化一个Cube。当时在测试机上看到Cube稳稳“躺”到地板上我知道桥接层已经起效果了。5. 这一周我踩过的坑从初始化失败到追踪静止5.1 设备能力判断在真机上“失效”第一个坑出现在设备校验环节。在编辑器里调用SenseAR的设备检测接口时返回正常装机到真机上后代码里拿到的结果却是“不支持”。排查后发现问题不在SDK而在于我把设备校验放在了相机权限授权之前。某些引擎在硬件检测阶段需要申请相机句柄权限没给到就进入检测会导致检测逻辑直接走异常分支。修正方式很简单先明确拿到相机权限再调用设备检测接口。另一个相关点是设备校验结果最好用引擎自带的状态码去判断不要只判断布尔值。部分机型虽然适配但可能处于低电量模式引擎会返回一个“性能受限”的状态码这时候启动SLAM虽然能跑但识别精度会下降。这一步放在正式版本里可以提前预警。5.2 黑屏但日志一切正常纹理格式与渲染时序问题集成过程中最折磨人的问题就是黑屏。日志没有报错ARSession状态正常平面识别的事件也有数据回调但屏幕就是黑的。我花了大半天才定位到根因——渲染线程的纹理时序问题。SenseAR输出的相机纹理是在引擎自己的渲染线程上更新的而Unity的相机背景渲染在另一个线程两边没有一个同步信号。结果就是时不时出现空纹理帧表现就是黑屏或者画面每隔几十帧闪一下黑。解决方式是把纹理更新放到Unity的渲染线程上执行具体来说是使用OnBeforeRender或者直接订阅ARFoundation的frameReceived事件确保在Unity渲染该帧之前已经拿到了SenseAR最新的一帧纹理。简单说就是先让SenseAR产帧Unity在渲染前取走顺序不能反。5.3 画面会动但追踪物在“原地飘”矩阵覆盖问题还有个干扰现象背景画面看起来是正常移动的但已经放置在地面上的Cube却在原地小幅抖动像是粘了根弹簧。这个问题排查到最后是位姿矩阵更新冲突。ARFoundation的ARSession和SenseAR都在向同一个相机Pose字段写数据你以为覆盖成了SenseAR的数据但实际上ARFoundation在某个内部逻辑里又把系统AR能力算出来的旧位姿写回去了。两套数据交替出现表现就是追踪物在两点之间来回抖。解决方式是彻底关掉ARFoundation默认的位姿计算路径明确让ARSession进入“外部位姿驱动”模式。这个能力在不同版本的ARFoundation里叫法不同我们用的4.2.x中有对应的开关可以设置打开后位姿完全由SenseAR通过桥接层注入。这里请大家仔细阅读自己所用ARFoundation版本的更新说明路径不对会导致设置无效。5.4 一条完整的排查思路从权限到坐标系逐步收窄如果你在集成时也遇到了类似问题我建议按这个顺序排查能少走很多弯路先确认相机权限已授权这是最底层的前提。确认SenseAR初始化回调正常触发日志中无明显错误状态码。确认设备适配检查通过排除引擎不支持当前机型的可能性。单独验证SenseAR的原生Demo能正常运行判断SDK本身是否健康。确认相机纹理能正常错绑到Unity材质上可以先输出一张静态纹理图做检查。最后再检查位姿矩阵同步验证Cube在静止状态下是否真的稳定在平面中心。按这个链路走大部分问题都能定位到具体的某一层而不是在多个变量之间乱猜。6. 第一篇结束前先交代一下后续计划第一轮的成果是让SenseAR的平面检测能力成功“接入”到ARFoundation项目里并且跑通了从相机画面到平面识别到Unity对象放置的完整链路。至于SenseAR更强的能力——例如更细粒度的人脸关键点跟踪、手势识别、以及场景重建——目前还没有做深度集成这些计划留到系列第二篇。在进入第二篇之前我建议你先把这几件事准备好准备至少两台不同厂牌、不同性能档位的Android测试机优先覆盖引擎适配列表里存在差异的机型。把SenseAR SDK的日志开关打开尤其是verbose级别的日志方便后续排查坐标系、平面置信度的问题。对当前能跑的版本做一个固定备份后续每改一步都能回退对比。集成第三方AR引擎这件事难的不是“怎么把包导进去”而是“怎么让两套系统在边界上不打架”。这篇记录的每一步基本都是在跟这种边界问题打交道。第二篇我会重点展开平面位姿同步的矩阵细节以及我们是如何在双引擎共存状态下解决坐标系漂移的。
阅读完成 · 觉得有帮助?
咨询建站