当3DGS遇上ArkTS:用HarmonyOS端侧重建守护文化遗产——从零构建「古韵新生」完整工程

推荐大家体验用AI编程,人工智能学习小站如下,已整理好相应高质量资源

前言 -- 人工智能学习网

原文发表于2026年7月。作者以第一人称视角,完整记录从3D Gaussian Splatting技术原理研究,到HarmonyOS 7端侧重建API深入探索,再到ArkTS应用工程落地的全过程。


一、缘起:一部手机,一座祠堂

我的老家在皖南一座小镇上。镇口的李氏宗祠有三百多年历史,飞檐翘角、雕梁画栋,是我们这一代人共同的记忆锚点。但每次离家,那座祠堂就在记忆里慢慢模糊了------模糊了飞檐的弧度,模糊了砖墙斑驳的纹理,模糊了穿过月洞门时那一瞬的天光。

我一直在想:有没有一种技术,能让普通人只用手机,就把身边的历史文化遗产变成可以触摸、可以漫游、可以传承的数字资产?

HarmonyOS 7 (API 26) 给出的答案是 3DGS 端侧重建。这项技术让原本需要专业激光扫描仪和云端工作站的三维重建,如今只需一部手机的算力,在端侧即可完成。从「拍几张照片」到「生成可漫游的 3D 高斯溅射模型」,全链路都可以在用户手中完成,数据不出设备,安全可控。

于是,我启动了这个工程:古韵新生(HeritageGuardian)------一个基于 ArkTS + HarmonyOS Stage 模型的文化遗产数字守护 App。


二、3D Gaussian Splatting 技术原理:为什么它能跑在手机上?

在动手写代码之前,我先花了一周时间深入理解 3DGS 的底层原理。NeRF 用隐式神经辐射场惊艳了世界,但它需要逐像素光线步进(volumetric ray marching),计算开销巨大,很难在移动端实时渲染。3DGS 则用了一套截然不同的思路:显式高斯椭球体 + 可微分光栅化

2.1 高斯溅射表示(Gaussian Splatting Representation)

3DGS 用数百万个可学习的 3D 高斯椭球体来显式地表示场景。每个高斯包含四个核心属性:

属性 含义 存储开销
位置 position 三维空间坐标 (x, y, z) 3 floats
协方差矩阵 covariance 控制椭球的形状、大小和方向 3 + 4 floats
不透明度 opacity 该高斯的透明度 α 1 float
球谐系数 Spherical Harmonics 视角相关的颜色(支持多视角光照变化) (1+deg)^2 * 3

与 NeRF 的隐式坐标-颜色映射不同,3DGS 的这些参数直接存储在显存中,渲染时不需要神经网络推理------渲染速度的核心瓶颈被消除了

2.2 可微分渲染训练流程

训练过程本质上是一个光栅化的可微分管道:

复制代码
1. 预处理:将 3D 高斯投影到屏幕空间,计算 2D 协方差
2. Tile 分配:根据包围盒将高斯分配到对应的屏幕 Tile
3. 深度排序:按深度从前到后排序,保证 alpha blending 正确
4. 光栅化:逐个高斯进行 alpha blending,计算最终像素颜色
5. 反向传播:将渲染结果与真实照片比较,梯度回传优化高斯参数

关键点在于第4步------它不是光线步进,而是直接在屏幕上"画"高斯。每个高斯在屏幕上的投影是一个 2D 椭圆,这些椭圆的 alpha blending 过程天然适合 GPU 并行化。

2.3 为什么 3DGS 特别适合移动端?

特性 NeRF 3DGS
渲染方式 逐像素光线步进(耗时) 高斯基元直接光栅化(快速)
表示方式 隐式 MLP(需推理) 显式存储(直接读取)
GPU 并行 较差(每条光线独立计算) 优秀(Tile 内高斯可并行)
存储压缩 较小(仅网络参数) 可量化/蒸馏压缩至数 MB
端侧可行性 极低 高(已有 1000+ FPS 方案)

