三维双曲空间中的万花筒结构

在我之前的文章中,已经讨论过了三维和四维球面上的万花筒三维欧式空间中的万花筒,本文来介绍三维双曲空间中的万花筒,也即蜂巢结构。这也是理论最复杂、结构最具多样性、视觉美感最奇妙的一类结构。下面开始我们奇妙的旅程吧!

本文图片使用了 Fragmentarium 软件渲染,代码在 github 上

  • 下图展示的是 Poincaré 单位球空间中的正双曲蜂巢 (5, 3, 5)

    这里 (5, 3, 5) 是一个记号,叫做 Schläfli 记号,就像生物学家给不同的蛋白质编号一样,这个记号是用来给不同的蜂巢结构编号的。

    从图中可以看到,整个蜂巢结构由许许多多小的胞腔组成,每个胞腔是一个正十二面体,这对应符号中的后两个 (3, 5),每个顶点与五个胞腔相邻,这对应符号中的第一个 5。

    注意双曲空间是一个在双曲度量下无穷大的空间,其中的物体与原点之间的双曲距离和欧式距离是指数增长的关系,所以虽然看起来远处的胞腔“急剧变小”,那只是我们在欧式空间中观察导致的错觉,实际上双曲度量下所有胞腔都是全等的。

    通过对正双曲蜂巢进行“截断”操作,我们可以得到更多与原蜂巢具有相同对称性,但是包含更多其它类型胞腔的蜂巢结构。下图是展示了一种对 (5, 3, 5) 蜂巢的截断操作:

  • 如果我们向着无穷远边界,即单位球面靠近,并且观察蜂巢在边界附近的样子的话,会发现它看起来更像是某种异星球上的雨林结构:

    上图展示的是另一种蜂巢结构 [(5, 3, 4, 3)] 在边界处的样子。注意与正 (5, 3, 5) 不同的是,这个蜂巢不是正的,它有三种不同的胞腔。

    对 [(5, 3, 4, 3)] 截断操作后得到的一种蜂巢如下:

    上面这几种蜂巢看起来模样差别挺大,但它们的每个胞腔在双曲空间中都是有限的多面体。这样类型的蜂巢叫做紧的 (compact)。紧的双曲蜂巢总共只有 9 类

  • 如果我们去掉紧致这个条件,即允许每个胞腔有位于无穷远处的顶点 (理想点),但是还保持胞腔的体积有限,则这样的蜂巢叫做仿紧的 (paracompact):

    上图来自 (3, 6, 3) 类,它的每个胞腔是一个类型为 (6, 3) 的多面体,(6, 3) 记号对应的是平面上正六边形密铺,所以这样的多面体可以看作是把正六边形密铺将其在无穷远处捏在一起得到的,有点类似于把一张无穷大的网拢在一起,所以每个胞腔有无穷多个顶点和无穷多个面,其中一个顶点是理想顶点。

    仿紧的蜂巢总共有 23 类

    另一种仿紧的蜂巢结构 (6, 3, 4):

    下图显示的是另一个仿紧蜂巢 (4, 4, 4) 在边界处的样子:

  • 如果更进一步,我们再去掉每个胞腔体积有限的条件,则这样的蜂巢叫做非紧的 (non-compact),这样的蜂巢有无穷多类。它们有一个共同的特点:蜂巢的某些顶点位于无穷远边界之外,叫做超理想顶点。下图显示的是 (4, 4, 5) 对应的蜂巢在边界处的样子:

    可以看到边界球面上出现了许多大小不一的“洞”,这样的每个洞其实都对应蜂巢的一个超理想顶点,你可以把边界球面想象成双曲空间的“时空之门”,超理想顶点都位于门的另外一侧的空间中。

  • 对于非紧的蜂巢,我们还可以从空间的外侧“管中窥豹”式地观察它,如下图所示:

    可以看到边界球面上出现了许许多多大小不一,排列规律的洞,它们对应的正是胞腔的超理想顶点。球面上除去洞之外剩下的部分叫做极限集。什么是极限集呢?打个比方,它们好比是内部的蜂巢在无穷远边界上的“落脚点”。一个准确的定义是:设 \(x_0\in\mathbb{H}_3\) 是三维双曲空间中一点,\(W\) 是蜂巢的对称群,于是 \(W\) 是一个 rank 等于 4 的 Coxeter 群。记 \(W(x_0)=\{w(x_0)\,|\, w\in W\}\)\(x_0\)\(W\) 作用下的轨道,则集合 \(W(x_0)\) 的聚点都位于无穷远边界球面 \(S^3\) 上。我们把 \(W(x_0)\) 的所有聚点组成的集合叫做 \(W\)极限点,把极限点的闭包叫做 \(W\)极限集,记作 \(\Lambda(W)\)。可以证明 \(\Lambda(W)\) 的定义不依赖于 \(x_0\) 的选取,并且 \(\Lambda(W)\) 是理想球面上在 \(W\) 作用下不变的最小非空闭集,而且 \(\Lambda(W)\) 不含内点!

    有趣的是,极限集在拓扑上是同胚于二维的 Cantor 集 Sierpiński 地毯的,见 John Baez 的这篇文章

  • 我们还可以在上半空间模型中去观察一个蜂巢,下图显示的是 (3, 7, 3) 这个蜂巢在上半空间模型中的样子:

    可以看到图中地面上出现了大大小小的二维 Poincaré 圆盘,它们每一个对应的都是 (7, 3) 密铺。这些圆盘每个都对应一个超理想顶点。

  • 下图则是 (4, 4, 5) 这个蜂巢在上半双曲空间内的样子,可以看到整个结构具有平面正方形密铺 (4, 4) 的对称性。

    而 (3, 6, 5) 自然会呈现平面六边形密铺 (3, 6) 的对称性:

    上面两种蜂巢都是非紧的,所以地面上会出现双曲圆盘的空洞。作为比较 (4, 4, 4) 作为仿紧的蜂巢,在上半空间模型中也有平面上的正方形密铺 (4, 4) 对称性,但是不会有空洞:

  • 我们也可以把双曲圆盘的空洞藏起来,这时整个结构像是一个多孔的海绵:

  • 最后是更多异星球雨林风格的蜂巢:

    (4, 4, 4) 蜂巢在上半空间模型中的样子:

    另一种非紧蜂巢在单位球边界处的样子:

