ギンの備忘録

デジタルアートやプログラミングやテクノロジー関連のこと。

p5.jsのP2DとWebGLの透過度による描写の違い

p5.jsのP2DとWebGLの透過度によって描写が異なっている様な気がします。
ブラウザ上では違いが分からないのですが、画像として保存した時に差異が顕在化しました。 比較のために半透明の四角形を明度、彩度を変えて描写したものを見てみましょう。
保存形式はpngとしています。

P2Dによる描写

f:id:gin_graphic:20201023073016p:plain:w250 f:id:gin_graphic:20201023073155p:plain:w250

WebGLによる描写

f:id:gin_graphic:20201023073026p:plain:w250 f:id:gin_graphic:20201023073211p:plain:w250

何が起きているのだろう

おそらくですが、WebGLモードで保存した画像に何かありそうな気がしますね。
背景を黒の描写を見ると分かりやすいですが、WebGLモードの方は保存した画像が半透明なんですね。
WebGLの方は保存した画像にアルファ値が残っているというか、有効になっているということですかね。
P2Dの方は保存した画像自体にはアルファ値が残っていないのかな。

詳細考察

保存された画像を解析していきます。
今回はLinux環境でコマンドidentify -verbose hoge.pngにて画像情報を比較していきます。

画像情報から差分が見えたので、わかりやすい部分を以下に抜粋します。

  • P2D保存PNG画像

Channel depth:
Red: 8-bit
Green: 8-bit
Blue: 8-bit
Alpha: 1-bit
Channel statistics:
...
Alpha:
min: 255 (1)
max: 255 (1)
mean: 255 (1)

Channel depth:
Red: 8-bit
Green: 8-bit
Blue: 8-bit
Alpha: 8-bit
Channel statistics:
...
Alpha:
min: 191 (0.74902)
max: 255 (1)
mean: 233.487 (0.915635)

アルファ値の深度が異なっています。 P2Dでは1bit、WebGLでは8bitです。
P2Dではアルファ値は無効な状態(どのピクセルも透明でない)で使われていないですが、 WebGLではアルファ値も描写した通りに保存されています。

保存形式の差がP2DとWebGLではあるようで、 それよって描写が異なる様に見えたということでした。 jpegで保存した場合にどうなるのかなど調べきれていない部分はありますが、 個人的にWebGLの透明度が残ることがわからず悩まされました。 原因を突き止めることができたのでよかったです。

最後に、今回使ったソースコードを以下に記載しておきます。

P2D描写でのソースコード

let bg=100;
let nx=7;
let ny=5;
let d=50;

function setup() {
   createCanvas(500, 500);

   colorMode(HSB);
   rectMode(CENTER);
   background(bg);

   strokeWeight(1);
   stroke(0,0,50,0.5);

   for(let i=0;i<nx;i++){
      for(let j=0;j<ny;j++){
         let col = color(360/(nx-1)*i ,(i==0)?0:100 , 100/ny*j, 0.5) ;
         let x = (i+0.5)*width/nx;
         let y = (j+0.5)*height/ny;
         push();
         fill(col);
         translate(x, y);
         rect(0, 0, d);
         pop();
      }
   }
}

function keyPressed(){
   //save PNG
   save("img_"+month()+day()+hour()+minute()+second()+".png");
}

WebGL描写でのソースコード

let bg=100;
let nx=7;
let ny=5;
let d=50;

function setup() {
   createCanvas(500, 500, WEBGL);

   colorMode(HSB);
   rectMode(CENTER);
   background(bg);
   translate(-width/2, -height/2);

   strokeWeight(1);
   stroke(0,0,50,0.5);

   for(let i=0;i<nx;i++){
      for(let j=0;j<ny;j++){
         let col = color(360/(nx-1)*i ,(i==0)?0:100 , 100/ny*j, 0.5) ;
         let x = (i+0.5)*width/nx;
         let y = (j+0.5)*height/ny;
         push();
         fill(col);
         translate(x, y);
         rect(0, 0, d);
         pop();
      }
   }
}

function keyPressed(){
   //save PNG
   save("img_"+month()+day()+hour()+minute()+second()+".png");
}