连续放置与一键优化(2.17.0)
VoxelKit 编辑器可以像画笔一样连续放置积木,也可以批量整理模型形状与颜色。这些功能在设备本地执行,无需搭建 Python 服务,不上传模型。原有单点添加与旋转行为默认不变。
连续放置
await editor.enterEdit();
editor.setSelectedColor('#D79962');
editor.setMode(VoxelEditMode.ADD_BRUSH);
单指拖动连续放置;双指平移/缩放仍走 Viewer 的现有配置。每一笔的拾取以开始时的模型为准,新方块不会在同一笔里继续作为放置支撑,从而避免堆成高塔。同一坐标只放置一次,整笔撤销一次。松手后再画可以叠加新的一层。空模型使用射线进入网格的首个单元作为初始放置位置。
如果宿主已有 ADD 按钮,不必改枚举:
editor.setAddBrushEnabled(true);
editor.setMode(VoxelEditMode.ADD);
// 恢复旧行为:单指拖动旋转,仅点击放置
editor.setAddBrushEnabled(false);
也可以在 VoxelEditorOptions.addBrushEnabled 中初始化。onAddBrushHit(x, y, z) 每个实际新增坐标触发一次,包括对称放置。回调异常不会中断放置。gestureLocks.voxelEdit 会拦截画笔;双指相机仍遵守宿主的平移/缩放锁与选择手势配置。显式 ADD_BRUSH 不受 addBrushEnabled=false 影响,需切回 ADD/VIEW 才退出该模式。
一次调用优化
const options = new VoxelOptimizationOptions();
options.kind = VoxelOptimizationKind.REMOVE_ISLANDS;
options.maxVoxels = 8;
options.keepLargest = true;
const result = await editor.optimize(options);
// result.added / removed / recolored / elapsedMs / warnings
editor.undo(); // 包含调色板的完整撤销
计算在 TaskPool,应用与 ArkGraphics 更新仍通过编辑器主线程的受控路径。optimize() 完成代表权威文档已应用,不代表最后一个 GPU Chunk 已提交完成;网格继续使用现有异步队列同步。不要在每个体素回调里再次调用优化。
先检查候选,再确认应用
const options = new VoxelOptimizationOptions();
options.kind = VoxelOptimizationKind.AUTO_REPAIR;
options.maxChanges = 5000;
options.fixBottom = false;
const candidate = await editor.previewOptimization(options);
// 宿主展示统计、warnings 或自行绘制 candidate.cells 的差异预览。
// 内置 Viewer 此时仍显示原模型,不自动覆盖预览颜色。
editor.applyOptimization(candidate);
previewOptimization()要求已进入且就绪的编辑会话;计算期间isUpdating()为 true。- 候选包含
size和 X 最快的Uint32Array cells:0 为空;非零是0xRRGGBB + 1。请勿修改候选。 applyOptimization(candidate)返回实际改变体素数;相同控制器仅保留最近一次候选。文档、颜色、模型切换后旧候选无效,需重算。cancelOptimization()丢弃候选并拒绝迟到结果;它不是操作系统级强杀 Worker,正在计算的任务仍可能短暂占用 CPU。不要连续发起大量任务。selectionOnly=true必须有非空选区。选区外实体不改,新增几何只允许落入选区的一层邻域;这比 3DEdit 某些全腔扩展操作更保守。lockedColors接收#RRGGBB[],被锁定颜色的实体不修改。- 形状优化的
maxChanges默认 5000,按完整连通候选片区分配;小预算可能使大连片候选完全不应用。颜色工具不受此几何预算限制;AUTO_REPAIR 的颜色步骤共享剩余预算。 - 默认拒绝将已有模型全部清空。最终结果超过 255 色会拒绝,不静默降色。
结构工具
| kind | 能力 | 主要参数 |
|---|---|---|
| AUTO_REPAIR | 清孤岛、表面修复、可选整平、分面杂色清理 | fixIslands=true、fixSurface=true、fixBottom=false、fixColors=true、islandSize=8、maxChanges=5000 |
| SURFACE_REPAIR | 六向表面的局部凸块/凹缺检测;要求三层实体背衬 | patchRadius=2 (1..5)、patchDepth=2 (1..8)、patchArea=12 (1..4096)、planeSupport=0.7 (0.5..1)、patchMode=both/spurs/pits |
| FLATTEN_BOTTOM | 按本地 Z 底面众数整平,不自动平移模型 | bottomPlane=-1 自动 (或 0..size-1)、bottomSupport=0.6、bottomDepth=2 (1..16)、bottomMode=both/fill/trim |
| FILL | 封闭内部填充;可开启微漏推断 | leakTolerance=0 (0..4)、nearest=true、fillColor=#D79962 |
| CAVITIES | 仅填充小封闭空腔 | maxVoxels=8,加 FILL 参数 |
| HOLLOW | 保持外形,移除距外界过远的内部实体 | wall=1.2、voxelSizeX/Y/Z=1 |
| SEAL | 三方向二维闭边孔洞,再按三维尺寸筛选 | diameter=3 (1..32)、holeDepth=2 (1..16) |
| REMOVE_ISLANDS | 六邻接孤立分量清理 | maxVoxels=8、keepLargest=true |
| SMOOTH | 按六邻居数去刺/补小凹陷 | spurNeighbors=2 (0..3)、pitNeighbors=5 (4..6)、smoothMode=both/spurs/pits、iterations=1 (1..8) |
| OFFSET_SURFACE | 按欧氏距离增厚或收缩 | direction=out/in、distance=1、voxelSizeX/Y/Z=1 |
| REINFORCE | 根据三轴连续厚度加固薄处 | wall=1.2、allowExterior=false、voxelSizeX/Y/Z=1 |
距离及壁厚与 voxelSizeX/Y/Z 使用同一单位,例如 pitch=0.2 毫米、wall=1.2 毫米。底面、孔径、层数、patch 参数仍以体素数计。网格不能越过原始 1..128³ 范围;增厚到边界会被截断。nearest=false 时新增方块采用 fillColor,true 使用最近原始实体颜色。
AUTO_REPAIR/SURFACE_REPAIR/FLATTEN_BOTTOM 具有连通性保护;删除会拆开原有连通区域时保留删除候选。该保护不是力学或打印可行性验证。自动底面置信度不足时不猜测,指定 bottomPlane 后重试。微漏推断不直接把虚拟封口写到表面;设计开口仍可能被误判为内部。
颜色工具
| kind | 能力 | 主要参数 |
|---|---|---|
| SMOOTH_COLORS | 固定原始 Lab 边界门限的线性光相邻扩散,不跨空气混色 | strength=0.65 (0..1)、steps=3 (1..12)、edgeThreshold=45 (0..200)、newColors=32 (1..255)、colorMode=generate/existing、surfaceOnly=true |
| ADJUST_COLORS | HSV 色相/饱和度/明度 | hue=0 (-3600..3600 度)、saturation=1 (0..10)、brightness=1 (0..10) |
| REPLACE_COLOR | 按 RGB 值替换,不要求知道调色板符号 | sourceColor=#FFFFFF、targetColor=#E0B483 |
| MATCH_PALETTE | CIE Lab 最近目标色 | palette,必须 1..255 个 #RRGGBB |
| REDUCE_COLORS | 按体素权重进行 Lab 聚类、使用原色代表 | count=16 (1..255) |
| MERGE_COLORS | 相近颜色归并到高频代表色 | threshold=10 (0..300 Lab 距离) |
| CLEAN_COLORS | 小色块边界投票,支持多轮/分面/向内传播 | maxVoxels=8、dominance=0.6 (0.5..1)、threshold=10、cleanPasses=1 (1..5)、connectivity=1 (1/2/3=6/18/26邻接)、surfaceOnly=true、faceAware=true、inwardLayers=0 (0..16) |
| EXTEND_COLORS | 将表面颜色向已有内部实体传播,不增加几何 | layers=2 (1..128) |
每轮清色使用快照,循环色状态停止;部分被保护的色块不当成“小块”清除。颜色过渡 generate 模式采用有界 RGB median-cut;色板已满时明确报错,可切 existing 或先 REDUCE_COLORS。优化重排调色板,但会保留颜色与撤销快照;不要缓存旧符号作为永久颜色 ID,应用后从 getState().palette 重新获取。
这些能力对齐 3DEdit 的本地操作类别,并不承诺 Pillow/SciPy 与 ArkTS 的量化色及等距平局逐字节一致。当前参数默认更保守(微漏关闭、几何预算有界);未接入远程 AI、制造检查、切件或连接件布尔。
不依赖 Viewer 的调用
VoxelOptimizer.optimize(input) 返回 Promise<VoxelOptimizationResult>,可在没有 ArkGraphics 场景时使用。VoxelOptimizationInput:
| 字段 | 内容 |
|---|---|
| size | 整数 1..128 |
| rows | size² 个长度为 size 的字符串,按 z/y/x 顺序;. 为空 |
| symbols / colors | 对齐的单字符调色板与 #RRGGBB 数组 |
| selection | 可选 Uint8Array,selectionOnly 时必须为 size³、且非空 |
| options | new VoxelOptimizationOptions() 并设置操作参数 |
所有参数应通过 Options 构造实例后赋值,避免以部分对象替代而丢失默认值。独立调用不自动进入编辑、不修改源文件;保存仍是编辑器 save/saveAs 或 Native Compiler 的下游。
网格关闭修复
viewer.setGroundGridVisible(false) 现在既设置 visible=false,也移除挂载。延迟构建只允许一个进行,已分配对象仍存在并不代表在场景中可见。重新打开复用对象,不重复上传;与方块本身的 AO 描边无关。