总而言之,双曲蜂巢分为紧、仿紧、非紧三大类,我们可以从单位球中心、单位球边界、单位球外部去观察它们,也可以转移到上半空间模型中去看,还可以将其做球极投影来观察边界上的图案,可谓变化繁复,难以尽述其中奥秘。

万花筒图案来自 Tits 锥的截面

这些图片虽然展示的都是三维场景,但是绝大部分计算都是在四维空间中进行的,这是因为在四维空间中蜂巢的对称性可以统一用反射变换来描述。“在四维空间中计算三维的场景”听起来比较玄妙,我来解释下:

注意到双曲蜂巢的对称群 \(W\) 是 rank 为 4 的 Coxeter 群,它可以看作是 \(\mathbb{R}^4\) 中的反射群,即在 \(\mathbb{R}^4\) 中摆放一些过原点的反射平面,平面之间的夹角是精心选择的,从而 \(W\) 可以由关于这些平面的反射生成。这些平面的正半空间之交是一个闭的凸锥形区域 \(C\)\(C\) 叫做基本区域,\(C\) 以及它在 \(W\) 作用下的所有镜像之并仍然是一个闭的凸锥 \(\mathcal{C}\)\(\mathcal{C}\) 叫做 Tits 锥。根据 \(W\) 不同,以及各个反射镜面摆放方式的不同,\(\mathcal{C}\) 的形状也不同。但是在标准几何实现中,\(\mathcal{C}\) 的形状是容易确定的:

  1. 在球面蜂巢的情形,\(\mathcal{C}\) 是全空间 \(\mathbb{R}^4\),这时 \(W\) 是有限 Coxeter 群。

  2. 在欧式蜂巢的情形,\(\mathcal{C}\) 是半空间 \[\{ w > 0 \,|\, (x,y,z,w)\in\mathbb{R}^4\}.\] 这时 \(W\) 是仿射 Coxeter 群,是无限群。

  3. 在双曲蜂巢的情形,\(\mathcal{C}\) 是 Minkowski 度量下的光锥 \[\{x^2+y^2+z^2-w^2 < 0 \,|\, (x,y,z,w)\in\mathbb{R}^4\}.\] 这时 \(W\) 是双曲 Coxeter 群,也是无限的。

    Error:噢,我在这里犯了错误,只有紧致蜂巢的 Tits 锥才会包含在光锥内部,仿紧蜂巢的 Tits 锥和光锥有切点,而非紧蜂巢的 Tits 锥会和光锥有交点。

