こんにちは!

今日は建築モデルを眺め回したいと思います。

まずは、Photonで複数人で眺め回せるようにしたいと思います。

とりあえず、ブラウザ上で結果が見たい(VRではありません)という方はこのボタンからどうぞ。

最新のgoogle chromeでしか動作確認できていません。矢印キーが効かないときは一回画面を右クリックしてみてから再度トライしてみて下さい。

スペースキーでジャンプもできます。

 

Photon でのマルチプレイヤーウォークスルーが終わったら、今度は自分のOculusGoで、VRウォークスルーを体験できるようにしてみたいと思います。

それでは始めましょう!

RhinoモデルをUnityに取り込む

前回までの流れ

これは前回の記事ですべて詳細に説明してありますので、下の記事をご参照ください!

FBX形式で書き出し、マテリアルの調整をして、FirstPersonControllerを追加します。

とりあえず、Unity内で一人でモデルを眺める事は、とても簡単にできるようになっています。

Photon Unity Networking の設定

Photon Unity Networking のインポート

これは、割と何回かやっているので、Photonのまとめ記事をご参照下さい。

さぁ、ここからが今回の肝になります。

モデルを複数人で眺めるようにしていきたいと思います。

少しC#も使いますが、丸ごとコピペで多分動くので、簡単にできると思います。

Photon の準備:Network Manager の設定

まずは、ネットワークマネージャーを作成します。

ヒエラルキービューで右クリックし、CreateEmptyを選択します。

名前をNetworkManagerと改名します。

これに、C#スクリプトをアタッチしていくことにします。

プロジェクトウインドウで、右クリックし、Create>C#Script でC#スクリプトを作成します。

名前をNetworkManagerに改名します。この時の名前がクラス名と異なるとエラーがでますので注意です。

C#スクリプトをダブルクリックしエディターを開きます。

内容を下記のように書き換えます。(コピペでOKです)

一応、私が分かる範囲で、注釈をつけてみています。

ご参考まで。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class NetworkManager : MonoBehaviour//ファイル名とクラス名が一致していることを確認
{

    [SerializeField] Text connectionText; //テキスト
    [SerializeField] Transform[] spawnPoints; //プレイヤーが出てくるポジションのキューブを入れる
    [SerializeField] Camera sceneCamera;  //シーンカメラ

    GameObject player;

    // Use this for initialization
    void Start()
    {
        PhotonNetwork.logLevel = PhotonLogLevel.Full;//情報を全部ください
        PhotonNetwork.ConnectUsingSettings("0.1"); //バージョン
    }

    // Update is called once per frame
    void Update()
    {
        connectionText.text = PhotonNetwork.connectionStateDetailed.ToString();//その情報をテキストに流します

    }

    void OnJoinedLobby()
    {
        RoomOptions ro = new RoomOptions() { isVisible = true, maxPlayers = 8 };//maxPlayerは人数の上限
        PhotonNetwork.JoinOrCreateRoom("Tomo", ro, TypedLobby.Default);//""内は部屋の名前

    }

    void OnJoinedRoom()
    {
        StartSpawnProcess(0f); //関数をスタート(引数(秒数0))
    }

    public void StartSpawnProcess(float respawnTime) //関数
    {
        sceneCamera.enabled = true; //シーンカメラオン
        StartCoroutine("SpawnPlayer", respawnTime); //コルーチンを開始
    }

    IEnumerator SpawnPlayer(float respawnTime) //コルーチンの中身
    {
        yield return new WaitForSeconds(respawnTime);

        int index = Random.Range(0, spawnPoints.Length);//ランダムでキューブを選ぶ
        player = PhotonNetwork.Instantiate("Capsule",
            spawnPoints[index].position,
            spawnPoints[index].rotation,
            0);//プレイヤープレファブの生成
        sceneCamera.enabled = false;//シーンカメラオフ
    }
}

C#スクリプトをセーブします。

そのスクリプトをコンポーネントとして、NetworkManagerのインスペクターウィンドウにドラッグ&ドロップしてアタッチします。

すると下記のようになります。

ConnectionTextとSpawnPointsとSceneCameraに何も入ってないのが分かります。

Textを作成します。

このテキストにはPhotonのコネクションの状態が常に表示されるようになっています。

ヒエラルキービューで右クリックし、UI>Textを作成します。

SpawnPoints(最初にランダムでFirstPersonControllerが出てくる所)を4つ設定したいと思います。

まずは、キューブを4つ作ります。ヒエラルキービューで右クリックし、3dObject>Cubeを選択します。

Cubeを右クリックしduplicateを3回行います。

できたキューブ4つをまとめて、NetworkManagerのSpawnPointsにドラッグ&ドロップします。

SpawnPointsは配列(順番を持ったもの)になっているので複数のオブジェクトを入れることができます。

そして、先ほど作ったテキストをConnectionTextにドラッグ&ドロップします。

それから、シーンカメラもドラッグ&ドロップします。

すると下記のように全部埋まったのが分かります。

これで、ネットワークマネージャーの設定は終わりです。

