近くにWaySpotがなくてもPrivateでサクッと作って8th Wall for Lightship VPSを試す


# WebARのプラットフォーム 8th WallでLightship VPSが使えるようになりました。

春頃にあったLightship Summitでも少し話があった8th Wall上で構築するWebARでLightShip VPSが使えるという話が実現しました。

https://www.globenewswire.com/news-release/2022/09/22/2521056/0/en/Niantic-launches-Lightship-VPS-for-Web-bringing-the-Real-World-Metaverse-to-the-browser.html

とりあえず、8th Wall for LightShip VPSで簡単なコンテンツを作るための手順を整理してみました。

## LightShip VPSとは

Lightship VPSとはNianticが手がけているVisual Positioning Systemです。最近はAppleやGoogleなどもVPSをサービスとして提供してきています。
NianticのVPSは現状は地域のスポット（史跡や観光名所）を中心に構成されています。これらはNianticが手がけるIngressのポータル、ポケモンGoのポケストップに対応しています。これをWaySpotとして定義しており、この周辺の空間スキャンした情報を利用してVPSを実現しています。このVPSに必要な情報は主にIngress等のゲーム内でプレーヤーが（ゲーム内での報酬と引き換えに）提供する形をとっています。
例えば、Lightship VPSでは以下のような情報を確認することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/4f2071a1-4ae3-30d8-82d7-779bc5aac947.png)

Scan Progressと書かれているところが時間帯別の空間スキャンされた回数を表しています。VPSの情報に必要な空間スキャンは光源の状態などを加味して
朝、昼、晩まんべんなく情報が集まっていないとVPSの情報として生成できない仕組みになっています。また、情報が一定量集まると自動でActivateがかかるという仕様でもないようです。もし近所に十分な回数のスキャンが実施されていれば、この画面からActivateボタン押すことでデータを生成することができます。ただ、一度Activateしてしまうと以降はスキャンデータの追加などは行えない仕様になっているため、もしかすると「押すのに躊躇する」という話も相まってあまりVPSとして使えるところが少ないのかもしれないです。
ちなみに、上記のスポットでは、現段階のスキャン数が昼間に2回、夕方/明け方に4回、深夜に7回となっています。深夜以外の時間帯で5回確保されていないのでStatusが推奨のグリーンになっていないという状況です。この3つの時間帯で一定回数スキャンされたものはActivateすることができ、成功するとVPSとしてのデータが生成されます。最低でも2つの時間帯で10回近くスキャンしないといけない仕様の様です。なお、Activateに成功するとスキャンした分のデータが生成されるようで、このスポットの場合は今Activate行うと13個のスキャンデータが生成されます。少し困りどころの1つとして「どのくらい上手くスキャンできているか」がわからないため、ほんとに十分なのかの判断ができないところかも。
ちなみに、スキャンについてはIngressもしくはWayfarer(iPhoneのみ)という専用アプリで実施可能です。

ActivateされたWaySpotについては以下の様にスキャンの結果生成された3Dデータ(赤枠)の情報が作られます。これを利用してLightship VPSでの位置合わせを実現することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/d6d09011-d360-d30a-246e-7896291532bc.png)

8th Wallではすでにいくつかの簡単なサンプルプロジェクトが公開されています。A-Frameを使用したものですが、まずは位置合わせで何か出してみるといった事を試すにはちょうどいいサンプルになっています。これらのプロジェクトを参考にして近くのWaySpotで何かを表示することは可能ですので今回はそれをやってみたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/4939d734-d888-ffe5-92f3-9b27f2fcae44.png)

### 現状のLightship VPSの課題

