前言

上一篇我们把智能生活助手的首页跑通了,今天来搞点酷的——给商品加一个 3D 展示功能。用户对着商品拍几张照片,App 就能在端侧重建出 3D 模型,然后 360° 旋转查看。这背后就是 HarmonyOS 7 引入的 3D Gaussian Splatting(3DGS) 端侧重建技术。

3DGS 到底是什么

Notion-style technical illustration explaining 3D

3DGS 全称 3D Gaussian Splatting,是一种用大量三维高斯球来表示场景的渲染技术。跟传统的 NeRF 比起来,它不需要漫长的神经网络训练,重建速度快一个数量级,渲染质量还不输。

简单来说,你拍一组照片,算法会:

  1. 提取特征点,估计相机位姿
  2. 用数百万个半透明的 3D 高斯球"填充"场景
  3. 通过 Splatting(泼溅)方式把高斯球投影到屏幕上完成渲染

以前这套流程得在服务器上跑,现在 HarmonyOS 7 把它搬到了端侧,利用 NPU + GPU 协同加速,手机上就能实时完成。

HarmonyOS 7 的端侧重建 API

系统提供了 @kit.SceneKit 模块,里面封装了 3DGS 重建的完整流程。核心类有三个:

  • ReconstructionSession:管理重建会话的生命周期
  • FrameProvider:负责输入图像帧的处理和位姿估计
  • GaussianRenderer:将重建结果渲染到 XComponent 上

整个流程不需要你自己写 SLAM 算法或者高斯优化,调 API 就行。

实战:商品 3D 展示功能

我们的需求很明确:用户进入商品详情页,点击"3D 查看"按钮,启动相机采集 → 端侧重建 → 3D 展示。

Notion-style architectural diagram of HarmonyOS 7

第一步:初始化 SceneKit 场景

先把 3D 渲染的容器搭好。这里用 XComponent 作为渲染画布,配合 SceneKit 的控制器来管理场景:

// pages/Product3DView.ets
import { sceneKit } from '@kit.SceneKit';

@Entry
@Component
struct Product3DView {
  private sceneController: sceneKit.SceneController = new sceneKit.SceneController();
  private gaussianNode: sceneKit.GaussianSplattingNode | null = null;
  @State isLoading: boolean = false;
  @State progress: number = 0;

  build() {
    Stack() {
      XComponent({
        id: 'scene3d',
        type: XComponentType.SURFACE,
        controller: this.sceneController.getXComponentController()
      })
        .width('100%')
        .height('100%')

      if (this.isLoading) {
        Column() {
          Text(`重建中... ${this.progress}%`)
            .fontSize(18)
            .fontColor('#FFFFFF')
          Progress({ value: this.progress, total: 100 })
            .width('60%')
            .color('#4FC3F7')
        }
        .width('100%')
        .height('100%')
        .backgroundColor('#80000000')
        .justifyContent(FlexAlign.Center)
      }
    }
  }
}

Notion-style step-by-step flowchart for implementi

XComponent 配合 SceneController 就能承载 3DGS 的渲染输出了,这跟之前用 SceneKit 做 AR 场景是同一套体系。

第二步:启动 3DGS 重建

接下来是核心部分——创建重建会话并喂入图像帧:

import { sceneKit, reconstruction } from '@kit.SceneKit';
import { camera } from '@kit.CameraKit';

// 创建重建会话
async function startReconstruction(
  controller: sceneKit.SceneController,
  onProgress: (pct: number) => void
): Promise<sceneKit.GaussianSplattingNode> {

  // 1. 配置重建参数
  const config: reconstruction.ReconstructionConfig = {
    mode: reconstruction.ReconstructionMode.HIGH_QUALITY,
    maxFrames: 120,            // 最多采集 120 帧
    enableDensification: true, // 开启稠密化
    gaussianCount: 500000      // 高斯球数量上限
  };

  // 2. 创建重建会话
  const session = await reconstruction.createSession(config);

  // 3. 订阅进度回调
  session.on('progress', (stage: string, percentage: number) => {
    onProgress(Math.round(percentage * 100));
  });

  // 4. 从相机帧创建 FrameProvider
  const frameProvider = new reconstruction.FrameProvider();
  frameProvider.setCameraIntrinsics({
    focalLength: { x: 1200, y: 1200 },
    principalPoint: { x: 540, y: 960 },
    resolution: { width: 1080, height: 1920 }
  });

  // 5. 逐帧送入(实际项目中从 CameraKit 拿帧)
  session.start(frameProvider);

  // 6. 等待重建完成
  const result = await session.waitForCompletion();

  // 7. 用重建结果创建高斯溅射节点
  const gaussianNode = new sceneKit.GaussianSplattingNode({
    sceneContent: result.sceneData,
    enableRealtime: true  // 开启实时渲染
  });

  // 添加到场景
  controller.getScene().addChild(gaussianNode);

  return gaussianNode;
}

这段代码跑通了整个重建链路。ReconstructionConfig 里的参数可以根据设备性能调节——低端设备把 gaussianCount 调小,重建速度会快很多。

第三步:手势交互与渲染控制

模型建好了,得让用户能旋转、缩放地看:

// 在 XComponent 上添加手势
.gesture(
  PanGesture()
    .onActionUpdate((event: GestureEvent) => {
      if (this.gaussianNode) {
        // 水平拖拽 → Y 轴旋转,垂直拖拽 → X 轴旋转
        const rotY = event.offsetX * 0.5;
        const rotX = event.offsetY * 0.5;
        this.gaussianNode.rotate({
          x: rotX, y: rotY, z: 0,
          order: sceneKit.RotationOrder.YXZ
        });
      }
    })
)
.gesture(
  PinchGesture()
    .onActionUpdate((event: GestureEvent) => {
      if (this.gaussianNode) {
        const scale = event.scale;
        this.gaussianNode.setScale({
          x: scale, y: scale, z: scale
        });
      }
    })
)

到这里,一个完整的"拍照→重建→3D 展示"流程就跑通了。

踩坑记录

实际开发中我踩了几个坑,提前说一下帮你省时间:

帧质量很重要。重建效果好不好,80% 取决于输入帧的质量。拍照时提醒用户慢慢转、保持距离一致,比调参数有用得多。我在 UI 上加了一个取景引导框和"请缓慢旋转商品"的提示,重建成功率直接提高了不少。

内存占用。50 万个高斯球的场景大概吃 200MB 内存,在 Mate 60 这种 12GB 的设备上没问题,但低端设备建议把 gaussianCount 压到 20 万以下。可以通过 deviceInfo.totalRAM 做动态适配。

重建耗时。高质量模式下大概 8-15 秒,标准模式 3-5 秒。如果你的场景对速度要求高(比如扫一扫看 3D),用标准模式就行,效果差距不大。

小结

3DGS 端侧重建是 HarmonyOS 7 里我最看好的特性之一。以前做 3D 展示要么靠预制的模型文件,要么靠云端渲染,现在手机自己就能搞定,对电商、家居、文博类 App 来说是质的提升。

下一篇我们聊互动卡片和闪控窗——这两个能力组合起来,能让你的 App 在桌面和系统级交互上玩出花来。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