QGIS データを Web で表示 #2 - Qgis2threejs

QGIS で作成したデータ（"プロジェクト"）を Web ページで表示する方法について、ノウハウを共有します。

前回の [QGIS データを Web で表示 #1 - qgis2web](https://qiita.com/softark/items/b625175f182694e4836e) に続いて、この二回目では、QGIS のプラグインである Qgis2threejs を使用して、Web 三次元地形図を作成します。

なお、以下の説明では QGIS 3.40 および Qgis2threejs 2.8 を使用しています。

## 1. Qgis2threejs をインストールする

メニュー・バーで `プラグイン > プラグインの管理とインストール ...` を選び、`Qgis2threejs` を検索してインストールします。

## 2. QGIS プロジェクト

QGIS で作成したプロジェクトを用意します。ここでは第1回で説明のために使用したものを少し修正したプロジェクトを使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/13baaf22-e862-b8eb-cf17-cf727db86b7e.png)

以下のレイヤ構成になっています。

| レイヤ名 | 種別 | 備考 |
|:--|:--|:--|
| スポット | ベクタ（点） | 公共建造物、名所 |
| 棚田 | ベクタ（ポリゴン）  |   |
| 境界線 | ベクタ（線） | 地区境界線 |
| DSM | ラスタ | 標高データ（後で詳述） |
| 航空写真 | XYZ タイル | Google Satellite |

縮尺が小さいためにスポットは表示されておらず、棚田もあまりよく見えませんが、全てのレイヤを表示している状態です。

これを下のスクリーンショットのように、境界線と背景を表示、スポット、棚田、DSM を非表示にした状態にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/3aaa55bb-75a9-d4bc-a5f5-f977e77f3451.png)

### 2-1. Qgis2threejs がプロジェクトから参照するもの

Qgis2threejs は、プロジェクトの次のデータを参照します。

- 標高データ用レイヤ
- テクスチャ画像作成用レイヤ
- ベクタ・レイヤ
- 表示範囲

#### 2-1-1. 標高データ用レイヤ

Qgis2threejs は、三次元ワイヤフレームを作成するために、標高データを持つレイヤを少なくとも一つ必要とします。

ここでは DSM というレイヤがそのために用意したレイヤです。

標高データとしては DEM または DSM を使用します。

- DEM ... 数値標高モデル (Digital Elevation Model)
    - 地表面の高さ情報を持つデータ。建物などの人工物は含まれず、地形の起伏を表すのに使用
- DSM ... 数値表層モデル (Digital Surface Model)
    - 建物や樹木などを含む地表面の高さを表すデータ。都市の3Dモデルなどに適している

なお、Qgis2threejs では DSM も含めて標高データを DEM と呼んでいます。

#### 2-1-2. テクスチャ画像作成用レイヤ

Qgis2threejs は、三次元ワイヤフレームに投影するテクスチャ画像を作成するためのレイヤを少なくとも一つ必要とします。

ここでは、`境界線` + `航空写真` の二つのレイヤをそのためのレイヤとしていますが、ラスタ・ベクタ・XYZ タイルなどを自由に組み合わせることが出来ます。背景の XYZ タイルだけでも構いません。

ただし、Qgis2threejs 起動後にテクスチャ画像作成用レイヤを選び直したり、描画順序を変更したりすることは出来ません。プロジェクトの現在の表示設定がそのまま適用されます。

#### 2-1-3. ベクタ・レイヤ

Qgis2threejs はベクタ・レイヤを表示することが出来ます。元のプロジェクトで非表示になっていても構いません。また、テクスチャ画像用レイヤに含まれていても、それとは別にベクタとして表示されます。

#### 2-1-4. 表示範囲

三次元表示する対象領域は、起動時の表示領域が初期設定として使用されます。ただし、後で説明するように、これは選択し直すことが出来ます。

## 3. Qgis2threejs を使う

メニュー・バーで `Web > Qgis2threejs > Qgis2threejs Exporter (WebEngine) または Qgis2threejs Exporter (WebKit)` を選びます。WebEngine、WebKit どちらでも構いません。すると、下図のようなダイアログが開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/ecb4461f-cc65-41d0-96cd-80a086525e15.png)

