制作栅格错觉动画是一个非常有趣且富有创造性的过程,它结合了视错觉原理、动画设计和编程(通常是使用p5.js或Processing这类工具)。

下面我将为你详细拆解如何一步步绘制一个经典的栅格错觉动画,并提供从基础到进阶的思路和代码示例。
核心原理:栅格错觉是如何产生的?
栅格错觉(如“赫尔曼网格错觉”)的原理是:当你的视觉系统在处理视网膜上高对比度的黑白边缘时,会进行“过度补偿”,从而在交叉点附近产生灰色的幻影。
- 关键元素:黑色背景、白色线条、线条交叉点。
- 错觉现象:在交叉点处,你会看到一个灰色的点,但当你把目光直接聚焦到这个点上时,灰点又会消失。
动画化的关键:就是让这些“关键元素”动起来,最简单、最有效的方式就是让整个栅格或背景动起来,这种微小的、持续的运动会让你的视觉系统持续进行“过度补偿”,从而让灰点幻觉变得非常明显和稳定。
制作步骤:以p5.js为例
我们将使用 p5.js 这个强大的创意编程库来制作,你不需要安装任何东西,只需访问 editor.p5js.org 就能开始编写和运行代码。

第一步:创建一个静态的栅格
我们画出产生错觉的基础——一个黑白相间的栅格。
function setup() {
createCanvas(400, 400);
noLoop(); // 先不画动画,先画静态的
}
function draw() {
background(0); // 黑色背景
stroke(255); // 白色线条
strokeWeight(10); // 线条粗细,这个很重要,太细效果不明显
// 画垂直线
for (let x = 0; x <= width; x += 30) {
line(x, 0, x, height);
}
// 画水平线
for (let y = 0; y <= height; y += 30) {
line(0, y, width, y);
}
}
运行这段代码,你会看到一个静态的黑白栅格,仔细看,你应该能在交叉点处看到灰色的幻觉点。
第二步:让栅格动起来(基础动画)
我们让这个栅格动起来,最简单的动画是上下或左右移动,我们将使用 frameCount 变量,它由p5.js自动更新,代表动画播放的帧数。
function setup() {
createCanvas(400, 400);
}
function draw() {
background(0);
stroke(255);
strokeWeight(10);
// --- 核心改动在这里 ---
// 创建一个偏移量,让它随着时间正弦波动
// sin() 函数的值在 -1 到 1 之间,我们把它映射到 -5 到 5 的像素
let offsetX = map(sin(frameCount * 0.05), -1, 1, -5, 5);
let offsetY = map(cos(frameCount * 0.05), -1, 1, -5, 5); // 也可以只用一个方向
// 画垂直线,加上偏移量
for (let x = 0; x <= width; x += 30) {
line(x + offsetX, 0, x + offsetX, height);
}
// 画水平线,加上偏移量
for (let y = 0; y <= height; y += 30) {
line(0, y + offsetY, width, y + offsetY);
}
}
代码解释:
frameCount * 0.05:frameCount是时间,乘以一个较小的数(0.05)可以减慢动画速度,让移动更平滑。sin(...):正弦函数可以创造出平滑的来回运动。map(value, fromLow, fromHigh, toLow, toHigh):这是一个非常有用的函数,它可以把一个数值范围映射到另一个范围,这里我们把sin函数的输出范围[-1, 1]映射到我们想要的像素移动范围[-5, 5]。line(x + offsetX, ...):在绘制每条线的时候,都加上这个动态计算的偏移量。
现在运行代码,你会看到栅格在轻微地、平滑地移动,观察交叉点,你会发现灰色的幻觉点变得异常清晰和稳定!
进阶技巧与创意方向
掌握了基础后,你可以尝试更多有趣的变体:
改变运动方式
不一定非要平移,还可以旋转或缩放。
旋转动画:
function draw() {
background(0);
stroke(255);
strokeWeight(10);
push(); // 保存当前画布状态
translate(width / 2, height / 2); // 将原点移动到画布中心
rotate(frameCount * 0.01); // 围绕中心点旋转
translate(-width / 2, -height / 2); // 将原点移回,以便栅格在正确位置绘制
// 画栅格...
for (let x = 0; x <= width; x += 30) {
line(x, 0, x, height);
}
for (let y = 0; y <= height; y += 30) {
line(0, y, width, y);
}
pop(); // 恢复画布状态
}
改变线条样式
- 虚线:使用
drawingContext.setLineDash([5, 10]);可以画出虚线,虚线栅格的错觉效果会更柔和。 - 颜色渐变:让线条的颜色随位置或时间变化,会产生更丰富的视觉效果。
- 线条粗细变化:让线条的粗细也动起来,
strokeWeight(5 + sin(frameCount * 0.05 + x) * 3);。
交互式栅格错觉
让用户与动画互动,体验会更有趣。
跟随鼠标移动:
function draw() {
background(0);
stroke(255);
strokeWeight(10);
// 使用鼠标的X坐标作为偏移量
let offsetX = map(mouseX, 0, width, -20, 20);
for (let x = 0; x <= width; x += 30) {
line(x + offsetX, 0, x + offsetX, height);
}
for (let y = 0; y <= height; y += 30) {
line(0, y, width, y);
}
}
栅格会跟随你的鼠标水平移动,你可以亲自感受运动对错觉效果的影响。
创造新的错觉图案
栅格不一定是方格,也可以是其他图案。
同心圆环错觉: 这种错觉的原理类似,当圆环快速旋转时,环与环的连接处会产生模糊或发光的错觉。
function draw() {
background(0);
stroke(255);
strokeWeight(8);
noFill();
let numRings = 15;
let spacing = 20;
push();
translate(width / 2, height / 2);
rotate(frameCount * 0.02); // 旋转整个图案
for (let i = 1; i <= numRings; i++) {
let radius = i * spacing;
ellipse(0, 0, radius * 2);
}
pop();
}
制作栅格错觉动画的核心思路可以概括为:
- 构建静态错觉:首先用高对比度的黑白元素(线条、形状)构建一个能产生视错觉的静态图案。
- 引入动态元素:让图案的位置、方向、大小或颜色随时间平滑变化。微妙的、持续的运动是效果最显著的方式。
- 选择工具:p5.js、Processing、甚至是带动画功能的SVG或CSS都是很好的选择,对于初学者,p5.js 是最友好的。
- 实验与创造:不要局限于经典图案,尝试结合其他原理(如颜色、透视)和交互方式,创造出属于你自己的独特错觉动画。
希望这个详细的指南能帮助你开启创作之旅!动手试试吧,你会发现其中的乐趣无穷。
