By Jules Kris, Tristan Bunn
はじめに
ようこそ! このチュートリアルでは、p5.jsでカラーグラデーションを描画する方法を紹介します。これは描画の章の最初の部分で、ステッカーベースの写真装飾アプリの作成を通じて学んでいきます。最初の演習では、放射状カラーグラデーションとブレンドモードを使用して、ウェブカムで撮影したセルフィーの上にレンズフレアステッカーを作成します。また、線形カラーグラデーションとブレンドモードを使用して、セルフィーの上にグラデーションフィルターを作成します。参考までに、レンズフレアとは写真やビデオに見られる視覚効果で、明るい光がカメラレンズ内で散乱することにより筋や円・ハロー効果を生み出し、画像にドラマチックまたは芸術的な雰囲気を加えるものです。フィルターは、デジタル画像のピクセルを変更したり、画像にオーバーレイして色調や色を変更したりする効果です。

ピンクのハート型メガネをかけた短い黒い巻き毛の白人の写真を撮影したウェブカムのスナップショット。 写真の上に赤から黄色の線形グラデーションフィルターがかかっています。カラフルな円が画像の上に散りばめられ、カラーグラデーションのオーバーレイがあります。 円の中にはカメラのレンズフレアを模した、ランダムな放射状カラーグラデーションがあります。 一部のカラーグラデーションはピンクから紫、シアンから緑、黄色からオレンジなどです。
前提条件
このチュートリアルを進めるには、以下が必要です:
- p5.jsの入門の章のチュートリアルを完了しているか、p5.jsでプロジェクトを作成する際の基本的な概念とベストプラクティスを理解していること。
- 学び、実験する意欲。好奇心と実験する意欲がもっとも重要な前提条件です。
このチュートリアルではp5.js Web Editorを使用し、すべてのレベルの学習者向けに設計されているので、コーディングが初めてでも心配しないでください - それを指導するのが私たちの役目です!
ステップ1: p5.js Web Editorとウェブカムのセットアップ
- p5.js Web Editorにアクセスします。
- アカウントにログインするか、新しいアカウントを作成して進捗を保存します。
- プロジェクト名を「Color Gradient Stickers」または好きな名前に変更します。
- ウェブカムをセットアップします:
createCanvas(640, 480)
を呼び出します。let
キーワードを使用してvideo
というグローバル変数を宣言します。この変数にはすぐに値を割り当てます。setup()
関数内で、video = createCapture(VIDEO)
を追加して、video
変数にcreateCapture(VIDEO)
オブジェクトを割り当てます。- これにより、ウェブカムを使用して
p5.MediaElement
を初期化し、ウェブカムからのビデオフィードをvideo
変数を使用してスケッチに取り込みます。 let
、createCapture()
、p5.MediaElement
のp5.jsリファレンスページを参照して詳細を学んでください。
- これにより、ウェブカムを使用して
setup()
内で.position(0, 0)
を追加して、位置を(0, 0)に設定し、キャンバスの左上に固定します。- ここでスケッチを実行すると、プレビューウィンドウにウェブカムからのビデオフィードが表示されるはずです。
- キャンバスにウェブカムを表示するためのこのサンプルスケッチを参照してください。
.position()
とp5.Element
のp5.jsリファレンスページを参照して詳細を学んでください。
- ウェブカムでスナップショットを撮る関数を作成します。
snapped
というグローバルBoolean変数を宣言し、false
を割り当てます。- この変数はスナップショットが撮られたかどうかを追跡し、状態変数として知られています。
- 状態に関する詳細については、MDN用語集のstate machineを参照してください。
setup()
関数の下にtakeSnap()
という関数を定義します。- 関数本体に
if (snapped === false) {}
または同等のif (!snapped) {}
を追加して、ユーザーがすでにスナップショットを撮ったかどうかを確認するif
文を使用します。 if
文の本体にimage(video, 0, 0)
を追加して、ウェブカムフィードのスナップショットを撮影し、キャンバスに配置します。- スケッチは
snapped
変数を使用してアプリの状態を追跡します -snapped
がfalse
に等しい場合、p5.jsはimage()
を使用してスナップショットを撮影します。
- スケッチは
- スナップショットを撮影した後、
image()
の下にsnapped = true
を追加します。- これにより、スナップショットが撮られたことをアプリに知らせます。
if
文の最後の行としてvideo.remove()
を追加して、ビデオを削除します。- これにより、
video
変数内のビデオ要素が削除され、image()
によってレンダリングされた静止画像を見ることになり、ビデオフィードは表示されません。
- これにより、
- 関数本体に
function
、if
、image()
、.remove()
のp5.jsリファレンスを参照して詳細を学んでください。
- スナップショットを撮るためのHTMLボタンを作成します。これはいくつかの異なる部分を使用して機能します:
createButton()
関数は新しいボタンを作成します。この関数内に文字列
'snap'
を入力することで、新しいボタンに「snap」というラベルを付けます。この新しいボタンは
snapButton
という変数に割り当てられます。snapButton
に.mouseClicked()
メソッドを追加し、ボタンがクリックされたときにtakeSnap()
を呼び出します。setup()
に以下のコードを追加することでこれを行うことができます://snapテキストの付いたボタンを作成 let snapButton = createButton('snap'); //snapボタンをクリックしたときにtakeSnap関数を実行 snapButton.mouseClicked(takeSnap);
createButton()
とmouseClicked()
のp5.jsリファレンスページを参照して詳細を学んでください。
HTMLボタンを作成することで、スケッチページのHTML内に<button></button>
を挿入し、ウェブカムフィードのスナップショットを撮るコードをトリガーするために使用しています。
コードは以下のようになります:
// ビデオオブジェクトの変数
let video;
/* 状態変数
false - スナップショットが撮られていない
true - スナップショットが撮られた */
let snapped = false;
function setup() {
createCanvas(640, 480);
//VIDEOオブジェクトをインスタンス化
video = createCapture(VIDEO);
//ウェブカムフィードが見えるように0, 0の位置に描画
video.position(0, 0);
//snapテキストの付いたボタンを作成
let snapButton = createButton('snap');
//snapボタンをクリックしたときにtakeSnap関数を実行
snapButton.mouseClicked(takeSnap);
}
/*まだ写真を撮っていない場合(snappedがfalse)
スナップショット用のビデオフレームを表示
snappedをtrueに設定し、ビデオフィードを削除して撮影した静止画だけを残す */
function takeSnap() {
if (snapped === false) {
image(video, 0, 0);
snapped = true;
video.remove();
}
}
再生ボタンを押すと、ウェブカムフィードが表示されます。「snap」ボタンをクリックして写真を撮ります。チュートリアルを進めながら、この写真の上にステッカーを重ねていきます。セルフィーのスナップショットは以下のようになります:

