スマートシティ開発に使えるかもしれないWebSDKの話

# はじめに

防災や観光など都市開発などをテーマとした場合の開発手法を色々と試しています。
様々な要件定義によっていろいろな開発手法が考えられますが、自身が受ける案件の中でよく挙げられる点は、

「VRやARなどに対応したい、高齢者や子供でも簡単に使えるようにしたい、開発の予算はない」

といったものです。

こうした要件の中で、最近、試しているのが、「ブラウザアプリ」による開発です。

アプリ開発の場合は、UnityやFlutterなどOSの違いを吸収してくれるSDKもありますが、
iOSの場合などはTestFlightの使い方などを習得する必要がある点や、仮に貸出用のスマートフォンなどを手配した場合、キッティングにかかる時間も多いため、ちょっとしたものをサクッと提供する場合には、ブラウザアプリの提供が欠かせません。

## 侮る事なかれブラウザゲームの現状

WebAssembly（通称Wasm）は、ブラウザゲームの開発に革命をもたらした技術の一つです。WebAssemblyは、ウェブブラウザで実行可能な低レベルのバイナリフォーマットです。これにより、C、C++、Rustなどの言語で書かれたコードをウェブブラウザで実行することが可能になります。WebAssemblyはJavaScriptよりも高速に実行できるため、ウェブアプリケーションやゲームにおいて、より複雑な計算や高度なグラフィックス処理が求められる場合に特に有用です。

## ワークショップなどで活用することのできるブラウザSDK

0->1でのものづくりの際には、ゲームエンジンの活用が欠かせません。ゲームエンジンはグラフィックスのレンダリング、物理演算、音声、スクリプティング、アニメーション、人工知能、ネットワーキングなど、ゲーム開発に必要な多くの機能やコンポーネントを提供します。ゲームエンジンは、開発者がゼロから全てをコーディングする代わりに、これらの準備された機能を使用して、ゲームの独自の要素やロジックに集中できるように設計されています。

今回はブラウザをテーマとしているので、ブラウザ開発によく用いられるゲームエンジンをご紹介します。
Babylon.js(microsoft)、three.js、Cesium、Filament (google)

今回は、地図などを主体とした仕組みでの活用が想定されるCesiumと、
汎用的なMicrosoft社のBabylonの2つをテーマとして簡単な仕組みを提供する流れを作りたいと思います。

# 1.Hostingサーバーの準備

何をやるにも、まずはサーバーの準備が必要です。
自分のローカルマシンで立ち上げてlocalhostでアクセスする方法もありますが、
作ったものを誰かに見てもらうということが大事、ということで、今回はGlitchと呼ばれるホスティングサーバーをご紹介しいます。

## Hostingサーバーの準備
Glichにアクセス
https://glitch.com/signin

## 右上のNew Projectを押下する
![スクリーンショット 2024-03-05 8.30.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/1238f322-d8ab-fe47-8768-a0394d5ee824.png)

## glitch-hello-websiteを押下する
![スクリーンショット 2024-03-05 8.30.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/0661a897-be4e-41d8-e8f4-bc62a4eec7c7.png)

## 左のファイルリストからindex.htmlを押下して、プログラミングをしよう

![スクリーンショット 2024-03-05 8.30.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/9d3b88b3-7e81-a75a-afd3-d6b2395fd007.png)

## 右上のShareを押下して、LivesiteのURLをコピーして、誰かに見てもらおう
![スクリーンショット 2024-03-05 8.31.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/3afd0793-d692-8ebd-11a6-7d2ca99d0368.png)


# 2.Cesiumを使ってみよう

### 2-0.GlichのAssetsに下記の3Dモデルを読み込んでみてください。
![スクリーンショット 2024-03-05 8.30.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/ba7ec324-9217-de90-0a4a-f8ca1562def1.png)

### 読み込んだ後、CopyURLを押下してリンクをコピーしよう
![スクリーンショット 2024-03-05 8.31.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/d8337a03-b843-a382-fda7-3a28429eb458.png)

## 2-1.Glichのindex.htmlに下記のコードをペーストしてみてください。

### ソースコードをコピーする

![スクリーンショット 2024-03-11 20.09.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/e9906d37-c4a0-ea4b-4436-eedbcc37de9e.png)

### コンテンツを追加したい場合は、表示したい地図の座標をGoogleMapで調べよう

![スクリーンショット 2024-03-11 15.09.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/331556b6-2c0d-1494-0d50-87a222a7b0f3.png)

### 簡単な内容

```javascript
      var target = viewer.entities.add({
        name : 'かわまちてらす閖上',
        // 緯度経度
        position: Cesium.Cartesian3.fromDegrees(140.94808025489982,38.17948338366141),
        point: {
          pixelSize: 16,
          color: Cesium.Color.YELLOW
        },
        label : {
          text: 'かわまちてらす閖上',
          font: 'bold 12pt Hiragino Maru Gothic ProN',
          style: Cesium.LabelStyle.FILL_AND_OUTLINE,
          outlineWidth: 10,
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          pixelOffset: new Cesium.Cartesian2(0, -16)
        }
      });

```

```javascript
function createModel(lon,lat,h, url) {
  var position = Cesium.Cartesian3.fromDegrees(lon,lat,h);
  var heading = Cesium.Math.toRadians(150);
  var pitch = Cesium.Math.toRadians(0);
  var roll = Cesium.Math.toRadians(0);
  var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
  var orientation = Cesium.Transforms.headingPitchRollQuaternion(
    position,
    hpr
  );
  var entity = viewer.entities.add({
    name: url,
    position: position,
    orientation: orientation,
    model: {
      uri: url,
      scale: 100,
    },
  });
}
createModel(140.94808025489982,38.17948338366141, 10, "./models/kaisendon.glb");
```

