様々な関数の使い方をおさらいし、作例コードを書くことで、自分の知識の定着を図っています。
今回は、curve() 関数の解説を行い、サンプルコードを書くことで、その使い方を学びます。p5.js は、安定版のバージョン 1.11.11 を使用しています。
内容については正確を期していますが、お気づきの点があればご指摘いただけると幸いです。
curve() 関数の説明と使い方
curve() | p5.js 公式リファレンス
説明
緩やかな傾斜を持つ、Catmull-Romスプライン曲線を描く関数です。
Catmull-Romスプライン曲線 | Wikipedia
曲線は始点、中間点A、中間点B、終点の 4つの座標点を緩やかに結ぶ形をとります。始点と終点を制御ポイント、中間点A と中間点B をアンカーポイントと呼びます。
4つの座標を指定しますが、描画されるのは中間点A と中間点B の間だけです。始点と終点は線を引き寄せるための「磁石」のようなものです。この磁石の置き場所によって曲線の曲がり具合が決まります。
書き方
シンプルに各点を並べていくだけです。
// 2D の場合
curve(
始点.x, 始点.y,
中間点A.x, 中間点A.y,
中間点B.x, 中間点B.y,
終点.x, 終点.y
)
// 3D の場合
curve(
始点.x, 始点.y, 始点.z,
中間点A.x, 中間点A.y, 中間点A.z,
中間点B.x, 中間点B.y, 中間点B.z,
終点.x, 終点.y, 終点.z
)
パラメータ
- 各点の座標を指定します。指定は必須です。
返り値
なし
p5.js 公式リファレンスのコード例の補足
公式リファレンス上の、2026-02-14 現在で 2番目に掲載されているコードについて補足します。
始点という「磁石」をマウスドラッグで移動させて曲線の変化を見られる例です。
let x1 = 5;
let y1 = 26;
let isChanging = false;
function setup() {
createCanvas(100, 100);
describe(
'A gray square with a curve drawn in three segments. The curve is a sideways U shape with red segments on top and bottom, and a black segment on the right. The endpoints of all the segments are marked with dots.'
);
}
function draw() {
background(200);
// Draw a black spline curve.
noFill();
strokeWeight(1);
stroke(0);
curve(x1, y1, 73, 24, 73, 61, 15, 65);
// Draw red spline curves from the anchor points to the control points.
stroke(255, 0, 0);
curve(x1, y1, x1, y1, 73, 24, 73, 61);
curve(73, 24, 73, 61, 15, 65, 15, 65);
// Draw the anchor points in black.
strokeWeight(5);
stroke(0);
point(73, 24);
point(73, 61);
// Draw the control points in red.
stroke(255, 0, 0);
point(x1, y1);
point(15, 65);
}
// Start changing the first control point if the user clicks near it.
function mousePressed() {
if (dist(mouseX, mouseY, x1, y1) < 20) {
isChanging = true;
}
}
// Stop changing the first control point when the user releases the mouse.
function mouseReleased() {
isChanging = false;
}
// Update the first control point while the user drags the mouse.
function mouseDragged() {
if (isChanging === true) {
x1 = mouseX;
y1 = mouseY;
}
}
左上の赤い点(始点)の側でマウスボタンを押すことで、始点をドラッグして動かせるようになります。ドラッグの開始をmousePressed()で、始点の移動をmouseDragged()で制御しています。
始点はキャンバス外まで持っていけるので、大きく動かすことでスプラインがどのようなものかの感覚が掴めるでしょう。
curve()は 3個ありますが、一個目が本物というか、スプラインを描いているものです。このcurve()で描かれるのはキャンバス上の黒い線です。
2個目と 3個目のcurve()は、実際には描かれない制御ポイントとアンカーポイント間を、説明のために赤い線で描画するためのものです。
curve() を使った作例: ランダムに生まれるスパイログラフ
制御ポイントとアンカーポイントを円周上で回転させながら curve() で曲線を引き、スパイログラフっぽい模様を描く作例です。
スプラインの制御しづらさを逆手に取ったというか、制御を放棄してみたら、幾何学的でありながら有機的な雰囲気もある不思議な模様が現れた、という感じです。
描画の度に制御ポイントとアンカーポイントはランダムに配置されます。マウスクリックで再描画します。
/*
* p5js サンプルコード
* curve() でスパイログラフっぽい模様を描く
*
* @author @deconbatch
* @date 2026-02-14
* @version 0.1
* @license CC0 1.0 https://creativecommons.org/publicdomain/zero/1.0/deed.ja
* p5js 1.11.11
*/
const ANCHOR_NUM = 3; // アンカーポイントの数
const SYMMETRY_NUM = 7; // 回転対称の数
function setup(){
createCanvas(720, 720);
colorMode(HSB, 360, 100, 100, 100);
noLoop();
}
function draw(){
// 制御ポイントをランダムに配置
const ctrl01 = createVector(
width * random(0.1, 2),
height * random(0.1, 2)
);
const ctrl02 = createVector(
-width * random(0.1, 2),
-height * random(0.1, 2)
);
// アンカーポイントをある程度ランダムに散らす
const anchors = [];
for (let i = 0; i < ANCHOR_NUM; i++) {
let t = random(0.8, 1.25) * TWO_PI * i / ANCHOR_NUM;
anchors.push(createVector(cos(t), sin(t)).mult(random(0.05, 0.35) * min(width, height)));
}
const baseHue = random(360);
const stepAngle = TWO_PI / SYMMETRY_NUM;
push();
translate(width * 0.5, height * 0.5);
background(0, 0, 90, 100);
for (let i = 0; i < SYMMETRY_NUM; i++) {
// 制御ポイントを回転
ctrl01.rotate(stepAngle);
ctrl02.rotate(stepAngle);
// アンカーポイントを回転
for (const an of anchors) {
an.rotate(stepAngle);
}
// 描画
drawStructure(anchors, ctrl01, ctrl02, baseHue);
}
pop();
}
/**
* アンカー点群を結ぶ曲線と頂点を描画する
*/
function drawStructure(_anchors, _cp01, _cp02, _hue) {
for (let i = 0; i < _anchors.length; i++) {
let an01 = _anchors[i];
let an02 = _anchors[(i + 1) % _anchors.length];
// 曲線描画
noFill();
stroke(0, 0, 0, 100);
curve(
_cp01.x, _cp01.y,
an01.x, an01.y,
an02.x, an02.y,
_cp02.x, _cp02.y
);
// 頂点描画
stroke(0, 0, 0, 100);
fill((_hue + i * 30) % 360, 40, 80, 100);
circle(an01.x, an01.y, 10);
}
}
function mouseClicked() {
redraw();
}
実行例








