7:カラー(Color)

カラーモデル

p5.jsではRGBカラーモデルがデフォルトなので、fill()やstroke()、background()関数などでは、0から255までの数値でRGB値を指定します。しかしカラーモデルは、colorMode()関数によって、HSBなどの別のモデルに変えることができます。

HSBカラーモデルは、色相(Hue、色合い)、彩度(Saturation、鮮やかさ)、明度(Brightness、明るさ)の3要素から成ります。

  • 色相:色の種類(赤、青、黄色など)。0から360度の範囲。
  • 彩度:色の鮮やかさ。0から100%の範囲
  • 明度:色の明るさ。0 – 100 % の範囲

多くの描画アプリケーションには、RGBのほかにHSBによる色の指定機能も備わっています。下図はGIMPの[描画色の変更]ダイアログボックスです。これを見ると、HTML表記でff0000の赤は、RGBでは(255,0,0)、HSBでは(360,100,100)で表されることが分かります(GIMPではHSVと呼ばれていますが、HSVはHSBの別名です)。

次のコードは、まずデフォルトのRGBモードで赤の矩形を描画し、colorMode()でHSBモードに変えた後、赤の円を描く例です。

function setup() {
    createCanvas(150, 100);
    noStroke();
    background(200);
    // RGBモードでの塗り色指定
    // RGB = (255,0,0)
    fill(255, 0, 0);
    rect(10, 10, 50, 50);

    // HSBモードに変更
    // HSB, 色相、彩度、明度の最大値
    colorMode(HSB, 360, 100, 100);
    // HSB = (360度、100%, 100%)
    fill(360, 100, 100);
    ellipse(100, 35, 50);
}

描画アプリケーションのカラー設定ダイアログボックスなどで、HSBモードでの数値を調べると、ほかの色も同様にして描画することができます。

リファレンスメモ

colorMode()

説明

colorMode()関数は、p5.jsがカラーデータを解釈する方法を変更する。デフォルトでは、fill()やstroke()、background()、color()関数のパラメータは、RGBカラーモデルによる0と255の間の値によって定義される。これは、colorMode(RGB, 255)で設定するのと同じ。代わりにcolorMode(HSB)を設定すると、HSBシステムが使用できるようになる。これは、デフォルトでcolorMode(HSB, 360, 100, 100, 1)が用いられる。またHSLも使用できる。

ノート:すでに存在しているカラーオブジェクトは、それが作成されたときのモードを覚えているので、それらに影響を与えることなく、好きなモードに変えることができる。

シンタックス

colorMode(mode, [max])
colorMode(mode, max1, max2, max3, [maxA])

パラメータ

mode:定数:RGBかHSB、またはHSL。それぞれ、Red/Green/Blue(赤緑青)、Hue/Saturation/Brightness(色相/彩度/明度)、Hue/Saturation/Lightness(色相/彩度/輝度)を意味する。
max:数値。全値の範囲
max1:数値。現在のカラーモードに応じた、赤または色相の範囲
max2:数値。現在のカラーモードに応じた、緑または彩度の範囲
max3:数値。現在のカラーモードに応じた、青または明度、または輝度の範囲
maxA:数値。アルファの範囲

色相(Hue)

色相(色合い)は、物体から反射したり物体を通過して伝わる色のことで、通常は色の名前(赤、青、黄など)を指します。カーソルを垂直方向にバーの上を動かすと、バーの色相が変化します。

const barWidth = 20;
let lastBar = -1;

function setup() {
    createCanvas(720, 400);
    colorMode(HSB, height, height, height);
    noStroke();
    background(0);
}

function draw() {
    let whichBar = mouseX / barWidth;
    if (whichBar !== lastBar) {
        let barX = whichBar * barWidth;
        fill(mouseY, height, height);
        rect(barX, 0, barWidth, height);
        lastBar = whichBar;
    }
}
解説

このサンプルではよく分からないので、もっと基本的な例を以下に示します。彩度と明度を100%のまま変更せず、色相を0から360度まで変えて、円環を描きます。

let hue = 360;
const saturation = 100;
const brightness = 100;

const radius = 250;
let centerX;
let centerY;