今現状のLightship VPSの課題があるとすれば、位置合わせに使えるWaySpotが少ないということでしょうか。ただ、WebARというジャンルでこれが使えるのは大きいと思います。
スポット自体はIngressのポータル情報とほぼ一緒なので、地域差はありますがある程度スポットはあるはずです。ただ、その地点のスキャン数が足りていないためにActivateできずに、ほとんどの場所が使えないのが実態です。この辺りはGoogleのGeospatial APIほど気軽じゃないというところがあると思います。
また、近くにWaySpotを設置して時間帯別にスキャンを実施し登録することも可能ですがなかなか手間がかかる作業ですし時間がかかります。実際にちょっと試してみたいと思っても使えるWaySpotがあっても遠いと検証にも困るというところで、一応検証目的でPrivateのWaySpotを作ったりすることができます。今回はそのあたりの手順を含めて紹介し、8th wall for Lightship VPSで簡単なコンテンツ表示をするサンプルを見ていきたいと思います。

## WaySpotのスキャンや登録方法

WaySpotに対してスキャンを行いVPSとして使うためにWayfarerというiPhone向けのアプリがNianticから提供されています。また、WaySpotのスキャンをするという点ではIngress等のゲーム内でも同じようにスキャンして情報を登録することができます。WaySpotを新しく作ったりする場合は8th Wall側からすることができます。

https://testflight.apple.com/join/VXu1F2jf

Wayfarerは正式版にはなっていないようでTestFlight経由で提供されています。
Lightship VPSではWayspotを有効化するために時間帯を分けて10回近くスキャンが必要なのですが、テスト用に作成するVPSについては1回スキャンして登録すれば、VPSとして利用することが可能になっています。とりあえず試したい場合は手軽に試すことが可能です。

### wayfarerアプリでのスキャン手順
アプリケーションを起動すると以下のようなログイン画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/f4f66abf-a417-f2ec-018f-45a305e12a32.png)

今回は8th wallで利用するWayspotを作成するので8th wallのアカウントでログインします。
ログインすると現在位置を中心とした地図が表示されます。「LOAD NEARBY WAYSPOTS」をタップすると周辺のWayspotが表示されます。ここからは既存のWaySpotを育成してVPSデータを生成できるようにActivateしたいのか、Private Scanでお試しするかで少し手順が変わります。


:::note info
すでにあるWaySpotのスキャンを追加したい場合
地図上のWaySpotをみてスキャンしたい場所まで行きます。当たり前ですが現地に行かないとスキャンはできないです。現地についたら、Wayspotを選択の上でScanをタップします。
この際UIにはそのWaySpotの詳細情報が記載されています。VPSを有効化するために複数の時間帯で十分な回数スキャンを行う必要があるので、スキャン回数とその時間帯の詳細を確認しておくと対応しやすいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/49879fa5-1e2f-8168-1be8-e6043c0c68ac.png)

:::

:::note info
PrivateのWayspotを作成したい場合
WaySpotを選択していない状態でスキャンしたい場所に移動し、スキャンを開始します。
画面上では以下の様に[Current Location: not available]となっている状態であれば、Privateで作成可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/43ad60da-b808-8e08-d6be-ee6a34db42e4.png)
:::

スキャンを開始するとカメラの映像に切り替わります。開始ボタンを押すと録画が始まりますので、できるだけ水平にスムーズに動くことを意識してスキャンする地点の場所を撮影していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/3d532de1-9df3-177b-4902-552393a9234c.png)

おそらくLiDARスキャンなどをしたことがある人はイメージつくかと思いますが、きれいにスキャンしようと思ったら色々苦労や工夫が必要になります。おそらくジンバル等色々ある方がきれいにスキャンできるのですが、何もなくても気を付ければそれなりの品質で撮影は可能でした。
Wayfarerでの撮影は1回が1分で連続で5回分撮影可能です。例えば朝に1分5回、夕方に1分5回スキャンするとほぼ必要な回数のスキャンを確保したことになります。検証用に作成するPrivateのものは**1回分でVPSに必要な情報が作成されます**。複数回撮影してもそれぞれ別のVPSデータを登録されてしまうため、失敗防止のために複数撮影するといった話がないのであれば1回だけで大丈夫です。
5回スキャンもしくは途中でスキャンを中断(1分毎に続行か終了かの確認が出る)すると撮影した情報で実行するか確認されます。問題ない場合は「Done」をタップし次へ進みます。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/36e752a3-f132-35de-d5e4-a57a13053fd2.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/28c0e8ba-5abf-1cd4-bd2b-20f11af76597.png)|
|-|-|