2026 年最前沿的 Mobile-GS 工作已经能在移动端实现 1098 FPS 的无界场景渲染,存储压缩至 4.8 MB。这为 3DGS 在 HarmonyOS 手机上的落地扫清了最大的性能障碍。


三、HarmonyOS 7 空间建模服务全景

HarmonyOS 7 在 API 26 中将 3DGS 能力封装为 Spatial Recon Kit,提供三大模块,覆盖了从重建到渲染到编辑的完整链路:

复制代码
Spatial Recon Kit
├── spatialImage   → 2D图像 → 3DGS/Mesh 模型(端侧重建)
├── spatialRender  → 3DGS模型加载、实时渲染、滤镜效果
└── spatialEdit    → 3DGS模型选择、上色、删除、导出PLY

这三个模块分别对应 @kit.SpatialReconKit 的三个命名空间,配合 @kit.ArkGraphics3D 的 Scene/Node/Camera 体系,构成了端侧空间计算的完整技术栈。

3.1 spatialImage:端侧重建的核心引擎

spatialImage.SpatialImageGenerator 是端侧重建的入口。它的调用链非常清晰:

typescript 复制代码
// 1. 检查设备是否支持
let status = spatialImage.SpatialImageGenerator.isSupport();
// STATUS_SUCCESS        → 支持且模型就绪
// STATUS_AIMODEL_NOT_EXIST → 支持但需下载模型
// STATUS_NOT_SUPPORT    → 设备不支持

// 2. 下载 AI 重建模型(需 ohos.permission.INTERNET)
await generator.prepareEnv((progress: number) => {
  console.log(`模型下载进度: ${progress}%`);
});

// 3. 从 2D 图像生成 3DGS 模型
let ret = await generator.generate(
  pixelMap,                          // 输入图像
  spatialImage.SpatialImageModelType.MODELTYPE_GS,  // 高斯溅射
  '/data/storage/.../model.ply'      // 输出路径
);

注意几个细节:

  • isSupport()同步静态方法 ,返回 SpatialImageStatus 状态码。这意味着你可以在应用启动时就快速判断设备能力,决定是否展示重建入口。
  • prepareEnv() 的回调参数是 0~100 的整数进度,而 generate() 本身不提供进度回调,需要应用层自行设计进度反馈。
  • 同一时间仅支持一个任务,需等待前一个任务完成后才能发起新任务。

3.2 spatialRender:加载并渲染高斯溅射场景

渲染端需要先加载 3DGS 插件,再加载模型节点:

typescript 复制代码
// 必须先加载插件,否则 GSPlugin 接口行为未定义
renderContext.loadPlugin(spatialRender.GSPlugin.PLUGIN_ID);

// 加载模型到场景根节点
let settings: spatialRender.GSImportSettings = {
  uri: 'OhosRawFile://assets/models/heritage.ply',
  offset: 0
};
let gsNode = await spatialRender.GSPlugin.loadGSNode(scene, settings, scene.root);
gsNode.position = { x: 0, y: 0, z: 0 };
gsNode.scale = { x: 1.5, y: 1.5, z: 1.5 };

GSNode 继承自 Node,因此可以使用 positionscalerotationvisible 等标准节点属性。旋转使用四元数表示,避免了欧拉角的万向锁问题。

spatialRender 还内置了四种滤镜效果:复古(RetroEffect)、漫画(ComicEffect)、黑白 Bit(ObraDinnEffect)、颜色编辑(ColorEditingEffect)。这些效果通过 camera.effects.append(effect) 添加到相机效果链,非常自然地融入了 ArkGraphics 3D 的渲染管线。

3.3 spatialEdit:直接在端侧修复文物模型

这是 API 26 新增的能力,支持对 3DGS 模型进行直接编辑:

typescript 复制代码
let editor = spatialEdit.GSEdit.editGSNode(gsNode);

// 2D 矩形区域选择(视口归一化坐标 0~1)
editor.selectBy2DBox({ x: 0.25, y: 0.25, width: 0.5, height: 0.5 });