function setup() {
    createCanvas(360, 300);
    // HSBカラーモードに変更
    colorMode(HSB, hue, saturation, brightness, 1);

    // 円の中心をキャンバスセンターにする
    centerX = width / 2;
    centerY = height / 2;

    noStroke();
    strokeWeight(2);
    background(0, 0, 100); // HSBの白

    // hue値は0から開始
    hue = 0;
}

function draw() {

    // 「7_6:円運動 p5.js JavaScript」
    const sinValue = sin(hue);
    const cosValue = cos(hue);
    const x = centerX + cosValue * radius;
    const y = centerY + sinValue * radius;

    // 塗り色を(hue値, 100,100)に設定
    fill(hue, saturation, brightness);
    // 円弧を描画
    arc(centerX, centerY, 250, 250, radians(hue), radians(hue + 1));
    // 小さな円を白で描画
    fill(0, 0, 100);
    ellipse(centerX, centerY, 170);

    // hue値が360になったらdraw()を停止
    if (hue > 360) {
        noLoop();
    }
    else {
        hue += 1;
    }
}

これを実行すると、下図の円環がアニメーションして描画されます。これは、前に紹介したGIMPの[描画色の変更]ダイアログボックスに表示される円環によく似ています。

彩度(Saturation)

彩度は、色の強度または純度であり、色相に比例したグレーの量を表します。”飽和した”色は純色で、”不飽和”の色はグレーの比率が大きいです。カーソルを垂直方向にバーの上を動かすと、バーの彩度が変化します。

const barWidth = 20;
let lastBar = -1;

function setup() {
    createCanvas(720, 400);
    colorMode(HSB, width, height, 100);
    noStroke();
}

function draw() {
    let whichBar = mouseX / barWidth;
    if (whichBar !== lastBar) {
        let barX = whichBar * barWidth;
        fill(barX, mouseY, 66);
        rect(barX, 0, barWidth, height);
        lastBar = whichBar;
    }
}
解説

このサンプルもよく分からないので、もっと基本的な例を以下に示します。

let hue = 360;
let saturation = 100;
let brightness = 100;

let isOn = false;

function setup() {
    createCanvas(420, 300);
    // HSBカラーモードに変更
    colorMode(HSB, hue, saturation, brightness, 1);
    strokeWeight(10);
    background(0, 0, 80); // HSBのグレー

    // ボタン
    buttonA = createButton('彩度 0 => 100');
    buttonA.position(5, 310);
    buttonA.size(100, 40);
    // ボタンのクリックで、変数を設定して描画開始
    buttonA.mousePressed(() => {
        // HSBの黄色は(60, 100, 100);
        // 青色は(240, 100,100)
        // 微妙な色(100,60,60)
        hue = 60;
        //hue = 240;
        // hue = 100
        saturation = 0;
        brightness = 100;
        //brightness = 60;
        isOn = true;
    });

}

function draw() {
    if (isOn) {
        // 線のHSBカラーを指定
        stroke(hue, saturation, brightness);
        // 太い線を縦に引く
        line(saturation * 4, 30, saturation * 4, 250);
        // 100になるまでsaturationを1ずつ大きくする
        //print(saturation);
        if (saturation >= 100) {
            noLoop();
        }
        else {
            saturation++;
        }
    }
}

左下の[彩度 0 => 100]ボタンをクリックすると、彩度0の黄(白)の矩形が右に大きくなっていき、最後は純粋な黄色で終わります。

この場合は、変数hueを60、brightnessを100に固定し、saturationを0から100まで1ずつ大きくしています。この彩度の変更にともなう色の変化を、GIMPの[描画色の変更]ダイアログボックスに置き換えると、次のようになります。

変数hueとsaturation、brightnessに与える数値を変えることで、ほかの色での彩度の変化を描画できます。下図はその例です。

明るさ(Brightness)

ダニエル・シフマンによる。このプログラムは、各ピクセルからマウスまでの距離を計算することで、イメージの部分的な明度を調整します。

let img;

function preload() {
    img = loadImage('assets/moonwalk.jpg');
}

function setup() {
    createCanvas(720, 200);
    pixelDensity(1);
    img.loadPixels();
    loadPixels();
}

