10 print 可以说是最早的生成艺术。本讲教程我们将会带你一起基于 p5.js 实现这一经典作品。 本教程假设你已经有了基础的编程经验,了解并熟悉变量定义、函数定义、循环、逻辑判断等基础知识
当提到计算机生成艺术(generative art)的时候,"10 PRINT" 是一个非常经典的程序,它可以生成无限变化的有趣的图案。这个程序最初是在1980年代创建的,被广泛用于早期的计算机和游戏机上。如今,在使用各种现代的编程语言和工具来生成艺术作品的时候,"10 PRINT" 仍然是一个受欢迎的选择。
我们先看看 10 PRINT 有什么样的魅力,能够经久不衰。下面是我们最终实现的效果。
开始第一步
万事开头难,但是对于 p5.js 来说,开头是最简单不过了。我们先从 p5.js 最基础的骨架代码开始,在画板上绘制一个白色的背景,并且绘制一条直线。
我们先来认识一下这几行简单的代码:
function setup() {
createCanvas(300, 300)
}
function draw() {
background(255)
line(0, 0, 100, 100)
}
setup和draw都属于 p5.js 的生命周期函数,其中setup只会执行一次,而draw则相当于渲染循环,会一遍又一遍地运行。createCanvas也是一个 p5.js 的内置函数,即创建一个给定尺寸的画板。background是一个设置背景颜色的内置函数,当我们调用了 background 后,画板之前的内容就会被清空掉。line是一个 p5.js 的内置函数,用来画直线的,line 接收四个参数,第一个第二个参数分别是起点的横坐标和纵坐标,第三个第四个参数分别是终点的横坐标和纵坐标。所以line(0, 0, 100, 100)的意思是画一条直线,起点坐标是 (0, 0) ,终点坐标是 (100, 100)
接下来,我们来看看如何基于这个简单的程序来实现 10 PRINT 的效果了。
10 PRINT 分析
仔细观察上面这幅图,我们可以看出有几个关键的点:
- 整幅图是由直线线条组成
- 直线线条的方向有两个,分别是向左、向右倾斜 45 度
加上红色的辅助线,我们可以更清晰地看到这一规律。
重新审视这个名为 10 PRINT 的绘画作品,你会发现它的表现更加清晰易懂了。实现这样一个有趣的效果只需要两步即可:
首先,将绘画板分割为一个个正方形的网格。 其次,通过在每个小正方形中绘制线条来表现图案,具体有两种方式:
1. 从左上角绘制直线到右下角
2. 从右上角绘制直线到左下角
这个其实是 Grid Tile Pattern 网格法,而 10 PRINT 是网格法里最基础的一个表现形式。
编码实现
1. 对画板空间进行网格分割
根据我们上面的分析,首先需要通过编码实现对画板空间的分割,将其划分为一个一个的小正方形格子。
画第一排的正方形
从上图中我们可以看出,要想画出一排正方形,我们从左边依次往右边画即可。
我们定义一个变量 space, 用它来表示正方形的边长,默认是 20。定义一个 squarePoint 的变量,用它来表示正方形左上角的坐标。要实现从左往右依次画正方形,我们用一个 for 循环就可以实现了,让正方形的左上角的 x 坐标依次递增即可。
其中 square 是 p5.js 内置的函数,可以绘制一个正方形。
画多排的正方形
有了绘制第一排正方形的经验,我们很容易绘制出多排正方形。我们只需要再外面再多加一层循环,将正方形的的左上角坐标从第一排的 y = 0 移动到最后一排 y = height 就可以了。
好了,最艰难的一步已经完成了,通过几行代码,我们实现了对画板进行网格的划分。
2. 在网格里画斜线
接下来,我们需要在已经划分好的网格中绘制向左倾斜和向右倾斜两条直线。那如何来画出这两条斜线呢,我们来看看下面这个示意图。
- 画右斜线
从图中我们可以看出,右斜线的起点是正方形的左上角坐标,终点是正方形的右下角坐标。起点坐标我们已经清楚,我们需要计算出终点坐标。终点的 x 坐标可以用
左上角坐标的 x 坐标 + 正方形边长来表示,终点的 y 坐标可以用左上角坐标的 y 坐标 + 正方形边长来表示。
// 起点坐标
const startPoint = squarePoint
// 终点坐标
const endPoint = {
x: squarePoint.x + space,
y: squarePoint.y + space
}
- 画左斜线
同理,左斜线的起点是正方形的右上角坐标,终点是正方形的左下角坐标,起点和终点的坐标计算代码如下。
// 起点坐标
const startPoint = {
x: squarePoint.x + space,
y: squarePoint.y
}
// 终点坐标
const endPoint = {
x: squarePoint.x,
y: squarePoint.y + space
}
明确了左右斜线的画法,我们就来画几条斜线看看具体的效果吧。
有了网格,有了向左向右两条斜线,我们还缺少重要的一点,那就是确定什么时候画左斜线,什么时候画右斜线。 最简单的,我们可以采用随机的策略。我们使用 p5.js 的 random 函数生成一个随机数,如果这个随机数大于 0.5,那么我们就画左斜线,否则就画右斜线。
const directionVal = random()
if (directionVal > 0.5) {
// 画左斜线
} else {
// 画左斜线
}
解决了这个问题,我们就可以完成整个画作了。
3. 组合在一起,最终代码效果
更进一步
看完了本教程,相信你已经可以自己独立做出一个 10 Print 艺术画作了,你还可以探索一下其他的变化,让你的画作如众不同。下面是一些可能的点:
- 修改线条的宽度,看看会发生什么。你可以使用
strokeWeight方法来实现这一点。 - 对线条进行着色。现在的线条是黑色的,你可以用
stroke方法来修改线条的颜色。 - 改变线条的长度。现在的线条都是统一长度的,你可以试着修改一下,动态改变线条的长度。提示,修改线条的起点和终点位置就可以实现,你可以在原来的位置上加一个随机偏移量。
- 在每个网格里动态添加一些其他的图形,或者多画几个线条试试。
快来动手试试吧。