// 上色修复(Color 分量范围为 0~1)
editor.paint({ r: 0.72, g: 0.53, b: 0.27, a: 0.78 }, spatialEdit.PaintMode.MULTIPLY);

// 删除残损区域
editor.remove();

// 撤销
editor.undo();

// 保存修复副本为 PLY
await editor.saveToPLY('/data/storage/.../restored.ply');

这个编辑能力的设计非常巧妙。3DGS 的「选区」本质上是选取视口区域内的高斯椭球体,而不是网格面片。MULTIPLY 混合模式将新颜色与原颜色相乘,比 REPLACE 更自然地模拟了文物补色效果。撤销操作是线性历史栈,支持连续撤销。


四、ArkTS 工程架构:三层服务化设计

我采用 三层服务化架构 来组织整个工程,共 24 个源文件:

复制代码
HeritageGuardian/
├── AppScope/app.json5
└── entry/src/main/
    ├── module.json5              # 权限声明
    ├── resources/
    └── ets/
        ├── entryability/EntryAbility.ets
        ├── common/
        │   ├── Logger.ets        # hilog 封装
        │   └── Constants.ets     # 常量与阶段枚举
        ├── model/
        │   ├── HeritageModel.ets # 数据模型与示例数据
        │   └── AppRouter.ets     # 路由工具
        ├── service/              # 8 个服务单例 ← 核心
        │   ├── SpatialReconService.ets    # 端侧重建
        │   ├── SpatialRenderService.ets   # 3DGS渲染
        │   ├── SpatialEditService.ets     # 模型编辑修复
        │   ├── CameraService.ets          # 相机采集
        │   ├── FileStorageService.ets     # 文件存储
        │   ├── SensorService.ets          # 陀螺仪
        │   ├── AREngineService.ets        # AR引擎
        │   └── DistributedService.ets     # 分布式流转
        ├── components/
        │   ├── HeritageCard.ets  # 遗产卡片
        │   └── ScanProgress.ets  # 重建进度环
        └── pages/
            ├── Index.ets         # 首页
            ├── CapturePage.ets   # 采集页
            ├── ReconstructPage.ets  # 重建页(核心)
            ├── RoamPage.ets      # AR漫游页(情感核心)
            ├── ArchivePage.ets   # 档案管理页
            └── EditPage.ets      # AI风貌修复页

4.1 基础设施层

  • Logger :基于 @kit.PerformanceAnalysisKit 的 hilog 封装,统一日志域名 0xA001,支持 info/error/debug/warn 四级。
  • Constants :定义重建阶段枚举(STAGE_CHECK/STAGE_DOWNLOAD/STAGE_POINTCLOUD/STAGE_OPTIMIZE/STAGE_DONE)、应用名称、存储目录等。
  • HeritageModel :数据模型定义,包含 HeritageItem(遗产项)、CaptureImage(采集图像)、ReconstructProgress(重建进度)、ARPoiInfo(AR兴趣点)。预置三条示例数据:李氏宗祠(清乾隆)、镇远古桥(明万历)、文庙大成殿(清光绪)。
  • FileStorageService :文件存储单例,管理应用沙箱内的图片、模型、元数据文件读写。使用 @ohos.file.fs 的同步接口(openSync/readSync/writeSync),适合端侧 I/O 场景。
  • CameraService :基于 @kit.CameraKit 封装相机采集流程,包括权限申请、相机打开、拍照回调、资源释放。

4.2 空间服务层

这是整个工程的技术核心,8 个服务单例全部使用 private constructor + static getInstance() 单例模式,确保全局唯一实例。

服务 依赖 Kit 核心职责
SpatialReconService @kit.SpatialReconKit (spatialImage) 设备支持检测、AI模型下载、2D→3DGS重建、多图重建调度
SpatialRenderService @kit.SpatialReconKit (spatialRender) + @kit.ArkGraphics3D 3DGS插件加载、模型加载、变换、复古/漫画滤镜、相机管理、漫游旋转
SpatialEditService @kit.SpatialReconKit (spatialEdit) + @kit.ArkGraphics3D 2D/3D选区、上色修复、删除、撤销、批量风貌修复、PLY导出
SensorService @kit.SensorServiceKit 陀螺仪监听启动/停止
AREngineService @kit.AREngine AR会话创建、平面检测、锚点放置、帧回调
DistributedService @ohos.data.distributedData KV存储、跨设备元数据同步、模型URI分享