次に登録する情報をpublicにするかPrivateに設定するかを選択します。WaySpotを指定しないスキャンの場合はPrivate一択です。次へをタップするとアップロードについての確認があります。データ量はそれなりに大きいので、スキャン後のアップロードは安定したWifiがある帰宅後に行うことも可能です。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/7331c325-5f8f-bc35-a19c-320a44d73103.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/876e02e3-edd6-35eb-296c-21ccf5f40342.png)|
|-|-|

最終的にアップロードが完了すると以下のようになります。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/f9ca5f3e-bd31-4839-ef52-46f8574dd4b6.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/fa9965da-3c6d-6b7b-7db5-152d4e741ec7.png)|
|-|-|

8th wall側では以下の様にPrivateのWaySpotが生成され処理中（黄色）になります。データが使えるようになるには最長で数時間はかかるので気長に待ちましょう。また、しばらくして「Not Activated」が表示された場合はスキャンの仕方の問題などによりVPSに必要な情報を生成できなかった可能性があります。こういった場合は再度登録しなおしてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/ad7e6c0f-26f8-1db8-0261-61f2717ef483.png)

以上でwayfarerのアプリの使い方は終わりですが、注意点がいくつかあります。
「とりあえずVPSのデータを作って検証したい/試してみたい」といった用途の場合、どのプラットフォームで開発するかでログインを変える必要があります。Lightship VPSはPublicの情報であれば特に意識しなくてもいいのですが、**テスト用に作成できるPrivateのVPS情報についてはLightshipと8th wallで別々に管理されています。**

### ログインをLightshipのアカウントで行った場合

Lightshipのアカウントでwayfarerにログインした場合は、Lightshipの方と連携するようになっています。例えばUnityでLightship VPSを使う際にPrivateなVPSを使いたい場合はこちらを選択します。実際WayfarerでPrivateスキャンを行うと以下の図のようにMy Meshesの中にスキャンした情報から生成された3D情報と撮影地点等の情報を見ることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/e7df64ad-7f64-ca01-72fd-d4e7d47d74c3.png)


### ログインを8th wallのアカウントで行った場合

8th wallのアカウントでwayfarerにログインした場合は、8th wallと連携するようになります。この時PrivateなWayspotが生成され利用することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/c0d44c67-a942-97a5-f0c3-22eda98687b3.png)


## サンプルを参考に実際にWaySpotにオブジェクトを表示してみる

次にサンプルを少し修正して実際に近くにあるWaySpotでオブジェクト表示できるアプリを構築してみましょう。周辺にWaySpotがある人はそこを利用する形ですがない場合はWayfarerでPrivateのWaySpotを作ります。今回は公開されているサンプルの中に「Lightship VPS Bespoke」というものがあります。このアプリは指定のWaySpot内でコンテンツを表示するものになっています。アプリを利用する為に必要な手順はこのプロジェクトのReadMe.mdが参考になります。

https://www.8thwall.com/8thwall/vps-bespoke/code/README.md

大まかな手順は以下の様になっています。このアプリではいくつかの風船っぽいCubeが空間に漂うコンテンツとなっているのでこれを自分のWayspotに合わせて調整して作ってみます。

1. 利用したいWaySpotをLightsip VPSから探し出しプロジェクトに追加する
1. プロジェクトに追加したWaySpotから周辺のメッシュ情報を取得する
1. Blender等でWaySpotのメッシュ情報を元にコンテンツを作成する
1. 8th wallに組み込む

### プロジェクトをクローンする

最初に自分のワークスペースにこのプロジェクトをクローンします。8th wallにログインしProject Libraryから「Lightship VPS Bespoke」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/4939d734-d888-ffe5-92f3-9b27f2fcae44.png)

詳細が表示されると[Clone Project]を押してプロジェクトをクローンします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/9ca7a41e-f0de-cfd9-421c-1eb85c8898b0.png)

これでまず必要な環境を構築できました。

### WaySpotをアプリに紐づける