## 2-3.Sandcastleをみてみる

Cesium には、CesiumJS の機能を試すことができるインタラクティブな環境として、Cesium Sandcastle というものが用意されています。コードを書き換えるだけでサンプルに手を加えることが可能となっています。

https://sandcastle.cesium.com/


# 3.Babylonを使ってみよう


### 2-0.GlichのAssetsに下記の3Dモデルを読み込んでみてください。
![スクリーンショット 2024-03-05 8.30.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/ba7ec324-9217-de90-0a4a-f8ca1562def1.png)

### 読み込んだ後、CopyURLを押下してリンクをコピーしよう
![スクリーンショット 2024-03-05 8.31.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/d8337a03-b843-a382-fda7-3a28429eb458.png)

## 2-1.Glichのindex.htmlに下記のコードをペーストしてみてください。
https://github.com/oggata/kaisendonverse/blob/main/index.html

## 3-e.完成イメージ
![スクリーンショット 2024-03-06 12.36.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/71ccaac1-98d8-6856-cb1a-5ce42dfc5742.png)

https://oggata.github.io/kaisendonverse/

## 3-e.コード開設

### シーンを作成して、重力と衝突を発生させる

```javascript
        var scene = new BABYLON.Scene(engine);
        scene.enablePhysics();
        scene.checkCollisions = true;
        scene.collisionsEnabled = true;
        scene.collisionEnabled = true;
        scene.gravity = new BABYLON.Vector3(0, -9.81, 0);
```


### ライトとカメラ、地面を作って準備

```javascript
        var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 2, -20), scene);
        camera.setTarget(BABYLON.Vector3.Zero());
        camera.attachControl(canvas, true);
        camera.checkCollisions = true;
        camera.applyGravity = true;
        camera.ellipsoid = new BABYLON.Vector3(2, 2, 2);
        camera.collisionRadius = new BABYLON.Vector3(0.5, 0.5, 0.5);
        camera.attachControl(canvas, true);
        camera.speed = 0.3;
        var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
        light.intensity = 0.8;
```

```javascript
var ground = BABYLON.Mesh.CreateGround("ground1", 1000, 1000, 2, scene);
        ground.receiveShadows = true;
        ground.checkCollisions = true;
        ground.physicsImpostor = new BABYLON.PhysicsImpostor(ground, BABYLON.PhysicsImpostor.BoxImpostor, {
          mass: 0,
          friction: 0.7,
          restitution: 1.5,
        }, scene);
```


### 海鮮丼を剛体にする

```javascript
          BABYLON.SceneLoader.ImportMeshAsync("", "./gltf/", "kaisendon.glb").then((result) => {
            var box3 = BABYLON.Mesh.CreateBox("crate", 2, scene);
            box3.position = new BABYLON.Vector3(0, 30, 0); 
            box3.checkCollisions = true;
            box3.applyGravity = true;
            box3.showBoundingBox = true;
            box3.visibility = 0;
            //質量や摩擦係
            box3.physicsImpostor = new BABYLON.PhysicsImpostor(box3, BABYLON.PhysicsImpostor.BoxImpostor, {
              mass: 2,
              restitution: 0,
              friction: 1,
            }, scene);
            result.meshes[0].scaling.x = 20;
            result.meshes[0].scaling.y = 20;
            result.meshes[0].scaling.z = 20;
            result.meshes[0].position = new BABYLON.Vector3(0, 29, 0);
            box3.addChild(result.meshes[0]);
          });
```


### ボタンを作ろう

```javascript
        let advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("myUI");
        var button1 = BABYLON.GUI.Button.CreateSimpleButton("but1", "kaisendon");
        button1.width = "150px"
        button1.height = "40px";
        button1.color = "white";
        button1.cornerRadius = 20;
        button1.background = "black";
        button1.onPointerUpObservable.add(function () {
          addObject();
        });
        advancedTexture.addControl(button1);
```



https://playground.babylonjs.com/#0VHCTL#32







# 3Dデータを自分で作ってみよう

事前にscanierseやlumaaiなどで撮影したデータを.glbファイルに変換させて利用する準備をしよう。

## 撮影したデータをGLTFでダウンロード

![スクリーンショット 2024-03-06 12.29.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/b342eb5a-8a3e-4009-c467-1433854aef01.png)

![スクリーンショット 2024-03-06 12.29.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43766/ac1a79ae-65ff-607f-e1d3-83aab537aecf.png)

## または、こちらで用意したサンプルデータをダウンロードできます

https://github.com/oggata/yuriage_models/tree/main/glb

ダウンロードした.glbファイルをビューアーを用いることで立体的にみることができます。
https://gltf-viewer.donmccurdy.com/



https://github.com/oggata/kaisendonverse/blob/main/index.html


https://oggata.github.io/kaisendonverse/



# VRにも対応できる


VR対応
https://www.youtube.com/watch?v=OqA8Xr3Njaw

電車走行(3画面分割)
https://oggata.github.io/train-demo/

動物パズル
https://oggata.github.io/animalmashup/

マップを探索するサンプル
https://playground.babylonjs.com/#0VHCTL#32

スケートボード
https://playground.babylonjs.com/#XMEL56#7