这三种情形对应的三维蜂巢图案可以通过用一个三维的超曲面 \(S\)\(\mathcal{C}\) 得到,当然我们没法真的在四维空间中画曲面,所以下面的插图都用三维的情形来代替,但是原理是一样的:

  1. 球面蜂巢的情形 \(S\) 是单位球面 \(x^2+y^2+z^2=1\)

    图中红色的部分 (其实是一个无穷长的三棱锥) 为基本区域 \(C\),它在 \(W\) 的作用下其 Tits 锥 \(\mathcal{C}=\cup_{w\in W} wC\) 会填满整个 \(\mathbb{R}^3\),用球面去截得到的是二维球面密铺。

  2. 欧式蜂巢的情形 \(S\) 是平面 \(z=1\)

    同样红色的部分 (也是一个无穷长的三棱锥) 为基本区域 \(C\),它在 \(W\) 的作用下其 Tits 锥 \(\mathcal{C}=\cup_{w\in W} wC\) 会填满整个上半空间 \(z>0\),用平面 \(z=1\) 去截得到的是二维欧式密铺。

  3. 双曲蜂巢的情形 \(S\) 是双曲面 \(x^2+y^2-z^2=-1\)

    同样红色的部分 (无穷长的三棱锥) 为基本区域 \(C\),它在 \(W\) 的作用下其 Tits 锥 \(\mathcal{C}=\cup_{w\in W} wC\) 会填满光锥 \(x^2+y^2-z^2<0\),用双曲面 \(x^2+y^2-z^2=-1\) 去截得到的是二维双曲密铺。

总之通过绘制 Tits 锥在 \(S\) 上的横截面我们就得了相应的蜂巢图案,这一方法对其它维数的密铺都是成立的。于是球面、欧式、双曲三种类型的蜂巢可以用统一的方式来处理,它分为两步:

  1. 对给定的 Coxeter diagram,首先确定其对应的几何类型 (球面/欧式/双曲),然后确定反射镜面以及对应的反射变换。

  2. 在用 raymarching 方法渲染场景时,对三维空间中一点 \(p\),我们首先将 \(p\) 提升为超曲面 \(S\) 上的点 \(q\),并将 \(q\) 关于各个镜面反复进行反射变换,直到 \(q\) 落入基本区域内 (这些反射操作都封装在一个函数 fold 里面),然后在四维空间中估计 \(q\) 到基本区域的各元素 (顶点/边/面) 的距离,由此来判断 \(p\) 是顶点、边、面或者都不是,再进行对应的渲染。

所以问题的关键就在于应该怎样摆放反射平面的位置,并写出对应的反射变换的表达式。这就要用到 Coxeter 群的标准几何实现。


\((W, S)\) 是一个 Coxeter 群,生成元集合 \(S\) 满足对任何 \(s,t\in S\)\(s^2=t^2=(st)^{m_{s,t}}=1\),其中 \(m_{s,t}\in\{1,2,\ldots,\infty\}\) 是正整数或者 \(\infty\)。记 \(|S|=n\)\(V = \mathbb{R}^n\),取对偶空间 \(V^\ast\) 的一组基 \(\Delta=\{\alpha_s \,|\, s\in S\}\),则我们总可以找到 \(V\) 中的一组向量 \(\Delta^\vee=\{\alpha_s^\vee \,|\, s\in S\}\) 使得对任何 \(s,t\in S\)\[c_{s,t} = (\alpha_s, \alpha_t^\vee) = -2\cos\frac{\pi}{m_{s,t}}.\]

注意 \(\Delta\) 是对偶空间 \(V^\ast\) 的一组基,而 \(\Delta^\vee\) 未必构成 \(V\) 的一组基 (比如在仿射 Coxeter 群的情形)。

矩阵 \(C=(c_{s,t})\) 叫做 Cartan 矩阵,这是一个对称矩阵,它的惯性指数决定了对应蜂巢的类型:

  1. 球面蜂巢对应 \(C\) 正定,即 \(C\) 的惯性指数为 \((n,0)\)
  2. 欧式蜂巢对应 \(C\) 半正定且秩为 \(n-1\),即 \(C\) 的惯性指数为 \((n-1,0)\)
  3. 双曲蜂巢对应 \(C\) 的惯性指数为 \((n-1,1)\)

对任何 \(s\in S\),定义 \(V\) 上的线性变换 \(\sigma_s\)\[\sigma_s(v) = v - (\alpha_s, v)\alpha_s^\vee,\quad v\in V.\]

容易验证 \(\sigma_s^2=1\),且 \(\sigma_s\) 保持超平面 \(H_s=\{v\in V \,|\, \alpha_s(v)=0\}\) 不变,并且由于 \((\alpha_s,\alpha_s^\vee) = 2\) 所以 \(\sigma_s\)\(\alpha_s^\vee\) 变为 \(-\alpha_s^\vee\),从而 \(\sigma_s\) 是一个关于超平面 \(H_s\) 的反射。不难验证 \((\sigma_s\sigma_t)^{m_{s,t}}=1\),所以 \(s\to\sigma_s\) 给出了 \(G\to\mathrm{GL}_n(V)\) 的一个表示,这个表示叫做 \(G\) 的标准几何实现。

