渲染架构与性能
本页解释 Viewer 为什么采用“后台准备、主线程创建场景、优先显示主体、描边可降级”的结构。它帮助你排查首帧、动画、光照或手势掉帧;它不是要求宿主直接操作 ArkGraphics 资源。
先看性能边界
| 组件负责 | 宿主仍需避免 |
|---|---|
| TaskPool 解析与面计划、Scene 代际取消、相机手势合并、延迟描边取消 | 在 build() 中反复创建 Controller/Viewer;并发导入;在手势/Overlay 回调中做同步大 I/O;在 Viewer 外套竞争的双指手势 |
构建成功、日志无错误或缓存命中都不能代替真机帧率和首帧观察。尤其是 Component3D 的可见性、材质资源和双指手势,必须在目标机型验证。
JSON 导入管线
JSON 文本 / URI
→ UTF-8 大小与头部检查
→ TaskPool 解析 data[z][y][x]
→ 真实占用 bounds + 贪心面计划
→ ArkGraphics 主线程创建 Geometry / Material / Scene
→ 两阶段 Component3D 挂载
→ 可选载入动画
→ PBR 单位网格或兼容 BORD 描边
主线程不应逐体素生成网格,也不应在 build() 内创建新的 Scene。VoxelJsonScene 内部会按场景代际取消失效的动画和延后描边,避免旧模型的资源晚到新模型上。
为什么 surfaceCount 通常远小于体素数
相邻、同材质的可见体素面会被合并成较大的平面。这称为贪心表面合并:它不会改变方块的总体外形,但可以显著降低 Geometry 和三角形数量。因此 VoxelLoadResult.surfaceCount 是衡量渲染表面复杂度的一个可用指标,而不是每个方块的六面总数。
VFP 1.3 快速预览管线
Picker URI
→ Header / Footer / DIR0 随机读取
→ META + PAL0 + PMSH(及可选预览缓存)
→ TaskPool 转换紧凑面计划
→ ArkGraphics 创建最终表面
→ 与 JSON 相同的相机、光照、手势与动画路径
这条路径刻意跳过首帧的完整 VOX0/VBUF 读取,目标是“尽快可看”;它不是编辑准备,也不是 source hash 权威校验。
JSON 与 VFP 选择建议
| 资产来源 | 建议入口 | 原因 |
|---|---|---|
| 用户/AI 刚生成、需要人可读与调试 | JSON + loadText()/loadUri() | 直接从源数据生成表面。 |
| 已发布、大尺寸、反复查看 | VFP 1.3 + loadUri() | 可利用预览缓存和选择性 URI 读取。 |
| 要编辑或确认权威体素 | 独立完整格式工具 | Viewer 的快速预览不是编辑准备。 |
贪心表面与单位描边
永久主体使用可见体素表面的贪心合并,减少 Geometry 与三角形数量。为了仍能看出单个体素边界,默认优先使用 PBR 材质内的单位网格纹理:
贪心表面 + Repeat UV + voxel_grid.png AO
→ 原始体素颜色不被覆盖
→ 描边随明暗面、光照和阴影变化
options.unitGridTexture = $rawfile('voxel/voxel_grid.png') 必须在首次加载前设置。静态 HAR 不能可靠在 ArkGraphics 内自行解析自身 rawfile Resource ID;宿主 Resource 可保证纹理创建。纹理不可用时才回退为独立 BORD Geometry,该路径会分批上传,首次描边更晚且对大模型更重。
首帧描边排查顺序
- 确认在第一次
load*()前设置options.unitGridTexture = $rawfile('voxel/voxel_grid.png')。 - 确认资源路径由安装后的 HAR 依赖解析,而不是把宿主业务图片错误地传作单位网格。
- 在同一设备比较“有纹理”和“故意留空”两种情况;后者可能走兼容描边,不能拿来判断 PBR 路径性能。
- 若黑色体素的线过分明显,先检查
exposure、环境光和主光,再决定是否隐藏voxelBordersVisible;不要通过叠加额外 Geometry 修补。
载入动画
- 默认
STACK是逐层堆砌;其余五种模式复用同一面计划,改变批次与路径。 - 临时动画 Geometry 在视觉播放前创建并显式隐藏,避免“完整模型先闪现再播放”。
- 播放期间输入被锁定;视觉结束时先恢复交互,临时资源再在后台释放。
- 任何新加载、页面释放或场景代际变更都会通过版本号取消失效任务。
动画与交互的关系
载入动画不是把整个场景截图移动,而是按面计划控制显示批次。为了避免完整模型先闪现、动画中几何创建导致掉帧或相机和临时对象错位,组件会在动画期间忽略相机手势。动画结束后立即恢复控制;其后的资源回收不应阻塞相机,但仍应在真机连续拖动中检查。
性能优先级
- 正确且快速显示不透明主体。
- 动画期间保证帧连续,不在播放中提交大批原生 Geometry。
- 手势期间优先相机响应;描边可以稍后补齐。
- 编辑准备(不属于 HAR)必须和预览资源隔离,不能拖慢只读首帧。
容量建议
| 情况 | 建议 |
|---|---|
| 128³ JSON 接近 15 MiB | 使用 loadUri(),让原始字节更早转交 TaskPool。 |
| 大型 VFP | 使用 VFP 1.3 + PMSH,并走 URI 选择性读取。 |
| 首帧缺描边 | 检查 unitGridTexture,不要先调高边线 Geometry 批次。 |
| 手势掉帧 | 检查宿主是否同步 rebuild 页面、套叠重手势或在回调里做 I/O。 |
| 内存压力 | 降低业务侧同时保留的 JSON/VFP 副本;不要并发加载多个模型。 |
没有跨设备加载时间、FPS 或功耗承诺。任何性能改动都需要分别验证小模型、典型 128³ 模型、深浅背景、首帧、动画和连续双指操作。
渲染调参的安全顺序
- 从默认
VoxelRenderTuning开始,关闭任何历史试验参数。 - 先调
exposure和keyIntensity,让主体在浅色/深色背景都能看清。 - 再调
ambientDiffuse、fillIntensity、rimIntensity,保留方块不同面的明暗关系。 - 最后才考虑 Bloom、暗角、色散等气氛效果。
- 每次变更都测试彩色、低饱和和纯黑体素;纯黑资产最容易暴露描边/阴影比例问题。
完整字段和默认值见 VoxelViewer API 参考。