作为华为 AR Engine 的一项基本能力,运动跟踪能力主要通过持续稳定跟踪终端设备的位置和姿态相对于周围环境的变化,同时输出周围环境特征的三维坐标信息,在 AR 技术的实际应用中起到了框架搭建的作用,是构建现实世界和虚拟世界的桥梁。
特性介绍
运动跟踪能力通过跟踪终端设备的位置和姿态相对于周围环境的变化,可以确定终端设备的虚拟坐标系与周围环境世界坐标系的变换关系,把终端设备的虚拟坐标系一起统一到周围环境的世界坐标系下,从观察者视角渲染虚拟物体,再叠加到摄像头图像中,从而实现虚拟与现实在几何上的融合。
比如在下图 AR 车展的场景中,就需要借助运动跟踪的能力,实时跟踪摄像头相对于周围环境的运动姿态和变化轨迹,通过建立虚拟世界和现实世界统一的几何空间,实现虚拟汽车在现实地面上的精准放置。
实现虚实融合的基本条件是实时跟踪终端设备的运动,并根据运动跟踪结果实时更新虚拟物体状态,才能在现实和虚拟世界之间建立稳定的联系,所以说,运动跟踪的精度与质量直接影响 AR 应用的整体效果,凡是出现延迟、误差等情况,都会造成虚拟物体抖动或者漂移,很大程度上破坏 AR 体验的真实感和沉浸性。
特性优势
近日,华为 AR Engine 3.0 使用 SLAM 3.0 技术,在技术指标方面取得了进一步的提升。
- 实现 6DOF 的运动跟踪方式(世界跟踪方式),能从不同距离、方向、角度观察虚拟物体,营造更加真实的 AR 体验环境;
- 实现单目 ATE(绝对轨迹误差)低至 1.6cm,确保虚拟物体稳定性,体验效果更佳。
- 平面检测时长小于 1 秒,平面识别和扩展速度更快。
集成步骤
一、 登录华为开发者联盟官网,创建应用。
二、 集成 AR Engine SDK。
- 打开 Android Studio 项目级 “build.gradle” 文件。添加 Maven 代码库。(这里以 7.0 以下版本举例) 在 “buildscript > repositories” 中配置 HMS Core SDK 的 Maven 仓地址。 在 “allprojects > repositories” 中配置 HMS Core SDK 的 Maven 仓地址。
- buildscript {
- repositories {
- google()
- jcenter()
- // 配置HMS Core SDK的Maven仓地址。
- maven {url "https://developer.huawei.com/repo/" }
- }
- }
- allprojects {
- repositories {
- google()
- jcenter()
- // 配置HMS Core SDK的Maven仓地址。
- maven {url "https://developer.huawei.com/repo/" }
- }
- }
- 打开项目中应用级的 “build.gradle” 文件。
- dependencies {
- implementation 'com.huawei.hms:arenginesdk:3.1.0.1'
- }
三、 代码开发
- 检查当前设备是否安装了 AR Engine,若已经安装则正常运行,若没有安装主动跳转应用市场,请求安装 AR Engine。
- private boolean arEngineAbilityCheck() {
- boolean isInstallArEngineApk = AREnginesApk.isAREngineApkReady(this);
- if (!isInstallArEngineApk && isRemindInstall) {
- Toast.makeText(this, "Please agree to install.", Toast.LENGTH_LONG).show();
- finish();
- }
- LogUtil.debug(TAG, "Is Install AR Engine Apk: " + isInstallArEngineApk);
- if (!isInstallArEngineApk) {
- startActivity(new Intent(this, com.huawei.arengine.demos.common.ConnectAppMarketActivity.class));
- isRemindInstall = true;
- }
- return AREnginesApk.isAREngineApkReady(this);
- }
- 运行前权限检查
- AndroidManifest里面配置相机权限
- <uses-permission android:name="android.permission.CAMERA" />
- private static final int REQUEST_CODE_ASK_PERMISSIONS = 1;
- private static final int MAX_ARRAYS = 10;
- private static final String[] PERMISSIONS_ARRAYS = new String[]{Manifest.permission.CAMERA};
- List<String> permissionsList = new ArrayList<>(MAX_ARRAYS);
- boolean isHasPermission = true;
- for (String permission : PERMISSIONS_ARRAYS) {
- if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
- isHasPermission = false;
- break;
- }
- }
- if (!isHasPermission) {
- for (String permission : PERMISSIONS_ARRAYS) {
- if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
- permissionsList.add(permission);
- }
- }
- ActivityCompat.requestPermissions(activity,
- permissionsList.toArray(new String[permissionsList.size()]), REQUEST_CODE_ASK_PERMISSIONS);
- }
- 调用 ARWorldTrackingConfig 接口,创建运动跟踪 ARSession,
- private ARSession mArSession;
- private ARWorldTrackingConfig mConfig;
- config.setCameraLensFacing(ARConfigBase.CameraLensFacing.FRONT); // 通过config.setXXX方法配置场景参数
- config.setPowerMode(ARConfigBase.PowerMode.ULTRA_POWER_SAVING);
- mArSession.configure(config);
- mArSession.resume();
- mArSession.configure(config);
- mSession.setCameraTextureName(mTextureDisplay.getExternalTextureId());
- ARFrame arFrame = mSession.update(); // 从ARSession中获取一帧的数据。
- // Set the environment texture probe and mode after the camera is initialized.
- setEnvTextureData();
- ARCamera arCamera = arFrame.getCamera(); // 可以从ARFrame中获取ARCamera,ARCamera对象可以获取相机的投影矩阵,用来渲染窗口。
- // The size of the projection matrix is 4 * 4.
- float[] projectionMatrix = new float[16];
- arCamera.getProjectionMatrix(projectionMatrix, PROJ_MATRIX_OFFSET, PROJ_MATRIX_NEAR, PROJ_MATRIX_FAR);
- mTextureDisplay.onDrawFrame(arFrame);
- StringBuilder sb = new StringBuilder();
- updateMessageData(arFrame, sb);
- mTextDisplay.onDrawFrame(sb);
- // The size of ViewMatrix is 4 * 4.
- float[] viewMatrix = new float[16];
- arCamera.getViewMatrix(viewMatrix, 0);
- for (ARPlane plane : mSession.getAllTrackables(ARPlane.class)) { // 从ARSession中获取所有的可跟踪平面。
- if (plane.getType() != ARPlane.PlaneType.UNKNOWN_FACING
- && plane.getTrackingState() == ARTrackable.TrackingState.TRACKING) {
- hideLoadingMessage();
- break;
- }
- }
- drawTarget(mSession.getAllTrackables(ARTarget.class), arCamera, viewMatrix, projectionMatrix);
- mLabelDisplay.onDrawFrame(mSession.getAllTrackables(ARPlane.class), arCamera.getDisplayOrientedPose(),
- projectionMatrix);
- handleGestureEvent(arFrame, arCamera, projectionMatrix, viewMatrix);
- ARLightEstimate lightEstimate = arFrame.getLightEstimate();
- ARPointCloud arPointCloud = arFrame.acquirePointCloud();
- getEnvironmentTexture(lightEstimate);
- drawAllObjects(projectionMatrix, viewMatrix, getPixelIntensity(lightEstimate));
- mPointCloud.onDrawFrame(arPointCloud, viewMatrix, projectionMatrix);
- ARHitResult hitResult = hitTest4Result(arFrame, arCamera, event.getEventSecond());
- if (hitResult != null) {
- mSelectedObj.setAnchor(hitResult.createAnchor()); // 在命中检测位置创建锚点,使得AREngine持续跟踪。
- }
- 根据锚点位置来绘制所需的虚拟物体。
- mEnvTextureBtn.setOnCheckedChangeListener((compoundButton, b) -> {
- mEnvTextureBtn.setEnabled(false);
- handler.sendEmptyMessageDelayed(MSG_ENV_TEXTURE_BUTTON_CLICK_ENABLE,
- BUTTON_REPEAT_CLICK_INTERVAL_TIME);
- mEnvTextureModeOpen = !mEnvTextureModeOpen;
- if (mEnvTextureModeOpen) {
- mEnvTextureLayout.setVisibility(View.VISIBLE);
- } else {
- mEnvTextureLayout.setVisibility(View.GONE);
- }
- int lightingMode = refreshLightMode(mEnvTextureModeOpen, ARConfigBase.LIGHT_MODE_ENVIRONMENT_TEXTURE);
- refreshConfig(lightingMode);
- });
来源:HMS Core