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 を組み合わせて使う下準備
今回の内容を試すための下準備として、ライブラリの読み込みなどが必要になります。
そのあたりの話は、[冒頭に掲載していた前の記事](https://qiita.com/youtoy/items/bbf9a0790ed9ea353080)に書いているので、そちらをご参照ください


## 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 の描画用レイヤーを作るという方法で、問題は解決できました。まず、そのプログラムを掲載します。

```javascript
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 による矩形の描画を行うようにしてみました。

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

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> のキャンバス上で、 <a href="https://twitter.com/hashtag/PixiJS?src=hash&amp;ref_src=twsrc%5Etfw">#PixiJS</a> の描画と p5js の描画の両方を扱う処理、うまくいったっぽい！<br><br>中央で画像が回転しているのが PixiJS での描画で、青っぽい四角が動いているのが p5.js による描画で、メインのキャンバスは p5.js の createCanvas() で生成したもののみを用いています。 <a href="https://t.co/p8gsWOMzhc">pic.twitter.com/p8gsWOMzhc</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1505169226700832772?ref_src=twsrc%5Etfw">March 19, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

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

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

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

```javascript
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);
  }
}
```

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

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">先ほどの、<a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> のキャンバス上で、 <a href="https://twitter.com/hashtag/PixiJS?src=hash&amp;ref_src=twsrc%5Etfw">#PixiJS</a> の描画と p5js の描画の両方を扱う処理のお試しの続き。<br><br>PixiJS で描画するスプライトの数を複数にしてみた（回転している 4つ）。青っぽい四角が動いている p5.js での描画は先ほどのものと同じ処理で変わりないです。<br><br>うまく動いてる！ <a href="https://t.co/S1qRyL1jkG">pic.twitter.com/S1qRyL1jkG</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1505176807523614725?ref_src=twsrc%5Etfw">March 19, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

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

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

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


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

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【p5.js と PixiJS を混ぜるお試しの続き】<br>ついに p5.js Web Editor上の <a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> をベースにしたプログラムで、 <a href="https://twitter.com/hashtag/PixiJS?src=hash&amp;ref_src=twsrc%5Etfw">#PixiJS</a> のグローフィルタ（PIXI.filters.GlowFilter）を適用する、というのができた！<br><br>キー操作でフィルタの ON/OFF もできるようにしていて、動画ではその切り替えも行っています。 <a href="https://t.co/FhxTUfnKPO">pic.twitter.com/FhxTUfnKPO</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1505462139691343873?ref_src=twsrc%5Etfw">March 20, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【カーソルの座標に合わせてグローフィルタのパラメータを変化させる】<br>p5.js Web Editor上の <a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> ベースのプログラムで、 <a href="https://twitter.com/hashtag/PixiJS?src=hash&amp;ref_src=twsrc%5Etfw">#PixiJS</a> のグローフィルタ（PIXI.filters.GlowFilter）を使う話の続き。<br><br>p5.js の mouseX・mouseY の値によって、グローフィルタの色・光り方の強度が変わるようにしてみた。 <a href="https://t.co/7yARnZXi3d">pic.twitter.com/7yARnZXi3d</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1505699305088503812?ref_src=twsrc%5Etfw">March 21, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>