function draw() {
    for (let x = 0; x < img.width; x++) {
        for (let y = 0; y < img.height; y++) {
            // 2Dグリッドから1Dでの位置を計算する
            let loc = (x + y * img.width) * 4;
            // イメージからRGB値を得る
            let r, g, b;
            r = img.pixels[loc];
            // マウスへの近さにもとづいて、明るさを変える量を計算する
            let maxdist = 50;
            let d = dist(x, y, mouseX, mouseY);
            let adjustbrightness = (255 * (maxdist - d)) / maxdist;
            r += adjustbrightness;
            // RGB値が0-255のカラー範囲に収まるように制限をかける
            r = constrain(r, 0, 255);
            // Make a new color and set pixel in the window
            //color c = color(r, g, b);
            let pixloc = (y * width + x) * 4;
            pixels[pixloc] = r;
            pixels[pixloc + 1] = r;
            pixels[pixloc + 2] = r;
            pixels[pixloc + 3] = 255;
        }
    }
    updatePixels();
}
解説

上記サンプルは非常に優れたかつ数学的で難しく、またHSBモードを使った明度の例ではないので、以下に、明度の例を示します。これは、前の例と変わりませんが、彩度ではなく明度を変化させています。

let hue = 360;
let saturation = 100;
let brightness = 100;

let isOn = false;

function setup() {
    createCanvas(420, 300);
    // HSBカラーモードに変更
    colorMode(HSB, hue, saturation, brightness, 1);
    strokeWeight(10);
    background(0, 0, 80); // HSBのグレー

    // ボタン
    buttonA = createButton('明度 0 => 100');
    buttonA.position(5, 310);
    buttonA.size(100, 40);
    // ボタンのクリックで、変数を設定して描画開始
    buttonA.mousePressed(() => {
        // HSBの黄色は(60, 100, 100);
        hue = 60
        saturation = 100;
        brightness = 0;
        isOn = true;
    });
}

function draw() {
    if (isOn) {
        // 線のHSBカラーを指定
        stroke(hue, saturation, brightness);
        // 太い線を縦に引く
        line(brightness * 4, 30, brightness * 4, 250);
        // 100になるまでbrightnessを1ずつ大きくする
        if (brightness >= 100) {
            noLoop();
        }
        else {
            brightness++;
        }
    }
}

カラー変数(Color Variables)

(ヨゼフ・アルバースへのオマージュ)。このサンプルでは、プログラムの中で、数値ではなく名前で参照するカラー用の変数を作成しています。

function setup() {
    createCanvas(710, 400);
    noStroke();
    background(51, 0, 0);

    const inside = color(204, 102, 0);
    const middle = color(204, 153, 0);
    const outside = color(153, 51, 0);

    print(inside.toString());
    print(inside);

    // 以下の3行は上の3行と同じ。
    // どちらでも好きな方を使用する。
    //const inside = color('#CC6600');
    //const middle = color('#CC9900');
    //const outside = color('#993300');

    // 変換のひとくくり -- ここから
    push();
    translate(80, 80);
    fill(outside);
    rect(0, 0, 200, 200);
    fill(middle);
    rect(40, 60, 120, 120);
    fill(inside);
    rect(60, 90, 80, 80);
    pop();
    // -- ここまで

    // また別の変換のひとくくり -- ここから
    push();
    translate(360, 80);
    fill(inside);
    rect(0, 0, 200, 200);
    fill(outside);
    rect(40, 60, 120, 120);
    fill(middle);
    rect(60, 90, 80, 80);
    pop();
    // -- ここまで
}

解説

color()関数を使用すると、p5.jsのカラーを表すp5.Colorオブジェクトが返されます。上記サンプルでは、それをinsideなどの変数で保持し、それをfill()関数に与えています。

次のコード(抜粋)を実行すると、同じ色に見える矩形が2つ描画されます。

// デフォルトのRGBモードでオレンジ色を作成
const orangeRGB = color(243, 182, 18);
// それを塗り色にして矩形を描画
fill(orangeRGB);
rect(10, 10, 40, 20);

// HSBモードに変更して、オレンジ色を作成
colorMode(HSB);
const orangeHSB = color(44, 93, 95);
// それを塗り色にして矩形を描画
fill(orangeHSB);
rect(10, 50, 40, 20);