总之只要确定了 \(\{\alpha_s\}\)\(\{\alpha_s^\vee\}\),就可以得出所有反射 \(\{\sigma_s\}\) 的表达式。

我们举一个双曲蜂巢 \((5, 3, 5)\) 的例子,其 Coxeter diagram 为

对应的 Cartan 矩阵为 \[(c_{ij}) = \begin{pmatrix} 1 & -\cos\frac{\pi}{5} & 0 & 0\\ -\cos\frac{\pi}{5} & 1 & -\cos\frac{\pi}{3} & 0\\ 0 & -\cos\frac{\pi}{3} & 1 & -\cos\frac{\pi}{5}\\ 0 & 0 & -\cos\frac{\pi}{5} & 1\\ \end{pmatrix}.\]

这时 Cantan 矩阵的惯性指数为 \((3, 1)\),从而合同于对角矩阵 \(\mathrm{diag}(1,1,1,-1)\),即存在可逆矩阵 \(A\) 使得 \[C = A^T\begin{pmatrix}1&&&\\&1&&\\&&1&\\&&&-1\end{pmatrix}A.\]

\(A\) 的列向量为 \(\{\alpha_1^\vee,\alpha_2^\vee,\alpha_3^\vee,\alpha_4^\vee\}\),则 \[\langle \alpha_i^\vee,\alpha_j^\vee\rangle_L = c_{ij}.\]

其中 \(\langle\cdot\rangle_L\) 是 Lorentz 内积 \[\langle x,y\rangle_L = x_1y_1 + x_2y_2 + x_3y_3-x_4y_4.\]

所以我们可以直接取泛函 \(\alpha_i\)\[\alpha_i(v) = \langle \alpha_i^\vee,v\rangle_L.\]

特别注意 \(\langle \alpha_i^\vee,\alpha_i^\vee\rangle_L = 1\),即每个 \(\alpha_i^\vee\) 都是 space-like 的。

不难写出如下的一组 \(\{\alpha_i^\vee\}\)\[\begin{align*} \alpha_1^\vee &= (1, 0, 0, 0),\\ \alpha_2^\vee &= (-\cos\frac{\pi}{5}, \sin\frac{\pi}{5}, 0, 0),\\ \alpha_3^\vee &= (0, -\frac{1}{2\sin\frac{\pi}{5}}, \sqrt{1-\frac{1}{4\sin^2\frac{\pi}{5}}}, 0),\\ \alpha_4^\vee &= (0, 0, -\frac{\cos\frac{\pi}{5}}{\sqrt{1-\frac{1}{4\sin^2\frac{\pi}{5}}}}, a). \end{align*}\]

其中 \(a\) 满足 \(\langle \alpha_4^\vee,\alpha_4^\vee\rangle_L = 1\)\(a\) 有两种选择,这取决于你选择的 hyperboloid 的分支。如果你选择上半分支 \(w>0\) 的话,为了保证所有半空间 \(\{\alpha_i>0\}\) 之交属于上半分支需要取 \(a<0\)。这是因为对 \(p=(x,y,z,w),w>0\)\(\langle \alpha_1^\vee,p\rangle_L > 0\) 说明 \(x>0\),进而 \(\langle \alpha_2^\vee,p\rangle_L > 0\) 说明 \(y>0\),继续 \(\langle \alpha_3^\vee,p\rangle_L > 0\) 说明 \(z>0\),而 \(\langle \alpha_4^\vee,p\rangle_L > 0, w>0\) 必须有 \(a<0\) 才能成立。

总之在 Cartan 矩阵对应的双线性型非退化的情形,可以用对应的内积来定义反射,这一点对球面的情形也是一样的。

图片的绘制原理

这些代码都是用 shader 程序渲染的,使用的是 raymarching 技术。raymarching 技术在绘制万花筒图案时非常有优势,因为可以将空间中的每个点变换到基本区域内,然后转化为对基本区域的绘制。这里麻烦的地方在于,raymarching 技术要求每次在视线行进的过程中,给出当前位置到场景的最小距离,然后沿着当前视线的方向按照此最小距离行进一步。这个距离必须是欧式距离,但是我们场景中物体的大小、位置都要按照双曲距离来,所以在计算过程中需要转到四维空间中的 hyperboloid 模型上计算,得出正确的双曲距离以后,再转换为一个“安全保守的”欧式距离供 raymarching 使用。这个难点最早由 knightyfractalforums 上解决。这个转换的步骤也是整个程序中最烧脑的部分。

 | 

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器