この状態で実行しても何も起きません。なぜならメインキャラクターのプレファブ(部品の塊)が存在しないからです。

これから、メインキャラのプレファブを作成していきたいと思います。

Photon の準備:プレファブ(部品の塊)の作成

Photon上でプレイヤーを動かしたい場合、Resourceフォルダにメインキャラのプレファブを入れておかなければなりません。

NetworkManagerの中のC#スクリプトのPhoton.Instantiate(プレファブの生成)をされた時に出てくるプレファブをあらかじめ作成するということです。

カプセルのキャラクターを選択し、プロジェクトウインドウにドラッグ&ドロップします。

これだけで、プレファブ化は成功ですが、色々と設定する必要があります。

まずはPlayerNetworkMoverというC#スクリプトをアタッチします。

これは自分のプレイヤーだけ動かし、他のプレイヤーの動きを受信するための、スクリプトです。

プレファブを選択し、インスペクターウィンドウで、AddComponent>Newscriptそして、名前をPlayerNetworkMoverと入力します。

C#スクリプトをエディターで開き、下のように記載します。(コピペでOKです。)

このC#スクリプトの肝は、PhotonView.isMineというbool値(trueかfalseを取る値)で、自分のキャラと相手のキャラを選別し、自分のキャラのコンポーネントだけをONにするという仕組みです。

当然、デフォルトでは、プレファブのコンポーネントを全部オフにしておく必要があります。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.Characters.FirstPerson;

public class PlayerNetworkMover : Photon.MonoBehaviour
{
    // Start is called before the first frame update
    Vector3 position;
    Quaternion rotation;
    float smoothing = 10f;


    void Start()
    {

        if (photonView.isMine)
        {
            ///自分のキャラ以外はコンポーネントをオフのままにします。
            GetComponent<FirstPersonController>().enabled = true;
            GetComponent<CharacterController>().enabled = true;
            GetComponent<AudioSource>().enabled = true;
            foreach (Camera cam in GetComponentsInChildren<Camera>())
                cam.enabled = true;
        }
        else
        {
            StartCoroutine("UpdateData");//コルーチンを始めます。
        }
    }
    ///場所の同期を取った時に間を補完する処理(スムーズに動く)。
    IEnumerator UpdateData()
    {
        while (true)
        {
            transform.position = Vector3.Lerp(transform.position, position, Time.deltaTime * smoothing);
            transform.rotation = Quaternion.Lerp(transform.rotation, rotation, Time.deltaTime * smoothing);
            yield return null;
        }
    }


    ///場所の同期を取る処理。
    void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        if (stream.isWriting)
        {
            stream.SendNext(transform.position);
            stream.SendNext(transform.rotation);
           
        }
        else
        {
            position = (Vector3)stream.ReceiveNext();
            rotation = (Quaternion)stream.ReceiveNext();
          
        }
    }
}

 

プレファブを選択し、インスペクターウィンドウから、FirstPersonController、CharacterController、AudioSourceの3つのチェックボックスをオフにします。

それから、忘れずに、プレファブについているカメラもチェックボックスをオフにしておきましょう。

これをしないと、あとから出てきたプレイヤーのカメラが全プレイヤーに有効になってしまいます。

それから、カプセルがゴロンと転がってしまわないようにFreezeRotationをXYZ全方向にチェックボックスをONにしておきます。

Photonでは、双方のプレイヤーが見えるオブジェクトにはPhotonViewというC#スクリプトを付けておかないといけません。

プレファブを選択し、インスペクターウィンドウを選択した状態でプロジェクトウィンドウの検索ボタンでphotonviewを検索しドラッグ&ドロップしてアタッチします。

そして、忘れずにPlayerNetworkMoverをPhotonViewの監視対象に入れておきましょう。

PlayerNetworkMoverをドラッグ&ドロップして、PhotonViewのObservedComponentsに入れればOKです。

最後にカプセルのプレファブについているカメラのタグをMainCameraに変更しましょう。

これをしていないと、FirstPersonControllerのカメラがnullになってしまい、NullExceptionError地獄に陥ります。

私はこれを忘れたため、数時間のタイムロスをしました。

これで、プレファブの設定は終わりです。

ファイルをビルド(プログラムとして吐き出す)して遊んでみましょう!

プログラムをビルドしてUnity内で複数人ウォークスルーを体験してみる

ファイルをビルドするにはfile>BuildSettingを選択します。

AddOpenScenesボタンをおし、Sceneカメラを選択しチェックボックスをオンにします。

Platformは下記のようにPCを選択します。

その他の設定はデフォルトで大丈夫です。

適当なフォルダを選択してBuild And Runをクリックしましょう。

下記のようなウィンドウが出てきます。

2人のプレイヤーで挙動を確認したいので、Windowedにチェックを入れ、ウィンドウモードでUnityとビルドしたファイル
両方の画面を確認できるようにします。

Playボタンで実行すると都市の中を歩き回れます。

同時にUnity側でも実行してみます。

双方のプレイヤーは別々の景色を眺める事ができ、相手のプレイヤーを探すと、存在の確認ができました。

 