次のコードで出力すると、下図に示す結果が得られます。

print(orangeRGB.toString());
print(orangeRGB);

リファレンスメモ

color()

説明

colorデータ型の変数に保持するカラーを作成する。パラメータは、現在のcolorMode()に応じてRGBかHSB値として解釈される。デフォルトのモードは0から255までのRGBなので、関数呼び出しcolor(255, 204, 0)は明るい黄色を返す。

color()に1つの値のみ与えられた場合には、グレースケール値として解釈される点に注意。2つめの値を追加すると、それはアルファ透明度として使用される。3つの値を指定すると、それらはRGBかHSB値として解釈される。4つめの値はアルファ透明度に適用される。

単一の文字列引数が与えられる場合には、RGBとRGBA、16進CSS色文字列、すべての名前付きカラー文字列がサポートされる。この場合、第2引数としてのアルファ数値はサポートされないので、RGBA形式を使用する必要がある。

シンタックス

color(gray, [alpha])
color(v1, v2, v3, [alpha])
color(value)
color(values)
color(color)

パラメータ

gray :数値:白と黒の間を指定する数値
alpha :数値:現在のカラー範囲(デフォルトは0-255)に関してのアルファ値
v1 :数値:現在のカラー範囲に関しての赤または色相値
v2 :数値:現在のカラー範囲に関しての緑または彩度値
v3 :数値:現在のカラー範囲に関しての青または明度値
value :文字列:カラー文字列
values :数値[]: カラーの赤、緑、青とアルファ成分を含む配列
color :p5.Color

戻り値

p5.Color: 生成されたカラー

p5.Color

説明

各カラーは、それが構築されるときに適用されるカラーモードとレベル最大値を保持する。これらは、入力引数の解釈(構築時以降のそのカラーのインスタンスに関して)と、たとえばsaturation()(カラーやピクセル配列から彩度値を取り出す関数)が要求されたときなどの出力のフォーマット化に使用される。

内部には、浮動小数点数形式で0から1の間に正規化された理想的なRGBA値を表す配列が保持されている。この配列から最も近いスクリーンカラー(0から255までのRGBAレベル)が算出され、レンダラーに公開される。

また、カラーの正規化された浮動小数点成分は、計算時にさまざまな表現でキャッシュされる。これは、すでに実行された変換の反復を避けるために行われる。

色同士の関係性(Relativity)

色はそれぞれが、ほかの色との関係性において知覚されます。上と下のバー(縦の帯)を構成する色は同じですが、その順番を変えることで、個々の色が上と下で違って見えるようになります。

let a, b, c, d, e;

function setup() {
    createCanvas(710, 400);
    noStroke();
    a = color(165, 167, 20);
    b = color(77, 86, 59);
    c = color(42, 106, 105);
    d = color(165, 89, 20);
    e = color(146, 150, 127);
    noLoop();
}

function draw() {
    drawBand(a, b, c, d, e, 0, width / 128);
    drawBand(c, a, d, b, e, height / 2, width / 128);
}

function drawBand(v, w, x, y, z, ypos, barWidth) {
    let num = 5;
    let colorOrder = [v, w, x, y, z];
    for (let i = 0; i < width; i += barWidth * num) {
        for (let j = 0; j < num; j++) {
            fill(colorOrder[j]);
            rect(i + j * barWidth, ypos, barWidth, height / 2);
        }
    }
}

解説

これはおそらく、「色の対比」と呼ばれる人間の目の知覚現象を扱ったものではないかと思われます。

対比
対比とは、ある色が他の色に影響されて、実際とは ちがって見える現象のことを指します

下図は、描画する縦の帯の幅を太くしたものです。これぐらい太くしても、上のbと下のbは違って見えます。

線形グラデーション(Linear Gradient)

lerpColor()関数は、2つのカラー間を補間するときに便利です。

// 定数
const Y_AXIS = 1;
const X_AXIS = 2;
let b1, b2, c1, c2;

function setup() {
    createCanvas(710, 400);

    // カラーを定義
    b1 = color(255);
    b2 = color(0);
    c1 = color(204, 102, 0);
    c2 = color(0, 102, 153);

    noLoop();
}

