智绘鸿蒙 · 如 7 而至端侧 AI 能力实战手记

端侧重建一座园子

智绘鸿蒙·如 7 而至

前言

立项时想做的事很清楚:带一团人逛苏州园林,走完把手机递过去——"刚才那座亭子,你手机上能看到三维的"。全部在端侧完成,不上传云端。

鸿蒙 7 这头对应的是 Spatial Recon Kit(空间建模服务)。名字里"重建"两个字让人乐观:既然叫空间建模服务,那重建应该是它的主业。

两周后我们把这件事停在了原型阶段。这篇复盘记三件事:我们以为的可行性从哪来、真实探测跑出了什么、以及为什么"探测全绿"是最危险的一版结论。

第一层:能力盘点,比想象中窄

先把 SDK 里的实际情况列出来,这是最容易查也最容易被跳过的一步。

位置 内容
@kit.SpatialReconKit 只导出 spatialRenderspatialEdit 两个命名空间
@hms.graphics.spatialRender.d.ts GSPluginGSNodeloadGSNodeTiledGSImportSettings(26.0.0 新增)
3DGS 重建相关接口 只在 API参考/Spatial_Recon_Kit/​C_API 下:HMS_SpatialRecon_Sessionspatial_recon_interface.h,库 libspatial_recon_ndk.z.so,起始版本 6.1.0(23)

结论一:重建能力没有 ArkTS 接口,只有 C API。 指南里那句"多视角与 AR 帧输入"意味着要自己写 NDK 层、自己喂 AR 帧。这不是"调用一个接口"的量级,是一个独立的图形/SLAM 集成项目。

而 ArkTS 侧能拿到的,只有渲染:把已经做好的 3DGS 模型画出来。也就是说,"云游一座园子"里我们能做的只有后半段,前半段要另找路径(离线重建、或者干脆用别人的模型)。

这一步如果一开始就做扎实,项目方向会完全不同。我们是在写完第一版 UI 之后才发现的。

第二层:探测跑下来,全绿

渲染侧我们做了一次完整探测,代码就是文档里那几行:

import { spatialRender } from '@kit.SpatialReconKit';
import { Scene, RenderContext } from '@kit.ArkGraphics3D';

const ctx: RenderContext | null = Scene.getDefaultRenderContext();
ctx?.loadPlugin(spatialRender.GSPlugin.PLUGIN_ID);
const scene: Scene = await Scene.load();
const node: spatialRender.GSNode =
  await spatialRender.GSPlugin.loadGSNode(scene, { uri, offset: 0 }, scene.root);

MatePad Pro(HarmonyOS 7 / API 26)上的输出:

canIUse SystemCapability.Graphics.SpatialRender  -> true
canIUse SystemCapability.Graphics.SpatialEdit    -> true
canIUse SystemCapability.ArkUi.Graphics3D        -> true
GSPlugin.PLUGIN_ID   -> 1450021d-c57f-d9ff-7770-c24fb3f3321c
RETRO_EFFECT_ID      -> a30c8a84-fbdc-4dbc-9511-5918f2ccbe49
getDefaultRenderContext -> ok
loadPlugin(GSPlugin)    -> ok
Scene.load()            -> ok root=container
loadGSNode              -> ok name=gsNode

三项系统能力都在,插件加载成功,场景创建成功,模型节点加载成功。到这里,任何人都会汇报"渲染打通了"。

第三层:全绿是假的

我们当时没有模型文件——手上一个 .ply / .glb 都没有。所以上面那次 loadGSNode 传的 uri 是随手写的一个路径:

OhosRawFile://assets/garden.ply      ← 这个文件不存在

它返回了 ok

于是加了两个对照:

loadGSNode(不存在的 .xyz)  -> ok name=gsNode
loadGSNode(空 uri)         -> 失败,但 code=undefined message=undefined

三条事实:

  1. 不存在的模型文件不会报错,接口照样返回一个名叫 gsNode 的节点。它是不是空的、有没有几何,从返回值上完全看不出来。
  2. 空字符串会抛异常,但抛出的对象没有 codemessage,不是文档里那套 BusinessError 形态。所以按错误码写的 catch 分支,在这里等于没写。
  3. Scene.root 的类型是可空(null),不是 undefined。用 !== undefined 判空能编译通过、也永远为真——这是个静默的逻辑错误。