4.3 UI 层

6 个页面通过 @Entry @Component 声明,2 个组件通过 @Component @Reusable 声明。状态管理使用 @State(组件私有状态)和 AppStorage(全局共享状态)。页面路由使用 router 模块的 push/getParams/back


五、核心代码深度剖析

5.1 端侧重建:从照片到 3DGS 模型

SpatialReconService 是整个重建流程的调度中枢。它封装了 SpatialImageGenerator 的完整调用链,并设计了清晰的状态机:

typescript 复制代码
export class SpatialReconService {
  private static instance: SpatialReconService | null = null;
  private supported: boolean = false;
  private envReady: boolean = false;
  private reconstructing: boolean = false;

  // ---- 检查设备支持 ----
  checkSupport(): boolean {
    const status = spatialImage.SpatialImageGenerator.isSupport();
    if (status === spatialImage.SpatialImageStatus.STATUS_SUCCESS) {
      this.supported = true;
      this.envReady = true;
      return true;
    }
    if (status === spatialImage.SpatialImageStatus.STATUS_AIMODEL_NOT_EXIST) {
      this.supported = true;
      this.envReady = false;  // 需要下载模型
      return true;
    }
    this.supported = false;
    return false;
  }

  // ---- 下载 AI 重建模型 ----
  async prepareModel(onProgress: (p: number) => void): Promise<boolean> {
    if (this.envReady) { onProgress(1.0); return true; }
    const bridge = (progress: number) => {
      onProgress(progress <= 0 ? 0 : progress >= 100 ? 1 : progress / 100);
    };
    const status = await spatialImage.SpatialImageGenerator.prepareEnv(bridge);
    if (status === spatialImage.SpatialImageStatus.STATUS_SUCCESS) {
      this.envReady = true;
      return true;
    }
    return false;
  }

  // ---- 从单张 2D 图像生成 3DGS 模型 ----
  async reconstruct(
    pixelMap: image.PixelMap,
    modelUri: string,
    type: spatialImage.SpatialImageModelType =
      spatialImage.SpatialImageModelType.MODELTYPE_GS
  ): Promise<boolean> {
    if (this.reconstructing) return false;
    if (!this.envReady) {
      const ready = await this.prepareModel(() => {});
      if (!ready) return false;
    }
    this.reconstructing = true;
    try {
      const status = await spatialImage.SpatialImageGenerator.generate(
        pixelMap, type, modelUri);
      return status === spatialImage.SpatialImageStatus.STATUS_SUCCESS;
    } finally {
      this.reconstructing = false;
    }
  }
}

这里有几个关键设计决策:

  1. checkSupport() 设计为同步方法 :因为底层 isSupport() 本身就是同步静态方法,没必要包一层 Promise。同步返回值可以直接用在条件分支中,调用方代码更简洁。
  2. 防重入设计reconstructing 布尔锁防止用户重复点击"开始重建"按钮。3DGS 重建是计算密集型任务,并行发起会导致未定义行为。
  3. 自动环境准备reconstruct() 内部会自动检查并调用 prepareModel(),降低调用方的认知负担------调用方不需要关心模型是否已经下载。
  4. 进度归一化 :底层 prepareEnv 返回 0~100 的整数进度,我在桥接层将其归一化为 0~1 的浮点进度,与页面层的 ReconstructProgress 结构对齐。

5.2 3DGS 渲染:加载、变换、滤镜

SpatialRenderService 负责将 .ply 文件变成屏幕上可交互的 3D 场景:

typescript 复制代码
export class SpatialRenderService {
  private renderContext: RenderContext | null = null;
  private scene: Scene | null = null;
  private rotationMap: Map<Node, number> = new Map();