### 3-1. 基本操作 - 表示するレイヤを選ぶ

左側に Layers のペインがありますので、"DEM" は後回しにして、表示可能なベクタ・レイヤを全て表示させてみると、下図のようにプレビューが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/c03b391c-a12e-e5da-d09e-8e1a0ea5ef34.png)

"スポット"、"棚田"、"境界線" が表示されているのが確認できます。

次に "DEM" の中の "DSM" を `ON` にすると、次のようなプレビューが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/e0babff0-5ecf-07f8-bb2c-b32871f3a097.png)

このような画面こそ求めていた三次元地形図なのですが、表示されるはずの "スポット" と "棚田" が表示されていないのが気になります。

そこで、`'Shift' + '↓'` を押して、視点を下げ、`'Shift' + 'Ctrl' + '↑'` を押してズームインすると、下の図のように、地形図を下から覗くことが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/18bb170c-d9bd-5703-43b7-b326b39d09da.png)

すなわち、"スポット" は標高データを持っていないために、標高 0 m の位置に表示されて、地形図の下に隠れていた訳です。"棚田" と "境界線" も同様です。

これの修正については後で説明します。

### 3-2. 基本操作 - 視点（カメラ位置）移動

ここまで来ると、マウスでぐりぐりして遊ぶことが出来ます。いや、生成された三次元地形図をさまざまな視点から眺めてチェックする必要が出て来ますので、視点（カメラ位置）を移動する方法に習熟するのが良いでしょう。下の表に操作方法をまとめておきます。

**マウス操作**
| マウス | 操作 |
|---|---|
| 左ドラッグ | オービット（軌道周回） |
| ホィール | ズーム |
| 右ドラッグ | パン |

**キーボード操作**
| キー | 操作 |
|---|---|
| 矢印 | 水平移動 |
| Shift + 矢印 | オービット（軌道周回） |
| Ctrl + 矢印 | 回転 |
| Shift + Ctrl + 上下 | ズーム |
| L | ラベル表示 |
| R | オービット・アニメーション |
| W | ワイヤーフレーム |
| Shift + R | 視点（カメラ位置）リセット |

### 3-4. 表示領域の指定

メニュー・バーから `Scene > Scene Settings ...` を選ぶと、次のようなダイアログが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/c3284565-26a2-f4c4-1ebf-64a32edf8cd8.png)

`World タブ > Base Extent` が表示領域を設定する箇所です。

初期値は `Use map canvas extent` が選択されていると思います。これは QGIS のキャンバスの現在の表示領域をそのまま適用するという設定です。

そのままにしておいても構いませんが、`Fixed extent` に変更して、自由に設定し直すことも出来ます。

- キャンバス上で領域を指定
    - `Select` ボタンを押して `Select Extent on Canvas` を選ぶと、QGIS のメイン画面に切り替わるので、マウスで矩形を描いて領域を指定する
- レイヤの領域を使用
    - `Select` ボタンを押して `Use layer extent` を選ぶと、更にどのレイヤを使うかを選ぶ小さなダイアログが表示されるので、目的のレイヤを選ぶ

どちらの場合も、`Center X`, `Center Y`, `Width` および `Height` が自動的に設定されます。そしてこれを手入力で微修正することが可能です。

`OK` または `適用` を押すと確定されて、新しい値に応じてプレビュー画面が再描画されます。

`Scene Settings` のダイアログには、この他にも項目がありますが、ここでは説明を割愛します。

### 3-5. テクスチャ画像の設定

レイヤ・パネルで "DSM" を選び、右クリック・メニューを呼び出して `Properties ...` を選択すると、次のようなダイアログが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/7cb7dfa4-0f8b-f403-1c08-7bf934376c75.png)

`Main タブ > Material > Image width` の項目によって、テクスチャ画像の解像度を（間接的に）設定することが出来ます。

