Processing filter(BLUR) の影色をコントロール

2022年10月9日日曜日

Processing テクニック

t f B! P L

Processing の filter(BLUR) 関数でぼやけさせるとき、影が黒っぽくなってしまう現象をコントロールしてみます。

👉 Read this article in English.

前回の記事「僕の Processing が p5.js の drawingContext に負けるはずがない!」で、白い円をランダムにぼやけさせるコードを書きました。

そのときに生成された画像がこちらです。

レイヤー毎にランダムにボヤケさせる

元々こちらの例にあるような p5.js の drawingContext での効果を模倣しようと作ったものです。


このときは、p5.js での結果と Processing の結果でなんとなくニュアンスが違うなと、単にそう思っていただけでした。

 

影が黒くなるわけ

このニュアンスの違いについて、えみーんさんから Tweet をいただき、「あ、私のは黒い影が出てるんだ」と気付きました。


なぜ黒い影が出てしまうのか?「黒」で思い当たるのはコードのこの部分です。


p.background(0.0, 0.0);

全体のコードはこちらです。


/**
 * ランダムなボケのレイヤーを重ねる
 * 
 * @author @deconbatch
 * @version 0.1
 * @license CC0
 * Processing 3.5.3
 * created 2022.09.23
 */

void setup(){

  size(640, 640);

  int layerNum  = 12; // レイヤー数

  background(0.0);
  for (int i = 0; i < layerNum; i++) {
    image(
          getLayer(
                   random(10.0) // ランダムなボケ
                   ),
          0, 0);
  }

}

/**
 * getLayer : _blur 分の BLUR をかけたレイヤーを返す
 */
PGraphics getLayer(float _blur) {

  int cNum = 24;

  PGraphics p = createGraphics(width, height);
  p.beginDraw();
  p.background(0.0, 0.0);
  p.noStroke();
  p.fill(240.0);
  for (int i = 0; i < cNum; i++) {
    p.circle(
             random(width),
             random(height),
             random(60.0)
             );
  }
  p.filter(BLUR, _blur);
  p.endDraw();
  return p;

}


レイヤーを複数重ねるため背景を透明にしているのですが、そのときに指定していた明度がゼロ、つまり「黒」でした。

試しにこの明度を上げてみましょう。


p.background(240.0, 0.0);

影が白くなりました!

 

影の色をコントロール

どうやら背景の明度、いやたぶん「色」が、ぼやけたときの影に影響を与えているようです。確認のため、青っぽい色を背景に指定してみます。透明度はゼロのままです。


p.background(64.0, 128.0, 255.0, 0.0);


ピンクにすると?


p.background(255.0, 128.0, 222.0, 0.0);


やはり、背景の「色」が影の色になるようです。

レイヤー毎に色を変えてみると、このとおり。


  p.colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
  p.background(random(210.0, 360.0), 80.0, 90.0, 0.0);

 

影の色をまだらにできる?

背景の色を指定することで、影の色をキャンバス全体で一様に決めることはできました。では、キャンバスの部分毎に色を変えることはできるでしょうか?

なんかおかしい…

例えば、p.background() の替わりに、このようなコードを書いてみました。キャンバスを4分割し、それぞれの色を変えています。


  int div = 2;
  p.blendMode(REPLACE);
  p.noStroke();
  for (int x = 0; x < div; x++) {
    for (int y = 0; y < div; y++) {
      float rw = width / div;
      float rh = height / div;
      p.fill(
             (x * 60.0 + y * 150.0) % 360.0,
             80.0,
             90.0,
             0.0
             );
      p.rect(x * rw, y * rh, rw, rh);
    }
  }

p.blendMode(REPLACE); が肝です。結果はこのようになります。


うん!うまく行って… あれ?何か変です。

よく見ると、それぞれの区分の左端だけが黒い影になっています。四角形の透明度を 100.0 にするとこうなるので、塗りそこねてるわけじゃありません。

64分割にして円を黒くすると、うまく行っていないことがよりはっきりとわかります。

どうも、各 rect() の左端だけ色が反映されていないようです。

 

苦肉の策

いろいろとトライしてみましたが、この問題は解決できませんでした。

苦肉の策として、透明度を 0.0 じゃなくて 1.0 にすることで、rect() の左端にも色を反映させることはできます。

しかし、完全な透明ではないので、背景に色が若干残ってしまいます。

 

そういうとこも可愛い

思ったとおりに動いてくれないのは困ります。しかし、こういうところも Processing が完成された既成の製品ではなく、人の手による手作りの環境という感じがして、私は好きなのです。

最後に影に色をつけた作例を紹介します。



/**
 * ランダムなボケでカラフルでファンシーな絵を作る
 *
 * @author @deconbatch
 * @version 0.1
 * @license CC0
 * Processing 3.5.3
 * created 2022.10.08
 */

void setup(){

  size(640, 640);
  smooth();
  
  int layerNum  = 12; // レイヤー数

  background(255.0);
  blendMode(SUBTRACT);
  for (int i = 0; i < layerNum; i++) {
    image(
          getLayer(
                   random(10.0) // ランダムなボケ
                   ),
          0, 0);
  }
  
}

/**
 * getLayer : _blur 分の BLUR をかけたレイヤーを返す
 */
PGraphics getLayer(float _blur) {

  PGraphics p = createGraphics(width, height);
  p.beginDraw();
  p.colorMode(HSB, 360.0, 100.0, 100.0, 100.0);

  // ランダム色の格子柄
  int div = 8;
  p.blendMode(REPLACE);
  p.noStroke();
  for (int x = 0; x < div; x++) {
    for (int y = 0; y < div; y++) {
      int rw = round(width / div);
      int rh = round(height / div);
      int rx = x * rw;
      int ry = y * rh;
      p.fill(
             random(360.0),
             90.0,
             80.0,
             1.0
             );
      p.rect(rx, ry, rw, rh);
    }
  }

  // ランダム配置の円
  int cNum = 12;
  p.blendMode(BLEND);
  p.fill(0.0, 0.0, 0.0, 100.0);
  for (int i = 0; i < cNum; i++) {
    p.circle(
             random(width),
             random(height),
             pow(random(9.0), 2)
             );
  }
  p.filter(BLUR, _blur);
  p.endDraw();
  return p;

}

 

参考までに、今回の実行環境

上記実行時の環境は Processing 3.5.3 on Linux でした。

試しに Processing 4.0.1 on Linux で実行したら、rect() の右端と下端に色が付かないという結果になりました。

 

QooQ