打造自己的中秋 AR 赏月应用:实现虚实融合的节日体验

中秋佳节,赏月、品茗、话家常是传统习俗。随着增强现实(AR)技术的发展,我们可以用鸿蒙的开发能力,打造一款 "AR 中秋赏月" 应用 ------ 让虚拟玉兔在现实场景中跳跃,让数字月饼 "飘落" 在桌面,甚至能通过 AR 扫描月亮触发专属节日特效。这里我将将带大家从技术选型到代码实现,完整搭建这款充满节日氛围的鸿蒙 T应用。

文章目录

  • 一、应用核心功能与技术栈
    • [1. 核心功能规划](#1. 核心功能规划)
    • [2. 技术栈依赖](#2. 技术栈依赖)
  • 二、前置准备:环境配置与资源准备
    • [1. 开发环境配置](#1. 开发环境配置)
    • [2. 中秋 AR 资源准备](#2. 中秋 AR 资源准备)
  • [三、核心代码实现:从 AR 场景初始化到互动功能](#三、核心代码实现:从 AR 场景初始化到互动功能)
  • [1. AR 场景初始化:连接 AR Engine 与相机](#1. AR 场景初始化:连接 AR Engine 与相机)
    • [2. 虚拟元素叠加:3D 模型与 AR 场景融合](#2. 虚拟元素叠加:3D 模型与 AR 场景融合)
    • [3. 互动与分享功能:截图保存与社交分享](#3. 互动与分享功能:截图保存与社交分享)
  • 四、开发注意事项与优化方向
    • [1. 性能优化](#1. 性能优化)
    • [2. 兼容性适配](#2. 兼容性适配)
    • [3. 用户体验优化](#3. 用户体验优化)
  • 五、总结

一、应用核心功能与技术栈

在开始开发前,我们先明确应用的核心场景与依赖技术,确保开发方向清晰:

1. 核心功能规划

AR 场景识别:通过鸿蒙 AR Engine 识别现实中的 "天空区域",将虚拟月亮模型叠加到真实天空中,实现 "虚实赏月" 效果;

节日互动特效:点击虚拟月亮触发玉兔跳跃、月饼飘落动画,支持手势缩放调整虚拟元素大小;

节日祝福分享:将 AR 赏月画面截图,生成带中秋文案的海报,支持分享到社交平台;

设备兼容性适配:适配鸿蒙手机、平板等不同尺寸设备,保证 AR 场景显示正常。

2. 技术栈依赖

基础框架:HarmonyOS Stage 模型(API 9+),TypeScript 作为开发语言;

AR 能力:依赖鸿蒙 AR Engine(@ohos.arengine),实现环境跟踪、平面识别、虚实叠加;

图形渲染:使用鸿蒙 ArkUI 的 3D 组件()加载 GLB 格式的中秋模型(月亮、玉兔、月饼);

权节日氛围的鸿蒙 TS 应用。

二、前置准备:环境配置与资源准备

在写代码前,我们需要完成两项关键准备工作,避免开发中出现环境或资源问题:

1. 开发环境配置

DevEco Studio 版本:需升级到 4.0 及以上,确保支持 API 9 + 的 AR Engine 能力;

AR Engine 依赖引入:在package.json中添加 AR Engine 依赖,或通过 DevEco Studio 的 "项目设置 - 模块设置" 手动引入:

bash 复制代码
"dependencies": {
  "@ohos.arengine": "^1.0.0",
  "@ohos.arkui.3d": "^1.0.0"
}

权限声明:在module.json5中声明必要权限,AR 场景核心依赖相机权限,分享功能依赖存储权限:
"reqPermissions": [
  {
    "name": "ohos.permission.CAMERA",
    "reason": "需要相机采集现实场景,实现AR赏月效果",
    "usedScene": { "abilities": ["MainAbility"], "when": "inuse" }
  },
  {
    "name": "ohos.permission.WRITE_MEDIA",
    "reason": "需要保存AR赏月截图,用于节日分享",
    "usedScene": { "abilities": ["MainAbility"], "when": "inuse" }
  }
]

2. 中秋 AR 资源准备

3D 模型:准备 GLB 格式的中秋相关模型,推荐从Sketchfab下载开源模型(需注意版权),如:

低多边形风格月亮模型(带光晕效果);

动态玉兔模型(含跳跃、捣药动画);

圆形月饼模型(带纹理贴图);

特效资源:准备粒子特效配置文件(如月饼飘落的粒子参数),用于增强节日氛围。

三、核心代码实现:从 AR 场景初始化到互动功能

接下来,我们分模块实现应用的核心功能,重点讲解 AR 场景搭建、虚拟元素叠加、互动逻辑三个关键部分。

1. AR 场景初始化:连接 AR Engine 与相机

首先需要初始化 AR Engine,建立相机采集与 AR 跟踪的关联,这是实现虚实融合的基础。我们在MainPage.ets中编写初始化逻辑:

bash 复制代码
import arengine from '@ohos.arengine';
import camera from '@ohos.multimedia.camera';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import { BusinessError } from '@ohos.base';

@Entry
@Component
struct ARMidAutumnPage {
  // AR Engine核心对象
  private arSession: arengine.ARSession | null = null;
  // 相机预览组件控制器
  private cameraPreviewCtrl: CameraPreviewController = new CameraPreviewController();
  // 是否初始化成功
  @State isInitSuccess: boolean = false;

  build() {
    Column() {
      // 相机预览(作为AR场景的现实背景)
      CameraPreview(controller: this.cameraPreviewCtrl)
        .width('100%')
        .height('100%')
        // 叠加3D虚拟元素(月亮、玉兔等)
        .overlay(() => {
          if (this.isInitSuccess) {
            AR3DElements() // 后续实现3D元素组件
          }
        })
    }
    .onPageShow(() => {
      this.initARSession(); // 页面显示时初始化AR
    })
    .onPageHide(() => {
      this.destroyARSession(); // 页面隐藏时销毁AR资源
    })
  }

  // 初始化AR Session与相机
  private async initARSession() {
    try {
      // 1. 检查并申请相机权限
      const hasCameraPerm = await this.checkAndRequestPermission('ohos.permission.CAMERA');
      if (!hasCameraPerm) {
        promptAction.showToast({ message: '请授予相机权限以使用AR功能' });
        return;
      }

      // 2. 创建AR Session
      this.arSession = await arengine.createARSession();
      // 3. 配置AR场景:启用环境跟踪(识别天空、平面)
      const config = await this.arSession.getConfig();
      config.enableEnvironmentTracking(true); // 开启环境跟踪
      await this.arSession.configure(config);

      // 4. 绑定相机:将AR Session与相机预览关联
      const cameraManager = camera.getCameraManager();
      const cameraDevice = await cameraManager.getCameraDevices()[0]; // 获取默认相机
      await this.arSession.bindCamera(cameraDevice);

      // 5. 启动AR Session
      await this.arSession.resume();
      this.isInitSuccess = true;
      console.log('AR场景初始化成功,可开始AR赏月');
    } catch (err) {
      console.error(`AR初始化失败:${(err as BusinessError).message}`);
      this.isInitSuccess = false;
    }
  }

  // 检查并申请权限
  private async checkAndRequestPermission(permName: string): Promise<boolean> {
    const atManager = abilityAccessCtrl.createAtManager();
    const tokenId = abilityAccessCtrl.getTokenId();
    try {
      const status = await atManager.checkPermission(tokenId, permName);
      if (status === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
        return true;
      }
      // 申请权限
      const result = await atManager.requestPermissionsFromUser(tokenId, [permName]);
      return result.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
    } catch (err) {
      console.error(`权限处理失败:${(err as BusinessError).message}`);
      return false;
    }
  }

  // 销毁AR Session,释放资源
  private async destroyARSession() {
    if (this.arSession) {
      await this.arSession.pause();
      await this.arSession.destroy();
      this.arSession = null;
      this.isInitSuccess = false;
    }
  }

}

2. 虚拟元素叠加:3D 模型与 AR 场景融合

AR 场景初始化成功后,需要将中秋 3D 模型(月亮、玉兔)叠加到现实场景中。这里我们使用 ArkUI 的 3D 组件,结合 AR Engine 的环境跟踪数据,确保虚拟元素 "锚定" 在现实空间中(如将月亮固定在天空区域)。

创建AR3DElements.ets组件,实现 3D 模型加载与位置校准:

bash 复制代码
import { Ark3D, Model, ModelLoader, Vector3 } from '@ohos.arkui.3d';
import arengine from '@ohos.arengine';

@Component
struct AR3DElements {
  // AR Session从父组件传递
  @Prop arSession: arengine.ARSession | null;
  // 月亮模型加载器
  private moonModelLoader: ModelLoader = new ModelLoader();
  // 玉兔模型加载器
  private rabbitModelLoader: ModelLoader = new ModelLoader();
  // 虚拟元素位置(初始设为天空区域)
  @State moonPosition: Vector3 = new Vector3(0, 2, -5); // x:水平, y:高度, z:距离
  @State rabbitPosition: Vector3 = new Vector3(-1, 1.8, -5);

  build() {
    Ark3D()
      .width('100%')
      .height('100%')
      .onReady(() => {
        this.loadModels(); // ARK3D就绪后加载模型
        this.trackSkyArea(); // 跟踪天空区域,校准月亮位置
      })
      .children([
        // 月亮模型
        Model(loader: this.moonModelLoader)
          .position(this.moonPosition)
          .scale(0.5, 0.5, 0.5) // 缩放模型大小
          .onClick(() => {
            this.triggerMoonEffect(); // 点击月亮触发特效
          }),
        // 玉兔模型
        Model(loader: this.rabbitModelLoader)
          .position(this.rabbitPosition)
          .scale(0.3, 0.3, 0.3)
          .animation('jump', true) // 自动播放跳跃动画
      ])
  }

  // 加载3D模型(GLB格式)
  private async loadModels() {
    try {
      // 加载月亮模型(路径需与项目资源目录对应)
      await this.moonModelLoader.load('assets/models/moon.glb');
      // 加载玉兔模型
      await this.rabbitModelLoader.load('assets/models/rabbit.glb');
      console.log('中秋3D模型加载成功');
    } catch (err) {
      console.error(`模型加载失败:${(err as BusinessError).message}`);
    }
  }

  // 跟踪天空区域,校准月亮位置(确保月亮显示在真实天空中)
  private async trackSkyArea() {
    if (!this.arSession) return;
    // 循环获取AR环境跟踪数据
    setInterval(async () => {
      try {
        const frame = await this.arSession.updateFrame(); // 获取AR帧数据
        const trackables = await frame.getTrackables(arengine.TrackableType.PLANE); // 获取平面跟踪结果
        for (const trackable of trackables) {
          const plane = trackable as arengine.ARPlane;
          // 判断是否为"天空平面"(AR Engine会识别天空为特殊平面)
          if (plane.getPlaneType() === arengine.ARPlane.PlaneType.SKY) {
            const centerPose = await plane.getCenterPose(); // 获取天空平面中心姿态
            // 根据天空平面位置调整月亮位置,确保虚拟月亮与真实天空对齐
            this.moonPosition = new Vector3(
              centerPose.getTranslationX(),
              centerPose.getTranslationY() + 1, // 向上偏移1单位,避免与天空平面重叠
              centerPose.getTranslationZ() - 2 // 向前偏移2单位,让月亮更"靠前"
            );
            break;
          }
        }
      } catch (err) {
        console.error(`天空跟踪失败:${(err as BusinessError).message}`);
      }
    }, 100); // 每100ms更新一次位置,确保实时对齐
  }

  // 点击月亮触发特效(玉兔跳跃、月饼飘落)
  private triggerMoonEffect() {
    // 1. 玉兔跳跃动画加速
    this.rabbitModelLoader.setAnimationSpeed('jump', 2); // 动画速度加倍
    // 2. 触发月饼飘落粒子特效(此处简化,实际需结合粒子组件实现)
    promptAction.showToast({ message: '中秋快乐!月饼来啦~' });
    // 3. 1秒后恢复玉兔动画速度
    setTimeout(() => {
      this.rabbitModelLoader.setAnimationSpeed('jump', 1);
    }, 1000);
  }
}

3. 互动与分享功能:截图保存与社交分享

最后,我们为应用添加 "截图分享" 功能,让用户能将 AR 赏月画面保存并分享给亲友。在MainPage.ets中添加分享按钮,并实现截图逻辑:

bash 复制代码
// 在MainPage.ets的build方法中添加分享按钮
Column() {
  // 相机预览与AR元素(原有代码)
  // ...

  // 分享按钮(固定在底部)
  Button('保存AR赏月画面')
    .width(200)
    .height(40)
    .backgroundColor('#FF4500')
    .textStyle({ color: 'white' })
    .margin({ bottom: 30 })
    .onClick(() => {
      this.captureARScreen(); // 点击触发截图
    })
}

// 截图并保存到相册
private async captureARScreen() {
  try {
    // 1. 检查存储权限
    const hasStoragePerm = await this.checkAndRequestPermission('ohos.permission.WRITE_MEDIA');
    if (!hasStoragePerm) {
      promptAction.showToast({ message: '请授予存储权限以保存截图' });
      return;
    }

    // 2. 对相机预览+AR元素区域截图(使用鸿蒙截图API)
    const pixelMap = await capturePixelMap(this.cameraPreviewCtrl); // 简化写法,实际需通过组件ID定位

    // 3. 保存截图到相册
    const mediaLibrary = media.createMediaLibrary();
    const savePath = `Pictures/ARMidAutumn/${new Date().getTime()}.png`;
    const saveResult = await mediaLibrary.saveImageToAlbum(pixelMap, savePath);

    if (saveResult) {
      promptAction.showToast({ message: `截图已保存到:${savePath}` });
      // 4. 可选:调用分享API,直接分享截图(需引入分享模块)
      // await shareImage(savePath);
    } else {
      promptAction.showToast({ message: '截图保存失败' });
    }
  } catch (err) {
    console.error(`截图失败:${(err as BusinessError).message}`);
  }
}

四、开发注意事项与优化方向

在实际开发中,还需要关注以下问题,确保应用体验流畅、稳定:

1. 性能优化

模型轻量化:中秋 3D 模型需控制面数(建议单个模型面数 < 10000),避免设备卡顿;

AR 帧率控制:通过arSession.setFrameRate(30)将 AR 帧速率设为 30fps,平衡性能与体验;

资源预加载:在应用启动时预加载 3D 模型,避免页面显示后加载导致的延迟。

2. 兼容性适配

设备支持:AR Engine 需设备支持 AR 功能(如具备陀螺仪、加速度计),可通过arSession.isSupported()判断设备兼容性;

屏幕适配:通过@ohos.device.screen获取屏幕尺寸,动态调整 3D 模型大小,避免在小屏设备上显示过大。

3. 用户体验优化

权限引导:当用户拒绝权限时,提供 "前往设置" 的跳转链接(通过abilityAccessCtrl.openPermissionSettings()实现);

加载提示:AR 初始化、模型加载时显示 "正在准备中秋 AR 场景..." 的加载动画,减少用户等待焦虑;

错误处理:当 AR Engine 初始化失败(如设备不支持),显示 "当前设备暂不支持 AR 功能,换个设备试试吧~" 的友好提示。

五、总结

ok,到这里就结束了。我们学习了如何结合鸿蒙 AR Engine 与 ArkUI 3D 能力,实现虚实融合的节日应用。从权限申请、AR 场景搭建,到 3D 模型叠加、互动功能实现,每一步都围绕 "技术赋能节日体验" 的核心,让传统中秋习俗与现代 AR 技术碰撞出有趣的火花。

后续我们还可以扩展更多功能,比如添加 "AR 中秋灯谜"(扫描特定图案触发灯谜)、"亲友 AR 同屏赏月"(通过分布式能力实现多设备同一场景互动)等,让应用更具趣味性和社交属性。最后祝大家中秋快乐,技术之路越走越宽!

相关推荐
枫叶丹45 天前
Rokid手势识别技术深度剖析
ar·手势识别·rokid
Teamhelper_AR6 天前
AR/VR赋能工业巡检:开启智能化运维新时代
ar·vr
Teamhelper_AR6 天前
AR技术赋能航空制造:开启智能装配新时代
ar·制造
虹科数字化与AR7 天前
安宝特案例丨从 “围台观摩” 到 “远程高清学”:安宝特AR远程医疗套装支撑南京医院手术带教
ar·ar智能眼镜·ar医疗·工业ar·ar示教带教
一马平川的大草原7 天前
Meta Ray-Ban Display眼镜将引领AR眼镜的智能化应用落地
ar·人机交互·智能化交互
北京阿法龙科技有限公司7 天前
AR眼镜在安防领域人脸识别技术方案|阿法龙XR云平台
ar·xr
fruge9 天前
【征文计划】基于Rokid眼镜平台的AR历史情景课堂创意应用
ar
微学AI10 天前
基于Rokid平台的AR沉浸式教育导览应用:从构思到实现的全流程研究
ar·rokid
Teamhelper_AR10 天前
智能制造浪潮下,AR技术重塑工业维护新范式
ar·制造