想管理 AR 场景?arViewController 场景管理详解

你有没有想过,一个完整的 AR 应用到底是怎么运作的?从打开摄像头、初始化 AR 引擎、配置各种追踪能力,到暂停恢复、销毁资源——这一整套流程靠什么来管理?

答案就是 arViewController。它是 AR Engine 的"大管家",负责 AR 会话的创建、配置、生命周期管理,以及 3D 场景的设置。你可以把它理解为 AR 应用的"控制器"——所有的 AR 能力都要通过它来启动和管理。

arViewController 包含什么?

下面是 AR 应用的完整生命周期流程:

失败

成功

切到后台

回到前台

退出页面

创建 ARViewContext

配置 AR 能力 config

注册回调 callback

加载 3D 场景 scene

调用 init 初始化 AR 会话

初始化成功?

检查权限和设备兼容性

AR 应用运行中

用户操作

调用 pause 暂停

调用 resume 恢复

调用 destroy 销毁

释放 CPU/GPU 追踪资源

释放所有资源

arViewController 模块主要提供两个核心东西:

  1. ARViewContext:AR 视图上下文,是整个 AR 应用的核心对象。它管理着 AR 会话、3D 场景、回调、配置等一切东西。
  2. ARViewCallback:AR 视图的回调抽象类,你需要继承它来实现自己的回调逻辑。

使用之前,先导入模块:

import { arEngine, arViewController } from '@kit.AREngine';

注意,arViewControllerarEngine 是从同一个包 @kit.AREngine 导入的。arEngine 提供各种 AR 数据类型和枚举,arViewController 提供场景管理能力。

怎么创建 ARViewContext?

创建 ARViewContext 非常简单,就一行代码:

import { arViewController } from '@kit.AREngine';

let context: arViewController.ARViewContext = new arViewController.ARViewContext();

ARViewContext 是整个 AR 应用的核心对象。你需要通过它来:

  • 配置 AR 会话的参数
  • 初始化和管理 AR 会话的生命周期
  • 设置 3D 场景
  • 注册回调函数
  • 管理虚拟模型的放置和移除

怎么配置 AR 能力?

下面是 AR 能力配置的决策流程:

环境追踪 SLAM

人体骨骼追踪

人脸追踪

图像识别

确定 AR 应用需求

需要哪些 AR 能力?

type: WORLD

type: BODY

type: FACE

type: IMAGE

配置平面检测模式

配置最大检测人数

配置前置摄像头

配置追踪图库

选择坐标系模式

选择功耗模式

选择深度模式

设置完成 调用 init 初始化

创建好 ARViewContext 之后,你需要告诉它你要用哪些 AR 能力。通过 config 属性来设置:

import { arEngine, arViewController } from '@kit.AREngine';

let context: arViewController.ARViewContext = new arViewController.ARViewContext();
context.config = {
  type: arEngine.ARType.WORLD,
  poseMode: arEngine.ARPoseMode.GRAVITY_AND_HEADING,
  powerMode: arEngine.ARPowerMode.POWER_SAVING,
  depthMode: arEngine.ARDepthMode.AUTOMATIC
};

config 接受一个 arEngine.ARConfig 对象,里面包含了 AR 会话的所有配置参数。我把常用的配置项整理一下:

type(ARType):AR 能力类型,这是最重要的配置。

  • WORLD(0x01):环境追踪能力,也就是 SLAM。用于平面检测、运动跟踪等。
  • BODY(0x02):人体跟踪与骨骼关键点识别能力。
  • FACE(0x10):人脸追踪能力。
  • IMAGE(0x80):图像识别能力。

这些类型是按位组合的,理论上你可以同时开启多个能力。但要注意,同时开启的能力越多,消耗的资源就越多。

planeFindingMode(ARPlaneFindingMode):平面检测模式。默认是 HORIZONTAL_AND_VERTICAL,同时检测水平面和竖直平面。

poseMode(ARPoseMode):世界坐标系的建立方式。默认是 GRAVITY(Y 轴跟重力对齐)。如果你想加上指南针方向,可以用 GRAVITY_AND_HEADING

powerMode(ARPowerMode):电源功耗模式。默认是 NORMAL。如果手机发热严重,可以换成 POWER_SAVING

focusMode(ARFocusMode):对焦模式。默认是 FIXED(固定焦点)。

depthMode(ARDepthMode):深度模式。默认是 DISABLED。如果需要深度信息,设成 AUTOMATIC

meshMode(ARMeshMode):网格模式。默认是 DISABLED。如果需要 Mesh 数据,设成 ENABLE