function draw() {
    // 背景
    setGradient(0, 0, width / 2, height, b1, b2, X_AXIS);
    setGradient(width / 2, 0, width / 2, height, b2, b1, X_AXIS);
    // 前景
    setGradient(50, 90, 540, 80, c1, c2, Y_AXIS);
    setGradient(50, 190, 540, 80, c2, c1, X_AXIS);
}

function setGradient(x, y, w, h, c1, c2, axis) {
    noFill();

    if (axis === Y_AXIS) {
        // 上から下へのグラデーション
        for (let i = y; i <= y + h; i++) {
            let inter = map(i, y, y + h, 0, 1);
            let c = lerpColor(c1, c2, inter);
            stroke(c);
            line(x, i, x + w, i);
        }
    }
    else if (axis === X_AXIS) {
        // 左から右へのグラデーション
        for (let i = x; i <= x + w; i++) {
            let inter = map(i, x, x + w, 0, 1);
            let c = lerpColor(c1, c2, inter);
            stroke(c);
            line(i, y, i, y + h);
        }
    }
}

解説

線形グラデーションとは、次のものを言います。Photoshopなどの描画アプリケーションをお使いの方にはお馴染みのカラー表現です。

線形グラデーションとは、描画領域の色を指定した方向へ線状に変化させていく手法のことである。 線形グラデーションは、開始点と終了点の2つの点と色を指定し、開始点から終了点に向けて次第に色が変化していくものである。 開始点と終了点は、上から下、右から左、斜め上から斜め下というようにユーザーが任意に指定できる。

線形グラデーションとは何?

上記サンプルでは、線形グラデーションを、細い線を縦または横に引くことで実現しています。その際には、グラデーションの開始と終了カラーの間のカラーをlerpColor()関数を使って求め、それを線の色にして描画しています。

ではポイントとなるこのlerpColor()関数を以降の例で見ていきましょう。次のコードを実行すると、下図の結果が得られます。

let fromColor;
let toColor;

function setup() {
  createCanvas(330, 400);
  noStroke();
  background(230);

  fromColor = color(0);
  toColor = color(255);

  // fromColor色の矩形を左上に描画
  fill(fromColor);
  rect(0, 10, 20, 100);

  // toColor色の矩形を右上に描画
  fill(toColor);
  rect(300, 10, 20, 100);

  // fromColorとtoColoramtをamt = 0で補間
  const interA = lerpColor(fromColor, toColor, 0);
  fill(interA);
  print(interA.toString());
  rect(0, 150, 20, 100);

  // fromColorとtoColoramtをamt = 0.5で補間
  const interB = lerpColor(fromColor, toColor, 0.5);
  fill(interB);
  print(interB.toString());
  rect(150, 150, 20, 100);

  // fromColorとtoColoramtをamt = 1で補間
  const interC = lerpColor(fromColor, toColor, 1);
  fill(interC);
  print(interC.toString());
  rect(300, 150, 20, 100);

  // fromColorとtoColoramtをamt = 0.25で補間
  const interD = lerpColor(fromColor, toColor, 0.25);
  fill(interD);
  print(interD.toString());
  rect(75, 150, 20, 100);

  // fromColorとtoColoramtをamt = 0.75で補間
  const interE = lerpColor(fromColor, toColor, 0.75);
  fill(interE);
  print(interE.toString());
  rect(225, 150, 20, 100);
}

上図の左上の矩形がfromColor(黒)で、右上の矩形がtoColor色(白)です。lerpColor()は、指定された2つのカラーの間のカラーを見つける関数です。この関数に、グラデーションを開始したいカラーと終了したいカラー、そして終了カラーにどれだけ近いかを示す数値amtを0から1までの値で指定すると、lerpColor()は、開始カラーと終了カラーの間でamtだけ終了カラーに近いカラーを返します。

上図の下部には黒やグレーの矩形が並んでいます。これは、lerpColor()関数にfromColorとtoColor、そしてamt引数として、0,0.25,0.5,0.75,1を渡した結果を示しています。これを見ると、amt=0のときはtoColorに最も近くないので黒、amt=0.5のときはtoColorに半分近いのでグレー、amt=1のときはtoColorに最も近いので白となることが確認できます。同様に、amtが0.25のときは濃いグレー、0.75のときは薄いグレーになります。

