之前的章節我們一直在探討如何疊加圓周運動來實現各種視覺藝術效果,接下來我們會繼續探索 p5.js 其他新的可能。
今天開始我們要學習如何用 p5.js 繪製繪製不規則形狀,這個功能牽涉到的函數比較多,主要有:
vertex()
beginShape()
endShape()
如果呼叫 beginShape(),相當於告訴 p5.js 說我要開始繪製一個或多個不規則多邊形,或是一個或多個線段,然後使用 vertex() 來標記每個頂點,最後用 endShape() 結束繪製,接著 p5.js 就會用線段連接剛剛標記的每的頂點並呈現在畫布上。
一個範例勝過千言萬語:
function setup() {
createCanvas(400, 400);
noFill(); // 不填充形狀,僅繪製輪廓
beginShape(); // 開始定義形狀
vertex(30, 30); // 指定第一個頂點
vertex(200, 50); // 指定第二個頂點
vertex(150, 180); // 指定第三個頂點
vertex(50, 150); // 指定第四個頂點
endShape(CLOSE); // 結束形狀定義,並閉合形狀
}

如果我只呼叫 endShape(); 而不是 endShape(CLOSE);,那最後一個頂點就不會第一個頂點相連,也就是說形狀不會閉合:
function setup() {
createCanvas(400, 400);
noFill(); // 不填充形狀,僅繪製輪廓
beginShape(); // 開始定義形狀
vertex(30, 30); // 指定第一個頂點
vertex(200, 50); // 指定第二個頂點
vertex(150, 180); // 指定第三個頂點
vertex(50, 150); // 指定第四個頂點
endShape(); // 形狀不會閉合
}

vertex(x, y)
vertex 函數其實還有另外三個參數 z、u、v 可以設定,用於指定頂點的深度和紋理映射坐標,但目前用不到,所以看不懂沒關係XD
主要功能就是標記頂點的座標值,所以 x、y 參數就夠用了。
beginShape([kind])
kind 不是一個必填參數,該參數指定了 p5.js 如何連接 vertex 所指定的頂點,有以下幾個值可以選擇:
POINTS如果指定為 POINTS,則 p5.js 對所有頂點都不做線段連接。
function setup() {
createCanvas(600, 600);
}
function draw() {
background(255, 50);
translate(width/2, height/2);
var radius = 150;
var point_num = 12;
beginShape(POINTS);
for (let i = 0; i < point_num; i++) {
vertex(
radius * cos(i * 2 * PI / point_num),
radius * sin(i * 2 * PI / point_num)
);
}
endShape(CLOSE);
}

LINESLINES 模式會依照標記順序將前後頂點兩兩一對聯成一線。
function setup() {
createCanvas(600, 600);
}
function draw() {
background(255, 50);
translate(width/2, height/2);
var radius = 150;
var point_num = 12;
beginShape(LINES);
for (let i = 0; i < point_num; i++) {
vertex(
radius * cos(i * 2 * PI / point_num),
radius * sin(i * 2 * PI / point_num)
);
}
endShape(CLOSE);
}

kind若不指定 kind,則所有的頂點都會與先後頂點互相連接。
function setup() {
createCanvas(600, 600);
}
function draw() {
background(255, 50);
translate(width/2, height/2);
var radius = 150;
var point_num = 12;
beginShape();
for (let i = 0; i < point_num; i++) {
vertex(
radius * cos(i * 2 * PI / point_num),
radius * sin(i * 2 * PI / point_num)
);
}
endShape(CLOSE);
}

TRIANGLES指定 TRIANGLES,頂點會依照標記順序三個三個一組連接成一個三角形。
function setup() {
createCanvas(600, 600);
}
function draw() {
background(255, 50);
translate(width/2, height/2);
var radius = 150;
var point_num = 12;
beginShape(TRIANGLES);
for (let i = 0; i < point_num; i++) {
vertex(
radius * cos(i * 2 * PI / point_num),
radius * sin(i * 2 * PI / point_num)
);
}
endShape(CLOSE);
}

TRIANGLE_FAN在 TRIANGLE_FAN 模式下,依照標記順序前後頂點會兩兩一對與第一個頂點連接成三角形。
function setup() {
createCanvas(600, 600);
}
function draw() {
background(255, 50);
translate(width/2, height/2);
var radius = 150;
var point_num = 12;
beginShape(TRIANGLE_FAN);
for (let i = 0; i < point_num; i++) {
vertex(
radius * cos(i * 2 * PI / point_num),
radius * sin(i * 2 * PI / point_num)
);
}
endShape(CLOSE);
}

TRIANGLE_STRIPTRIANGLES 會讓頂點依照標記順序三個三個一組連接成一個三角形,也就是說如果有編號 1~6 的頂點,那 (1, 2, 3) 和 (4, 5, 6) 會各自連接成三角形。
TRIANGLE_STRIP 也一樣,但每個點都能重複使用,也就是說如果有編號 1~6 的頂點,那 (1, 2, 3)、(2, 3, 4)、(3, 4, 5)、(4, 5, 6)、(5, 6, 1) 都會被連接成一個三角形。
function setup() {
createCanvas(600, 600);
}
function draw() {
background(255, 50);
translate(width/2, height/2);
var radius = 150;
var point_num = 12;
beginShape(TRIANGLE_STRIP);
for (let i = 0; i < point_num; i++) {
vertex(
radius * cos(i * 2 * PI / point_num),
radius * sin(i * 2 * PI / point_num)
);
}
endShape(CLOSE);
}

QUADS指定 QUADS,頂點會依照標記順序四個四個一組連接成一個四邊形。
function setup() {
createCanvas(600, 600);
}
function draw() {
background(255, 50);
translate(width/2, height/2);
var radius = 150;
var point_num = 12;
beginShape(QUADS);
for (let i = 0; i < point_num; i++) {
vertex(
radius * cos(i * 2 * PI / point_num),
radius * sin(i * 2 * PI / point_num)
);
}
endShape(CLOSE);
}

再講 QUAD_STRIP 和 TESS 就有點太多了,現在用不到,就先不講了XD
endShape()
我們可以決定是要呼叫 endShape(CLOSE) 或是 endShape(),若傳入參數 CLOSE,那 p5.js 會認定第一個頂點和最後一個頂點分別為順序上的前後頂點,這會影響這兩個頂點會不會被 p5.js 所連接。
https://p5js.org/reference/p5/beginShape/