第 2 章:从 Three.js 转换到 vtk.js

学习目标

本章使用 Three.js 经验帮助你定位 vtk.js 对象,但不要求记住一张机械的“类名翻译表”。读完后,你应该能指出为什么一个 vtk.js 可见对象通常涉及 Data、Mapper、Actor 和 Property,及其与 Three.js <code>Mesh</code> 的边界。

2.1 先看粗略对应

Three.js 中常见的概念 vtk.js 中相关的对象 类比的边界
<code>BufferGeometry</code> <code>vtkPolyData</code> 后者除了点和多边形,还可包含线、顶点单元以及关联数据
<code>BufferAttribute</code> <code>vtkDataArray</code> 数组通常还要挂到 Point Data 或 Cell Data 上
<code>Mesh</code> <code>vtkActor</code> + <code>vtkMapper</code> + <code>vtkProperty</code> 显示对象、数据映射和外观被拆开
<code>Scene</code> <code>vtkRenderer</code> Renderer 同时管理相机和相关渲染状态
<code>WebGLRenderer</code> <code>vtkRenderWindow</code> 与具体视图 vtk.js 将窗口组织与浏览器绘制后端分层
<code>OrbitControls</code> <code>vtkRenderWindowInteractor</code> + 交互样式 输入事件被转成相机等操作

这张表只用于入门。它无法解释体数据、过滤器和科学数组;也不意味着这些对象的 API 可以按 Three.js 的方式直接替换。

2.2 为什么 Mesh 被拆成多个对象

在 Three.js 中,Mesh 把几何体和材质放到一起,再作为场景对象参与渲染。vtk.js 的表面渲染通常拆成以下层次:

vtkPolyData ──> vtkMapper ──> vtkActor ──> vtkRenderer
   数据          映射       可见对象       场景与相机

<code>vtkPolyData</code> 回答“点、线、面及其数值是什么”;<code>vtkMapper</code> 回答“这份数据怎样用于绘制”;<code>vtkActor</code> 回答“这个结果放在哪里、是否显示”;<code>actor.getProperty()</code> 则保存颜色、不透明度、线框等部分外观设置。

例如,改变 <code>actor.setPosition(…)</code> 移动的是场景中的表示,不要求重新生成 <code>vtkPolyData</code> 的点坐标。改变 Source 的半径则会改变生成的数据。这种区分让你能准确判断一个操作应作用于哪一层。

Mapper 不是 Material。 它除了参与渲染,还连接数据管线,并可选择标量数组和颜色映射。把它只当作材质,会让后面的按值着色和体渲染 API 显得莫名其妙。

2.3 PolyData 与 ImageData 是两种不同的数据组织方式

<code>vtkPolyData</code> 适合显式的点及连接关系。一个三角形要有三个点坐标,还要记录这三个点构成同一个单元。它可以用于表面,也可以只包含点或线。

<code>vtkImageData</code> 适合规则的二维或三维采样网格。它不必逐个存储每个采样点的坐标,而是保存:

对于没有旋转的简单情形,下标 <code>(i, j, k)</code> 的位置可理解为 <code>origin + (i, j, k) × spacing</code>。一般情形还要应用 <code>direction</code>;因此不能把所有 <code>vtkImageData</code> 都当成永远与世界坐标轴对齐。第 11 章会用小网格逐个验证这些量。

请特别区分数据类型与显示方式:<code>vtkImageData</code> 不等于“只能做体渲染”。它也能显示切片,或通过算法产生等值面的三角形数据。

2.4 数组的归属比数组的形状更重要

在 Three.js 中,你可能习惯说“每个顶点一个颜色”。vtk.js 还会让你明确选择:

若两个相邻三角形共享点,点数据能够在公共点上保持连续;若每个三角形各有一个单元值,两块区域可以出现明显边界。这里的关键不是数组能否塞进 GPU,而是数据的物理意义和显示解释。第 8–10 章会专门说明 <code>vtkDataArray</code>、Point Data 和 Cell Data。

2.5 从“搭场景”转换成“追数据”

阅读 vtk.js 示例时,推荐按下面顺序提问:

  1. 输入数据从 Reader、Source 还是手工构造而来?
  2. 输出是什么数据类型,有哪些数值数组?
  3. 中间经过哪些 Filter?
  4. 哪个 Mapper 接收结果?它显示哪个数组?
  5. 哪个 Actor 或 Volume 将结果加入 Renderer?

这一顺序有助于排查“显示出来了但颜色不对”“能看到切片却看不到体渲染”等问题。若从 Actor 开始找,往往会漏掉真正发生问题的数据层。

本章小结

Three.js 经验可以帮助你理解相机、场景、表面和 GPU 渲染,但 vtk.js 的主线是数据对象及其处理关系。下一章会把数据流与场景中的对象关系分开画出来,解释为何代码里同时存在 <code>setInputConnection</code>、<code>setMapper</code> 和 <code>addActor</code>。