リファレンスメモ

lerpColor()

説明

lerpは、Linear Interpolate(線形補間)の略。2つのカラーをブレンドして、2色の間に3番めのカラーを見つける。amtパラメータは、2つの値間を補間する量。0.0は最初のカラーと等しく、0.1は最初のカラーに非常に近く、0.5はちょうど中間になることを意味する。0未満の量は0と扱われ、同様に1より大きな量は1に制限される。これはlerp()関数の振る舞いと異なるが、この処置がないと、範囲を超えた数値が奇妙で予測不能なカラーを生成することになるので、必要。

カラーの補間方法は、現在のカラーモードによって異なる。

シンタックス

lerpColor(c1, c2, amt)

パラメータ

c1 :p5.Color: このカラーから補間
c2 :p5.Color: このカラーまで補間
amt :数値:0と1の間の数値

戻り値

p5.Color: 補間されたカラー

前のp5.jsのサンプルを参考にすると、最も分かりやすい横長矩形のグラデーションを作成するコードは次のように記述できます。

function setup() {
    createCanvas(400, 400);
    noStroke();
    background(230);

    // 黒と白
    const fromColorA = color(0);
    const toColorA = color(255);
    // 赤と青
    const fromColorB = color(255, 0, 0);
    const toColorB = color(0, 0, 255);
    // 微妙な緑と微妙なピンク
    const fromColorC = color(17, 215, 82);
    const toColorC = color(213, 20, 215);

    // setGradient()関数では、グラデーションの開始位置と幅、高さが自由に変更できる
    setGradient(10, 10, 300, 100, fromColorA, toColorA);
    setGradient(10, 120, 200, 100, fromColorB, toColorB);
    setGradient(10, 230, 380, 60, fromColorC, toColorC);
}

// 線の描画を開始するxとy位置、描画する幅、高さ、開始カラーと終了カラーを受け取り、
// 縦線を描画することでグラデーションを表す関数
function setGradient(startX, startY, bandW, bandH, col1, col2) {
    const max = startX + bandW
        // 変数iをstartXから開始し、maxになるまで、1ずつ大きくする
    for (let i = startX; i <= max; i++) {
        // iを、startXからmaxの範囲から、0から1の範囲にマッピングする
        // 「4_7:マッピング(対応付け) p5.js JavaScript」
        const amt = map(i, startX, max, 0, 1);
        // カラーの補間
        const col = lerpColor(col1, col2, amt);
        // col色の細い縦線を描画する
        stroke(col);
        line(i, startY, i, startY + bandH);
    }
}

円形グラデーション(Radial Gradient)

同心円を連続して描画し、あるカラーから別のカラーに変化するグラデーションを表現します。

// 円の直径
let dim;

function setup() {
    createCanvas(710, 400);
    // 円の直径はキャンバスの幅の半分
    dim = width / 2;
    // print(dim)  // 355
    background(0);
    // カラーモードをHSBに変える
    colorMode(HSB, 360, 100, 100);
    noStroke();
    ellipseMode(RADIUS);
    // フレームレートを1にする => 1秒に1回、forループが実行される
    frameRate(1);
    //noLoop();
}

function draw() {
    background(0);
    // iを0から開始し、キャンバス幅まで、dimずつ大きくする
    for (let x = 0; x <= width; x += dim) {
        // print(x); // xは0,355,710,0,355,710,...を繰り返す
        drawGradient(x, height / 2);
    }
}

