Babylon.js Playground にあるの公式サンプル「Particle System Examples」を最小化してみたり利用するパーティクル用画像を変えてみたりする

## はじめに
この記事では、以前書いた以下の記事でも使った [Babylon.js Playground上の公式サンプル「Particle System Examples」](https://playground.babylonjs.com/#0K3AQ2#3067)を扱います。

●Babylon.js Playground上のサンプルで自分が欲しい部分を ChatGPT に取り出してもらう【完走賞ゲット-22】 - Qiita
　https://qiita.com/youtoy/items/051e8e723dbd2bd72dff

上記の記事では、Babylon.js Playground上のコードを最小化していたのですが、今回は HTML のファイル全体を最小化してみます。
また、パーティクルシステムで利用されている画像を別のものに変更する、というのもやってみます。

## 今回の内容
Babylon.js Playground上でコードを扱う際には、JavaScript のプログラムの一部のみを編集するだけで処理を実行でき、HTML や CSS などの記載は考慮せずに扱えるので便利です。
しかし、これを別のサーバーでホスティングしようとすると、HTML や CSS、そして JavaScript の処理全体を記載する必要があります。

単純に動かすだけなら、Babylon.js Playground からファイルのダウンロードをすれば、HTML ＋ CSS ＋ JavaScript の全体を含むものを入手できます。

しかし、そこで入手できる内容は、処理に不要なライブラリをロードしていたりするものになっています。

### HTML を最小化する
以前、Babylon.js のシンプルな処理を行う際に、最低限必要な内容を書いたものを準備する、ということをやったことがありました。そして、その内容を以下の記事に書いています。

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

今回、それと似たようなことをやってみます。

#### ロードするライブラリを必要なものだけにする
Babylon.js Playground から入手できるファイルの不要な部分を除く、というのをやってみます。

冒頭でロードされているライブラリは以下の通りですが、「Particle System Examples」の処理では不要なものが多そうです。
実際、コメントアウトして処理に影響のないものを見ていくと、残す必要があったのは babylon.js のみでした。

```html
    <!-- Babylon.js -->
    <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script> -->
    <!-- <script src="https://assets.babylonjs.com/generated/Assets.js"></script> -->
    <!-- <script src="https://cdn.babylonjs.com/recast.js"></script> -->
    <!-- <script src="https://cdn.babylonjs.com/ammo.js"></script> -->
    <!-- <script src="https://cdn.babylonjs.com/havok/HavokPhysics_umd.js"></script> -->
    <!-- <script src="https://cdn.babylonjs.com/cannon.js"></script> -->
    <!-- <script src="https://cdn.babylonjs.com/Oimo.js"></script> -->
    <!-- <script src="https://cdn.babylonjs.com/earcut.min.js"></script> -->
    <script src="https://cdn.babylonjs.com/babylon.js"></script>
    <!-- <script src="https://cdn.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script> -->
    <!-- <script src="https://cdn.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script> -->
    <!-- <script src="https://cdn.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script> -->
    <!-- <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.js"></script> -->
    <!-- <script src="https://cdn.babylonjs.com/serializers/babylonjs.serializers.min.js"></script> -->
    <!-- <script src="https://cdn.babylonjs.com/gui/babylon.gui.min.js"></script> -->
    <!-- <script src="https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js"></script> -->
```

#### JavaScript　の処理を少し編集する
最小化とは関係ないですが、JavaScript　の処理を少し編集します。

具体的には、var を let や const に変えておきます。それに伴い `window.addEventListener()` を除き `window.` がついている部分は除くなどしました。

#### 変更後のコード
上記の対応を行った変更後のコードは以下のとおりです。

```html
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <title>Babylon.js sample code</title>
    <script src="https://cdn.babylonjs.com/babylon.js"></script>

    <style>
      html,
      body {
        overflow: hidden;
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
      }

      #renderCanvas {
        width: 100%;
        height: 100%;
        touch-action: none;
      }

      #canvasZone {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="canvasZone"><canvas id="renderCanvas"></canvas></div>
    <script>
      const canvas = document.getElementById("renderCanvas");

      const startRenderLoop = function (engine, canvas) {
        engine.runRenderLoop(function () {
          if (sceneToRender && sceneToRender.activeCamera) {
            sceneToRender.render();
          }
        });
      };

      let engine = null;
      let scene = null;
      let sceneToRender = null;
      const createDefaultEngine = function () {
        return new BABYLON.Engine(canvas, true, {
          preserveDrawingBuffer: true,
          stencil: true,
          disableWebGL2Support: false,
        });
      };

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

        const light0 = new BABYLON.PointLight(
          "Omni",
          new BABYLON.Vector3(0, 2, 8),
          scene
        );
        const camera = new BABYLON.ArcRotateCamera(
          "ArcRotateCamera",
          -Math.PI / 2,
          (7 * Math.PI) / 16,
          20,
          new BABYLON.Vector3(0, 0, 0),
          scene
        );
        camera.attachControl(canvas, true);

        const ground = BABYLON.Mesh.CreatePlane("ground", 50.0, scene);
        ground.position = new BABYLON.Vector3(0, -50, 0);
        ground.rotation = new BABYLON.Vector3(Math.PI / 2, 0, 0);
        ground.material = new BABYLON.StandardMaterial("groundMat", scene);
        ground.material.backFaceCulling = false;
        ground.material.diffuseColor = new BABYLON.Color3(0.3, 0.3, 1);

        const particleSystem = new BABYLON.ParticleSystem(
          "particles",
          2000,
          scene
        );
        particleSystem.particleTexture = new BABYLON.Texture(
          "textures/flare.png",
          scene
        );

        particleSystem.emitter = BABYLON.Vector3.Zero(); // the starting position
        particleSystem.minEmitBox = new BABYLON.Vector3(-1, -1, -1); // Bottom Left Front
        particleSystem.maxEmitBox = new BABYLON.Vector3(1, 1, 1); // Top Right Back

        particleSystem.color1 = new BABYLON.Color4(0.7, 0.8, 1.0, 1.0);
        particleSystem.color2 = new BABYLON.Color4(0.2, 0.5, 1.0, 1.0);
        particleSystem.colorDead = new BABYLON.Color4(0, 0, 0.2, 0.0);

        particleSystem.minSize = 0.1;
        particleSystem.maxSize = 0.5;

        particleSystem.minLifeTime = 0.3;
        particleSystem.maxLifeTime = 1.5;

        particleSystem.emitRate = 1500;

        particleSystem.blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE;

        particleSystem.gravity = new BABYLON.Vector3(0, -9.81, 0);

        particleSystem.direction1 = new BABYLON.Vector3(-7, 8, 3);
        particleSystem.direction2 = new BABYLON.Vector3(7, 8, -3);

        particleSystem.minAngularSpeed = 0;
        particleSystem.maxAngularSpeed = Math.PI;

        particleSystem.minEmitPower = 1;
        particleSystem.maxEmitPower = 3;
        particleSystem.updateSpeed = 0.005;

        particleSystem.start();

        return scene;
      };

      const initFunction = async function () {
        const asyncEngineCreation = async function () {
          try {
            return createDefaultEngine();
          } catch (e) {
            console.log(
              "the available createEngine function failed. Creating the default engine instead"
            );
            return createDefaultEngine();
          }
        };

        engine = await asyncEngineCreation();
        if (!engine) throw "engine should not be null.";
        startRenderLoop(engine, canvas);
        scene = createScene();
      };
      initFunction().then(() => {
        sceneToRender = scene;
      });

      // Resize
      window.addEventListener("resize", function () {
        engine.resize();
      });
    </script>
  </body>
</html>
```

なお、パーティクルシステム用の画像は、HTMLファイルといっしょにダウンロードされたものを使っています。具体的には `textures` フォルダ内の「flare.png」というファイルで、以下の画像です。

![flare.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/f4105008-f979-18c8-98a1-7fb971b127bb.png)

これを使って描画される内容は、公式サンプルと同じ以下の見た目のものです（処理の内容などを変えてないので、当然なのですが...）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/5da1f0d7-b695-b676-190b-8944f51011ec.png)

少し拡大して見てみると、以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/56b59cf5-da53-f9ee-bddd-1522925a3345.png)

### パーティクルシステム用の画像を変えてみる
次に、パーティクルの見た目を簡単に変更するため、「パーティクルシステム用の画像を別のものに変える」というのを試します。

Babylon.js で用意されている、パーティクルシステム用の画像（やそれ以外の画像）については、公式ドキュメントの以下に記載されています。

●The Texture Library | Babylon.js Documentation
　https://doc.babylonjs.com/toolsAndResources/assetLibraries/availableTextures

この中から差しかえをする画像を選んでみます。
sparkle という名前の以下の画像を用います。

![sparkle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/3f4599cb-fbfd-f6f0-f346-dca2fd9e1904.png)

変更後の描画結果は、以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/da1a570c-5cdc-6845-b659-382960599f5c.png)

拡大して見てみると、差しかえ後の画像が使われているのが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/1a753c22-44d9-590b-f801-eff7ab0b9299.png)