maxMapSize:存储地图数据的最大内存大小,单位是 MB。可设定范围 100MB ~ 16GB,默认 800MB。建议根据设备的内存容量来设置,太大会导致意外错误。

cameraLensFacing:相机镜头朝向。默认是 REAR(后置摄像头)。如果要做自拍特效,设成 FRONT。注意,当设为 FRONT 时,type 必须是 FACEBODY 才会生效。

maxDetectedBodyNum:当类型为 BODY 时,要检测的人体数量最大值。默认是 1,最大是 2。

配置要在 init() 之前设置好。初始化之后再改配置可能不会生效。

怎么初始化 AR 会话?

配置好之后,调用 init() 来初始化 AR 会话:

import { arViewController } from '@kit.AREngine';
import { BusinessError } from '@kit.BasicServicesKit';

let context: arViewController.ARViewContext = new arViewController.ARViewContext();
await context.init();

init() 是一个异步方法,返回 Promise<void>。调用之后,AR Engine 会:

  1. 检查权限(需要 CAMERAGYROSCOPEACCELEROMETER 三个权限)
  2. 检查设备兼容性
  3. 启动摄像头
  4. 初始化传感器
  5. 创建 AR 会话
  6. 设置 3D 渲染场景
  7. 开始追踪

初始化过程中可能会失败,常见的错误码有:

  • 201:权限未授予。你需要确保应用有摄像头、陀螺仪和加速度计的权限。
  • 801:设备不兼容。这个设备不支持 AR 能力。
  • 1009200007:配置不支持。你设置的某些配置参数在当前设备上不可用。
  • 1009200010:摄像头不可用。可能被其他应用占用了。

所以最好用 try-catch 来处理初始化失败的情况。

怎么设置 3D 场景?

AR 应用通常需要在现实画面上叠加 3D 虚拟内容。这就需要一个 3D 渲染场景。通过 scene 属性来设置:

import { Scene } from '@kit.ArkGraphics3D';
import { arViewController } from '@kit.AREngine';

Scene.load().then((scene: Scene) => {
  let context: arViewController.ARViewContext = new arViewController.ARViewContext();
  context.scene = scene;
}).catch((err: BusinessError) => {
  console.error(`Failed to load scene. Code is ${err.code}, message is ${err.message}.`);
});

这里先用 Scene.load() 加载一个 3D 场景,然后把它赋值给 context.sceneScene@kit.ArkGraphics3D 提供的 3D 场景管理类。

你也可以反过来,获取当前设置的场景:

import { arViewController } from '@kit.AREngine';

let context: arViewController.ARViewContext = new arViewController.ARViewContext();
context.scene;

scene 属性既是 getter 也是 setter,你可以随时读取或修改当前的 3D 场景。

怎么获取 AR 会话?

初始化成功后,你可以通过 session 属性获取底层的 AR 会话对象:

import { arViewController } from '@kit.AREngine';

let context: arViewController.ARViewContext = new arViewController.ARViewContext();
context.session;

session 返回的是 arEngine.ARSession 对象。如果初始化成功,返回 ARSession 实例;如果初始化失败或还没初始化,返回 undefined

拿到 ARSession 之后,你就可以使用 AR Engine 的底层能力了,比如:

  • getFrame():获取当前帧数据
  • getAllTrackables():获取所有可追踪对象
  • createAnchor():创建锚点

打个比方,ARViewContext 是"总经理",ARSession 是"技术总监"。总经理负责整体管理,技术总监负责具体的技术活。

怎么注册回调?

AR 应用需要对各种事件做出响应——新平面被检测到、平面更新、每一帧刷新。这些都通过回调来处理。

你需要继承 ARViewCallback 类,实现自己的回调逻辑:

import { arEngine, arViewController } from '@kit.AREngine';
import { Node } from '@kit.ArkGraphics3D';

class ARViewCallbackImpl extends arViewController.ARViewCallback {

  onAnchorAdd(ctx: arViewController.ARViewContext, node: Node, anchor: arEngine.ARAnchor): void {
    console.info('onAnchorAdd');
    console.info(`add anchor id = ${String(anchor.id)}`);
    console.info(`add anchor translation = ${anchor.getPose().translation}`);
    console.info(`add node pose = ${node.position}`);
  }

  onAnchorUpdate(ctx: arViewController.ARViewContext, node: Node, anchor: arEngine.ARAnchor): void {
    console.info('onAnchorUpdate');
    console.info(`update anchor id = ${String(anchor.id)}`);
    console.info(`update anchor translation = ${anchor.getPose().translation}`);
    console.info(`update node pose = ${node.position}`);
  }