// xは0,355,710,0,355,710,..で、yは200
function drawGradient(x, y) {
    // radiusは175.5
    let radius = dim / 2;
    // 色相値を0から360の間でランダムに決める
    let hue = random(0, 360);
    // rを177.5から開始し、rが0より大きい間、1ずつ小さくする
    // rは177.5,176.5,175.5,...0.5と小さくなる。
    // 繰り返し回数は177回。forループ内のコードは1回のdrawGradient()の呼び出しで、
    // 177回実行される
    //let count = 0
    for (let r = radius; r > 0; --r) {
        //print('----------------')
        //print(count + '回め');
        // 塗りをランダムなHSBカラーにする
        fill(hue, 90, 90);
        // 円を描画
        //print(r);
        ellipse(x, y, r, r);
        //print('前: ' + hue);
        // hueを1大きくする => 色相が変化する
        // hueは繰り返しのたびに1ずつ大きくなるが、360より大きくなるとき、
        // 360で割った余り(つまり小さな数値)になるので、
        // hueが360を超えることはない
        hue = (hue + 1) % 360;
        //print('後: ' + hue);
        //print('----------------')
        //count++;
    }
}

<解説>
このサンプルは、カラーを変えてアニメーションする円を3つ描くという複雑なことをしています。行われていることの内容や変数の変化はコード内にコメントで記述しておいたので、そちらを参照してください。このサンプルの特徴は、フレームレートを1秒に1回に抑えたdraw()関数の1回の描画で、HSBカラーモードのhue値をランダムに決め、その値を1ずつ177回大きくする方法で、円形グラデーションを描画していることです。

一方で、もっと単純に、あるカラーから別のカラーまでの円形グラデーションを描画する方法も知りたくなるでしょう。前に見たlerpColor()関数を使うと、同様の方法で描画できます。以下はその例です。

let fromColor, toColor, radius

function setup() {
    createCanvas(400, 300);
    ellipseMode(RADIUS);
    noFill();
    strokeWeight(2);
    noLoop();

    // fromColorとtoColorのカラーを決める
    //fromColor = color(0);
    //toColor = color(255);

    fromColor = color(255, 0, 0);
    toColor = color(0, 0, 255);
    // 円の半径
    radius = 120;
}

function draw() {
    background(230);
    drawGradientByLerpColor(fromColor, toColor, radius);
}

// fromColorとtoColor、半径を受け取り、円形グラデーションを描画する
function drawGradientByLerpColor(col1, col2, rad) {
    // 変数iを0から開始し、半径になるまで、1ずつ大きくする
    for (let i = 0; i <= rad; i++) {
        // 0:radのときのiは、0:1でいくつに相当するか?
        const amt = map(i, 0, rad, 0, 1);
        // カラーの補間
        const col = lerpColor(col1, col2, amt);
        // col色の細い線で円をキャンバスの中心に描画
        stroke(col);
        ellipse(width / 2, height / 2, i, i);
    }
}

カラーの補間(Lerp Color)

繰り返し四辺形をランダムに作成し、そのカラーを赤から青までのカラーで補間します。

function setup() {
    createCanvas(720, 400);
    background(255);
    noStroke();
    frameRate(5);
}

function draw() {
    background(0);
    // 向こうが透けて見えるようにカラーに透明度をつける
    from = color(255, 0, 0, 0.2 * 255);
    to = color(0, 0, 255, 0.2 * 255);
    // toに33%似ている
    c1 = lerpColor(from, to, 0.33);
    // toに66%似ている
    c2 = lerpColor(from, to, 0.66);

    for (let i = 0; i < 15; i++) {
        // 左端の四辺形は赤
        fill(from);
        quad(
            random(-40, 220), random(height),
            random(-40, 220), random(height),
            random(-40, 220), random(height),
            random(-40, 220), random(height)
        );
        // その右の四辺形は赤紫
        fill(c1);
        quad(
            random(140, 380), random(height),
            random(140, 380), random(height),
            random(140, 380), random(height),
            random(140, 380), random(height)
        );
        // その右の四辺形は紫
        fill(c2);
        quad(
            random(320, 580), random(height),
            random(320, 580), random(height),
            random(320, 580), random(height),
            random(320, 580), random(height)
        );
        // 右端の四辺形は青
        fill(to);
        quad(
            random(500, 760), random(height),
            random(500, 760), random(height),
            random(500, 760), random(height),
            random(500, 760), random(height)
        );
    }
}

<解説>
p5.jsのサンプルでは背景を白で描画していますが、ここでは黒に変えています。黒にすると、予想外におどろどろしい感じが出るように思えます。quad()関数については「2_3:p5.js 線、四角形、三角形、長方形を描く」で述べています。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA