PixiJS を p5.js の上で使いつつ p5.js の描画も組み合わせる(環境は p5.js Web Editor を利用)


以下の記事の続きのような内容になり、今回も開発・実行環境は p5.js Web Editor を利用します。

●PixiJS を p5.js のキャンバスの上で統合させる形で使う(環境は p5.js Web Editor を利用)【試行錯誤の途中】 - Qiita
 https://qiita.com/youtoy/items/bbf9a0790ed9ea353080

この記事でやりたいことは、p5.js で用意したキャンバスを利用しつつ、その上で PixiJS の描画を扱うというものです。上記の記事では、p5.js の draw() から PixiJS の描画に関わるパラメータの変更を行うところまでやっていました。
しかし、p5.js での描画を行って、それを PixiJS と組み合わせた形にするのができていませんでした(描画が変な状態になっていました)。

今回は、この部分の改善対応を進めていきます。

PixiJS と p5.js を組み合わせて使う下準備

今回の内容を試すための下準備として、ライブラリの読み込みなどが必要になります。
そのあたりの話は、冒頭に掲載していた前の記事に書いているので、そちらをご参照ください

PixiJS の背景透過

前回やろうとして、うまくいっていなかった PixiJS の背景透過から着手します。
ググってみると、以下のやり方ができそうだということが分かりました。

●pixi.jsで背景を半透明にする | Runstant
 http://runstant.com/pentamania/projects/82dc0e31

●Transparent Background - PixiJS Examples
 https://pixijs.io/examples/#/demos-basic/transparent-background.js

上記のものは、 PIXI.Application() の中でのオプション指定で transparent: true を指定する、というもののようでした。これを、前回の記事で作ったプログラムで試すと、メインのキャンバスの背景透過が実現できました。

さらに、p5.js の描画を PixiJS と組み合わせて意図通りの描画をさせる、というものに着手していきます。

p5.js の描画と PixiJS の描画とを組み合わせる

前回の記事では、p5.js で作成したキャンバスを直接 PixiJS の Application() を紐付けて、この状態で、p5.js のキャンバス上で描画を行ってみたら、意図しない描画の崩れが発生していました。原因に関しては、PixiJS の描画との競合が生じたのか、または別の原因なのかは分かっていない状態でした。

これを改善する方法を考えてみたのですが、PixiJS の描画を p5.js のメインのキャンバスと切り離してやれば良いのではないかと思いました。具体的には、 createGraphics() を使って PixiJS用の描画レイヤーを準備し、p5.js のメインのキャンバスはこれと分けるという戦略です。

createGraphics() を使った方法を試す

結論から書くと、 createGraphics() を使って PixiJS の描画用レイヤーを作るという方法で、問題は解決できました。まず、そのプログラムを掲載します。

let pg;
let app, bunny;

function setup() {
  createCanvas(400, 400);
  pg = createGraphics(width, height, WEBGL);

  app = new PIXI.Application({
    view: pg.elt,
    width: width,
    height: height,
    backgroundColor: 0x2c3e50,
    transparent: true,
  });
  app.loader
    .add("bunny", "https://pixijs.io/examples/examples/assets/bunny.png")
    .load(startup);
}

function startup() {
  bunny = new PIXI.Sprite(app.loader.resources.bunny.texture);

  bunny.anchor.set(0.5);
  bunny.x = app.renderer.width / 2;
  bunny.y = app.renderer.height / 2;
  app.stage.addChild(bunny);
}

function draw() {
  background(220);

  if (bunny) {
    bunny.rotation += 0.1;

    rect(frameCount % width, frameCount % height, 100, 100);
    
    fill(100, 100, 190);
    image(pg, 0, 0);
  }
}

先ほど書いていたように、 PIXI.Application() で、transparent: true を指定しました。また、PixiJS の描画は、WebGLモードを設定した createGraphics()` で作った部分に紐付けて、p5.js で作成したメインのキャンバス上に image()` で描画するような形にしています。
そして、PixiJS による描画をメインのキャンバスに描画する前に、p5.js による矩形の描画を行うようにしてみました。

これを実行した結果は以下の通りで、想定通りの動作になりました。

なお、オプション指定の部分で、透過させる背景に backgroundColor: 0x2c3e50 という背景色指定をしていますが、これは透過が失敗した時のために分かりやすいように設定したものです。背景透過がうまくいった場合は、設定した意味がないものになります。

スプライトの個数を増やしてみる

次に、描画するスプライトの数を複数にしてみます。

具体的なプログラムは以下となります。

let pg;
const spriteNumMax = 4;
let app,
  bunny = Array(spriteNumMax);

function setup() {
  createCanvas(400, 400);
  pg = createGraphics(width, height, WEBGL);

  app = new PIXI.Application({
    view: pg.elt,
    width: width,
    height: height,
    backgroundColor: 0x2c3e50,
    transparent: true,
  });
  app.loader
    .add("bunny", "https://pixijs.io/examples/examples/assets/bunny.png")
    .load(startup);
}

function startup() {
  for (let i = 0; i < spriteNumMax; i++) {
    bunny[i] = new PIXI.Sprite(app.loader.resources.bunny.texture);

    bunny[i].anchor.set(0.5);
    bunny[i].x = app.renderer.width * 0.3 + 50 * i;
    bunny[i].y = app.renderer.height * 0.3 + 50 * i;
    app.stage.addChild(bunny[i]);
  }
}

function draw() {
  background(220);

  if (bunny[spriteNumMax - 1]) {
    for (let i = 0; i < spriteNumMax; i++) {
      bunny[i].rotation += 0.05 * (i + 1);
    }

    rect(frameCount % width, frameCount % height, 100, 100);

    fill(100, 100, 190);
    image(pg, 0, 0);
  }
}

そして、動作している時の様子は以下のとおりです。

無事に意図通りに動きました。

おわりに

今回、p5.js で作ったメインのキャンバス上で、PixiJS と p5.js の描画を両方扱うような処理を試しました。

今後は、PixiJS が得意で p5.js には標準実装されていなそうな処理を扱うネタをやっていければと思います。

【追記】 その後の進捗

元々やりたかったこととして、p5.jsベースのプログラムの中で PixiJS のフィルタを使う、というものがあったのですが、それができそうな感じになってきました。