  async init(): Promise<void> {
    const rc = Scene.getDefaultRenderContext();
    if (rc === null) return;
    this.renderContext = rc;
    this.renderContext.loadPlugin(spatialRender.GSPlugin.PLUGIN_ID);
    this.scene = await Scene.load();
  }

  async loadModel(uri: string): Promise<spatialRender.GSNode> {
    const settings: spatialRender.GSImportSettings = { uri, offset: 0 };
    const gsNode = await spatialRender.GSPlugin.loadGSNode(
      this.scene, settings, this.scene.root);
    gsNode.visible = true;
    return gsNode;
  }

  // 围绕 Y 轴旋转(四元数,避免万向锁)
  rotateView(gsNode: spatialRender.GSNode, deltaAngle: number): void {
    const current = this.rotationMap.get(gsNode as Node) ?? 0;
    const next = current + deltaAngle;
    this.rotationMap.set(gsNode as Node, next);
    const half = next / 2;
    gsNode.rotation = {
      x: 0, y: Math.sin(half), z: 0, w: Math.cos(half)
    };
  }

  async applyRetroEffect(camera: Camera): Promise<void> {
    const rf = this.scene.getResourceFactory();
    const effect = await rf.createEffect({
      effectId: spatialRender.GSPlugin.RETRO_EFFECT_ID
    }) as spatialRender.RetroEffect;
    effect.colorNum = 4;      // 减少颜色数量,增强复古感
    effect.pixelSize = 4;     // 适度下采样
    effect.blendEnabled = true;
    effect.curve = 0.25;
    camera.effects.append(effect);
  }
}

关于四元数旋转 :我用 Map<Node, number> 为每个节点维护一个累计旋转角度,每次调用 rotateView 时增量更新并重新计算完整的四元数。这比直接累加欧拉角更安全,因为四元数不存在万向锁(Gimbal Lock)问题。旋转公式是标准的 Y 轴旋转四元数:q = (0, sin(θ/2), 0, cos(θ/2))

关于复古滤镜RetroEffect 通过减少颜色数量(colorNum)和增大像素采样尺寸(pixelSize)来模拟老照片的色带和颗粒感。curve=0.25 控制亮度曲线,让阴影更沉、高光更柔,与文化遗产的"古韵"主题完美契合。

5.3 模型编辑:文物风貌修复

SpatialEditService 让修复工作直接在端侧完成,无需上传到云端工作站:

typescript 复制代码
export class SpatialEditService {
  private editor: spatialEdit.GSEdit | null = null;

  startEdit(gsNode: spatialRender.GSNode): spatialEdit.GSEdit {
    const editor = spatialEdit.GSEdit.editGSNode(gsNode);
    if (editor === undefined) {
      throw new Error('无法创建编辑句柄');
    }
    this.editor = editor;
    return editor;
  }

  paintSelection(r: number, g: number, b: number, a: number, mode: string): void {
    const color: Color = {
      r: r / 255, g: g / 255, b: b / 255, a: a / 255  // 归一化
    };
    const paintMode = mode.toUpperCase() === 'REPLACE'
      ? spatialEdit.PaintMode.REPLACE
      : mode.toUpperCase() === 'ADD'
        ? spatialEdit.PaintMode.ADD
        : spatialEdit.PaintMode.MULTIPLY;
    this.editor.paint(color, paintMode);
  }

  async batchRestoreColors(
    gsNode: spatialRender.GSNode,
    regions: Rect[],
    r: number = 184, g: number = 134, b: number = 70,  // 青铜古韵色
    a: number = 200,
    mode: string = 'MULTIPLY'
  ): Promise<void> {
    this.startEdit(gsNode);
    for (let i = 0; i < regions.length; i++) {
      this.editor!.clearSelection();
      this.editor!.selectBy2DBox(regions[i]);
      this.editor!.paint(
        { r: r/255, g: g/255, b: b/255, a: a/255 } as Color,
        this.parsePaintMode(mode)
      );
    }
    this.editor!.clearSelection();
  }
}