- 数値が小さいほど低解像度
    - 粗い画像になる
    - 一定の縮尺を超えないと表示しない設定のレイヤは除外されるおそれがある
    - 表示は軽くて速くなる
- 数値が大きいほど高解像度
    - 細かい画像になる
    - 表示は重くて遅くなる

`OK` または `適用` を押すと確定されて、新しい値に応じてプレビュー画面が再描画されます。

地形レイヤの `Layer Propertys` のダイアログには、この他にも項目がありますが、ここでは説明を割愛します。

### 3-6. ベクタ・レイヤの設定

レイヤ・パネルでベクタ・レイヤ（例えば "スポット"）を選び、右クリック・メニューを呼び出して `Properties ...` を選択すると、次のようなダイアログが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/59318994-0e22-1888-6535-8135111cacba.png)

#### 3-6-1. 標高値の適用

`Main タブ > Z coordinate > Mode` を `Absolute` から `Relative to "DSM" layer` に変更して `OK` を押します。

これによって、地物はその場所に応じて "DSM" レイヤから標高値を取得して、地形図上のしかるべき位置に表示されるようになります。

#### 3-6-2. ラベルの設定

`Labels` タブに切替えると、次のようなダイアログが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/64398f41-06f9-d309-9ffe-91795cd8ef0f.png)

- Show Labels ... ラベルを表示するか否かを設定します。初期値は `OFF` になっていて、ラベルは表示されません
- Position ... ラベルを表示する標高値を設定します。通常は `Relative` を選び、点の上方何 m の位置に表示するかを数値で指定します
- Text ... ラベルに表示する属性フィールド、フォント、サイズ、縁取り、背景、引出線を指定します。サイズはスライダーによる固定値しか選べません

`OK` または `適用` を押すと確定されて、新しい値に応じてプレビュー画面が再描画されます。

ベクタ・レイヤの `Layer Propertys` のダイアログには、この他にも項目がありますが、ここでは説明を割愛します。

### 3-7. エクスポート（Export）

ここまでの作業で、下の図のようなプレピューが表示されるようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/272c4182-0a7b-50e7-983d-1f1ec442ca6a.png)

ここで一旦エクスポートして、ウェブ・ブラウザで結果を確認します。

メニュー・バーで `File > Export to Web...` を選ぶと、下の図のようなダイアログが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/09cedfdb-3d3e-467b-ac58-3af240ae83bf.png)

- Output directory ... 出力先フォルダを指定。選び直さない限り、毎回、同じフォルダに出力される
- HTML filename ... `index.html` または好みのファイル名を指定
- Page title ... ページのタイトルを指定
- Preserve the current viewpoint ... 現在の視点（カメラ位置）を初期値とする
- Enable the viewer to run locally ... ON を推奨（少なくとも開発中は）

以上のように設定して `Export` ボタンを押すと、指定したフォルダの直下に必要なファイルが全てされ、ダイアログが `Log` タブに切り替わります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/9ed0485f-0f4d-3013-7b25-71d701f1cab3.png)

`Web page file` のリンクをクリックすると、ウェブ・ブラウザが起動して、エクスポートされた Web ページを表示します。

このとき、`Enable the viewer to run locally` を `OFF` にしてエクスポートした場合は、
> Error
> This browser doesn't allow loading local files via Ajax. See plugin wiki page for details.

というエラーが表示されて、ページが表示されません。「ローカル・ファイルを Ajax 経由で読み込むことが許されていません」ということですね。運用環境に配備すれば解決する問題ですが、少なくとも開発中は `Enable the viewer to run locally` を `ON` にしておく方が楽です。

## 4. カスタマイズ

作成されたファイルを運用環境に配備する前に、index.html に修正を加えてカスタマイズすることが可能です。CSS や javascript の修正も不可能ではありませんが、難易度は高くなります。

お奨めするのは、index.htm の中にある `pageinfo` のセクションを日本語に翻訳することです。