ピンクのハート型メガネをかけた短い黒い巻き毛の白人が、あごの下に手を置いてポーズをとり、優しく微笑んで右を見ている。
試してみよう!
現在、セルフィーは自動的にキャンバスの寸法にサイズ調整されています。image(video, 0, 0)
の呼び出しで位置を設定した後に、幅パラメータと高さパラメータを追加してセルフィーの幅と高さを調整してみてください。これにより、セルフィーを伸縮させたり歪ませたりできます。それができたら、image関数を再度使用してセルフィーを複製し、今度は異なる位置とサイズのパラメータを使用してみてください。
ステップ2: 写真の上に線形グラデーションフィルターを追加する
次に、colorMode()
、blendMode()
、lerpColor()
を使用して、セルフィーの上に線形カラーグラデーションを作成します。
- setup関数に
colorMode(HSB, 360, 100, 100);
を追加します。これにより、colorMode()
がデフォルトのRGB(赤、緑、青)の代わりにHSB(色相、彩度、明度)を使用するように設定されます。360は色相の範囲用です。これは任意の数値でも構いませんが、360はカラーホイールの度数に関連するため一般的な慣例です。100の値は、それぞれ彩度と明度を表します。再び、100は便利に0%から100%の範囲で考えられるため人気のある慣例です。まだ色を混ぜていませんが、ここで定義したシステムをコードの後半で使用します。