クローンが完了したら、プロジェクトを選択してエディターを起動します。エディターのメニューの中にあるLightship VPS（下から3番目の地図アイコン）を選択するとLightship VPSのWaySpotに関する情報をアクセスすることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/b7e532e4-0e5e-40af-e6cb-e2dc81c9f537.png)

マップ上には周辺のWaySpotが表示されていますが、実際にVPSとして利用できるものはActivate済みのスポットのみです。どれかわからりにくいのでフィルター条件で[Not Activated]を外するといいと思います。ここでもし近所にないという場合は遠くに出向くか近所でPrivateなSpotを作成します。Lightship VPS上でもWaySpotの作成は可能ですが**Publicのスポットしか作成できません**。今後Lightship VPSのスポットとしてふさわしいと思われる場所を追加する場合はここから作成します。ただし、審査はあるのでそれなりに時間はかかると思います。ちなみに脱線ですが、Ingressではポータルとしてゲーム内でプレイヤーに申請してもらう方式になっています。最近はVPSに必要なスキャンもアプリ内で提供してもらえるようになっています。
利用したいSpotを見つけたらそのアイコンをクリックします。
詳細を表示すると以下の様にプロジェクトに追加するボタンが表示されます。Spotには複数のスキャン結果が保存されています。Activateのために一定回数のスキャンが必要なのはこういった情報が日光などの光源による差異を補完するためのものだと思います

:::note info
WaySpotのプロジェクトへの登録は必須ではないです。
Lighitship VPSから情報を取得する際、コンテンツ利用者が付近にいる場合にスポットの検出は可能になっています。この際、任意のスポットを検出するのか、プロジェクトで管理されているスポットのみ検出するのかといった事を分けて制御することができます。今回のような特定のスポットに対するコンテンツでは、任意のスポットを検出しても意味はないですし効率がわるいです。また、開発時にどのスポットを利用したコンテンツなのかを把握したり、現地の空間に干渉せずにコンテンツを表示させる必要が出てくると思います。こういった場合、登録しておく方が管理面でも楽だと思いますし、プロジェクトに含めておくと現地のモデルをダウンロードできるため扱いやすくなります。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/da3705ae-6578-8f1f-4998-3d8a7a9db875.png)

プロジェクトに追加すると[Project Wayspots]に追加されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/4712f5c7-9192-8e06-47cf-e37eed8f6bbd.png)

表の最右列がモデルのダウンロードボタンになっています。列の表題のところをクリックするとモデルの形式やクオリティが選択できるのでほしい形式のものを選択します。後で利用するのでダウンロードを押して取得しておきます。また、ここで書かれているNameを控えておきます。このアプリではコンテンツの表示をこの名前で確定させています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/0d4e2694-1186-0ad5-2991-fa46097a1da5.png)

表示させるコンテンツは何でもいいのですが、サンプルにあるものをそのまま流用しました。位置調整のためにこちらの方もダウンロードします。8th wallのコードエディタでsqualoons.glbをダウンロードしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/3ef41fd4-a55a-dde8-2bcd-14002bcc6fcf.png)

後はBlenderで調整します。先ほどダウンロードしたVPSのモデルと、squaloons.glbをインポートしていい場所に配置します。位置が決まったらCubeだけを選択してExportしSqualoons2.glbなどとして保存し8th wallにアップロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152548/ce618ad6-569c-8774-cab9-aac364485b25.png)

最後に、8th wallのコードエディタでbody.htmlを編集します。
変更が必要な個所としては以下の3点です。

* a-asset-itemタグのID:vps-meshのsrcを今回追加したスキャンデータのファイル名に変更
* a-asset-itemタグのID:vps-meshのsrcを今回追加した調整済みのコンテンツのファイル名に変更
* a-entityタグのnamed-wayspot属性を"name: <WaySpot名>"に設定

named-wayspot属性に設定するWaySpot名は先ほどこのプロジェクトに登録したWaySpotのNameを記述します。このサンプルは後述のnamed-wayspot.js内で、Lightship VPSで管理されるWaySpotと照合を行います。