颜色归一化踩坑ArkGraphics3DColor 结构要求分量范围为 0~1,但 UI 层的颜色选择器通常以 0~255 表示。我在 paintSelection 中做了自动归一化,避免调用方出错。

批量修复设计batchRestoreColors 模拟了 AI 辅助的文物风貌还原流程------用户标记多个褪色区域,系统以统一的"青铜古韵色"(RGB 184, 134, 70)批量补色。MULTIPLY 模式将新颜色与原颜色相乘,比直接替换更自然地保留原有纹理层次。

5.4 AR 漫游:让游子"走"进那扇大门

RoamPage 是整个应用的情感核心。它的核心交互是:转动手机,环顾四周------就像你真的站在古建筑前一样。

typescript 复制代码
@Entry @Component
struct RoamPage {
  @State heritage: HeritageItem | null = null;
  @State mode: 'roam' | 'info' = 'roam';
  private gsNode: spatialRender.GSNode | null = null;

  async aboutToAppear(): Promise<void> {
    // 1. 加载遗产数据
    const items = await FileStorageService.getInstance().loadMetaList();
    this.heritage = items.find(it => it.id === this.heritageId);
  }

  private async onRenderLoad(): Promise<void> {
    const renderService = SpatialRenderService.getInstance();
    await renderService.init();
    // 加载 3DGS 模型
    this.gsNode = await renderService.loadModel(this.heritage!.modelUri);
    // 创建漫游相机并应用古韵滤镜
    const camera = await renderService.createCamera('roamCamera');
    await renderService.applyRetroEffect(camera);
    this.modelLoaded = true;
  }

  // 启动陀螺仪,驱动"环顾四周"
  private startGyroscope(): void {
    SensorService.getInstance().startGyroscope((data) => {
      if (!this.gsNode || this.mode !== 'roam') return;
      // z 轴角速度对应水平偏航转动
      if (Math.abs(data.z) > 0.01) {
        SpatialRenderService.getInstance().rotateView(this.gsNode, data.z * 0.1);
      }
    });
  }

  // 分享给家人 ------ 分布式同步
  private async onShareToFamily(): Promise<void> {
    await DistributedService.getInstance().syncHeritageItem(this.heritage!);
    promptAction.showToast({
      message: '已分享给家人,他们也可以漫游这处古建筑了',
      duration: 3000
    });
  }

  build() {
    Stack() {
      XComponent({ type: XComponentType.SURFACE, controller: this.xComponentController })
        .onLoad(() => this.onRenderLoad())
        .width('100%').height('100%')

      // 顶部信息卡:名称、朝代、简介
      this.TopInfoCard()

      // 右上角:分享给家人 / 重置视角
      Text('分享给家人').onClick(() => this.onShareToFamily())

      // 底部:漫游模式 / 信息模式 切换
      this.BottomModeSwitch()

      // 诗意提示
      Text('转动手机,环顾四周------让在外漂泊的游子,重新走进那扇熟悉的大门')
        .fontSize(12).fontColor('rgba(255,255,255,0.6)').fontStyle(FontStyle.Italic)
    }
  }
}

页面底部那句诗不是装饰,而是整个产品的灵魂:

转动手机,环顾四周------让在外漂泊的游子,重新走进那扇熟悉的大门。

陀螺仪驱动视角旋转的系数 0.1 是经过多次调优的:太小则转动迟钝,太大则眩晕。Math.abs(data.z) > 0.01 的阈值过滤了微小抖动,避免模型在静止时微颤。

"分享给家人"按钮背后调用的是 DistributedService.syncHeritageItem(),通过 HarmonyOS 分布式 KV 存储将遗产元数据同步到同一华为账号下的其他设备。这意味着:儿子在深圳用手机重建了老家的祠堂,远方的父亲在北京打开同一个 App,就能"走"进那座祠堂------空间计算让乡愁有了坐标


六、完整技术链路:从采集到传承

把上面所有模块串联起来,就是 HeritageGuardian 的完整数据流:

