Unity上でNays2DHの計算結果を3D表示する【開発記録 vol.4】

# はじめに
表題の通り、iRIC Nays2DHの計算結果をUnity上で3D表示できるようにしよう！
という個人的なプロジェクトの開発記録です。
6月中にパーティクルによる流速表示ができるところまで持っていきたいですね。

# 現状の共有
Gameビューでカメラを操作（上昇&下降、前進、旋回）できるようになりました。
ちなみにカメラ操作でA、Sキーを使用したため、表示結果の切り替えは
A、Sキーではなく矢印キーで行えるように変更しました。
![Animation1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1147458/927c9ca1-a5b0-968f-8a1d-a0073ec027ea.gif)

今回はキーボードでカメラ操作を行う方法について解説していきます。

# キーボードによるカメラ操作
## カメラ操作の種類
カメラの操作方法としては以下2パターンが考えられるかなと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1147458/528ac00f-9830-74a1-327a-12f74e7ef14c.png)


一般に3Dソフトを触られている方はマウスで操作する方が馴染みがあると思いますが、
河川の場合は視点をぐりぐり回して下から覗き込むような操作は不要かなと思い、
カメラの角度は固定したままキーボード操作で移動できるような仕様を採用しました。

ちなみにキーボード操作による視点移動は以下の利点があると考えています。
- 誰でも直感的に操作できる
- マウスの無い環境（ノートPC）でも操作しやすい
- （作り手的に）実装が簡単

## 実装方法
Hierarchyで右クリック⇒Create Emptyを選択し、名前を"CameraObject"とします。
その後、"CameraObject"を右クリックしてCameraを選択すると、カメラが配置されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1147458/6d07ef9f-ce3f-5ab1-4952-3a475a48da96.png)

配置直後はカメラが水平方向に向いていますが、河川を見る場合は斜め下を見たいです。
そのため、**CameraのTransform**にてRotationでX軸周りに30°回転させます。
（CameraObjectのTransformではないことに注意！）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1147458/80bea207-01df-28b1-c666-0fca814c12e7.png)

あとはカメラを動かすスクリプトかけていきます。

```cs:CameraMove.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraMove : MonoBehaviour
{
    public float speed = 20f;
    public float rot = 50f;

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        //前進 Spaceキー
        if (Input.GetKey(KeyCode.Space))
        {
            Vector3 velocity = this.gameObject.transform.rotation * new Vector3(0, 0, speed); //Zがカメラ進行方向
            this.gameObject.transform.position += velocity * Time.deltaTime;

        }

        //上昇 Wキー
        if (Input.GetKey(KeyCode.W))
        {
            Vector3 velocity = this.gameObject.transform.rotation * new Vector3(0, speed * 0.5f, 0); //Yが上下方向
            this.gameObject.transform.position += velocity * Time.deltaTime;

        }

        //降下 Sキー
        if (Input.GetKey(KeyCode.S))
        {
            Vector3 velocity = this.gameObject.transform.rotation * new Vector3(0, -speed * 0.5f, 0);  //Yが上下方向
            gameObject.transform.position += velocity * Time.deltaTime;

        }

        //左旋回 Aキー
        if (Input.GetKey(KeyCode.A))
        {

            this.gameObject.transform.Rotate(0f, -rot * Time.deltaTime, 0f); //Y軸回りが旋回方向

        }
        //右旋回 Dキー
        if (Input.GetKey(KeyCode.D))
        {
            this.gameObject.transform.Rotate(0f, rot * Time.deltaTime, 0f); //Y軸回りが旋回方向

        }

    }
}
```

これを**CameraObject**に追加すればOKです。
（今度はCameraじゃないので注意！）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1147458/d2b57102-19b4-f70d-3b8b-615bfd6e7dc4.png)

## 補足
「CameraとCameraObjectを間違えないでね」感を出しましたが、
なんで間違えたらいけないのか補足的な説明をしてきます。

Unityにはグローバル座標とローカル座標があります。
「グローバル座標は原点(0,0,0）からの絶対的な位置や向き」、
「ローカル座標は親オブジェクトからの相対的な位置や向き」
といった表現をするっぽいのですが、ざっくり以下のイメージでいれば良いと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1147458/9997c963-004f-3ab7-5ecc-7cc270bfddbf.png)

今回いじったモデルでは、CameraObjectの座標系はグローバル座標、
Cameraの座標系はローカル座標（CameraObjectからの相対的な座標系）です。

今回実現したい視点は、カメラの向きは斜め下に傾けたいけど、
カメラの移動方向自体は水平方向を保ってほしいと考えました。

そのため、ローカル座標であるCameraの座標系を傾けていますが
キーボード操作による移動スクリプトはグローバル座標であるCameraObjectに
適用しています。

もしスクリプトをCameraに適用した場合、
30°傾いたローカル座標に則って移動してしまうので
カメラを前進させると、カメラが地表面に向かってどんどん沈んでいきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1147458/dddc1fca-1d5a-2702-69cc-dbe6afe6b2a4.png)

# おわりに
今回はカメラ操作について説明しました。
次回からはいよいよパーティクルを使って流速を表現したいなと
思っていますが、どうなることやら...

# （自分用）やりたいことのメモ
- 流速をパーティクルで表示したい
- PLATEAUの建物を表示したい
- 水面のシェーダーを流速と合わせたい