Processing/p5.js で、手書きの線で囲ったようなキャンバスを

2022年10月19日水曜日

p5.js Processing テクニック

t f B! P L
雑な線で描く手作り感キャンバス

いつも真四角のキャンバスじゃ、つまらない!

ということで、miku さんのこちらのツイートを参考にさせていただいて、手書きの線で囲ったようなキャンバス、背景を作ってみたいと思います。


👉 Read this article in English.

絵画に見られるような下塗りの表現に使えるかもしれません。

A Veil, a Printed Image 1891 Odilon Redon

A Veil, a Printed Image 1891 Odilon Redon French | The Metropolitan Museum of Art | Open Access

 

4本の雑な線でキャンバスを描く

先のツイートの手法を使って、四角形の4辺に沿って順番に線を引いていけば、「雑な線」で描いた四角形ができるはずです。

四角形の四辺

Processing/p5.js のvertex() 系の関数を使えば、線だけの四角形も描けるし、


内部を塗った四角形も描けるので、作品作りでの使いみちが広がりそうです。

 

Processing サンプルコード

Processing の bezierVertex() を使うことで、曲線での囲み図形を描けます。

bezierVertex() | Reference / Processing.org

ここでは内部を塗った四角形のサンプルコードを書きました。


/**
 * 雑な線で描く手作り感キャンバス
 * ref. https://twitter.com/BaroqueEngine/status/1580529748115353602
 * 
 * @author @deconbatch
 * @version 0.1
 * @license CC0
 * Processing 3.5.3
 * created 2022.10.17
 */

void setup(){
  size(640, 800);
  colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
  smooth();
  noLoop();

  float margin = 120.0;
    
  background(0.0, 0.0, 90.0, 100.0);
  
  pushMatrix();
  translate(margin * 0.5, margin * 0.5);
  noStroke();
  fill(40.0, 15.0, 80.0, 100.0);
  handDrawnRect(width - margin, height - margin, 0.05);
  popMatrix();

}

/**
 * handDrawnRect : draw hand-drawn rectangle
 * _w, _h : rectangle width, height
 * _t     : twist ratio
 */
void handDrawnRect(float _w, float _h, float _t) {
  beginShape();
  twistedVertex(0.0, 0.0, _w, 0.0, _t); // upper
  twistedVertex(_w, 0.0, _w, _h, _t);   // right
  twistedVertex(_w, _h, 0.0, _h, _t);   // bottom
  twistedVertex(0.0, _h, 0.0, 0.0, _t); // left
  endShape();
}

/**
 * handDrawnRect : draw background
 * _sx, _sy : start point
 * _ex, _ey : end point
 * _t       : twist ratio
 */
void twistedVertex(float _sx, float _sy, float _ex, float _ey, float _t) {
  float dLen = dist(_sx, _sy, _ex, _ey) * _t;
  float secL = random(0.2, 0.4);
  float trdL = secL * 2.0;

  vertex(_sx, _sy);
  bezierVertex(
               lerp(_sx, _ex, secL) + random(-1.0, 1.0) * dLen,
               lerp(_sy, _ey, secL) + random(-1.0, 1.0) * dLen,
               lerp(_sx, _ex, trdL) + random(-1.0, 1.0) * dLen,
               lerp(_sy, _ey, trdL) + random(-1.0, 1.0) * dLen,
               _ex,
               _ey
               );
}

 

p5.js サンプルコード

p5.js でも同様に bezierVertex() が使えます。

bezierVertex() | reference | p5.js

Processing でのサンプルコードとほぼ同じものですけど、皆様の移植のお手間を省くために掲載いたしました。


/**
 * 雑な線で描く手作り感キャンバス
 * ref. https://twitter.com/BaroqueEngine/status/1580529748115353602
 * 
 * @author @deconbatch
 * @version 0.1
 * p5.js 1.1.3
 * created 2022.10.17
 */

function setup() {
  createCanvas(640, 800);
  colorMode(HSB, 360, 100, 100, 100);
  smooth();
  noLoop();

  const margin = 120.0;
    
  background(0, 0, 90, 100);
  
  push();
  translate(margin * 0.5, margin * 0.5);
  noStroke();
  fill(40, 15, 80, 100);
  handDrawnRect(width - margin, height - margin, 0.03);
  pop();
}

/**
 * handDrawnRect : draw hand-drawn rectangle
 * _w, _h : rectangle width, height
 * _t     : twist ratio
 */
function handDrawnRect(_w, _h, _t) {
  beginShape();
  twistedVertex(0.0, 0.0, _w, 0.0, _t); // upper
  twistedVertex(_w, 0.0, _w, _h, _t);   // right
  twistedVertex(_w, _h, 0.0, _h, _t);   // bottom
  twistedVertex(0.0, _h, 0.0, 0.0, _t); // left
  endShape();
}

/**
 * handDrawnRect : draw background
 * _sx, _sy : start point
 * _ex, _ey : end point
 * _t       : twist ratio
 */
function twistedVertex(_sx, _sy, _ex, _ey, _t) {
  const dLen = dist(_sx, _sy, _ex, _ey) * _t;
  const secL = random(0.2, 0.4);
  const trdL = secL * 2.0;

  vertex(_sx, _sy);
  bezierVertex(
               lerp(_sx, _ex, secL) + random(-1.0, 1.0) * dLen,
               lerp(_sy, _ey, secL) + random(-1.0, 1.0) * dLen,
               lerp(_sx, _ex, trdL) + random(-1.0, 1.0) * dLen,
               lerp(_sy, _ey, trdL) + random(-1.0, 1.0) * dLen,
               _ex,
               _ey
              );
}


p5.js の場合は手書き風の線や面を描けるライブラリ「p5.scribble」等を使う手もあります。


function setup() {
  createCanvas(640, 800);
  colorMode(HSB, 360, 100, 100, 100);
  smooth();
  noLoop();

  const margin = 60.0;
  
  background(0, 0, 90, 100);

  const sb = new Scribble();
  const xc = [margin, width - margin,
              width - margin, margin]
  const yc = [margin, margin,
              height - margin, height - margin]
  stroke(40, 15, 80, 100);
  strokeWeight(6);
  sb.scribbleFilling(xc, yc, 5, -30);
}

p5.scribble で描いた四角形

 

ちょっとひと工夫

四角形の頂点を合わせるため、始点と終点にはランダムなズレは盛り込みませんでした。

始点と終点をランダムにすると、塗りのときはいいとして、線だけのときにこうなってしまいます。無理に一筆書きで描いているような不自然な感じですね。

無理に一筆書きしたような四角

線だけのときは beginShape() と endShape() を辺ごとに切って、一筆書きじゃなくするといいかもしれません。

一辺毎に線を引いた四角形

 

既存の絵画の模倣ではなく

これで思っていた「手書きの線で囲ったようなキャンバス・背景」が描けました。あとは、この背景の上に何を描くかですね。

先に「絵画に見られるような下塗りの表現に使えるかもしれません」と言いましたが、あくまで自分の作品の背景に変化をつけるという意味で使いたいところです。既存の絵画を模倣するということではなく、クリエイティブ・コーディングならではの表現を目指すことを忘れないでいきたいと思います。

作例
作例

 

QooQ