【Babylon.js】Playgroundで遊んでみよう

こんなものを作りました。( [Playgroundで見る](https://playground.babylonjs.com/#I2Q4K4#5) )
![screenshot_22-12-21_2-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507339/b0c76664-aa3c-bced-6abb-5ca7d655ef41.png)

# はじめに

ARIの土井です。去年のアドベントカレンダーから記事投稿ができておらず、久しぶりの投稿になってしまいました。
今回は1か月ほど前にさわり始めたBabylon.jsについての記事を書きたいと思います。

https://www.babylonjs.com/

# Babylon.js とは

Microsoft社が提供しているWebGLフレームワークです。2022年5月5日にv5.5.5がリリースされ様々な機能の追加アップデートがありました。Release VideoがYoutubeで公開されているので、ぜひ見てみてください。

<p><iframe width="560" height="315" src="https://www.youtube.com/embed/zELYw2qEUjI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>

# Playground とは

[Playground](https://playground.babylonjs.com/)では、Web上でBabylon.jsを簡単に試すことができます。アカウントの登録なども不要で無料で試せます。左画面のJavascriptのコードを修正し、画面上部の `▶` をクリックすると、右側の画面に3Dのオブジェクトが描画されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507339/7c7c19c8-fd87-cceb-73bf-2fb7ea19032f.png)

Javascriptのソースコードは、`BABYLON.Scene`というオブジェクトを返す `createScene` 関数を作るだけです。関数内で`BABYLON.Scene`のインスタンス`scene`を作成し、カメラやライト、3Dモデルなどを`scene`に追加します。

開発したコードは保存することができます。保存すると一意のURLが発行されて他の人に共有することも可能です。

# Playgroundで遊んでみる

この記事ではPlaygroundで以下の3つを試してみようと思います。

* [GLB形式の3Dモデルの読み込み](#glb形式の3dモデルの読み込み)
* [SkyBoxの作成](#skyboxの作成)
* [Materialの修正](#materialの修正)

## GLB形式の3Dモデルの読み込み

### 3Dモデルの用意

まずGLB形式の3Dモデルを用意します。これは3Dモデルのファイル形式のひとつであるglTFをバイナリ形式に変換したものです。GLBは3Dモデル作成ツールで自作したり、3D素材サイトから入手したりといった方法がありますが。今回はOfficeソフトから入手する方法を紹介します。

Excelを起動して、`挿入` > `図` > `3Dモデル` > `3Dモデルのストック` をクリックします。
![画像3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507339/fb9783b8-e7c4-8d8e-21a1-59802b2584e1.png)

検索ボックスに探している3Dモデルの名前を入力し、一覧から画像を選択して`挿入`をクリックします。(サッカーボールにしてみました)
![画像6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507339/1cb4c5d7-4a65-e1af-9d53-a67c1d08afa7.jpeg)

エクセル上に3Dモデルが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507339/c49f736f-7a8e-d21b-aa7b-12bd16307559.png)

次に (Windows10/11をお使いの方は) ペイント3Dを起動します。エクセル上の3Dモデルを`Ctrl+c`でコピーし、ペイント3Dに`Ctrl+v`で貼り付けます。

![画像7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507339/f99c33e8-f03f-3586-ae65-dcec40bc8b07.jpeg)

3Dモデルを保存します。コピーとして保存の`3Dモデル`を選択し、`.glb`形式で保存します。
![画像8.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507339/73eb3077-425c-b7b8-19b5-ac7696497e2e.jpeg)

これでGLB形式の3Dモデルを準備できました。

### 3Dモデルの読み込み

用意した3Dモデルの`.glb`ファイルをbase64エンコードした文字列をコード中に直接記載するとPlaygroundに3Dモデルを読み込むことができます。（※自分はWindows端末を使っていますがGitBashをインストールしていたので以下のコマンドでエンコードしました。）

```bash:windowsでのbase64エンコード
$ base64 -w 0 /path/to/xxx.glb > ~/encoded_glb.txt
```

[Playground](https://playground.babylonjs.com/)にアクセスし以下のコードを入力します。`base64_encoded_str`の値は`.glb`をbase64変換した文字列に置き換えてください。

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

    // カメラの作成・回転
    const camera = new BABYLON.ArcRotateCamera("camera1", -2.5, 2, 1.5, new BABYLON.Vector3(0, 0, 0), scene);
    camera.useAutoRotationBehavior = true;
    camera.autoRotationBehavior.idleRotationSpeed *= 5;
    camera.attachControl(canvas, true);

    // ライトの作成
    const light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
    light.intensity = 0.7;

    // 3Dモデルの読み込み
    const base64_encoded_str = "xxx"; // glbをbase64エンコードした文字列
    const base64_model_content = "data:;base64," + base64_encoded_str;
    BABYLON.SceneLoader.Append("soccer_ball", base64_model_content, scene);

    return scene;
};
```

Playgroundの上部にある`▶`ボタンをクリックすると、コードが実行されて3Dモデルが表示されました。

[Playgroundで見る](https://playground.babylonjs.com/#I2Q4K4)
![screenshot_22-12-20_1-32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507339/d0664dd8-287a-ec8a-fa53-8d59926d7a50.png)

## Skyboxの作成

背景が暗いのでSkyboxを作成してみます。Babylon.jsでは標準でいくつかの`.dds`ファイルを提供しておりPlaygroundに読み込むことができます([.ddsファイル一覧](https://doc.babylonjs.com/toolsAndResources/assetLibraries/availableTextures#hdr-as-dds))。Skyboxを作成するために以下のようにコードを修正してみます。

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

    // カメラの作成・回転
    const camera = new BABYLON.ArcRotateCamera("camera1", -2.5, 2, 1.5, new BABYLON.Vector3(0, 0, 0), scene);
    camera.useAutoRotationBehavior = true;
    camera.autoRotationBehavior.idleRotationSpeed *= 5;
    camera.attachControl(canvas, true);

-   // ライトの作成
-   const light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
-   light.intensity = 0.7;
+   // Skyboxの作成
+   scene.environmentTexture = BABYLON.CubeTexture.CreateFromPrefilteredData("/textures/SpecularHDR.dds", scene);
+   scene.createDefaultSkybox(scene.environmentTexture);

    // 3Dモデルの読み込み
    const base64_encoded_str = "xxx"; // glbをbase64エンコードした文字列
    const base64_model_content = "data:;base64," + base64_encoded_str;
    BABYLON.SceneLoader.Append("soccer_ball", base64_model_content, scene);

    return scene;
};
```

実行してみると建物のようなものが描画されて明るくなりました。`.dds`のファイル名を変えると他のパターンも読み込めるので試してみてください。

[Playgroundで見る](https://playground.babylonjs.com/#I2Q4K4#1)
![screenshot_22-12-18_18-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507339/f492601a-02df-bdba-487b-a3b23d6f5c48.png)

## Materialの修正

サッカーボールの表面に少し光沢をつけるために、Materialを修正してみます。

まず、Playgroundの画面上部にある`Inspector`ボタンをクリックします。すると、右側にScene内のノードやマテリアルなどの情報が表示されます。以下の画像の通り、base64エンコード形式で読み込んだモデルに付与されているMaterial名を確認すると`51`となっていることがわかります。

![画像11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507339/3cf29c8b-fd3b-a58e-ceb0-26af7a38b571.jpeg)

Material名を確認したら以下のようにコードを修正します。

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

    // カメラの作成・回転
    const camera = new BABYLON.ArcRotateCamera("camera1", -2.5, 2, 1.5, new BABYLON.Vector3(0, 0, 0), scene);
    camera.useAutoRotationBehavior = true;
    camera.autoRotationBehavior.idleRotationSpeed *= 5;
    camera.attachControl(canvas, true);

    // Skyboxの作成
    scene.environmentTexture = BABYLON.CubeTexture.CreateFromPrefilteredData("/textures/SpecularHDR.dds", scene);
    scene.createDefaultSkybox(scene.environmentTexture);

    // 3Dモデルの読み込み
    const base64_encoded_str = "xxx"; // glbをbase64エンコードした文字列
    const base64_model_content = "data:;base64," + base64_encoded_str;
-   BABYLON.SceneLoader.Append("soccer_ball", base64_model_content, scene);
+   BABYLON.SceneLoader.AppendAsync("soccer_ball", base64_model_content, scene).then(function (scene) {
+       let mat = scene.getMaterialByName("51"); // material名からmaterialを取得
+       mat.metallic = 0;
+       mat.roughness = 0.05;
+       mat.reflectionTexture = scene.environmentTexture;
+   });

    return scene;
};
```

`AppendAsync`で3Dモデルを読み込んだ後、3Dモデルに適用されているMaterialを参照してパラメータを変更します。

| 属性 | 説明 |
|:-:|:-:|
| `metallic` | 金属のような光沢を出すことができる。0(非金属)～1(金属)の間で指定。 |
| `roughness` | 表面の粗さを指定する。0(反射強い)～1(反射弱い)の間で指定。 |
| `reflectionTexture` | 物体表面に反射して映るテクスチャを指定。 |

以下が実行結果です。

[Playgroundで見る](https://playground.babylonjs.com/#I2Q4K4#5)
![screenshot_22-12-21_2-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507339/b0c76664-aa3c-bced-6abb-5ca7d655ef41.png)

サッカーボールの表面に光が反射して、少しリアル感が増した気がします！

# まとめ

今回はPlaygroundに3Dモデルを表示して色々遊んでみました。Web上で気軽に試せるのがいいですね。Playgroundの他にも色んなツールが提供されているので、これからも試していこうと思います。