读过《思考的乐趣》的朋友一定还记得最后一章中那个令人匪夷所思的四维超立方体(hypercube),生活在三维世界中的我们居然也可以去想象更高维的空间,真是有趣。
建模
可视化的第一步就是建模,类似于三维立方体,用四维坐标(x, y, z, w)表示超立方体的顶点。按照每增加一个维度,顶点数翻倍的规律来看,超立方体的顶点是立方体的两倍,即 16 个顶点。一种典型的超立方体的所有顶点可由下表列出。
Vertex | X | Y | Z | W |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
1 | 1 | 0 | 0 | 0 |
2 | 0 | 1 | 0 | 0 |
3 | 1 | 1 | 0 | 0 |
4 | 0 | 0 | 1 | 0 |
5 | 1 | 0 | 1 | 0 |
6 | 0 | 1 | 1 | 0 |
7 | 1 | 1 | 1 | 0 |
8 | 0 | 0 | 0 | 1 |
9 | 1 | 0 | 0 | 1 |
10 | 0 | 1 | 0 | 1 |
11 | 1 | 1 | 0 | 1 |
12 | 0 | 0 | 1 | 1 |
13 | 1 | 0 | 1 | 1 |
14 | 0 | 1 | 1 | 1 |
15 | 1 | 1 | 1 | 1 |
可以看到前 8 个顶点的 w 坐标值为 0,也就是说用这八个点去取出超立方体的一个超平面(hyperplane),这个超平面就是一个立方体。类似的,它有 32 条边,24 个面。
对边进行考虑,可以发现 12 条边构成一个立方体,将表格前八个顶点构成的立方体的 w 值设为 1(或者说将它沿 w 轴平移),将得到的几何体的每个顶点与变换前的顶点相连,计算边数得 12+12+8 = 32 条边。
利用离散数学的知识,我们可以建立顶点集和边集,用以表示一个超立方体。在绘制时将遍历边集,绘制出所有边,完成可视化的工作。
投影
类似在纸面上绘制立方体,我们将超立方体投影(projection)到三维空间,从而达到可视化的目的。若沿着 w 轴进行平行投影,可直接得出一个立方体,它们的顶点是重叠的(请参考这里)。
在可视化的同时为了便于观察和理解,我们将顶点的 w 值均匀(若可以动态旋转并投影,则是否为 1/3 就不重要了)的投影在其余坐标轴上。比如 P(x, y, z, w) 变换到 P(x-(1/3)w, y-(1/3)w, z-(1/3)w)。
这里的几何体仅仅进行了 xyz 轴的旋转,换句话说,只移动了摄像机。
旋转
利用 OpenGL 的工具函数可以方便的沿着某个轴进行旋转,所以沿着 x、y、z 轴旋转几何体是很方便的,旋转的结果也是易于理解的。若将 w 轴考虑在内的话,就必须要手工进行模型变换了,以 XW 旋转为例,使用变换矩阵:
[cos(t) 0 0 sin(t)
0 1 0 0
0 0 1 0
-sin(t) 0 0 cos(t)]
将模型中的点通过与变换矩阵相乘,所得点即为旋转后的点。之后进行投影和绘制。
生成结果
啊呀~和 Wiki 里的 GIF 图不太像,修改一下投影方法,完成~
不过,就算投影看上去是一个立方体嵌套在另一个里面,实际上却根本不是那回事。(至于旋转 XW 实际上发生了什么,对照下面链接中的平行坐标系大概就能看懂了。)
这里有一个不错的演示工具,可以提供参考:
http://exposedata.com/hypercube/rotate/