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 ダウンロードページ

Unityを起動できたら、適当な名前でプロジェクトを作成します。このときTemplateは3Dにしてください。

プロジェクトが生成できたら次にような画面になります。

Unity

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

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

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

補足

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

ゲームオブジェクトを追加する

試しに、球のゲームオブジェクトを追加してみましょう。
ステータスバーからGameObject > 3D Object > Sphereを選択してみてください。次にようになります。

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

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

LineRenderer

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

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

GameObjectを選択した状態でInspectorウィンドウのAdd Componentをクリックします。

この検索窓でLine Rendererと検索し、候補に出たLineRendererを選択します。
追加すると次のようにInspectorにLineRendererコンポーネントが追加されます。

LineRendererはPositionsに設定した点を通るような線を描きます。
それではLineRendererを使ってみましょう。Inspectorで設定を次の図のように変更します。

画像通りに設定するとこのようになります。
(x,y,z)=[(0,0,0), (0,4,0), (4,4,0)]を通る線になっています。

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

Oculus Riftでの開発

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

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

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

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

操作アバターを追加

ProjectウィンドウにおいてAssets > Oculus > VR > Prefabsの中にあるOVRPlayerControllerをHierarchyウィンドウにドラッグアンドドロップします。

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

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

適切に追加するとHierarchyウィンドウが次のようになります。

アバターテスト

アバターが動作するかテストします。まずはこのプロジェクトをVRに対応させましょう。
ステータスバーのFile > Build Settingsを開き、
ポップアップウィンドウのPlayer Settingsを押します。
Inspectorウィンドウの場所にPlayerSettingが開かれるはずです。
XR Settingsを開きVirtual Reality SDKsにOculusを追加します。

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

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を0にしてください

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

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

お絵かきのスクリプトをかく

ではスクリプトをかいていきましょう。

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

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

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

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ウィンドウの指定の場所にドラッグアンドドロップします。

最後の調整

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

お絵かきタイム!

これでPlayするとこうなります。

おわりに

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

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

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