Babylon.js の公式ミニマムサンプル の HTML に Webカメラの映像の表示を足してみる

この記事は、以下の記事の続きです。

●Babylon.js を実行するミニマムな HTML について調べてみた ＆ ミニマムな変更を加えてみる - Qiita
　https://qiita.com/youtoy/items/7ccaab2d8f90c1f5ff76

今回の記事では、「Webカメラ映像を利用する」という内容を追加したのですが、その理由は「Webカメラの映像に対する画像認識処理を行う仕組み」を作って試したかったためです（※ 具体的には以下の内容）。

https://twitter.com/youtoy/status/1624737044084957185

これまで、ブラウザ上での「Webカメラの映像に対する画像認識処理を使った仕組み」は、描画の部分にp5.js という描画ライブラリを組み合わせたものをいろいろ試してきました。

しかし、それと似たようなことを Babylon.js でやってみようと思った時、そもそも Babylon.js で Webカメラを利用するというのは試したことがなかったので、まずはその部分をシンプルに実現する内容を作ってみました。

## Babylon.js で Webカメラを使う
### BABYLON.VideoTexture の CreateFromWebCam
公式の情報などで、「Babylon.js で Webカメラを使う方法」を調べてみると、以下の「CreateFromWebCam」を使う方法があるようでした。

●BABYLON.VideoTexture の CreateFromWebCam
　https://doc.babylonjs.com/typedoc/classes/BABYLON.VideoTexture#CreateFromWebCam

（他に Webカメラに関連しそうなものは「[CreateFromWebCamAsync](https://doc.babylonjs.com/typedoc/classes/BABYLON.VideoTexture#CreateFromWebCamAsync)」や「[CreateFromStreamAsync](https://doc.babylonjs.com/typedoc/classes/BABYLON.VideoTexture#CreateFromStreamAsync)」というものもあるようでした）

### Babylon.js Playground上のサンプル
Babylon.js Playground上のサンプルで、CreateFromWebCam が使われているものを見てみます。検索などで探して、出てきたものをいくつか掲載してみます。

- [CreateFromWebCam | Babylon.js Playground](https://www.babylonjs-playground.com/#1R77YT#2)
- [live cam sphere | Babylon.js Playground](https://playground.babylonjs.com/#582KAL#2)
- [webcam playground | Babylon.js Playground](https://www.babylonjs-playground.com/#8TGMEQ#0)

この内容も参考にしつつ、実装をしてみます。

### Webカメラを利用してみる
[前回の記事の中で作った HTML](https://qiita.com/youtoy/items/7ccaab2d8f90c1f5ff76) に、Webカメラ周りの処理を追加してみます（その他の部分も、少しパラメータを変えてみたり）。

```html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Babylon Template</title>

    <style>
      html,
      body {
        overflow: hidden;
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
      }
      #renderCanvas {
        width: 100%;
        height: 100%;
        touch-action: none;
      }
    </style>

    <script src="https://cdn.babylonjs.com/babylon.js"></script>
  </head>

  <body>
    <canvas id="renderCanvas"></canvas>

    <script>
      const canvas = document.getElementById("renderCanvas");
      const engine = new BABYLON.Engine(canvas, true);

      const createScene = function () {
        const scene = new BABYLON.Scene(engine);

        const camera = new BABYLON.FreeCamera(
          "camera1",
          new BABYLON.Vector3(0.5, 5, -8),
          scene
        );
        camera.setTarget(BABYLON.Vector3.Zero());
        camera.attachControl(canvas, true);
        camera.rotation.x -= Math.PI * 0.05;

        const light = new BABYLON.HemisphericLight(
          "light",
          new BABYLON.Vector3(0, 1, 0),
          scene
        );
        light.intensity = 0.7;

        const plane1 = BABYLON.Mesh.CreatePlane("plane1", 7, scene);
        plane1.rotation.z = Math.PI;
        plane1.position.y = 1;
        const videoMaterial = new BABYLON.StandardMaterial("texture1", scene);
        videoMaterial.emissiveColor = new BABYLON.Color3(1, 1, 1);

        BABYLON.VideoTexture.CreateFromWebCam(
          scene,
          function (videoTexture) {
            videoMaterial.diffuseTexture = videoTexture;
            plane1.material = videoMaterial;
          },
          { maxWidth: 256, maxHeight: 256 }
        );

        return scene;
      };

      scene = createScene();
      engine.runRenderLoop(function () {
        scene.render();
      });
      window.addEventListener("resize", function () {
        engine.resize();
      });
    </script>
  </body>
</html>
```

Webカメラ用の処理で追加した部分は、以下のとおりです。

```javascript
        const plane1 = BABYLON.Mesh.CreatePlane("plane1", 7, scene);
        plane1.rotation.z = Math.PI;
        plane1.position.y = 1;
        const videoMaterial = new BABYLON.StandardMaterial("texture1", scene);
        videoMaterial.emissiveColor = new BABYLON.Color3(1, 1, 1);

        BABYLON.VideoTexture.CreateFromWebCam(
          scene,
          function (videoTexture) {
            videoMaterial.diffuseTexture = videoTexture;
            plane1.material = videoMaterial;
          },
          { maxWidth: 256, maxHeight: 256 }
        );
```

Webカメラの映像を表示する部分として、Plane を用意しています。
そして、その後でマテリアルを準備したり、Webカメラの映像を Plane に表示させたりする処理を行っています。

これを実行すると、以下のように Webカメラの映像を表示することができました。

![Webカメラの映像の表示](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/1c013262-419c-cf10-fca6-f0a7e22a302a.png)

## 余談
MediaPipe の JavaScript版は、これまで p5.js と組み合わせて、光学迷彩とか超簡易VTuber とか試作をいろいろやってました（以下は、光学迷彩を作ってみた、という事例の 1つ）。

https://twitter.com/youtoy/status/1558731638783492099