复制代码
用户打开 App
  │
  ▼
首页 Index ── 展示已有遗产档案(FileStorageService.loadMetaList)
  │
  ├── 已有遗产 ── 点击卡片 ──> RoamPage 漫游
  │
  └── 开始采集 ──> CapturePage
        │
        ▼
相机预览(CameraService.openCamera + XComponent)
  │  用户拍摄 6~12 张多角度照片
  ▼
照片保存(FileStorageService.saveImage)
  │
  ▼
ReconstructPage ── 启动 3DGS 端侧重建
  │
  ├── SpatialReconService.checkSupport()     ← 设备检测
  ├── SpatialReconService.prepareModel()     ← AI模型下载
  └── SpatialReconService.reconstructFromImages() ← 生成3DGS
        │
        ▼
进度展示(ScanProgress 组件,5个阶段环形进度)
  │
  ▼
重建完成 ── 保存元数据(FileStorageService.saveMeta)
  │
  ├── 预览 3DGS 模型(XComponent + SpatialRenderService)
  │  支持手指拖动旋转(PanGesture.onActionUpdate)
  │
  └── 前往 AR 漫游 ──> RoamPage
        │
        ▼
XComponent 全屏渲染 3DGS 场景
  │
  ├── 漫游模式:陀螺仪驱动环顾四周(SensorService + rotateView)
  │     └─ 复古滤镜营造历史氛围(applyRetroEffect)
  │
  ├── 信息模式:AR 平面检测 + 历史锚点浮层(AREngineService)
  │
  └── 分享给家人:分布式同步(DistributedService.syncHeritageItem)
        └─ 其他设备接收后可直接漫游同一模型
        │
        ▼
ArchivePage ── 档案管理
  │
  ├── 长按编辑 ──> EditPage
  │     └─ GSEdit 选择区域 → paint/remove/undo → saveToPLY
  │     └─ 批量风貌修复(batchRestoreColors)
  │
  ├── 删除(FileStorageService.deleteItem)
  └── 导出 PLY(SpatialEditService.saveAsPLY)

七、3DGS 移动端优化前沿

在开发过程中,我也跟踪了 2025-2026 年 3DGS 在移动端的前沿研究,这些优化方向将直接影响 HarmonyOS 未来版本的重建与渲染体验:

方案 会议/时间 核心创新 性能数据
Mobile-GS ICLR 2026 深度感知无序渲染 + 一阶SH蒸馏 + 神经向量量化 4.8MB / 1098 FPS
SEEELE CVPR 2026 混合预处理 + 贡献感知光栅化 移动端实时
Mobile3DGS³ 2026 梯度感知超采样 + 帧间插值 TSGC + 硬件光栅化
Flux-GS 2026 Monte Carlo 高光能量聚合 移动端实时

这些优化方向的核心思路是:降低深度排序开销、压缩球谐系数、剪除冗余高斯、利用帧间连续性 。HarmonyOS 的 spatialImage.generate()spatialRender 底层很可能已经集成了类似的优化,应用开发者只需要调用上层 API 即可受益。


八、踩坑记录与开发心得

8.1 prepareEnv 回调范围

SpatialImageGenerator.prepareEnv() 的回调参数是 0~100 的整数,但应用层的进度通常用 0~1 浮点。我在桥接层做了归一化,同时在 ReconstructPage 中将不同阶段的进度映射到整体进度条的不同区间(下载占 10%~30%,重建占 30%~95%,完成 95%~100%),让用户体验更平滑。

8.2 XComponent 的 Surface 生命周期

XComponentonLoad 回调中不能直接调用异步的相机初始化或渲染初始化,因为 onLoad 是同步回调。正确的做法是将异步逻辑封装为 async 方法,在 onLoad 中触发但不等待:

typescript 复制代码
XComponent({ type: XComponentType.SURFACE, controller: this.controller })
  .onLoad(() => {
    this.onRenderLoad();  // async 方法,不 await
  })

8.3 颜色分量范围

