Unityで点群のロード・表示

## 概要

点群データ（LAS）をUnity上で読み込めるようにしてみます。
これまでにも、いろいろな手法が解説されていると思います。

- pcacheとして点群を読み込み、VFX Graphを使う
- テキストファイルを読み込む

などいろんなアプローチがあります。
この記事では、八分木(octree)で空間インデックス構築済みの形式である[Potree](https://github.com/potree/potree/)に変換して読み込ませます。
既存のアセットを利用するだけなので、あまり難しくありません。

## Potreeを用意する

適当な点群データを引っ張ってきます。
ここでは、[浜松城の点群（出典：「静岡県ポイントクラウドデータベース」）](https://pointcloud.pref.shizuoka.jp/lasmap/ankendetail?ankenno=29XXX00010002)を使います。
CC-BYで公開されています。
ダウンロードした点群は同じフォルダに格納してください。

必要に応じて、CloudCompareなどを使って間引きなどを行ってください。
（上記データセットの規模なら不要だと思います）

LASファイルを全部落としてきたら、[Potree Converter](https://github.com/potree/PotreeConverter/releases/tag/1.6)を用意します。
```PotreeConverter_1.6_windows_x64.zip```をダウンロードして、展開します。

コマンドプロンプトなどシェルを開いて

```
PotreeConverter LASファイルを置いたフォルダ -o 出力先フォルダ
```

を実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644525/ae3841cf-4969-40b1-9a57-c84353336d6a.png)

出力フォルダを見ると、点群が細かいファイルに分割されて格納されていますが、これは八分木に基づいて分割されています。

## Unityで点群を読み込む

Unityで新規プロジェクトを立ち上げます。

[BA_PointCloud](https://github.com/SFraissTU/BA_PointCloud)を[ダウンロード](https://github.com/SFraissTU/BA_PointCloud/releases/tag/1.4)します。
UnityPackageをダウンロードし、ダブルクリックするとUnityでこのようなダイアログが出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644525/6179f968-be18-3ed6-1f31-534ff112a120.png)
「インポート」します。

必要なスクリプトやシェーダなどがインポートされるので、点群を読み込むためのもろもろを行っていきます。

---

プロジェクト→Assetsフォルダに「StreamingAssets」フォルダを作成します。
ここにPotreeに変換した点群を投入していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644525/d909eb8a-e349-52c7-7c29-286301a9f93f.png)

小さなファイルがたくさんあるので、かなり時間がかかると思います。
（Unity詳しくないので微妙ですが、単一ファイルにまとめるなど簡略化する方法あるかもしれません）

---

シーンを右クリックして、空のGameObjectを作成します。
「Dynamic Point Cloud Set」をコンポーネントに追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644525/001a76a7-0f96-279a-05a8-eb5a9b68e9f8.png)

同じ要領で、空のGameObjectを作成します。
「Point Cloud Loader」をコンポーネントに追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644525/2bb7bb11-2a37-165d-a582-a67ab6bb3af2.png)

さらに、空のGameObjectを作成します。
「Default Mesh Configuration」をコンポーネントに追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644525/500dbad4-c7ec-3a2f-c692-19ad5d486d63.png)

既存のMain Cameraオブジェクトに「Camera Controller」を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644525/eba1b974-8d50-d982-b8b8-d74df461ccaa.png)

それぞれのコンポーネントに設定をしていきます。

### Point Cloud Loader

点群のロード場所などを設定します。

- Cloud Path
  - StreamingAssetsへ配置したフォルダ名
- Streaming Assets As Root
  - true
- Set Controller
  - Point Cloud Setを指定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644525/dd3906ce-fd12-1671-3179-bac12851c216.png)

### Dynamic Point Cloud Set

総合的な管理を行うコンポーネントです。
一度に読み込む点群の量やバッファなどを制御することができます。
パフォーマンス調整などに使えると思います。

- Mesh Configuration
  - Default Mesh Configurationを指定
- User Camera
  - Main Cameraを指定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644525/c54ec29c-53a2-3d6a-a6cb-0c916748d22d.png)

### Default Mesh Configuration

点群のシェーダに渡す設定を行います。
お好みで大丈夫です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644525/39f15a35-7472-13d5-7e07-78c1e04b6cda.png)

----

設定は大体こんな感じで終了です。

## 結果

無事浜松城がUnity上でレンダリングされました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644525/9e89c710-f518-7698-6602-7e0351565def.png)

視点を動かしてみるとわかりやすいですが、視点を動かした先の点群が充填されるように読み込まれていきます。
近傍にある点群では密な点群を表示し、遠くにある点群では疎な点群が読み込まれているはずです。
Potreeを使うと、Level of Detailのような感じで動的に読み込みできるようです。