结论二:探测全绿只能证明"接口存在且可调用",不能证明"渲染会发生在屏幕上"。 真正的验收标准只有一个:看到像素。要么截屏里出现模型,要么用 XComponent 绑上场景后确认有帧。我们停在了前者都没做到的位置。

一次合格的自检应该长什么样

把这次的教训翻译成可执行的四条,下次直接照做:

  1. 准备一个正对照。 一个已知能渲染出来的最小模型(哪怕是一个几 KB 的 .glb 立方体)。没有正对照,所有"成功"都无法区分"真的通了"和"接口宽容"。
  2. 准备一个负对照。 故意传空 uri、传错扩展名、传不存在的文件,看接口分别怎么反应。这次的三个关键事实全部来自负对照,成本不到二十分钟。
  3. 验收看输出侧。 绑定 XComponent 之后截屏比对,或者数帧。返回值只配当线索,不配当结论。
  4. 异常要按最坏情况写。 抛出来的对象可能没有 code、没有 message,甚至不是 BusinessError。日志里至少要把 JSON.stringify(e)typeof e 一起打出来,否则线上只会看到一行 undefined。

为什么当时会判断错

复盘下来有两个原因,都值得记住。

第一个是把"能力存在"当成"链路可用"。 canIUse 返回 true、loadPlugin 不抛异常,这些是系统能力清单层面的事实,和"我这台设备上能不能跑起来"之间还隔着模型文件、渲染循环、视图绑定三层。

第二个是接口太宽容。 一个对不存在的文件返回成功的 API,会让所有基于返回值的自检失效。这类接口只能配合"输出侧验证"用——截图、比对像素、或者拿一个已知能渲染的模型做正对照。我们这轮缺的就是正对照:手里没有一个确定能渲染的 .glb,所以连"渲染管线到底通不通"都无法判定。

如果继续做,路径是什么

按优先级排:

  1. 先拿一个已知能渲染的模型,把 XComponent + Scene 的显示链路打通,用截图确认像素出现。这一步不做,后面全是纸面推演。
  2. 重建侧走离线。端侧 C API 重建的工程量和风险都很高,先用桌面端 3DGS 工具产模型、端侧只负责渲染,验证体验是否成立。
  3. 分包与流式TiledGSImportSettings 是 26.0.0 新加的瓦片化加载,说明官方也在解决大场景内存问题。真实园林场景一定会走到这条路,值得提前验证。
  4. 最后才考虑端侧采集重建(多视角 + AR 帧输入)。

真机数据

项目 实测值
设备 MatePad Pro(HarmonyOS 7 / API 26,序列号略)
三项 syscap 全部 true
loadPlugin / Scene.load 均成功(未单独计时,整轮探测在 1 秒内完成)
loadGSNode(文件不存在) 返回 ok,节点名 gsNode
loadGSNode(空 uri) 抛异常,code / message 均为 undefined
ArkTS 侧重建接口 无(仅 C API,起始 6.1.0(23))

能力探测结果,前三项 syscap 全为 true

loadGSNode 对不存在的文件同样返回 ok

总结

Spatial Recon Kit 的 ArkTS 侧现在只适合做一件事:渲染别人产出的 3DGS 模型。适合"离线重建 + 端侧展示"的场景,比如文旅、房产、展陈里预先做好的点位模型。

不适合"拍一段视频当场生成三维"。那条路目前要下到 C API 和 NDK,而且要先解决 AR 帧输入与算力预算。

这次最大的收获不是接口知识,是一条方法论:接口不报错不等于事情成功了。凡是返回值不能自证的链路,验收就得从输出侧做。

💡 一句话loadGSNode 会为一个不存在的文件返回成功——所以判断 3DGS 通没通,别看日志里的 ok,去看屏幕上有没有像素。

参考文献

  1. 加载 3DGS 模型(开发指南):https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/spatial-recon-load
  2. spatialRender(ArkTS API 参考):https://developer.huawei.com/consumer/cn/doc/harmonyos-references/spatial-recon-spatialrender
  3. SpatialRecon(C API 参考):https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-spatialrecon
  4. Spatial Recon Kit 术语:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/spatial-recon-glossary