第 5 阶段练习与参考答案
按教程目录完成第 16–18 章后,运行阶段示例。先尝试手算,再用页面表格核对。
练习 1:一条视线与一张切片
第 5 阶段示例在 z=0 到 z=8 的区段采样。若间距为 1,采样点在 z=0.5,1.5,...,7.5。这与第 4 阶段选择 K=5 切片有什么本质区别?
参考答案
K=5 切片只显示固定索引平面上的值;本例的一条视线读取多个 z 位置,并把多处的颜色与不透明度按前后顺序合成一个像素。整幅体渲染图还需对许多屏幕像素重复视线计算。
练习 2:在网格点之间插值
示例中第 2 层四角值是 [35,45,41,51],第 3 层四角值是 [80,90,86,96]。在 (i,j,z)=(0.5,0.5,2.5) 处,插值标量是多少?
参考答案
第 2 层中心为 (35+45+41+51)/4=43,第 3 层中心为 (80+90+86+96)/4=88。z=2.5 位于两层中间,所以结果是 (43+88)/2=65.5。示例默认间距下第三次采样正好显示 65.5。
练习 3:查询两条传递函数
示例颜色函数在标量 60 处设置 RGB [0.12,0.75,0.78]。透明阈值为 50、倍率为 1 时,不透明度控制点是 (50,0) 和 (70,0.12)。标量 60 的颜色与参考不透明度分别是什么?若把不透明度改成 0,颜色还会对最终像素有贡献吗?
参考答案
颜色直接取该控制点的 [0.12,0.75,0.78]。60 位于 50 与 70 中间,默认线性过渡下 α 为 0.06。若 α=0,贡献权重 (1−A)α=0,所以该样本无论是什么颜色都不会贡献到最终像素。
练习 4:手算前向后合成
前方样本为红色 (1,0,0)、α=0.5;后方样本为蓝色 (0,0,1)、α=0.5。从 C=(0,0,0), A=0 开始,算两步后的预乘颜色与累计不透明度。若背景是白色,最终显示 RGB 是多少?
参考答案
第一步 C=(0.5,0,0), A=0.5。第二步透过率是 1−0.5=0.5,权重为 0.5×0.5=0.25,得到 C=(0.5,0,0.25), A=0.75。剩余白背景贡献 (1−A)×(1,1,1)=(0.25,0.25,0.25),最终 RGB 为 (0.75,0.25,0.5)。
练习 5:采样间距修正
某均匀区域在参考距离 1 下的不透明度为 0.36。改成两个长度 0.5 的采样区段后,每段应使用多少 α,才能保持相同的总透过率?若错误地每段都沿用 0.36,总不透明度会变成多少?
参考答案
每段应为 1−(1−0.36)^0.5=0.2。两段透过率为 0.8²=0.64,总不透明度仍为 0.36。若每段仍用 0.36,透过率为 0.64²=0.4096,总不透明度为 1−0.4096=0.5904,明显更实。
练习 6:函数定义域之外
不透明度函数最低控制点为 (0,0),最高为 (200,0.75)。查询标量 230,默认开启 clamping 时会得到什么?关闭 clamping 后又会怎样?
参考答案
默认端点钳制取最高控制点的 y,即 0.75。执行 opacityFunction.setClamping(false) 后,定义域外返回 0,230 将变成透明。查询前还应检查真实数组值范围,避免控制点只覆盖一小段数据。
练习 7:把函数接入体渲染对象
设已经有 vtkVolume 对象 volume、颜色函数 colorFunction 和不透明度函数 opacityFunction。写出把这两条函数配置到第 0 个标量分量,并指定参考物理距离为 1 的 API。此步骤是否已经完成整幅体渲染?
参考答案
const property = volume.getProperty();
property.setRGBTransferFunction(0, colorFunction);
property.setScalarOpacity(0, opacityFunction);
property.setScalarOpacityUnitDistance(0, 1);
这是 vtkVolumeProperty 的配置。还需要把 vtkImageData 交给 vtkVolumeMapper,将 Mapper 连接 Volume,把 Volume 加入 Renderer 并渲染。第 6 阶段会完整实现。