```diff_html
    <!-- page info -->
    <div id="pageinfo">
-     <h1>Current View URL</h1>
+     <h1>現在のビューの URL</h1>
      <div><input id="urlbox" type="text"></div>
-     <h1>Usage</h1>
+     <h1>操作方法</h1>
      <table id="usage">
-       <tr><td colspan="2" class="star">Mouse</td></tr>
-       <tr><td>Left button + Move</td><td>Orbit</td></tr>
-       <tr><td>Mouse Wheel</td><td>Zoom</td></tr>
-       <tr><td>Right button + Move</td><td>Pan</td></tr>
+       <tr><td colspan="2" class="star">マウス</td></tr>
+       <tr><td>左ドラッグ</td><td>オービット（軌道周回）</td></tr>
+       <tr><td>ホィール</td><td>ズーム</td></tr>
+       <tr><td>右ドラッグ</td><td>パン</td></tr>

-       <tr><td colspan="2" class="star">Keys</td></tr>
-       <tr><td>Arrow keys</td><td>Move Horizontally</td></tr>
-       <tr><td>Shift + Arrow keys</td><td>Orbit</td></tr>
-       <tr><td>Ctrl + Arrow keys</td><td>Rotate</td></tr>
-       <tr><td>Shift + Ctrl + Up / Down</td><td>Zoom In / Out</td></tr>
-       <tr><td>L</td><td>Toggle Label Visibility</td></tr>
-       <tr><td>R</td><td>Start / Stop Orbit Animation</td></tr>
-       <tr><td>W</td><td>Wireframe Mode</td></tr>
-       <tr><td>Shift + R</td><td>Reset Camera Position</td></tr>
-       <tr><td>Shift + S</td><td>Save Image</td></tr>
+       <tr><td colspan="2" class="star">キーボード</td></tr>
+       <tr><td>矢印</td><td>水平移動</td></tr>
+       <tr><td>Shift + 矢印</td><td>オービット（軌道周回）</td></tr>
+       <tr><td>Ctrl + 矢印</td><td>回転</td></tr>
+       <tr><td>Shift + 上 / 下</td><td>ズーム イン / アウト</td></tr>
+       <tr><td>L</td><td>ラベル表示 ON / OFF</td></tr>
+       <tr><td>R</td><td>オービット・アニメーション 開始 / 停止</td></tr>
+       <tr><td>W</td><td>ワイヤフレーム・モード</td></tr>
+       <tr><td>Shift + R</td><td>カメラ位置をリセット</td></tr>
+       <tr><td>Shift + S</td><td>画像を保存</td></tr>
      </table>
```

上記に続く `About` の所も、自分のサイトへのリンクに書き換えても良いかもしれません。

エクスポートによって毎回ファイルが作成され直すことを考えると、差し替え用のコード断片を保存しておいて利用するのが良いでしょう。

## 5. 運用環境への配備（デプロイ）

エクスポートされたフォルダ内にある全てのファイルとサブ・フォルダをウェブ・サーバのドキュメント・ルート以下のしかるべき場所にアップロードし、他のページからリンクを張ります。それだけです。QGIS のプロジェクト・ファイルやデータ・ファイルをウェブ・サーバにアップロードする必要はありません。

## 6. ベクタ・レイヤについて

Qgis2threejo はベクタ・レイヤをそのまま扱うことが出来ます。表示の `ON` / `OFF` も切り替えることが出来て便利なのですが、一つ注意すべきことがあります。

どういうことかと言うと、線やポリゴンが十分な密度の点によって構成されていない場合、オブジェクトの一部が地形ポリゴンに埋没する、ということです。端点や構成点が正しい標高値を得ていても、線の中間部分が地形の標高より低くなることが多いためです。

この問題には、線を太くする、標高値に下駄を履かせる、オブジェクトのタイプを変更するなど、いくつか対処法がありますが、見た目を良くしようとすると簡単ではありません。

そういう理由から、このサンプル・プロジェクトでは、ベクタ・データである "境界線" をテクスチャ画像の要素として扱いました。"棚田" については、タイプを "Polygon" から "Extruded" に変更して、何とかベクタ・データとして扱えるようにスタイルを設定しています。