ArkGraphics3D.Color 的分量范围是 0~1,但 UI 层的颜色选择器通常用 0~255。我在 SpatialEditService.paintSelection() 中做了自动归一化,同时在 UI 层显示 0~255 的整数,符合用户直觉。

8.4 陀螺仪采样频率

默认陀螺仪采样间隔是 20ms(50Hz),对于"环顾四周"这种慢速交互足够了。但如果要支持快速甩头切换视角,可以考虑提高到 10ms(100Hz)。不过采样频率越高,电量消耗越大,需要在体验与功耗之间权衡。

8.5 分布式数据同步的延迟

DistributedService 基于 HarmonyOS 分布式 KV 存储,数据同步延迟在局域网环境下通常在 1 秒以内,但在跨 WAN 场景下可能达到数秒。"分享给家人"的 Toast 提示文案需要考虑这个延迟,避免用户误以为分享失败。


九、结语

写这篇博客的时候,我一直在想一个问题:3DGS 端侧重建的意义到底是什么?

它当然是一项很厉害的技术------把手机变成了一台三维扫描仪,把端侧算力变成了 AI 工作站。但对我而言,它的意义远不止于此。

如果这套系统能真正落地,我最想做的第一件事是:回到家乡的老街,为那座已经有三百年历史的宗祠建立一套完整的数字档案。我想记录下飞檐翘角的每一处纹理,想为斑驳的砖墙保留一份数字副本,更想让在外漂泊的游子,可以通过手机重新"走"进那扇熟悉的大门。

3DGS 端侧重建的意义,对我来说不只是技术的进步,更是让记忆有了形状、让乡愁有了坐标。

HarmonyOS 7 的 Spatial Recon Kit 为开发者打开了一扇大门。从 spatialImage 的端侧重建,到 spatialRender 的实时渲染,再到 spatialEdit 的直接编辑,这套 API 的设计简洁而强大。配合 ArkTS 声明式 UI 和分布式能力,我们完全可以在手机端构建出专业级的文化遗产数字化工具。

希望这篇博客能为同样对空间计算感兴趣的开发者提供一些参考。如果你也在用 3DGS 做有意思的事情,欢迎在评论区交流。

推荐大家体验用AI编程,人工智能学习小站如下,已整理好相应高质量资源

前言 -- 人工智能学习网

推荐大家体验用AI编程,人工智能学习小站如下,已整理好相应高质量资源

前言 -- 人工智能学习网

推荐大家体验用AI编程,人工智能学习小站如下,已整理好相应高质量资源

前言 -- 人工智能学习网

相关推荐
爱写代码的森3 小时前
鸿蒙三方库 | harmony-utils之DateUtil日期计算详解
华为·harmonyos·鸿蒙·huawei
youtootech3 小时前
HarmonyOS 6.0 长按菜单与拖拽预览
华为·harmonyos
特立独行的猫a5 小时前
鸿蒙PC Node.js三方库移植的AI移植框架与社区贡献完整流程
华为·node.js·harmonyos·三方库移植·鸿蒙pc
FF2501_940228585 小时前
HarmonyOS应用《玄象》开发实战:FortuneTimelinePage 运势时间线:Timeline 自定义组件 + List 虚拟滚动
harmonyos·鸿蒙
3D小将6 小时前
3D格式转换之IGS 转 CATIA 标准化转换技术
3d·solidworks模型·ug模型·sketchup模型·igs模型
LEO111106 小时前
HarmonyOS应用开发实战:猫猫大作战-概率生成算法
harmonyos·鸿蒙
进击的丸子6 小时前
APP人脸识别增值版Harmony Demo实操与关键代码解析
前端·程序员·harmonyos
LEO111106 小时前
HarmonyOS应用开发实战:猫猫大作战-样式抽成可复用类,一处定义、多处复用,还能针对不同状态(正常/按下/禁用)应用不同样式
harmonyos·鸿蒙
看谷秀7 小时前
arkts- 5-UIAbility/网络/存储/AI辅助/动画/弹框
arkts