跳到主要内容

快速开始

本页的目标是让你在一个 ArkUI 页面里完成一次真正可用的体素预览:能加载 JSON/VFP、可响应触控,且页面退出时不会留下场景或异步任务。若你还不了解这个组件负责什么,先读 欢迎与介绍

开始前检查

条件为什么需要
HarmonyOS API 23 / 6.1.0 或兼容环境VoxelViewer 使用 ArkUI/ArkGraphics 3D 能力。
设备具备 SystemCapability.ArkUi.Graphics3D没有该能力无法在页面上呈现 Component3D
在真机或支持 ArkGraphics 的模拟器测试DevEco 的设计预览不能证明 3D 场景、手势或材质工作正常。
一份 JSON 或 VFP 样本JSON 需符合本页最小合同;VFP 支持 1.2/1.3。
选输入方式
  • 已经有 JSON 字符串:loadText()
  • 已经拿到 rawfile/网络缓存的完整字节:loadBytes()
  • 来自系统文件选择器:loadUri(),这是大 VFP 的优先方式。

1. 安装

推荐通过字符科技 OHPM 仓安装。打开 DevEco Studio 的 Terminal,进入宿主工程根目录后执行:

ohpm config set registry http://ohpm.charactech.cn/repos/ohpm/
ohpm install voxel-kit

第一条命令将 OHPM 下载源设为字符科技仓;第二条命令会安装当前仓中的 voxel-kit,并更新工程的 oh-package.json5 与 lock 文件。可在 OHPM 的 voxel-kit 页面 查看包信息与版本。

若团队只希望对单个工程使用该源,可在工程根目录新增或修改 .ohpmrc

registry=http://ohpm.charactech.cn/repos/ohpm/

随后仍在工程根目录执行:

ohpm install voxel-kit

不要手动把本地 HAR 路径作为常规安装方式。以下写法只用于仓库开发或未发布 HAR 的本地验证:

{
"dependencies": {
"voxel-kit": "file:./libs/voxelKit.har"
}
}

业务代码始终从包根导入:

import { VoxelViewer, VoxelViewerController, VoxelViewerOptions } from 'voxel-kit';

不要从 voxel-kit/src/... 或任何 internal 路径导入。它们不是版本兼容契约。

仓库内开发也可使用:

{
"dependencies": {
"voxel-kit": "file:../voxel-preview"
}
}

2. 第一个 JSON 预览

import {
VoxelLoadAnimationMode,
VoxelViewer,
VoxelViewerController,
VoxelViewerOptions
} from 'voxel-kit';

@Entry
@Component
struct HousePreviewPage {
private readonly options: VoxelViewerOptions = new VoxelViewerOptions();
private readonly controller: VoxelViewerController = new VoxelViewerController(this.options);

aboutToAppear(): void {
// 在首次 load* 前设置。该图片由 HAR 依赖携带,宿主负责解析 Resource。
this.options.unitGridTexture = $rawfile('voxel/voxel_grid.png');
this.options.animationMode = VoxelLoadAnimationMode.STACK;
this.options.loadAnimationDurationMs = 1500;
this.options.showGroundGrid = true;

this.controller.loadText(this.readModelText(), 'house.json')
.then((result) => {
console.info(`loaded=${result.voxelCount}, faces=${result.surfaceCount}`);
})
.catch((error: Error) => {
console.error('Voxel import failed: ' + error.message);
});
}

build() {
VoxelViewer({ controller: this.controller })
.width('100%')
.height(520)
}

aboutToDisappear(): void {
this.controller.dispose();
}

private readModelText(): string {
return '';
}
}

不要在 build()new VoxelViewerController(),也不要每次状态更新时创建新的 Options/Controller 对。Controller 持有可变场景引用和内置刷新回调,必须保持稳定。

这段示例中最容易遗漏的是 unitGridTexture:它并不是要求业务自己实现描边,而是让静态 HAR 在 ArkGraphics 中取得由宿主解析好的 PBR 网格纹理。未设置时模型仍能载入,但大模型可能先显示主体,随后走兼容描边路径。

2.1 读取成功与失败

