p5.js 创意编程,点和线的乐章

最后更新于 2023-04-29

《点和线的乐章》是 beauty of pixel 原创的艺术作品。本教程将会涉及到坐标系和坐标点的介绍,弧度,三角函数,p5.js 颜色的介绍和使用,p5.js 画板的旋转等内容。

具体效果参见视频 b站视频

## 作品分析

仔细观察上面的作品实例图,我们可以发现有如下特点

  1. 是由直线和点组成
  2. 点的位置在直线的端点上
  3. 直线的长度是在有规律地变化
  4. 直线在不停地旋转,最终形成叠加的运动效果

## 实现原理

  1. 以画板中心为圆心
  2. 让画板以一定的角速度旋转
  3. 让一个点 A 围绕该圆心做圆周运动,即围绕着圆心运动
  4. 在该点 A 运动的同时,以该点为圆心,画出另一个围绕该点做圆周运动的点 B
  5. 连接点 B 前一次的位置和点 B 本次的位置形成一条线段

下面我们一起来实现吧

## 开始第一步

我们先在画板的中心画一个小圆形,当作圆心

这几行代码主要是 p5.js 内置的函数和变量的使用,其中一些我们在10 PRINT 生成艺术,基于 p5.js 的实现教程里已经见到过

  1. setupdraw 都属于 p5.js 的生命周期函数,其中 setup 只会执行一次,而 draw 则相当于渲染循环,会一遍又一遍地运行。
  2. createCanvas 是一个 p5.js 的内置函数,用来创建一个特定尺寸的画板。
  3. background 是一个设置背景颜色的内置函数,当我们调用了 background 后,画板之前的内容就会被清空掉。
  4. windowWidthwindowHeight 是我们这次新使用的 p5.js 属性,代表了画板所在页面的宽度和高度。
  5. colorMode 是一个设置颜色模式的内置函数,我们将本画板的颜色模式设置为 HSB,每个颜色分量的值设置为 100。默认情况下,p5.js 的颜色模式是 RGB 模式,每个颜色的分量值是 255。具体可以参见此篇关于颜色的介绍

还有一行代码是我们需要重点认识的,那就是 translate(width / 2, height / 2)

### translate 平移坐标系

我们基于 translate(width / 2, height / 2) 实现了平移坐标系,将坐标系的原点平移到了画板的中心,那什么是坐标系、原点和中心点呢?我们来具体了解一下。

#### 笛卡尔坐标系

当我们在进行创意编程时,经常需要处理坐标。例如,我们可能会以某个点为起点画线段,或者在画布的中心画一个圆形。这个点就是表示物体所在的位置,也就是它的坐标。坐标系是表示物体位置的一种方式,其中我们最常使用的是笛卡尔坐标系和极坐标系。这一节我们重点介绍笛卡尔坐标系。

笛卡尔坐标系是一种二维坐标系,由两条直线组成,水平的线称为横轴,也叫 X 轴,垂直的线称为纵轴,也叫 Y 轴,它们交汇的点是原点,其坐标标记为 (0, 0)。

X 轴向左右两个方向水平延伸,而 Y 轴向上下两个方向垂直延伸。

在笛卡尔坐标系中,每个点都有一对坐标 (x, y) 来确定其位置,其中 x 表示点在横轴上的位置,y 表示点在纵轴上的位置。

如下图所示,我们在坐标系上的 (5, 5) 的位置,画了一个圆形。

#### p5.js 坐标系

需要注意的是,在 p5.js 中,我们使用的坐标系是笛卡尔坐标系的一种变体,坐标系的原点在左上角, x 轴从原点向右延展,y 轴 从原点向下延展。

备注:p5.js 底层是基于浏览器的 canvas 元素来进行绘图的操作,这个翻转的坐标系其实是 canvas 使用的坐标系。关于更多 canvas 的介绍,可以参阅 mdn 的相关文章。

了解完了坐标系和坐标相关的信息,我们再看看这个平移的代码

1
2
// 将坐标系原点平移到画板的中心
translate(width / 2, height / 2)

translate(x, y) 是 p5.js 提供的平移画板的函数,它的作用是将画板的原点移动特定的水平偏移量和垂直偏移量。

注意,x, y 是移动的偏移量,而不是移动到点 (x, y) 的位置

widthheight 是 p5.js 提供的内置变量。width 表示画板的宽度,height 表示画板的高度,那么 width / 2height / 2 就是宽度的一半和高度的一半,正好表示了画板的中心位置。

下图是画板移动到中心点后的示意图。

我们通过代码来认识一下平移的过程。

上述示例代码中,我们先在点 (20, 20) 的位置绘制了一个 20 像素的圆,然后将画板平移到中心位置,再在距离中心 (20, 20) 点的位置绘制了一个 20 像素的圆。再次,我们将画板的原点向下和向右平移了 20 像素,然后再在距离新原点 (20, 20) 的位置又绘制了一个 20 像素的圆。

## 画出点 A,让它围绕圆心做圆周运动

如何让一个点,绕着另一个点做圆周运动,这是一个数学问题。我们看看如下的示例图。

我们要让点 A 绕着半径为 10 的圆心做圆周运动,那么就需要将点 A 的坐标计算出来。点 A 绕着圆心做圆周运动,变化的其实是点 A 和圆心形成的直线与 X 轴的夹角 θ

根据任意时刻形成的夹角 θ,我们可以通过勾股定理来计算出点 A 的横坐标 X 和 纵坐标 Y 的值。

勾股定理的计算公式如下:

$x = r \cos \theta$
$y = r \sin \theta$

我们可以得出任意夹角 θ 对应的点 A 坐标代码如下

1
2
3
4
5
6
7
8
// 圆半径
const radius = 10

// θ 对应的 X 坐标
const x = radius * cos(theta)

// θ 对应的 Y 坐标
const y = radius * sin(theta)

解决了点 A 坐标的问题,接下来就是让点 A 运动起来了,我们只需要让 θ 角不停地从 0 增加即可。代码如下:

上面的代码中,我们定义了一个变量 theta,它代表了当前的夹角值,在每帧的渲染函数 draw 中,我们让 theta 每次增加 0.5,即夹角以 0.5 的变化量依次递增,这样就可以实现圆周运动。

## 计算并画出点 B

A 点围绕圆心做圆周运动,而 B 点围绕 A 点做圆周运动。同理我们可以计算出点 B 的横坐标 X 和 纵坐标 Y 的值。

需要注意的是,B 点是围绕 A 做圆周运动,所以 B 坐标在计算时,需要加上 A 坐标的 X、Y 值。

## 连线,点和线的乐章

从上一步的结果看,我们已经离目标很接近了,就差一一条线了,这一步我们来加上这一条线。

我们连线的规则是连接 B 的前一次坐标点和这一次坐标点,形成一条直线。

我们将夹角的改变量做成了可配置,你可以尝试拖动下看看效果。

下面是具体的代码和运行效果。

## 更进一步

本次教程,我们基于基础的点和线,实现了一个华丽的乐章。不经意间我们修改了某个参数,出来了便是另外一个与众不同的结果,生成艺术和创意编程最大的乐趣或许就在这里,遇见未知的美好。

接下来,你可以做更多的尝试,比如下面一些可能的点:

  1. 我们实现的连线是 B 的前一次坐标和本次坐标连接,当然也可以简单一点,直接连接 A 点和 B 点形成一条直线,你可以修改一下上面的代码试试。
  2. 我们目前是绘制了一个点 B,你可以尝试把直线的另一个点也绘制出来看看。
  3. 尝试改变一下点的大小呢?