OpenStreetMapとA-FrameでWebVR会津観光をしよう

Qiita投稿3つ目の初心者です。よろしくお願いいたします。

# 前書き

弊社の地図ガチ勢上司より、[OpenStreetMap](https://www.openstreetmap.org/)の誕生日が本日8月9日なので、OpenStreetMapかつ地元観光資源で記事を書くのだフハハハハ…という話があり、今回の記事を書くに至りました。

`OpenStreetMap` の誕生日ってなんだろうと思い調べてみると、 `OpenStreetMap.org` のドメイン名取得の記念日とのことです。
参考：
[Birthday - OpenStreetMap Wiki](https://wiki.openstreetmap.org/wiki/Birthday)
[Celebrate the 16th OSM anniversary!](https://blog.openstreetmap.org/2020/08/01/celebrate-the-16th-osm-anniversary/)
OpenStreetMapさん、お誕生日おめでとうございます！

記事の内容としては、[OpenStreetMap(OSM)の3DマップとA-Frameを使ってWebVRを作ってみた](https://qiita.com/syntan/items/b89471803a27320256a6)と同じようなことをしていきますが、osmファイルのファイルフォーマット変換に別のツールを使った方法があるので、それぞれの変換結果を比較して、どちらを使うか選択しようと思います。また、今回2つのマップモデルを一つの空間に設置するので、移動を簡単にするため瞬間移動ギミックを追加したWebVRを構築していこうと思います。

# 前提環境
* OS：Windows 10
* Webブラウザ：FireFox 55以降 記事中では78.0.2を使用
* Blender：2.8X 記事中では2.83.2を使用(今回は比較のための参照使用のみです)

# 1. OpenStreetMapから3Dマップデータを取得
取得方法の詳細は[OpenStreetMap(OSM)の3DマップとA-Frameを使ってWebVRを作ってみた](https://qiita.com/syntan/items/b89471803a27320256a6)をご参照ください。

今回は、会津若松鶴ヶ城、飯盛山さざえ堂を取り出していきます。

## 1.1. 会津若松鶴ヶ城
![鶴ヶ城OSMエクスポート.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/60d5d38e-652f-8ae2-0c00-cd8b41454546.png)

## 1.2. 飯盛山さざえ堂
![さざえ堂OSMエクスポート.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/0c3d5dcc-1a37-bb51-0928-81de8a6f18bc.png)

# 2. OSMファイルを変換

A-FrameではOSMファイルは直接読み込めないため、glTFファイルもしくはOBJファイルへ変換する必要があります。
※A-Frameの公式ドキュメントによると、glTFが推奨されています。理由としては、表現力が高いこと、アニメーションがつけれること…など。
参考：[3D Models - A-Frame](https://aframe.io/docs/0.9.0/introduction/models.html)

## 2.1. OBJファイルとMTLファイルへ変換

OpenStreetMap公式から紹介されている[OSM2World](https://wiki.openstreetmap.org/wiki/OSM2World)を使用して、OSMファイルからOBJファイルとMTLファイルへ変換が行えます。
OBJファイルがモデルの形状(ジオメトリ)情報を持ち、MTLファイルがモデル表面の色など質感(マテリアル)情報を持ちます。

### 2.1.1. OSM2Worldの使い方
[OSM2World Download](http://osm2world.org/download/)の0.2.0をダウンロードします。
![OSM2World Download.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/1862e649-cfd3-efe1-e07e-caf971dcf426.png)
ダウンロードしたZIPを解凍し、 `OSM2World.jar` をダブルクリックで起動します。

> OSM2World はJRE(Java Runtime Environment) 1.6 以降を必要とします。

とのことなので、起動できなかった場合はJREの導入をしましょう。
起動できた画面は下記です。
![OSM2World 起動画面.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/6478eeb2-82a0-b191-5dd2-4f52ddf87def.png)

起動出来たら、上部メニューのFile>Open OSM fileからOSMファイルを開きます。読み込み完了まで少し時間がかかります。
![OSM2World OSM読み込み.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/2fb79c6b-6c05-0bbe-5348-93c834599c1e.png)

鶴ヶ城を読み込んだ画面は下記です。
![OSM2World 鶴ヶ城読み込み.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/bc4e32e7-cbdb-e517-874c-91fc8a5053ef.png)

上部メニューのFile>Export OBJ fileから保存先を指定すると、OBJファイルと同じフォルダに対応するMTLファイルが出力されます。出力完了まで少し時間がかかります。
![OSM2World 鶴ヶ城OBJエクスポート.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/f4561b25-010d-bdb8-dc52-9831ac88a507.png)

さざえ堂も同様に出力しました。
![OBJ出力後.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/a8fe9283-3e05-ff59-d648-a6342fbabada.png)

## 2.2. Blenderアドオンで読み込んだものと比較

下記が、Blenderアドオン `blender-osm` で読み込んだもの
※ `blender-osm` の使用方法は[OpenStreetMap(OSM)の3DマップとA-Frameを使ってWebVRを作ってみた](https://qiita.com/syntan/items/b89471803a27320256a6)をご参照ください。
![blender-osm.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/4e2d6ead-d84b-2746-3e55-b63ae343ea3f.png)
下記が、 `OSM2World` で変換したOBJ、MTLファイルを読み込んだもの
![OSM2World.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/9a744802-6676-c63b-d18c-19daaea2e1ae.png)
木が生えましたね。用途によって使い分けができそうです。
今回のようにVR観賞用としては、にぎやかな方がいいと思うので、 `OSM2World` の結果を採用です。この前はglTFファイルの読み込みを行っていたので、今回はOBJファイルをそのまま使ってみます。

# 3. WebVRの構築

鶴ヶ城とさざえ堂の2つのマップモデルを読み込み、そのまま移動するのは大変なので、それぞれを瞬時に行き来できる瞬間移動ギミックを追加します。

## 3.1. HTMLコード

```index.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Hello, VR Aizu!</title>
        <!-- aframe-extras requires 0.9.X aframe -->
        <script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script>
        <!-- https://github.com/donmccurdy/aframe-extras -->
        <script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras@v6.1.0/dist/aframe-extras.min.js"></script>
        <script src="script/teleport.js"></script>
    </head>
    <body>
        <a-scene background="color: #EEEEEE">
            <a-assets>
                <a-asset-item id="shiro-obj" src="models/shiro.obj"></a-asset-item>
                <a-asset-item id="shiro-mtl" src="models/shiro.obj.mtl"></a-asset-item>
                <a-asset-item id="sazaedo-obj" src="models/sazaedo.obj"></a-asset-item>
                <a-asset-item id="sazaedo-mtl" src="models/sazaedo.obj.mtl"></a-asset-item>
            </a-assets>

            <!-- light -->
            <a-light color="#FFEEEE" position="-1 1 0"></a-light>
            <a-light color="#333" type="ambient"></a-light>

            <!-- objects -->
            <a-entity id="shiro" 
                    position="0 0 0" 
                    rotation="0 0 0" 
                    obj-model="obj: #shiro-obj; mtl: #shiro-mtl" 
                    scale="1 1 1" 
                    shadow="">
            </a-entity>
            <a-entity id="sazaedo" 
                    position="0 60 -640" 
                    rotation="0 0 0" 
                    obj-model="obj: #sazaedo-obj; mtl: #sazaedo-mtl" 
                    scale="1 1 1" 
                    shadow="">
            </a-entity>

            <!-- movement control -->
            <a-entity id="rig"
                movement-controls
                position="0 0 0">
                <a-entity camera
                            position="0 1.6 0"
                            look-controls="pointerLockEnabled: true">
                </a-entity>
                <a-entity id="ctlL" laser-controls="hand: left"></a-entity>
                <a-entity id="ctlR" laser-controls="hand: right"></a-entity>
            </a-entity>

        </a-scene>
    </body>
</html>
```

`index.html` のフォルダ階層に、 `models` フォルダを作成し、上記で出力したOBJファイル、MTLファイルを入れています。同様にして `script` フォルダを作成し、 `teleport.js` ファイルを入れています。

## 3.2. JavaScriptコード

```teleport.js
window.addEventListener('load', function (event){
    const ctlL = document.getElementById("ctlL");
    const ctlR = document.getElementById("ctlR");
    const rig = document.getElementById("rig");

    //Trigger Released
    ctlL.addEventListener('triggerup', function (event) {
        rig.setAttribute('position', {x: 0, y: 0, z: 0});
    });
    ctlR.addEventListener('triggerup', function (event) {
        rig.setAttribute('position', {x: 0, y: 60, z: -640});
    });
});
```

コントローラーのトリガーボタンが離されたタイミングで発生するイベントに、プレイヤーの位置を変更するギミックを設定しています。

* 左手のコントローラーのトリガーアップ：{x: 0, y: 0, z: 0}地点(鶴ヶ城)へ移動
* 右手のコントローラーのトリガーアップ：{x: 0, y: 60, z: -640}地点(さざえ堂)へ移動

## 3.3. 配置関係
![a-frameインスペクター 配置関係.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/fc69a6da-6dac-2231-fbc0-e630216f5113.png)
実際の配置関係とは異なりますが、さざえ堂のマップからお城を眺められたら面白いかなぁ…という思いでさざえ堂マップの配置を少し高い位置へ配置してみました。

# 4. VRで実行した様子
レッツバーチャル会津観光！
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">VRで会津観光してみた<a href="https://twitter.com/hashtag/%E4%BC%9A%E6%B4%A5%E8%A6%B3%E5%85%89?src=hash&amp;ref_src=twsrc%5Etfw">#会津観光</a> <a href="https://twitter.com/hashtag/aframe?src=hash&amp;ref_src=twsrc%5Etfw">#aframe</a> <a href="https://twitter.com/hashtag/VR?src=hash&amp;ref_src=twsrc%5Etfw">#VR</a> <a href="https://twitter.com/hashtag/WebVR?src=hash&amp;ref_src=twsrc%5Etfw">#WebVR</a> <a href="https://twitter.com/hashtag/OpenStreetMap?src=hash&amp;ref_src=twsrc%5Etfw">#OpenStreetMap</a> <a href="https://twitter.com/hashtag/OpenStreetMap16?src=hash&amp;ref_src=twsrc%5Etfw">#OpenStreetMap16</a><br><br>地図データ：© OpenStreetMap contributors<br>Happy Birthday OpenStreetMap🎂 <a href="https://t.co/KHIrxYo7x8">pic.twitter.com/KHIrxYo7x8</a></p>&mdash; syntan (@synsyntan) <a href="https://twitter.com/synsyntan/status/1292318371506135042?ref_src=twsrc%5Etfw">August 9, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# ライセンス

記事中で使用した、オープンソースライブラリ、3Dモデルのライセンスです。

## コード
* A-Frame：[The MIT License Copyright © 2015-2017 A-Frame authors.](https://github.com/aframevr/aframe/blob/master/LICENSE)
* aframe-extras：[The MIT License (MIT) Copyright (c) 2016 Don McCurdy](https://github.com/donmccurdy/aframe-extras/blob/master/LICENSE)

## 地図データ
* © [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors

# 参考
* https://aframe.io/docs/0.9.0/introduction/
* https://tks-yoshinaga.hatenablog.com/entry/oculus_quest_aframe