UnityでVRお絵かき ~LineRendererと遊ぶ~

#はじめに
皆さん、仮想世界に浸ってますか？
仮想世界の住人からたくさんの歓声が上がっているような気がします。

。。。

さて、私はInfratopという会社でプログラミングスクールのメンターをしています。
そこではRailsをメインに扱っていますが、最近の私のブームがVR開発です。

2016年VR元年以降、VRを体験する機会が急速に増えています。
VR ZONEやVR PARKといったVRを体験する施設ができたり、
VTuberなんていうコンテンツが登場したりしています。
また、Oculus Goといった低価格なVR機器も登場し、手軽にVRの体験・開発ができるようになりました。

#本題
本記事では、VR開発の足がけとしてUnity超初心者向けにVRお絵かきをUnityで実装する方法を解説します。

- Unityを使う
- Oculus Riftでの開発(Oculus Integration)
- VRお絵かき

#環境
- Unity 2018.2.14f1
- Oculus Rift

# Unityの使い方とLineRenderer
## プロジェクトを作成
Unityをインストールしていない方はこちらからダウンロードしてインストールをお願いします。
[Unity ダウンロードページ](https://unity3d.com/jp/get-unity/download)

Unityを起動できたら、適当な名前でプロジェクトを作成します。このときTemplateは3Dにしてください。
<img width="1112" alt="スクリーンショット 2018-12-10 19.16.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/346b29b5-f337-4907-a7cc-3bcf93d5b13d.png">

プロジェクトが生成できたら次にような画面になります。<img width="1792" alt="スクリーンショット 2018-12-10 19.20.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/548c7154-370f-df2d-f029-c41bc7a19b67.png">

## Unity
Unityで登場する概念を簡単に説明します。
Unityで大事なものは大きく二つ、**ゲームオブジェクト**と**コンポーネント**です。

- ゲームオブジェクトは、カメラや光源、直方体や球などのモデルといった**オブジェクト**です。
- コンポーネントは、物理エンジンやネットワーク管理といった**機能**です。

Unityでは**ゲームオブジェクトにコンポーネントで機能を付け加えて**アプリケーションを作り上げていきます。コンポーネントだけで存在することは原則ありません。

###補足
例えば、ネットワークのサーバ機能をアプリケーションに追加するときには**空のゲームオブジェクト**を作成し、それにネットワークの機能を持ったコンポーネントを追加するということをします。

## ゲームオブジェクトを追加する
試しに、球のゲームオブジェクトを追加してみましょう。
ステータスバーから`GameObject > 3D Object > Sphere`を選択してみてください。次にようになります。<img width="2021" alt="スクリーンショット 2018-12-10 19.38.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/830596be-6ddd-2b31-98c7-3584df18df75.png">

ここで画面の説明をします。

- 左のHierarchyウィンドウでは、シーンごとのオブジェクトを管理します。図の場合、SampleSceneというものがあり、その中にカメラと光源と球のゲームオブジェクトが存在しています。
- 真ん中のSceneウィンドウでは、編集中のシーンの画面が見えています。球が見えていますよね。隣のタブのGameウィンドウを開くと、アプリケーションを実際に起動したときの見え方に変わります。
- 右のInspectorウィンドウでは、選択しているゲームオブジェクトに付加してあるコンポーネント情報が表示されます。TransformコンポーネントのPositionの値を変化させると、Sceneでの球の位置が変わります。

![7720acc5d502031eb6145f0303ca0b58.gif](https://qiita-image-store.s3.amazonaws.com/0/131386/b02e65dd-9372-091c-c3e2-a12063baf8d0.gif)

## LineRenderer
それではお絵かきソフトの根幹となるLineRendererを使っていきましょう。
LineRendererはコンポーネントです。空のゲームオブジェクトを作成し、それにLineRendererコンポーネントを追加します。

Sphereを追加したときと同様に、ステータスバーから`GameObject > Create Empty`で空のゲームオブジェクトを作成します。Hierarchyに`GameObject`という名のゲームオブジェクトが追加されたでしょうか。

GameObjectを選択した状態でInspectorウィンドウの`Add Component`をクリックします。
<img width="634" alt="スクリーンショット 2018-12-10 19.56.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/bb8fd3ff-a472-5699-a0ff-220b6edff874.png">
この検索窓でLine Rendererと検索し、候補に出たLineRendererを選択します。
追加すると次のようにInspectorにLineRendererコンポーネントが追加されます。
<img width="584" alt="スクリーンショット 2018-12-11 18.17.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/78ad1de3-3886-e3ba-e58d-79ee7f468e73.png">

LineRendererはPositionsに設定した点を通るような線を描きます。
それではLineRendererを使ってみましょう。Inspectorで設定を次の図のように変更します。
<img width="882" alt="スクリーンショット 2018-12-10 20.06.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/aa1ceb9d-d950-c4be-1a50-207c91547964.png">


画像通りに設定するとこのようになります。
`(x,y,z)=[(0,0,0), (0,4,0), (4,4,0)]`を通る線になっています。
<img width="2021" alt="スクリーンショット 2018-12-10 20.13.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/9cdae59a-93a9-54b0-d330-9ee3f6933622.png">

## 
ここまででUnityの簡単な使い方の話を終わります。
大事なことは、Unityでは**ゲームオブジェクトにコンポーネントを付けてアプリケーションを作ること**です。
それではVR開発に内容をシフトしていきましょう。

# Oculus Riftでの開発
本記事ではOculus Riftを使って開発します。
Oculusは、UnityでOculus　Riftを使うためのツールを提供してくれているのでそれを利用します。

Asset Storeウィンドウを開いてOculus Integrationを探しましょう。
そしてimportをします。Oculus integrationの全てをimportして大丈夫です。

※Assetというのはライブラリやマテリアルなどの総称です。
Asset Storeでは便利なアセットが無償/有償で配布されているので色々覗いてみると面白いです。

<img width="2276" alt="スクリーンショット 2018-12-10 20.30.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/52e86647-c791-628e-7237-3d7c26d0e79f.png">

importが成功するとProjectウィンドウにOculusというフォルダが追加されます。
ProjectウィンドウからHierarchyウィンドウや、Inspectorウィンドウにドラッグアンドドロップすることで、ゲームオブジェクトやコンポーネントを追加できます。

## 操作アバターを追加
Projectウィンドウにおいて`Assets > Oculus > VR > Prefabs`の中にある`OVRPlayerController`をHierarchyウィンドウにドラッグアンドドロップします。

次に、`Assets > Oculus > Avatar > Content > Prefabs`の`LocalAvatar`を`OVRPlayerController > OVRCameraRig > TrackingSpace`にドラッグアンドドロップします。
これでLocalAvatarがOVRPlayerControllerの子要素になります。
子要素にすることでプレイヤーに関するゲームオブジェクトをまとめて管理することができます。

※この段階で球とLineRenderer用のGameObjectは消しておきましょう。

適切に追加するとHierarchyウィンドウが次のようになります。
<img width="435" alt="スクリーンショット 2018-12-11 15.57.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/7bbe27e1-4de5-c7f3-57ca-2f54818e3270.png">

## アバターテスト
アバターが動作するかテストします。まずはこのプロジェクトをVRに対応させましょう。
ステータスバーの`File > Build Settings`を開き、
ポップアップウィンドウの`Player Settings`を押します。
Inspectorウィンドウの場所にPlayerSettingが開かれるはずです。
XR Settingsを開きVirtual Reality SDKｓにOculusを追加します。
<img width="427" alt="スクリーンショット 2018-12-11 16.04.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/cc168f3e-dd4b-b5ea-ecb0-72d82526616f.png">

設定が完了したら、Oculus Riftを接続したことを確認し、Unity上部のPlayボタンを押します。
これだけでHMDやOculus Touchのトラッキング情報を反映したアバターが登場します。ね、簡単でしょ。

![avatar-test.gif](https://qiita-image-store.s3.amazonaws.com/0/131386/6b649318-a056-c8d3-d2c3-3ab61845a245.gif)

#VRお絵かき
ここからメインのVRお絵かきの話です。
これまではプログラムの記述をする必要はありませんでしたが、ここからはスクリプトがメインです。

## スクリプト
Unityでは`C#`か`Unity Script`を使ってプログラムの記述をします。本記事では`C#`で記述していきます。

ただVRお絵かきをするに必要なスクリプトは多くありません。簡単に流れを示します。

```
Oculus Touchのボタンが押されたことを検知
↓
LineRendererを付加したPrefabからゲームオブジェクトを生成
↓
ボタンを押してる間、コントローラーの位置情報をLineRendererのPositions配列に追加
↓
ボタンを離したらDrawを終了
```

## Prefab（プレハブ）
ここでPrefabという概念が登場します。
**Prefabはゲームオブジェクトとコンポーネントのセットを格納できるアセット**です。
同じ構造のゲームオブジェクトを繰り返し生成するときに使います。例えば、ゲームの敵キャラやプレイヤーなどですね。

ここでは、LineRendererをもつゲームオブジェクトのPrefabを用意します。
Hierarchyウィンドウで空のゲームオブジェクトを作成し、LineRendererコンポーネントをそれに追加します。
ゲームオブジェクトの名前はわかりやすいようにLineObjectにしています。
LineRendererのプロパティを次のように設定します。

**必ずSizeを０にしてください**
<img width="568" alt="スクリーンショット 2018-12-11 16.48.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/58fd2b0d-9cff-3822-cb08-f375e3d7f494.png">

次にこれをPrefab化します。ProjectウィンドウでAssetsフォルダの下にPrefabsフォルダを作成します。
Projectウィンドウでのフォルダやファイルの作成は、Projectタブの下のcreateか右クリックでできます。
HierarchyウィンドウのLineObjectを、ProjectウィンドウのPrefabsフォルダにドラッグアンドドロップします。

![dac12d416e600b606f6e457325ab2e44.gif](https://qiita-image-store.s3.amazonaws.com/0/131386/c7b8174d-e79c-e0d7-ff41-d9dd5c604f48.gif)

これでLineObjectのPrefab化ができました。現在HierarchyウィンドウにあるLineObjectはもういらないので削除しましょう。

## お絵かきのスクリプトをかく
ではスクリプトをかいていきましょう。

ProjectウィンドウのAssetsフォルダにScriptsフォルダを作成し、DrawManagerというC#スクリプトファイルを作成します。

作成したらDrawManagerをダブルクリックしましょう。
Unityのinstall時にVisualStudioもinstallしていれば、VisualStudioでDrawManagerファイルが開かれます。

DrawManagerの中身を次にようにします。
コメントアウトに細かいことを書いたので詳しくはそちらで確認してください。

```c#:DrawManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DrawManager : MonoBehaviour {

    //変数を用意
    //SerializeFieldをつけるとInspectorウィンドウからゲームオブジェクトやPrefabを指定できます。
    [SerializeField] GameObject LineObjectPrefab;
    [SerializeField] Transform HandAnchor;//positionを取得するコントローラーの位置情報

    //現在描画中のLineObject;
    private GameObject CurrentLineObject = null;

    private Transform Pointer
    {
        get
        {
            return HandAnchor;
        }
    }

    // Use this for initialization
    void Start () {
		
	}

	
	// Update is called once per frame
	void Update () {
        // ここから追加コード

        var pointer = Pointer;
        if(pointer == null)
        {
            Debug.Log("pointer not defiend");
            return;
        }

        //Oculus Touchの人差し指のトリガーが引かれている間
        if(OVRInput.Get(OVRInput.RawButton.RIndexTrigger))
        {
            if(CurrentLineObject == null)
            {
                //PrefabからLineObjectを生成
                CurrentLineObject = Instantiate(LineObjectPrefab, new Vector3(0, 0, 0), Quaternion.identity);
            }
            //ゲームオブジェクトからLineRendererコンポーネントを取得
            LineRenderer render = CurrentLineObject.GetComponent<LineRenderer>();

            //LineRendererからPositionsのサイズを取得
            int NextPositionIndex = render.positionCount;

            //LineRendererのPositionsのサイズを増やす
            render.positionCount = NextPositionIndex + 1;

            //LineRendererのPositionsに現在のコントローラーの位置情報を追加
            render.SetPosition(NextPositionIndex, pointer.position);
        } 
        else if (OVRInput.GetUp(OVRInput.RawButton.RIndexTrigger))//人差し指のトリガーを離したとき
        {
            if(CurrentLineObject != null)
            {
                //現在描画中の線があったらnullにして次の線を描けるようにする。
                CurrentLineObject = null;
            }
        }
	}
}

```

## Scriptの変数に割りあて
InspectorウィンドウでOVRPlayerControllerにDrawManagerコンポーネントを追加します。

scriptの`[SerializeField]`によって、ドラッグアンドドロップでスクリプト内の変数に直接ゲームオブジェクトやPrefabを指定できます。

LineObjectのPrefabとOVRPlayerControllerの子要素にあるRightHandAnchorを、Inspectorウィンドウの指定の場所にドラッグアンドドロップします。

<img width="591" alt="スクリーンショット 2018-12-11 18.32.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/719bcff8-5064-39c4-650e-f1459b08f62e.png">

![e1959a6bba5f92311c2da86d417c88a3.gif](https://qiita-image-store.s3.amazonaws.com/0/131386/d5565aa9-f487-f24a-0f26-27eba978601e.gif)

## 最後の調整

- OVRPlayerControllerにカメラがあるのでMainCameraは不要です。Hierarchyから消しましょう。
- 地面が今無いので、このままだとアバターが下に消えていきます。ステータスバーから`GameObject > 3D Object > Plane`で地面を追加します。
- OVRPlayerControllerのTransformの`y`値を1にします。

## お絵かきタイム！
これでPlayするとこうなります。

![draw.gif](https://qiita-image-store.s3.amazonaws.com/0/131386/c7f25d52-8f9f-4e33-7c5d-9989d613f07b.gif)

## おわりに
いかがだったでしょう。
Unityを使えばVRの開発が簡単にできます。Unityの公式ドキュメントは日本語にも対応していますし、かなりわかりやすいです。環境さえ整えてしまえば簡単に進められます。

Oculus Riftを使うには高スペックのPCが必要ですが、2019年春発売予定のOculus Questは、スタンドアローンでありながら6DoFです(位置のトラッキングができる。スタンドアローンの代表格Oculus Goは3DoFで向きのトラッキングしかできない)。HMDの開発が進むと、VR開発を**始める**敷居はドンドン下がっていくでしょう。

VR開発やっていきましょう！！