  async onFrameUpdate(ctx: arViewController.ARViewContext, sysBootTs: number): Promise<void> {
    let arSession: arEngine.ARSession | undefined = ctx.session;
    if (arSession) {
      let frame: arEngine.ARFrame = arSession.getFrame();
      if (!frame) {
        console.error('Failed to get arSession.frame, it is undefined or null');
      } else {
        console.info(`Succeeded in getting arSession.frame = ${frame.timestamp}`);
        await frame.release();
      }
    } else {
      console.error('Failed to get arSession, arSession is undefined');
    }
  }
}

let context: arViewController.ARViewContext = new arViewController.ARViewContext();
context.callback = new ARViewCallbackImpl();

然后通过 context.callback 把回调实例注册进去。

三个回调方法的作用:

onAnchorAdd(ctx, node, anchor):当 AR 会话检测到新平面(或其他可追踪对象)时触发。AR Engine 会自动创建锚点和对应的场景节点,然后通过这个回调通知你。参数说明:

  • ctx:当前 ARView 的上下文信息
  • node:新建锚点对应的 AR 场景节点
  • anchor:新创建的锚点

onAnchorUpdate(ctx, node, anchor):当已有锚点更新时触发。参数跟 onAnchorAdd 一样。

onFrameUpdate(ctx, sysBootTs):每帧刷新前触发。sysBootTs 是系统启动时间戳,单位是微秒。你可以在这里获取当前帧的 AR 数据,做实时渲染和逻辑处理。

生命周期管理:暂停、恢复和销毁

AR 应用不是一直运行的。用户切到后台、锁屏、或者退出 AR 页面时,你需要暂停或销毁 AR 会话来节省资源。

暂停:

import { arViewController } from '@kit.AREngine';

let context: arViewController.ARViewContext = new arViewController.ARViewContext();
context.pause();

pause() 会暂停相机跟踪与 AR 场景渲染。调用之后,AR Engine 不再消耗 CPU/GPU 资源来做追踪计算,但 AR 会话本身还保持着。用户回到 AR 页面时,可以快速恢复。

恢复:

import { arViewController } from '@kit.AREngine';

let context: arViewController.ARViewContext = new arViewController.ARViewContext();
context.resume();

resume() 会恢复之前暂停的相机跟踪和 AR 场景渲染。调用之后,AR Engine 继续工作。

销毁:

import { arViewController } from '@kit.AREngine';

let context: arViewController.ARViewContext = new arViewController.ARViewContext();
context.destroy();

destroy() 会销毁 ARViewContext,释放所有资源,包括 AR 会话和 3D 场景。这个方法是异步的,返回 Promise<void>。在退出 AR 页面时调用,确保不会泄露资源。

一个典型的 AR 页面生命周期是这样的:

  1. 页面创建:new ARViewContext() → 设置 configinit() → 设置 scene → 设置 callback
  2. 用户切到后台:pause()
  3. 用户回到前台:resume()
  4. 用户退出页面:destroy()

坐标系转换

AR Engine 用的是重力对齐世界坐标系,而 3D 渲染引擎(AGP)用的是自己的世界坐标系。两个坐标系不一样,所以在 3D 场景里放虚拟物体时,需要做一次坐标转换。

ARViewContext 提供了 transformPose() 方法来帮你做这个事情:

import { arViewController } from '@kit.AREngine';
import { Vec3, Quaternion } from '@kit.ArkGraphics3D';

let context: arViewController.ARViewContext = new arViewController.ARViewContext();
let pose: Vec3 = { x: 1.0, y: -1.0, z: -0.5 };
let rot: Quaternion = {
  x: -0.1,
  y: 0.2,
  z: -0.3,
  w: 0.5
};
context.transformPose(pose, rot);

transformPose(position, rotation) 接收两个参数:

  • position(Vec3):位姿坐标信息
  • rotation(Quaternion):位姿朝向信息(四元数)

返回的是转换后的 arEngine.ARPose 对象,如果参数无效或创建失败,返回 null

打个比方,你在 AR 坐标系中检测到了一个平面,它的位姿是 (1.0, -1.0, -0.5)。你想在 3D 场景里对应的位置放一个虚拟物体,就需要先用 transformPose 把这个位姿从 AR 坐标系转换到 AGP 渲染坐标系,然后再设置虚拟物体的位置。

设备兼容性检查

不是所有设备都支持 AR 能力。在使用之前,你可以用 isARTypeSupported() 来检查:

import { arEngine, arViewController } from '@kit.AREngine';

arViewController.isARTypeSupported(arEngine.ARFeatureType.ARENGINE_FEATURE_TYPE_FACE);

