pixi.jsで背景を(半)透明にする

pixi.jsが描画するcanvasをオーバーレイしたかったので背景色を半透明にしようとしてました。

f:id:pentamania:20200504141038p:plain
イメージ図

これは一見簡単そう(&地味)ですが、実現するのに若干躓いたのでメモしておきます。

前提

pixi.jsはv5.2.0を使用。主にgoogle chromeで検証してます。(モダンブラウザなら大きな違いはない・・・はず)

以下のような雛形HTMLをベースにしています。
描画結果をわかりやすくするため、canvas背後に確認用divボックスをおいてます。
またpixi側には仮のスプライトを配置します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta http-equiv="x-ua-compatible" content="IE=Edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <title>pixi starter</title>
  <style type="text/css">
    .container {
      position: relative;
    }
    canvas {
      border: 1px solid black;
    }
    .box {
      position: absolute;
      top: 100px;
      left: 100px;
      background: #FADC8D;
      width: 200px;
      height: 200px;
      z-index: -1;
    }
  </style>
</head>
<body>

<div class="container">
  <div class="box">このボックスは確認用</div>
  <canvas id="pixi-view"></canvas>
</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.2.0/pixi.min.js'></script>
<script>
  /* 以降に表記するスクリプトはここに書いたもの */
  const SCREEN_SIZE = 256
  const app = new PIXI.Application({
    width: SCREEN_SIZE,
    height: SCREEN_SIZE,
    view: document.getElementById("pixi-view"),
  });

  // テスト用の星スプライト
  const star = new PIXI.Graphics();
  star.lineStyle(2, 0xFFFFFF);
  star.beginFill(0x35CC5A, 1);
  star.drawStar(0, 0, 5, 50);
  star.endFill();
  star.position.set(app.view.width/2, app.view.height/2)
  app.stage.addChild(star);
  
  // ループ処理
  app.ticker.add((delta)=> {
    star.rotation -= 0.01 * delta;
  });
</script>

以降のコードはところどころ前後省略してますので、そのつもりで適宜補完してください。

背景を完全に透明にするには

はじめに思いつくのが、App(renderer)の生成時のオプションとしてbackgroundColorにアルファ値を渡すことですが、backgroundColorには6桁の16進数でRGB値までしか渡せません(*)。

var app = new PIXI.Application({
  width: SCREEN_SIZE,
  height: SCREEN_SIZE,
  view: document.getElementById("pixi-view"),

  // アルファチャンネルは指定できない
  backgroundColor: 0xff00ff,
  // backgroundColor: 0xff00ff00, // これはうまくいかない
});

(* 厳密には渡せますが、期待したような結果にはなりません)

背景を透明にするにはbackgroundColorではなくtransparentというオプションを指定します。

const app = new PIXI.Application({
  width: 256,
  height: 256,
  view: document.getElementById("pixi-view"),

  transparent: true,
});

ただし気をつけたいのがtransparentと同時にbackgroundColorを指定していると、背後にあるDOMがその設定の影響を(なぜか)受けます。
例えばbackgroundColorがピンクだったら、ピンク色のフィルターがかかったようになります。

const app = new PIXI.Application({
  width: SCREEN_SIZE,
  height: SCREEN_SIZE,
  view: document.getElementById("pixi-view"),

  backgroundColor: 0xff00ff,
  transparent: true,
});

f:id:pentamania:20200504141654p:plain

これはこれで面白いと思いますが、意図してない場合はbackgroundColorは無指定にします。

背景を半透明にするには

では半透明にするにはどうすればいいのでしょうか。
canvas全体の不透明度を変えるだけならCSSでopacityを変更すると言ったこともできますが、スプライト等はそのまま・背景だけを変えたい場合はその方法では駄目です。

これは今の所、スクリーン全体を覆うGraphicsを用意して、それを背景代わりに使う方法しか思いつきませんでした。
(ググっても出てこない)

const backgroundAlpha = 0.8; // 透明度設定

const app = new PIXI.Application({
  width: SCREEN_SIZE,
  height: SCREEN_SIZE,
  view: document.getElementById("pixi-view"),

  // 本来の背景は透明にする
  transparent: true,
});

// 背景代わりのGraphicsを設定
const backgroundVeil = new PIXI.Graphics();
backgroundVeil.beginFill(0x000000, backgroundAlpha);
backgroundVeil.drawRect(0, 0, app.view.width, app.view.height);
backgroundVeil.endFill();
app.stage.addChild(backgroundVeil);

// テスト用の星スプライト
const star = new PIXI.Graphics();
star.lineStyle(2, 0xFFFFFF);
star.beginFill(0x35CC5A, 1);
star.drawStar(0, 0, 5, 50);
star.endFill();

これで冒頭のイメージ図を再現できます。

👇出力サンプル👇

runstant.com