Escher-Droste 变换:从复指数映射到 WebGL 实时渲染
背景
埃舍尔的《画廊》(Print Gallery, 1956)是 20 世纪最迷人的版画之一——一个年轻人站在画廊里看画,画中的城市蜿蜒伸展,画中画循环嵌套,中心留下一个空白漩涡。2002 年,荷兰数学家 de Smit 和 Lenstra 用复分析填补了那个 46 年悬而未决的空白。
这个工具就是把那篇论文的核心思想——复指数映射和极坐标重参数化——搬进浏览器,变成拖拽即用的实时交互。
数学核心
复指数映射
Droste 效应的本质是把线性周期折叠成环形周期。核心变换只有一行:
1 | w = exp(α · log(z)) |
其中 α = a + bi 是复参数:
- 实部 a 控制缩放——每一圈放大多少倍
- 虚部 b 控制旋转——每一圈扭转多少度
物理意义:取对数 → 线性缩放+旋转 → 取指数回去。对数空间里的直线对应原空间里的螺旋。
三种映射模式
复指数平铺(Log Tile)
适合无缝纹理和重复图案。把图片当作对数平面中的纹理单元,通过复指数映射回普通平面。公式最简洁:
1 | float denom = u_alpha_r * u_alpha_r + u_alpha_i * u_alpha_i; |
每一层都是上一层的缩放+旋转复制,层与层之间自然衔接,得到经典的螺旋嵌套效果。
圆形周期(Circular Period)
适合单向递归的图像——画廊、走廊、门框、镜中镜。把原本向一个方向深入的空间折叠成闭合圆环:
1 | 径向距离 → 递归深度(对数映射) |
圆心是最内层(原图远处),外圈是最外层(原图近处),一圈一圈向外展开。
论文幂映射(Power Map)
遵循 de Smit & Lenstra 原始论文的思路:
1 | F(z) = F₀(z^(1/β)) |
通过幂映射把原图空间弯曲,更接近数学本质,但对非数学化的输入图像不稳定。
技术实现
WebGL 片段着色器
整个变换运算都在 GPU 上完成。834 行单 HTML 文件,核心 shader 仅 89 行 GLSL。
架构:
1 | JavaScript 控制面板 |
关键设计决策:
逐像素逆映射:对输出图像的每个像素,反算它在源图中的纹理坐标。这样做的好处是不需要预计算任何网格或点云,任意分辨率直接渲染。
延迟渲染(debounce):拖动滑块时不是每帧都重绘,而是用
requestAnimationFrame合并连续事件,避免卡顿。preserveDrawingBuffer: true:WebGL 默认渲染后丢弃缓冲区内容。开启这个标志后toDataURL能直接导出当前画面,无需额外的离屏渲染。导出模式高分辨率:导出 PNG 时临时把 canvas 调到 2048px 长边,渲染完再恢复预览尺寸。用
gl.finish()确保 GPU 完成绘制再读像素。
边缘模式
| 模式 | 行为 |
|---|---|
| 循环平铺(Repeat) | fract(tc) —— 无穷复制 |
| 钳制(Clamp) | 超出 [0,1] 的纹理坐标透明化 |
| 镜像(Mirror) | abs(fract(tc * 0.5 + 0.5) * 2.0 - 1.0) —— 折叠式反射 |
非 2 的幂纹理处理
WebGL 1.0 对非 2 的幂纹理有限制:不能使用 mipmap。工具检测到非 POT 图片时自动使用 LINEAR 过滤 + CLAMP_TO_EDGE 包裹模式,禁用 mipmapping,保证任意尺寸图片都能正常渲染。
参数指南
| 参数 | 推荐范围 | 效果 |
|---|---|---|
| 旋转角度/层 | 0° ~ 8°(画廊图) | 控制螺旋扭转程度 |
| 缩放倍率/层 | 1.8 ~ 2.2 | 每层的缩放因子,决定螺旋密度 |
| 整体缩放 | -2 ~ 2 | 对数域的全局缩放 |
| 中心 X/Y | 30% ~ 70% | 螺旋中心在画面中的位置 |
一个对画廊图效果极好的起点配置:
1 | 映射方式:圆形周期 |
设计选择:为什么是单文件 HTML
没有构建工具、没有 npm 依赖、没有打包步骤,834 行一个文件搞定。理由很明确:
- 零启动成本:双击打开即用,
python -m http.server即可本地开发 - 部署极简:丢到 GitHub Pages 就行,不需要 CI/构建/压缩
- 可审计:所有代码在一个文件里,右键查看源码一次看完,没有压缩混淆
参考
- de Smit, B. & Lenstra, H.W. (2003). The Mathematical Structure of Escher’s Print Gallery. Notices of the AMS, 50(4), 446–451.
- Escher-Droste 变换详细推导 (Université de Montréal)
在线体验
拖入一张图片,选择映射方式,滑动参数,点击导出。所有渲染在本地 GPU 上完成,无服务器参与。