在做基于真实物理空间的增强现实(AR)应用开发时,几个业务痛点经常同时出现:工业设备巡检场景中,巡检员戴着 AR 眼镜或举着平板进入厂房,暗光甚至全黑环境下视觉 SLAM 会瞬间丢失跟踪;展品展示或设备结构拆解要求极高渲染精度,传统 Mesh 贴图模型在半透明材质和复杂光影反射下表现生硬;还有一类特殊场景需要把 AR 解算能力部署到无人机或外置全景相机上,手机自带传感器数据根本用不上。
HarmonyOS 7.0 的 AR Engine 更新,针对这些深度场景给出了一套组合能力:通过底层 C API 直接干预相机闪光灯以解决暗光 SLAM 丢失,开放预览流原始图像数据的直接获取,引入 3D 高斯模型的原生加载支持,并开放外部传感器数据注入进行空间解算。本文以暗光环境下的高精度数字孪生巡检为例,把这四个新特性串联起来,梳理底层流转逻辑和工程落地的关键点。
一、几个核心 API 的能力拆解
1. C API 闪光灯控制(ARSession_OpenFlash)
早期 AR Engine 中相机被引擎独占管理,环境光变暗导致特征点提取失败时,应用层拿不到 Camera 控制权,无法主动开闪光灯,只能眼看着 Tracking 状态变为 LOST。新增的 C API HMS_AREngine_ARSession_OpenFlash 允许开发者在 C/C++ 层直接向运行中的 ARSession 下发闪光灯开关指令。函数签名如下:
- int32_t HMS_AREngine_ARSession_OpenFlash(const HMS_AREngine_ARSession* session, int32_t mode);
复制代码
mode 为 0 表示关闭,1 表示常亮 Torch 模式。这个设计的价值是绕过了上层 CameraKit 的权限协商,直接插入到 AR 引擎内部状态机的补光逻辑中。由于 AR SLAM 对曝光时间极其敏感,底层引擎收到 OpenFlash 指令后会自动调整曝光策略和 ISO 参数,避免突然高光导致特征点过曝而引发位姿跳变。
2. ArkTS 预览流数据抽取(arFrame.acquireCameraImage)
很多场景需要拿到 AR Engine 计算出的 6DoF 位姿,同时还要分析当前画面内容,比如跑本地 AI 缺陷检测模型。以前的做法是拉两路流,移动端功耗和带宽压力很大。新增的 arFrame.acquireCameraImage() 允许业务层直接从 AR 引擎内部渲染流水线中拷出当前物理相机图像帧,实现一虾两吃。调用方式为:
- let imageBuffer = arFrame.acquireCameraImage();
复制代码
返回对象包含图像宽、高、格式(通常为 YUV_420_888)以及 ArrayBuffer 数据。关键点在于返回的是原始 YUV 格式,没有经 GPU 做 RGB 色彩空间转换,因此抽取开销极小,适合直接送入 NPU 做深度学习推理,大多数 NPU 算子原生支持 YUV 处理。
3. 3D 高斯模型加载(arViewController.loadGSModel)
3D Gaussian Splatting 相比 NeRF 的优势在于保证照片级渲染质量的同时实现实时光栅化渲染。它用数百万个带颜色、不透明度、协方差矩阵的高斯椭球体来表达三维空间。新增 API 提供一键加载 .ply 格式高斯模型的能力:
- arViewController.loadGSModel(context, modelPath, scale);
复制代码
底层会自动将庞大的点云数据加载进显存,并启用 HarmonyOS 自研高斯光栅化管线,开发者无需手写 Compute Shader 做高斯排序和 Alpha 混合。
4. 外部传感器计算模式(ARRemoteSensorMode)
这是最具工业价值的能力。比如通过 Type-C 外接安装在安全帽上的深度相机模组,或者把手机 AR Engine 作为算力节点接收局域网内无人机传回的数据。通过配置会话的传感器模式并调用 C API HMS_AREngine_ARSession_FeedSensorData,可以向引擎注入时间戳严格对齐的外部图像和 IMU 数据。配置方式为:
- arConfig.sensorMode = AREngine.ARRemoteSensorMode.EXTERNAL_CAMERA_AND_IMU;
复制代码
启用该模式后,AR Engine 会挂起内部设备相机和传感器驱动轮询,开启高速数据接收缓冲区。开发者需要自己实现高精度时间戳对齐(PTP 或 NTP 同步),SLAM 对图像与 IMU 之间延时极为苛刻,通常要求同步误差小于 1 毫秒。
二、工程落地的关键实现
核心工程结构按功能模块划分:ARInspectionPage 承载 XComponent 和交互,AREngineManager 做 AR 会话与状态机全局管理,GsModelRenderer 负责高斯模型加载与渲染,ExternalSensorDriver 负责外部相机与 IMU 数据流读取和时间戳对齐。闪光灯控制和外部数据注入放在 C++ 层通过 NAPI 暴露给 ArkTS,AR 生命周期和高斯模型加载在 ArkTS 层完成。
1. C++ 层封装闪光灯控制
在 NAPI 层调用 C API 时,需要缓存全局 Session 指针。示例代码如下:
- #include "napi/native_api.h"
- #include "huawei_arengine_interface.h"
- #include <hilog/log.h>
- static HMS_AREngine_ARSession* g_arSession = nullptr;
- static napi_value SetFlashMode(napi_env env, napi_callback_info info) {
- size_t argc = 1;
- napi_value args[1] = {nullptr};
- napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
- int32_t mode = 0;
- napi_get_value_int32(env, args[0], &mode);
- if (g_arSession == nullptr) {
- OH_LOG_ERROR(LOG_APP, "ARSession is null, cannot set flash.");
- return nullptr;
- }
- int32_t ret = HMS_AREngine_ARSession_OpenFlash(g_arSession, mode);
- if (ret != 0) {
- OH_LOG_WARN(LOG_APP, "Failed to open flash, error code: %{public}d", ret);
- }
- napi_value result;
- napi_create_int32(env, ret, &result);
- return result;
- }
复制代码
2. ArkTS 层:预览流抽取与高斯模型加载
帧循环中需要同时处理暗光检测、闪光灯控制和预览帧抽取。参考实现如下:
- export class AREngineManager {
- private isFlashOn: boolean = false;
- public async initSession(context: Context) {
- let config = new AREngine.ARConfig();
- config.sensorMode = AREngine.ARRemoteSensorMode.DEFAULT;
- this.arSession = new AREngine.ARSession();
- await this.arSession.configure(config);
- this.arSession.resume();
- }
- public loadInspectionModel(modelPath: string) {
- if (!this.arViewController) return;
- // .ply 高斯模型通常几十MB到上百MB,建议放本地存储而非 rawfile
- this.arViewController.loadGSModel(modelPath, 0.5);
- }
- public onFrameUpdate(frame: AREngine.ARFrame) {
- let lightEstimate = frame.getLightEstimate();
- if (lightEstimate.getState() === AREngine.LightEstimateState.VALID) {
- let pixelIntensity = lightEstimate.getPixelIntensity();
- // 开启阈值 0.15,关闭阈值 0.3,防止临界点频繁闪烁
- if (pixelIntensity < 0.15 && !this.isFlashOn) {
- flashControl.setFlashMode(1);
- this.isFlashOn = true;
- } else if (pixelIntensity > 0.3 && this.isFlashOn) {
- flashControl.setFlashMode(0);
- this.isFlashOn = false;
- }
- }
- // 零拷贝获取相机图像,YUV_420_888 格式
- let cameraImage = frame.acquireCameraImage();
- if (cameraImage) {
- let rawBuffer = cameraImage.data;
- // TODO: 送入 NPU 模型推理,推理后必须及时释放,避免渲染管线无 Buffer 可用
- }
- }
- }
复制代码
两个关键设计决策值得注意。一是防抖动机制:开启阈值 0.15、关闭阈值 0.3 是实际车间测试得出的经验值,环境光在临界点波动时闪光灯不会疯狂跳闪。二是零拷贝获取:acquireCameraImage() 拿到的是底层物理内存映射块,没有 CPU 深拷贝,业务层推理时要极其小心生命周期,切忌长期持有,否则底层渲染管线无 Buffer 可用会引发画面卡死。
三、避坑指南
外部传感器模式的时间戳对齐是重中之重。如果不理解 SLAM 中 IMU 预积分对时间戳的极度敏感性,盲目把网络接收到的外部视频流喂给引擎,大概率只会得到一堆报错。硬件强同步是玩转 RemoteSensor 模式的前提底线。此外,高斯模型文件体量很大,加载时要考虑内存占用和加载耗时,scale 参数需要根据实际模型空间尺度微调。
梳理下来,HarmonyOS 7.0 AR Engine 这次升级的核心逻辑是开放与下放:把原本深埋在引擎黑盒里的曝光控制、原始数据流抽取、传感器输入源选择全部交还给开发者。对 3D Gaussian Splatting 的原生支持,则在渲染维度上追平了业界最新标准。实际工程中这些能力往往组合使用:极暗环境中调用 C API 开启闪光灯,同时通过 acquireCameraImage 提取提亮后的画面送给本地缺陷检测模型,再将问题部件用高精度 3D 高斯模型叠加到真实物理空间上。正是这些底层 API 的串联,让开发者可以用 ArkTS 与 C++ 构筑具备生产力价值的企业级空间计算应用。 |