スマホで草を生やすために必要なことの考察

## はじめに
この記事は[Akatsuki Advent Calendar 2017](https://qiita.com/advent-calendar/2017/aktsk)の3日目の記事です。
2日目: [timecop 実装解説](https://qiita.com/TobiasGSmollett/items/f6888f092bc7895e1995)

スマホでオープンワールドを作りたくなりました。
広大な大地、大量の木や草などのオブジェクト。
これらをスマホで表現してみることに挑戦します。
今回はその一環で、まずは草を大量に表示することに挑戦し、処理速度の面で必要なことを考えてみます。

## 用意したもの
- UE4
.18.1
- [Open World Demo Collection](https://www.unrealengine.com/marketplace/item/bb1785d2edc04e1e8df3c7dd3e4b0ff3)
- [Infinite Affordable Landscapes](https://www.unrealengine.com/marketplace/infinite-affordable-landscapes)
- iPhone7

こんな感じのマップを使用します。
4km * 4kmのマップです。
![map01.png](https://qiita-image-store.s3.amazonaws.com/0/55107/44f6b67d-c3c6-9bb3-7bb4-cc6596945c88.png)
![map02.png](https://qiita-image-store.s3.amazonaws.com/0/55107/82c01072-194f-0103-f493-e163ae4e253c.png)
スマホで起動してみます。
![2017-12-03 20.03.29.png](https://qiita-image-store.s3.amazonaws.com/0/55107/57e17189-4d37-b23c-6016-008ae52b08cb.png)
初期マップのfpsは**60fps**でした。
今回はこの草をスケーリングして使います。
![grass00.jpg](https://qiita-image-store.s3.amazonaws.com/0/55107/f73dbb29-245b-c8fb-862c-02e3011ffce8.jpeg)

## インスタンス化
1つのメッシュを複数配置する際にインスタンス化をしておくと1回のDrawCallで描画が可能です。
草や木などに最適です。
(インスタンス化メッシュの作り方は、使うゲームエンジンによって違うと思うので、ここでは書きません)
これを使ってマップ全体に草を生やします。
PCで見ると、こんな感じになります。ちなみに1fpsも出ませんでした。今にも落ちそう・・・。
![instance01.png](https://qiita-image-store.s3.amazonaws.com/0/55107/ed2fc744-3f26-bad7-a6f3-1d0c5a3eac97.png)
これをスマホで起動すると・・・落ちました、まあそうなりますね・・・。

## LOD
LODとは、カメラの近くにあるオブジェクトはクオリティ高く表示し、遠くにあるオブジェクトはクオリティ低く表示するLevel of Details(略してLOD)の事です。遠くのオブジェクトは画面上でわずかなピクセルしか使わず、プレイヤーからほとんど見えないので、複雑で詳細なメッシュを持つ意味は薄いです。
以下のように、遠くにあるモデルほど、モデルのクオリティを落とすよう設定します。
triangles: 765
vertices: 621
![grass00.jpg](https://qiita-image-store.s3.amazonaws.com/0/55107/f73dbb29-245b-c8fb-862c-02e3011ffce8.jpeg)
triangles: 278
vertices: 342
![grass01.jpg](https://qiita-image-store.s3.amazonaws.com/0/55107/f326ac5b-3b1b-d6a2-ebab-13c86d28e97c.jpeg)
triangles: 18
vertices: 36
![grass02.jpg](https://qiita-image-store.s3.amazonaws.com/0/55107/d3db5560-46f2-766a-5eb0-33edfee0c83c.jpeg)
実際に使う際は、最終的に張りぼてにするのがいいと思います。
PCで見ると、こんな感じになります。
before
![lod01.jpg](https://qiita-image-store.s3.amazonaws.com/0/55107/483ea297-d117-5c86-bff2-3a22da5cd0f5.jpeg)
after
![lod02.jpg](https://qiita-image-store.s3.amazonaws.com/0/55107/2d50ff1c-5b74-298c-305d-c12c9c1dd7fe.jpeg)
LODを使うと、このように見た目はほぼ変わらずに処理速度を上げることができます。

しかし、スマホで起動すると・・・落ちました、もう一段階なにかやってみましょう。

## 距離によるカリング
LODで遠くのオブジェクトはクオリティを低くしましたが、今度は遠くにあるオブジェクトはそもそも描画しないようにしてみます。
カメラから半径10mの範囲にしか草を描画しない設定にします。
![cull01.jpg](https://qiita-image-store.s3.amazonaws.com/0/55107/a81f059f-4746-dd28-46d7-7548aa3301cf.jpeg)
![cull02.jpg](https://qiita-image-store.s3.amazonaws.com/0/55107/4b80d630-fe53-3d9f-d423-68044d81fec9.jpeg)

以下はスマホのスクショです。
![cull03.png](https://qiita-image-store.s3.amazonaws.com/0/55107/5ad4f1da-a781-8cfa-5499-84cec3ac783b.png)
結果は**35fps ~ 45fps**となりました。

## 草と地面の配色
しかし、どうも草が生えているところと生えていないところの境界がきになります。
そこで、地面の色と草の色を似せて、その境界を目立たなくしてみます。
ちなみにこの手法は、最近だとゼルダBotWでも使われてます。
before
![cull03.png](https://qiita-image-store.s3.amazonaws.com/0/55107/5ad4f1da-a781-8cfa-5499-84cec3ac783b.png)
after
![cull04.png](https://qiita-image-store.s3.amazonaws.com/0/55107/6734fe62-170a-c10f-140e-f51d6b960d31.png)

まだ調整の余地はありますが、無調整の草よりかは目立たなくなりました。

## まとめ
- 同じメッシュを大量に描画する際はインスタンス化メッシュを使おう
- そしてLODを使おう
- 距離によるカリングをして、処理速度を稼ぎましょう
    - その際は、境目を目立たなくするような工夫をしましょう
    - 今回は触れませんでしたが、草の密度についても検討しましょう

何だかんだでPCとスマホ共通の最適化になってしまいましたが、一旦ここまでにします。

## おまけ
今回の開発、検証は全てWindowsでやりました。
全てBlueprintで構成されていて、プラグインをなにもいじっていなければ、itunes connectにアップロードする以外はすべてwindowsで完結できます。
※プラグインを何かしらオフにするだけでもwindowsでビルドできなくなります。
今回私はVRのプラグインをオフにしたことでちょっとハマりました・・・。