三个加载方法都返回同一种 Promise<VoxelLoadResult>。把成功与失败放在同一个业务入口处理,避免在回调里又开始一次导入:

private async openJson(text: string): Promise<void> {
try {
const result = await this.controller.loadText(text, 'house.json');
console.info(`已载入 ${result.voxelCount} 体素,合并表面 ${result.surfaceCount}`);
// result.sourceFormat 为 JSON;VFP 成功时为 VFP。
} catch (error) {
// error 是 Error,message 与 getLastError() 一致。
console.error('导入失败:' + error.message);
}
}

getStatus() 返回给用户看的中文说明,不应被业务当作稳定枚举;若你要展示自己的 Loading,使用 VoxelLoadOverlayMode.EXTERNALonLoadOverlayStateChanged,详见 接入与生命周期

3. 从 rawfile 载入 VFP

const content: Uint8Array = await this.getUIContext().getHostContext()
.resourceManager.getRawFileContent('voxel/house.vfp');
const copy = new Uint8Array(content.length);
copy.set(content);
await this.controller.loadBytes(copy.buffer, 'house.vfp');

loadBytes() 的前 4 个字节为 VFPK 时自动走 VFP;否则按 UTF-8 JSON 处理。VFP 数据没有 JSON 15 MiB 上限,但完整 ArrayBuffer 会占用宿主内存;大型文件优先使用 Picker URI。

如果该 rawfile 是 JSON,也可以用相同的 loadBytes();由组件自动识别即可。只有你已拥有文本并且希望更明确地约束 JSON 时,才使用 loadText()

4. 从系统 Picker 导入

import { picker } from '@kit.CoreFileKit';

private async importModel(): Promise<void> {
const documentPicker = new picker.DocumentViewPicker(this.getUIContext().getHostContext());
const options = new picker.DocumentSelectOptions();
options.fileSuffixFilters = [
'Voxel JSON|.json',
'Voxel Format Package|.vfp'
];
options.maxSelectNumber = 1;

const uris = await documentPicker.select(options);
if (uris.length > 0) {
await this.controller.loadUri(uris[0]);
}
}

不要将 Picker URI 视为普通 POSIX 文件路径,也不要在 loadUri() 之外再通过 fileIo 打开它。HAR 会在 URI 授权有效期内完成打开、读取、解析和关闭;VFP 1.3 会选择性读取预览所需区段。

4.1 一个完整的导入按钮模式

Picker 取消并不属于模型加载错误,建议把它与真实 I/O/格式错误分开:

private async importModel(): Promise<void> {
const documentPicker = new picker.DocumentViewPicker(this.getUIContext().getHostContext());
const options = new picker.DocumentSelectOptions();
options.fileSuffixFilters = ['Voxel JSON|.json', 'Voxel Format Package|.vfp'];
options.maxSelectNumber = 1;

const uris = await documentPicker.select(options);
if (uris.length === 0) {
return; // 用户取消
}

try {
await this.controller.loadUri(uris[0]);
} catch (error) {
// 显示 error.message 或让内置 Overlay 显示失败状态。
console.error(error.message);
}
}

同一 Controller 上要等这次 await 结束后,才允许用户开始下一次导入。若 UI 需要禁用按钮,可用 controller.isLoading() 或自己的导入任务状态。

5. 最小 JSON 约定

字段要求
grid_size1..128 的整数。
colors非空体素字符到颜色的映射。
datadata[z][y][x] 读取,展开后必须恰好有 grid_size³ 项。
空体素.
坐标系Z-up,x 最快、y 次之、z 最慢。

JSON 解析失败、网格大小错误、颜色符号未定义或超过 maxJsonBytes 都会使 Promise reject,同时可通过 getLastError() 取到可展示文本。

下一步:把最小示例变成产品界面

你想做的事阅读下一页
改背景、图片、加载遮罩或手势体验接入与生命周期
查询每个 Options、回调与光照参数VoxelViewer API 参考
读取 VFP 目录/META、提取内嵌 GLB 或 PNG 缩略图Reader API 概览
在真机测试大模型与 Picker 失败场景测试与排障