这个方法返回 booleantrue 表示支持,false 表示不支持。

你可以检查不同的特性类型:

  • ARENGINE_FEATURE_TYPE_FACE:人脸识别与跟踪特性
  • ARENGINE_FEATURE_TYPE_BODY:人体骨骼点识别与跟踪特性
  • 还有其他更多特性类型

这个检查很重要,因为不同设备的硬件能力不同。比如有些低端设备可能不支持人体骨骼追踪,强行使用会报 801(Device not compatible)错误。

管理虚拟模型

ARViewContext 还提供了管理虚拟模型的方法。你可以在人脸关键点位置放置、移除和清除 3D 模型:

放置模型:

import { arEngine, arViewController } from '@kit.AREngine';

let context: arViewController.ARViewContext = new arViewController.ARViewContext();
// 此处为用户本地存放模型路径
let resourcePath:ResourceStr = $rawfile('xxxx/xxxx');
context.loadAsset(resourcePath, arViewController.LandmarkType.LEFT_EYE);

loadAsset(resourcePath, landmark) 在指定的关键点处放置一个 3D 模型。resourcePath 是模型文件的路径,landmark 是关键点类型。

移除模型:

import { arEngine, arViewController } from '@kit.AREngine';

let context: arViewController.ARViewContext = new arViewController.ARViewContext();
context.removeAsset(arViewController.LandmarkType.LEFT_EYE);

removeAsset(landmark) 移除指定关键点上已放置的模型。

清除所有模型:

import { arViewController } from '@kit.AREngine';

let context: arViewController.ARViewContext = new arViewController.ARViewContext();
context.clearResource();

clearResource() 一次性清除所有已放置的模型。这个方法是异步的,返回 Promise<void>

错误码速查

在使用 arViewController 的过程中,可能会遇到各种错误。把常见的错误码整理一下:

错误码 含义 常见原因
201 权限未授予 缺少摄像头、陀螺仪或加速度计权限
801 设备不兼容 设备不支持 AR 能力
401 参数无效 传入的参数不合法
1009200001 通用失败 AR Engine 内部错误
1009200007 配置不支持 设置了设备不支持的配置参数
1009200008 资源耗尽 内存不足或资源被占满
1009200009 服务不可用 AR 服务未启动或崩溃
1009200010 摄像头不可用 摄像头被其他应用占用
1009200201 ARView 无效操作 在错误的状态下调用了 API
1009200202 需要 3D AR 场景 没有设置 scene 就调用了需要场景的方法
1009200203 需要 AR 配置 没有设置 config 就初始化
1009200204 AR 会话设置失败 初始化过程中出错
1009200205 AR 场景相机设置失败 3D 场景的相机初始化失败

遇到错误时,先看错误码,再对照这个表排查原因。大部分问题都是权限、设备兼容性或配置参数导致的。

一个完整的 AR 应用流程

最后把整个流程串起来:

import { arEngine, arViewController } from '@kit.AREngine';
import { Scene } from '@kit.ArkGraphics3D';
import { Node } from '@kit.ArkGraphics3D';
import { BusinessError } from '@kit.BasicServicesKit';

// 1. 创建 ARViewContext
let context: arViewController.ARViewContext = new arViewController.ARViewContext();

// 2. 配置 AR 能力
context.config = {
  type: arEngine.ARType.WORLD,
  planeFindingMode: arEngine.ARPlaneFindingMode.HORIZONTAL_AND_VERTICAL,
  poseMode: arEngine.ARPoseMode.GRAVITY_AND_HEADING,
  powerMode: arEngine.ARPowerMode.POWER_SAVING,
  depthMode: arEngine.ARDepthMode.AUTOMATIC
};

// 3. 注册回调
context.callback = new ARViewCallbackImpl();

// 4. 加载 3D 场景
Scene.load().then((scene: Scene) => {
  context.scene = scene;
}).catch((err: BusinessError) => {
  console.error(`Failed to load scene. Code is ${err.code}, message is ${err.message}.`);
});

// 5. 初始化 AR 会话
await context.init();

// 6. 暂停(用户切到后台时)
context.pause();

// 7. 恢复(用户回到前台时)
context.resume();

// 8. 销毁(退出 AR 页面时)
await context.destroy();

这就是一个完整的 AR 应用生命周期。从创建、配置、初始化,到暂停恢复、销毁,每一步都有对应的 API。

arViewController 是 AR Engine 的入口。掌握了它,你就掌握了 AR 应用的整体框架。至于具体的 AR 能力(平面检测、人体追踪、人脸追踪等),都是在这个框架之上运行的。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