色相、彩度、明度を色スペクトル全体で説明する3次元の円グラフで、虹色のグラデーションがあります
上の図からわかるように、色相は色を変更し(0から360)、彩度は白から完全な鮮やかさまでの色の鮮やかさを変更し(0から100)、明度は黒から完全な強度までの色の強さを変更します(0から100)。
以下の例では、HSBカラーを使用してキャンバス全体に線形カラーグラデーションを作成しています。色相の値は左から右に増加します:
その他のバリエーション:
- この例では、HSBカラーを使用してキャンバス全体に線形カラーグラデーションを作成しています。彩度の値が左から右に増加します。
- この例では、HSBカラーを使用してキャンバス全体に線形カラーグラデーションを作成しています。明度の値が左から右に増加します。
次に、自分のスケッチで同様のことを行います:
gradientFilter()
という新しい関数を定義します。- この関数内で、
startColor
とendColor
という変数を作成し、グラデーションの両端の色のHSB値を割り当てます。このコードでは、赤から黄色へのグラデーションです。両方の色は完全に彩度が高く(灰色ではなく鮮やか)、明度は50%です。異なる色の値を試して、好みのものを見つけることができます。 - キャンバスの高さに相当する数のピクセルだけ水平線を描くために
for
ループを使用します。これらの線は互いに積み重ねられ、それぞれが少しずつ異なるストロークの色を持ち、グラデーション効果を作り出します。ループはy
がキャンバスの高さに達するまで実行され、このy
値を使って各線を操作します。for (let y = 0; y < height; y += 1)
for
ループ内で:amt
という変数を作成します。map()
関数を使用して、0からheight
(480)の範囲のy変数を0から1の範囲に再マッピングします。gradColor
という変数を作成し、lerpColor()
関数を使用してstartColor
とendColor
の間をamt
変数で補間します。補間とは、2つの色の値の間を徐々に移動することを表すfancyな言い方です。stroke()
の色をgradColor
に設定します。line()
関数を使用して、x-y座標(0,y
)から(width
,y
)までの線を描きます。
- この関数内で、
- setup関数に
blendMode(LIGHTEST)
の呼び出しを追加します。blendMode()
にLIGHTEST
引数を渡すことで、グラフィックが重ね合わされたときにもっとも明るい色だけが描画されることが保証されます。これにより、線形グラデーションが写真の上に半透明のオーバーレイとして表示され、写真の明暗の値とうまく相互作用します。 mousePressed()
関数を定義します。- 関数本体内で、
snapped
変数が真であるかどうかをチェックするif
文を作成します。これは、ユーザーがすでに写真を撮影し、ステッカーを適用する準備ができていることを示します - その場合、gradientFilter()
関数を呼び出すことができます。
- 関数本体内で、
コードは以下のようになるはずです:
let video;
/* 状態変数
false - スナップショットが撮られていない
true - スナップショットが撮られた */
let snapped = false;
function setup() {
createCanvas(640, 480);
//カラーモードをRGBの代わりにHSBに設定
colorMode(HSB, 360, 100, 100);
//VIDEOオブジェクトをインスタンス化
video = createCapture(VIDEO);
//ウェブカムフィードが見えるように0, 0の位置に描画
video.position(0, 0);
//snapテキストの付いたボタンを作成
let snapButton = createButton("snap");
//snapボタンをクリックしたときにtakeSnap関数を実行
snapButton.mouseClicked(takeSnap);
blendMode(LIGHTEST);
}
//マウスを押したときにgradientFilter関数を実行
function mousePressed() {
if (snapped === true) {
gradientFilter();
}
}
/*まだ写真を撮っていない場合(snappedがfalse)
スナップショット用のビデオフレームを表示
snappedをtrueに設定し、ビデオフィードを削除して撮影した静止画だけを残す */
function takeSnap() {
if (snapped === false) {
image(video, 0, 0);
snapped = true;
video.remove();
}
}
//forループとlerpColorを使用して画面に線形グラデーションを描画
function gradientFilter() {
let startColor = color(0, 100, 50);
let endColor = color(60, 100, 50);
for (let y = 0; y < height; y += 1) {
let amt = map(y, 0, height, 0, 1);
let gradColor = lerpColor(startColor, endColor, amt);
stroke(gradColor);
line(0, y, width, y);
}
}
再生ボタンを押すと、スナップショットを撮影し、キャンバスをクリックしてグラデーションフィルターを適用できます。グラデーションが写真のもっとも暗い部分にもっとも劇的に適用されるのがわかります。これは、使用しているblendMode()
、彩度、明度の設定によるものです。

ピンクのハート型メガネをかけた短い黒い巻き毛の白人が、あごの下に手を置いてポーズをとっている写真に、垂直の赤から黄色の線形グラデーションがカメラフィルターとして適用されています。LIGHTESTブレンドモードのため、カラフルなグラデーションは特に彼の暗い髪と暗いシャツに目立って見えます。