これで、複数人で同じ部屋の中で同じ都市を眺める事ができることが確認できたことになります。

ウェブにビルドしてみたので、もしよかったら、遊んでみて頂けると嬉しいです!

最新のgoogle chromeでしか動作確認できていません。矢印キーが効かないときは一回画面を右クリックしてみてから再度トライしてみて下さい。

スペースキーでジャンプもできます。

VRで建築ウォークスルーを体験する設定

次に、やっとVRで建築ウォークスルーを体験する設定に入ります!

色々あるので、最後までよろしくお願いいたします。

PC側の設定(Java SE Development Kit + Android SDK)とUnityの設定とビルドの仕方

PC側の設定につきましては一度凄く分かり易い記事を作成していますので、下の記事をご覧ください。

幾つか必要なプログラムのダウンロードが必要です。

Java SE Development Kit のインストールと、Android SDKのダウンロードとインストールが必要です。

この設定は一度してしまえば何度もする必要はありません。

それから、Unity側の設定もいろいろと必要です。

これはファイル名を決めたりなので、毎回必要です。

詳細は下記の記事をご参照下さい。

Oculus Integration のインポート

やっとVRの所にたどり着きました。

私はOculus Goを使用しているので、Oculus Ingegrationのインポートが必要になります。

これを入れると沢山エラーが出たり色々するのですが、これについても以前一度記事にしていますので下の記事をご参照ください。

それ以外にも下記のエラーが出ますが、これについてはLerpのDeltaTimeが0以下になるといけないようなので、0.1fを足してあげることにします。

詳細は下記リンク(英語)をご参照ください。

can someone explain how using Time.deltaTime as 't' in a lerp actually works?

NetworkManagerのC#スクリプトの該当部分を以下のように書き換えます。

transform.rotation = Quaternion.Lerp(transform.rotation, rotation, 0.1f+ Time.deltaTime * smoothing);

 

これでエラーが回避できましたね!

 

Oculus Go 側の開発者モードの設定

それから、忘れずにOculusGo側の開発者モードの設定をしておきましょう。

まず、携帯でOculusのアプリを開き、自分のオキュラスを選択します。

すると、その他の設定というのが出てくるので、そこをタップして開発者モードを探しオンにします。

上から4番目の開発者モードをオンにすればOKです!


開発者モードの設定をした状態だと、PC側でオキュラスをエクスプローラー上では認識しなくなるので、エクスプローラ上でデータのやり取りが必要な場合はオフにする必要があります。

Oculus Go のリモコンで縦横移動とジャンプをする設定

このままの設定でOculusGoにビルドすることもできますが、現在の設定ではまだリモコンのボタンに何も割り振られてないので動けません。

この設定をするためには、FirstPersonControllerのC#スクリプトをいじる必要があります。

原文は以下のようになっています。

private void GetInput(out float speed)
        {
            // Read input

            
            float horizontal = CrossPlatformInputManager.GetAxis("Horizontal");
            float vertical = CrossPlatformInputManager.GetAxis("Vertical");

            bool waswalking = m_IsWalking;

これを下記のように書き換えます。

private void GetInput(out float speed)
{
    // Read input
    Vector2 primaryTouchpad = OVRInput.Get(OVRInput.Axis2D.PrimaryTouchpad);
    float horizontal = primaryTouchpad.x;
    float vertical = primaryTouchpad.y;

    //float horizontal = CrossPlatformInputManager.GetAxis("Horizontal");
    //float vertical = CrossPlatformInputManager.GetAxis("Vertical");

    bool waswalking = m_IsWalking;

これで、縦横の動きがコントローラーのスクロールで再現することができます。

次にジャンプです。これはトリガーを引いたらジャンプに改変します。

FirstPersonController.csの下記の部分を改変してジャンプがトリガーで動くようにします。

 

private void Update()
 {
     RotateView();
     // the jump state needs to read here to make sure it is not missed
     if (!m_Jump)
     {
         // m_Jump = CrossPlatformInputManager.GetButtonDown("Jump");//原文
         m_Jump = OVRInput.GetDown(OVRInput.Button.PrimaryIndexTrigger);//改変後
     }

 

そして、最後に一番重要なOVRInput.Update();という一文をUpdateの中に入れておきます。

これを入れないと、OculusGoのリモコンを認識しません。

private void Update()
        {
            OVRInput.Update();

これで設定完了です!!

セーブしてビルドすると未来都市の中をOculusGoで縦横無尽に動き回れますよ!

オキュラスをスマホで無理やり撮ってみました(笑

まとめ

ここまでかなり色々な設定があったと思います。

どれも最初は大変なのですが、一回しか必要でない設定であったり、そうでないものも、段々と慣れていきますので、数を重ねるごとに簡単に感じるようになってくるのではないでしょうか。

Oculus Go 等のVRギアがあれば、自分が作った建築の中をVRで歩き回れますので、皆さんも是非トライしてみて下さいね!

それではまた!

スポンサーリンク
おすすめの記事