第 12 章:vtkMapper——从数据到可绘制的表面
学习目标
本章沿着第 9–10 章建立的 vtkPolyData 继续走向屏幕。读完后,你应该能选择 setInputData 或 setInputConnection,解释 Mapper、Actor 各自负责什么,并能检查表面不显示或颜色不符合预期时究竟是哪一层出了问题。
12.1 把 Mapper 放回两条管线
在 Three.js 中,你通常把几何和材质一起交给 Mesh。vtk.js 则把“数据从哪里来”与“这个数据如何成为可绘制对象”分开:
vtkPolyData ──> vtkMapper ──> vtkActor ──> vtkRenderer
数据 映射与选择 场景对象 视图
vtkMapper 面向表面数据。它接收 vtkPolyData,为渲染后端准备几何,并决定是否根据数据中的标量数组给表面着色。它本身没有放置位置,也不会自行加入场景。vtkActor 持有 Mapper,提供变换、可见性及 vtkProperty。第 13 章专门解释后两者。
这里的“映射”含有两层意思:将数据集转换为可绘制的图元,以及将选中的标量经颜色表转换为颜色。不要把它理解为只负责颜色的工具。
12.2 已有数据:setInputData
第 4 阶段示例手工构造了 81 个点、128 个三角形的 vtkPolyData。将这个已经存在的数据对象交给 Mapper:
const mapper = vtkMapper.newInstance();
mapper.setInputData(surface);
这意味着 Mapper 的输入就是 surface。你可以用 mapper.getInputData() 检查当前数据。接着建立场景对象:
const actor = vtkActor.newInstance();
actor.setMapper(mapper);
renderer.addActor(actor);
renderer.resetCamera();
renderWindow.render();
上面三行解决的是不同的问题:setMapper 连接 Actor 与 Mapper;addActor 让 Renderer 管理它;resetCamera 调整相机以看见数据。只有第一行不会使东西自动出现在画布上。第 4 阶段示例的完整代码在这里。
12.3 算法输出:setInputConnection
若数据由 Source 或 Filter 计算出来,常用的是输出端口连接:
const sphereSource = vtkSphereSource.newInstance({ radius: 1 });
const mapper = vtkMapper.newInstance();
mapper.setInputConnection(sphereSource.getOutputPort());
两种输入方式的要点如下:
| 情况 | 连接方式 | 后续变化 |
|---|---|---|
手工创建、已经持有 vtkPolyData |
setInputData(polyData) |
数据对象变化后由修改时间通知管线 |
| 来自 Source 或 Filter | setInputConnection(algorithm.getOutputPort()) |
保留算法之间的连接;上游参数变化时可重新计算输出 |
例如修改 sphereSource.setRadius(1.5) 后,下一次管线更新能够从 Source 取得新球体。若先取出一次输出,再把那一刻的数据交给 setInputData,就不能把这一步当作与 Source 的持续连接。复杂的 Source → Filter → Mapper 管线将在第 24–25 章展开。
12.4 一个 Mapper 可以选择哪些数据
第 10 章展示了 Point Data 与 Cell Data。Mapper 必须决定采用哪一种关联,以及是否启用标量着色:
mapper.setScalarVisibility(true);
mapper.setScalarModeToUsePointData();
mapper.setScalarRange(0, 100);
setScalarModeToUsePointData() 使用点属性集合中的标量;setScalarModeToUseCellData() 使用单元属性集合。默认标量模式会先找活动点标量,再找活动单元标量,但显式指定能让示例更容易读。若有多个点数组,需要按名称挑选,第 14 章会解释 setScalarModeToUsePointFieldData() 与 setColorByArrayName()。
setScalarVisibility(false) 会关闭按数组着色。这时可以观察 Actor 的单色外观。它不会从数据集中删除数组;重新打开后,Mapper 仍可使用原来的数据。
12.5 “数据变了”与“画面变了”
Mapper 的输入、标量模式、颜色范围改变后,通常还需要调用 renderWindow.render() 让画面更新。若直接写入 vtkDataArray.getData() 返回的 TypedArray,应按第 8 章说明调用数组的 dataChange(),以更新数值范围缓存与修改状态。只调用 render() 并不会自动发现底层内存被直接改写。
反过来,旋转 Actor 或更改它的不透明度,并没有改变 vtkPolyData 的点和单元。排错时先问“我改的是数据、Mapper 还是 Actor”,能避免在错误对象上寻找原因。
12.6 常见故障定位
| 现象 | 首先检查 |
|---|---|
| 完全没有表面 | Mapper 是否有输入;Actor 是否设置 Mapper 并加入 Renderer;相机是否已取景 |
| 有表面但颜色单一 | getScalarVisibility();数据集是否有选中的标量;标量模式是否匹配数组关联 |
| 改了上游算法却没见变化 | 是否用 setInputConnection 保留了端口连接;是否重新渲染 |
| 数值全挤在颜色表一端 | getScalarRange() 与数组真实的 getRange() 是否相配 |
Mapper 不保证输入数据一定有效。若 vtkCellArray 中有越界点 ID,或 Point Data 元组数与点数不符,应先回到第 9–10 章修正数据结构。
本章小结
vtkMapper 是数据管线与可见场景之间的桥。setInputData 接收现成数据,setInputConnection 保留上游算法连接;标量设置决定数据值如何参与表面着色。下一章把 Mapper 包装成真正可摆放、可改变外观的 Actor。