ピンクのハート型メガネをかけた短い黒い巻き毛の白人が、あごの下に手を置いてポーズをとっている写真に、垂直の赤から黄色の線形グラデーションがカメラフィルターとして適用されています。LIGHTESTブレンドモードのため、カラフルなグラデーションは特に彼の暗い髪と暗いシャツに目立って見えます。
ステップ3: カラーグラデーションステッカーを追加する
放射状グラデーションを使用して、写真の上に配置するカラフルなレンズフレアを作成しましょう。
- 新しい
lensFlare()
関数を定義します。 - レンズフレアを作成するために
circle()
関数を使用します。diameter
という変数を作成し、50に設定します。h
という変数を作成し(これは色相に使用します)、150に設定します。
for (let d = diameter; d > 0; d -= 1)
で始まるforループを作成します。このループは、異なるストロークの色を持つ複数の円を描画し、滑らかにブレンドして虹のような塗りつぶし効果を作り出します。- forループ内で、
fill(h, 90 90)
と書きます。これにより、色相にh
変数、彩度に90、明度に90が割り当てられます。 circle(mouseX, mouseY, d)
と書きます。これにより、円のx座標がmouseX
、y座標がmouseY
、直径がd
に設定されます。h
を(h + 1) % 360
に設定します。forループを使用してHSB値、特に色相値を反復処理しています。モジュロ演算子(%
)は色相値のサイクルを助け、h値が360を超えた場合に「ラップアラウンド」して0から再開し、色のブレンドが繰り返されるようにします。
- forループ内で、
- サイズと色のバリエーションを作成するために、
diameter
をrandom(50, 200)
に、h
をrandom(150, 360)
に設定します。 mousePressed
関数のif
文内で、lensFlare()
を呼び出します。
完成したスケッチのコードは以下のようになるはずです:
let video;
/* 状態変数
false - スナップショットが撮られていない
true - スナップショットが撮られた */
let snapped = false;
function setup() {
createCanvas(640, 480);
//カラーモードをRGBの代わりにHSBに設定
colorMode(HSB, 360, 100, 100);
//VIDEOオブジェクトをインスタンス化し、0, 0の位置に描画
video = createCapture(VIDEO);
video.position(0, 0);
//snapテキストの付いたボタンを作成
let snapButton = createButton('snap');
//snapボタンをクリックしたときにtakeSnap関数を実行
snapButton.mouseClicked(takeSnap);
blendMode(LIGHTEST);
noStroke();
}
//マウスを押したときにgradientFilterとlensFlare関数を実行
function mousePressed() {
if (snapped === true) {
gradientFilter();
lensFlare();
}
}
/*まだ写真を撮っていない場合(snappedがfalse)
スナップショット用のビデオフレームを表示
snappedをtrueに設定し、ビデオフィードを削除して撮影した静止画だけを残す */
function takeSnap() {
if (snapped === false) {
image(video, 0, 0);
snapped = true;
video.remove();
}
}
//画面をクリックしたときに放射状グラデーションで塗りつぶされた円を描画
//各円のサイズと色はdiameterとh変数に含まれるランダムな値
function lensFlare() {
let diameter = random(50, 200);
let h = random(150, 360);
for (let d = diameter; d > 0; d -= 1) {
fill(h, 90, 90);
circle(mouseX, mouseY, d);
h = (h + 1) % 360;
}
}
//forループとlerpColorを使用して画面に線形グラデーションを描画
function gradientFilter() {
let startColor = color(0, 100, 50);
let endColor = color(60, 100, 50);
for (let y = 0; y < height; y += 1) {
let amt = map(y, 0, height, 0, 1);
let gradColor = lerpColor(startColor, endColor, amt);
stroke(gradColor);
line(0, y, width, y);
}
}
最終結果を見るために再生ボタンを押し、写真の異なる部分をクリックして複数のレンズフレア効果を追加します。

ピンクのハート型メガネをかけた短い黒い巻き毛の白人の写真を撮影したウェブカムのスナップショット。 写真の上に赤から黄色の線形グラデーションフィルターがかかっています。 カラフルな円が画像の上に散りばめられ、カラーグラデーションのオーバーレイがあります。 円の中にはカメラのレンズフレアを模した、ランダムな放射状カラーグラデーションがあります。 一部のカラーグラデーションはピンクから紫、シアンから緑、黄色からオレンジなどです。
ステッカーを追加し続けると、写真全体を覆うことができます。LIGHTEST
blendMode()
がキャンバスの異なるレイヤーとどのように相互作用するかに注目してください。

ピンクのハート型メガネをかけた短い黒い巻き毛の白人がポーズをとっています。写真全体にレンズフレアがかかっており、キャンバス全体が多色のレンズフレアで覆われ、下の人物の画像がかすかに見えるだけです。
試してみよう!
blendMode
を異なる設定に変更して、スケッチにどのような影響があるか確認してください! 私たちはLIGHTEST
を選択しましたが、完全なオプションリストはblendMode
のp5.jsリファレンスページで確認できます。
まとめ
このチュートリアルではウェブカムのビューをインスタンス化し、circle
を使用して放射状グラデーションを作成し、line
を使用して線形グラデーションを作成し、color()、lerpColor()、blendMode()関数を使用して写真に適用するレンズフレアステッカーを作成する方法を学びました。 次のチュートリアルでは、beginShape()
、endShape()
、vertex()
、bezier()
、bezierVertex()
を使用して、さらにユニークなステッカーを作成します!
参考のために、完成したプロジェクトのサンプルコードがあります。
次のステップ
次のレッスンに進みましょう:カスタムシェイプとスムーズカーブ!