```html:body.html
<a-scene
  landing-page
  vps-coaching-overlay
  background="color: #303030"
  renderer="colorManagement: true"
  gltf-model="dracoDecoderPath: https://cdn.8thwall.com/web/aframe/draco-decoder/"
  xrextras-runtime-error
  xrextras-loading
  xrweb="enableVps: true">

  <a-assets>
    <a-asset-item id="vps-mesh" src="./assets/5d75b326729d.glb"></a-asset-item> <!-- VPSのスキャンデータ  -->
    <a-asset-item id="squaloons-mesh" src="./assets/squaloons3.glb"></a-asset-item> <!-- 表示されるCube等の3Dオブジェクト -->
  </a-assets>
  
  <a-camera
    position="0 1.8 4"
    raycaster="objects: .cantap"
    cursor="fuse: false; rayOrigin: mouse;">
  </a-camera>

  <a-entity named-wayspot="name: 5d75b326729d"> <!-- name : <WaySpot名>  -->
    <a-entity
      gltf-model="#vps-mesh"
      xrextras-hider-material> <!-- VPSのスキャンデータ  -->
    </a-entity>
    <a-entity 
      gltf-model="#squaloons-mesh"
      cubemap-realtime
      animation-mixer="clip: *"> <!-- name : 表示されるCube等の3Dオブジェクト  -->
    </a-entity>
  </a-entity>
 
  <a-light type="directional" intensity="0.5" position="1 1 1"></a-light>
  <a-light type="ambient" intensity="1"></a-light>
</a-scene>
```

コンテンツとしては以上で完了です。WaySpotの名前や3Dモデルの情報が間違っていなければ、現地のスポットをスキャンすることでコンテンツが表示されるはずです。もし表示されない場合は、スキャンがうまくいっていない可能性はあります。このアプリについてはスキャン中は画面に[Scanning...]と表示はされるため、この表示が消えているのにコンテンツが表示されないのはプログラムの方を疑うといいのかもしれないです。

### Lightship VPSの動作部分

このアプリケーションで実際にLightship VPSとどう疎通しているのか、コードを見ていきます。コード自体は至ってシンプルです。WaySpotに関するイベントを登録し該当する処理を実装指定だけになります。このアプリケーションでは[xrprojectwayspotfound],[xrprojectwayspotupdated]の2つのイベントを監視するようになっています。
xrprojectwayspotfoundイベントは、プロジェクトに追加しているWaySpotが見つかった場合に発生するイベントです。今回のロジックではWaySpot名が一致すると、3Dコンテンツのタグ要素を有効にすることで空間にコンテンツを可視化しています。xrprojectwayspotupdatedイベントは、位置と方向の調整ですね。状態が更新されれば座標系を修正する処理が入っています。

```javascript:
const namedWayspotComponent = {
  schema: {
    name: {type: 'string'},
  },
  init() {
    const {object3D} = this.el
    const {name} = this.data
    object3D.visible = false

    const foundWayspot = ({detail}) => {
      if (name !== detail.name) {
        return
      }
      object3D.visible = true
    }

    const updateWayspot = ({detail}) => {
      if (name !== detail.name) {
        return
      }
      object3D.position.copy(detail.position)
      object3D.quaternion.copy(detail.rotation)
    }

    this.el.sceneEl.addEventListener('xrprojectwayspotfound', foundWayspot)
    this.el.sceneEl.addEventListener('xrprojectwayspotupdated', updateWayspot)
  },
}

export {namedWayspotComponent}
```

なお、VPS自体を有効化している部分はA-Frameのa-sceneタグの中で設定しています。

```html:body.html
<a-scene
  landing-page
  vps-coaching-overlay
  background="color: #303030"
  renderer="colorManagement: true"
  gltf-model="dracoDecoderPath: https://cdn.8thwall.com/web/aframe/draco-decoder/"
  xrextras-runtime-error
  xrextras-loading
  xrweb="enableVps: true">
```

なお、任意のWaySpotを見つけた場合のイベントであれば以下の様に書き換えることで動作するようです
```javascript
this.el.sceneEl.addEventListener('xrmeshfound', foundWayspot)
this.el.sceneEl.addEventListener('xrmeshupdated', updateWayspot)
```