朝闻道

Shadertoy 作品:Escher 风格的非周期铺砖动画

赵亮 / 2020-12-06


周末刚完成了一个有点 "烧脑" 的 Shadertoy 项目,Escher 风格的非周期铺砖,请欣赏:

小屏的时候有锯齿现象,全屏效果更好,你可以点击窗口左上角的 "Impossible aperiodic tiling" 标题前往 Shadertoy 网站查看源代码。

你能看出这个动画的奥妙之处在哪里吗?

直观上看,这个动画由一些 "错落有致",但又无缝拼接在一起的房间组成,每个房间有三个面可见,这三个面上各自绘制了一些 "窗户",房间的颜色、窗户的开闭、朝向都是不断变化的,但是仔细一看,诶,好像一些房间的窗口的朝向是 "矛盾" 的哎?这种整体布局和谐但是局部细节与真实世界矛盾的艺术风格由埃舍尔 (1898-1972) 所创立,所以这个作品也可以叫做 Escher 风格的不可能铺砖。

实际上在这个动画里面基本的几何元素只有菱形,这些菱形分为两种:胖菱形和瘦菱形。在代码中我是对每一个像素,首先确定其所属的菱形,然后计算它到各个装饰元素 (菱形边界、窗户、窗台) 的 signed distance field 函数 d,根据 d 的值来混合颜色,特别还根据菱形的类型和方向加上了阴影的效果,使得整个画面看起来有立体感。

生成动画中菱形排列的算法非常奇妙,它来自 de Bruijn 1981 年的发现,是所谓构造非周期铺砖的网格法 1 (aperiodic tiling),而添加窗户的点缀则是受到了 Greg Egan 的 Javascript 动画启发。我很久之前就知道 de Bruijn 的方法,并且也写过一些代码绘制这样的图案 (比如这个博客的背景图片),但是看到 Greg Egan 的动画以后还是萌发了在 shader 里面做出一个更漂亮的 3D 效果来的想法。这个念头憋了好久,终于前几天利用晚上业余时间动手折腾了一番,捣鼓出了上面的效果。不过我的动画与 Greg Egan 不同的地方在于 Greg Egan 是精心选择了每一个菱形的窗户的开口方向,使得所有的房间的窗户看起来都是矛盾的;而我这里为了让窗户也能动起来只是随机选择了其开口的方向,所以只有部分房间的窗户是矛盾的。


所以话说了半天,什么是非周期铺砖?

非周期铺砖是指满足如下条件的一组瓷砖:

  1. 它们可以不重叠、无空隙地铺满整个平面。
  2. 但是不管怎样用它们铺满平面,得到的图案都没有平移对称性:你把图案向任何方向平移任意长度的距离都不可能与原图案重合。

最著名的非周期铺砖的例子是彭罗斯铺砖,它有两种不同的版本:一种使用的是 "飞镖" 和 "风筝",另一种使用的是 "胖菱形" 和 "瘦菱形"。这些图案都是带有定向约束的:两块瓷砖只有当它们对应的边定向一致时才允许并排拼在一起。

彭罗斯铺砖有许多奇妙的性质,比如:

  1. 有无穷多种 (准确的说是不可数多种) 互不相同的彭罗斯铺砖,它们彼此之间不能通过平移和旋转重叠在一起。
  2. 但是对任何一种彭罗斯铺砖,其任何有限的区域都在其它所有彭罗斯铺砖中出现无穷多次。换句话说,你不可能通过观察一个有限的范围来判断是哪一种或者不是哪一种铺砖,不管你观察的范围有多大

de Bruijn 在他的论文中用两种新的方法对彭罗斯铺砖的构造进行了推广 (multigrids 法和 cut-projection 法),这两种方法是等价的,它们不但可以构造出更一般的非周期菱形铺砖,而且可以推广到更高的维数。在本文开头的动画中,演示的是一个 "星状" 非周期铺砖,它的某些顶点由 10 个瘦菱形围成一个星状区域,这在彭罗斯铺砖中是不可能出现的,所以它不同于任何彭罗斯铺砖。我曾经使用 POV-Ray 渲染过一个场景,展示了这一图案 (见地面) 和 "飞镖/风筝" 图案:

de Bruijn 的方法相对于经典的 inflation-deflation 方法有许多优点,值得一提的是当维数 \(n=4\) 时 de Bruijn 方法给出的正是 Ammann-Beenker 铺砖:

你可以在我的这个脚本中试试不同的 DIMENSION 来获得不同的非周期图案。


  1. N.G. de Bruijn. Algebraic theory of Penrose's non-periodic tilings of the plane.