## 7. アニメーション

Qgis2threejs では、あらかじめ登録した一連のポイントに従って視点（カメラ位置）を移動させ、三次元地形図の表示を連続的に変化させることが出来ます。言ってみれば、仮想的な地形の上にドローンを飛ばして動画を撮影し、それを再生する機能です。

### 7-1. Animation パネル

メニュー・バーで `Window > Panels > Animation` を `ON` にすると、下の図のように、レイヤ・パネルの下にアニメーション・パネルが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/c97f0dd0-aee8-a8ec-7214-370fe593f3da.png)

### 7-2. フレーム（カメラ位置）の追加

`Camera Motion` を選択して、`＋` ボタンを押すと、下に `Group` が追加され、さらにその下に `keyframe 1` が追加されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/70b9f942-378d-f4f7-63f5-f5d4ca77e820.png)

これがアニメーションの開始位置になります。

次に、地形図にズーム・インして、もう一度 `＋` ボタンを押します。すると `keyframe 2` が追加されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/d422a471-b390-48de-29b0-4726d4fbd591.png)

またもう少しカメラを移動して `keyframe 3` を追加し、と、この作業を繰り返していきます。

- `再生` ボタン ... アニメーションを再生して確認することが出来ます
- `ー` ボタン ... フレームを削除することが出来ます
- `鉛筆` ボタン ... フレームのパラメータを編集出来ます
    - `Name` ... フレームの名称
    - `Narrative Content` ... このフレームで停止して写真などを表示することが出来ます
    - `Easing` ... 次のフレームまでの移動速度変化
    - `Delay` ... アニメーション開始までの待機時間（`ms`）
    - `Duration` ... アニメーションにかける時間（`ms`）

地形の周囲を `オービット` で周回するのを基本にして、時々 `ズーム`、`パン`、`回転`、`平行移動` でカメラ位置を調整すると、比較的楽にアニメーションを作成出来ます。

### 7-3. フェードイン & フェードアウト

`Camera Motion` 以外のレイヤを選択して、`＋` ボタンを押すと、`Change Opacity ...` メニューが出ます。選択すると、`Opacity` （不透明度）を入力する小さなダイアログが表示されます。`0`（透明）以上、`1`（不透明）以下の数値を入力します。すると、レイヤの下に `Opacity group` が追加され、さらにその下に `Opacity` のフレームが追加されます。

少なくとも、もう一つのフレームを追加すると、`Opactiy` のアニメーション、すなわち、フェードインまたはフェードアウトが登録されます。

`Opacity` のフレームについても、`Delay` と `Duration` を変更することが出来ます。`Delay` を調節することによって、カメラ位置のアニメーションの途中からレイヤをフェードイン・フェードアウトすることが出来ます。

### 7-4. エクスポート時のアニメーション指定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/6137c465-701b-8a50-f55a-25fe54d2e3b8.png)

アニメーションを有効にするためには、`Export to Web` ダイアログで `Animation and Narative` を有効にする必要があります。

`Start animation once the scene has been loaded` を `ON` にすると、アニメーションが自動開始されるようになります。

## 8. Qgis2threejs の長所と短所

### 8-1. 長所

- 手軽
- 軽快
- 面白い

地形図の表示と動作は非常に軽快です。

### 8-2. 短所

- 時間が溶ける（特にアニメーション）

## 9. 実装例

最後に、説明に使用した QGIS プロジェクトから Qgis2threejs で作成した Web 三次元地形図の実装例を紹介します。

- [岩座神の三次元地形図](https://isarigami.net/map/3d/index.html)

結構、軽快に動作します。視点の移動など、操作方法については、左上の information アイコンをクリックするとヘルプが表示されます。

## And so, what's next?

次は、いよいよ、QGIS Server、QWC2(QGIS Web Client 2)、MapCache を使っての、本格的な Web 地図の作成です。まずは、QGIS Server を動かすところから着手します。

- [QGIS データを Web で表示 #3 - QGIS Server](https://qiita.com/softark/items/c1da4f9a52e6727a5e97)