読者です 読者をやめる 読者になる 読者になる

MRが楽しい

MRやVRについて学習したことを書き残す

公式チュートリアル「HOLOGRAMS 210 2章」を試してみる

本日はチュートリアルお試し枠です。
いつも通り、以下ブログの記事を参考に実施します。
・HOLOLENS 公式チュートリアル HOLOGRAMS 210 GAZE 2章
 https://azure-recipe.kc-cloud.jp/2016/12/holograms-210-2/

参考記事にある通りにチュートリアルを実施します。
アプリをビルドすると、宇宙飛行士アプリにカーソルが出現するようになりました。
f:id:bluebirdofoz:20170517004644j:plain
カーソルは宇宙飛行士に当たっている間は青色のカーソルです。
f:id:bluebirdofoz:20170517004655j:plain
その他を見ると、白色のカーソルに変化します。
f:id:bluebirdofoz:20170517004659j:plain
更に見ている箇所のオブジェクトが白色に発行しています。
(上記画面だと右足が白くなっているのが分かります)


今回の新しい技術ポイントは特定オブジェクトを見るとカーソルの色が変わるという点です。
追加したスクリプトを確認します。
まず、カーソルオブジェクトに追加したCursorManagerクラスです。
・CursorManager.cs

            if (GazeManager.Instance.Hit)
            {
                // 2.b: SetActive true the CursorOnHolograms to show cursor.
                CursorOnHolograms.SetActive(true);
                // 2.b: SetActive false the CursorOffHolograms hide cursor.
                CursorOffHolograms.SetActive(false);
            }
            else
            {
                // 2.b: SetActive true CursorOffHolograms to show cursor.
                CursorOffHolograms.SetActive(true);
                // 2.b: SetActive false CursorOnHolograms to hide cursor.
                CursorOnHolograms.SetActive(false);
            }

            // 2.b: Assign gameObject's transform position equals GazeManager's instance Position.
            gameObject.transform.position = GazeManager.Instance.Position;

            // 2.b: Assign gameObject's transform up vector equals GazeManager's instance Normal.
            gameObject.transform.up = GazeManager.Instance.Normal;

GazeManagerがオブジェクトにヒットするとCursorOnHolograms側のオブジェクトを有効化し、ヒットしていないときはCursorOffHolograms側のオブジェクトを有効化する。
後はカーソルオブジェクトの位置を視線の位置に移動するだけです。
色の変化は2つのオブジェクトが交互に切り替わっているだけということです。


次に視線を制御するGazeManagerクラスです。
・CursorManager.cs

            // 2.a: Perform a Unity Physics Raycast.
            // Collect return value in public property Hit.
            // Pass in origin as gazeOrigin and direction as gazeDirection.
            // Collect the information in hitInfo.
            // Pass in MaxGazeDistance and RaycastLayerMask.
            Hit = Physics.Raycast(gazeOrigin,
                           gazeDirection,
                           out hitInfo,
                           MaxGazeDistance,
                           RaycastLayerMask);

以下で学習したRaycastの仕組みが利用されています。
bluebirdofoz.hatenablog.com


RaycastLayerMaskの設定は以下によると、衝突の無視を行う対象を選択するようです。
・Physics.Raycast
 https://docs.unity3d.com/jp/540/ScriptReference/Physics.Raycast.html

今回はDefault,Water,UIを無視するように設定しています。
これにより宇宙飛行士のアタリ判定にのみ、衝突判定が発生します。
・CursorManager.cs

            if (Hit)
            {
                // If raycast hit a hologram...

                // 2.a: Assign property Position to be the hitInfo point.
                Position = hitInfo.point;
                // 2.a: Assign property Normal to be the hitInfo normal.
                Normal = hitInfo.normal;
            }
            else
            {
                // If raycast did not hit a hologram...
                // Save defaults ...

                // 2.a: Assign Position to be gazeOrigin plus MaxGazeDistance times gazeDirection.
                Position = gazeOrigin + (gazeDirection * MaxGazeDistance);
                // 2.a: Assign Normal to be the user's gazeDirection.
                Normal = gazeDirection;
            }

ヒット時はヒットオブジェクトに合わせた距離と衝突角を設定します。
これをCursorManagerクラスで利用することで、カーソルがオブジェクトに沿う形で表示することができます。
ヒットしていない時は指定最大距離の位置と視線の角度をそのまま設定しているようです。


更に追加したInteractibleManagerクラスです。
・InteractibleManager.cs

        if (GazeManager.Instance.Hit)
        {
            RaycastHit hitInfo = GazeManager.Instance.HitInfo;
            if (hitInfo.collider != null)
            {
                // 2.c: Assign the hitInfo's collider gameObject to the FocusedGameObject.
                FocusedGameObject = hitInfo.collider.gameObject;
            }
(中略)
            if (FocusedGameObject != null)
            {
                if (FocusedGameObject.GetComponent<Interactible>() != null)
                {
                    // 2.c: Send a GazeEntered message to the FocusedGameObject.
                    FocusedGameObject.SendMessage("GazeEntered");
                }

こちらは衝突したオブジェクトに"GazeEntered"関数の呼び出しを実行していました。
試しに宇宙飛行士の各パーツのスクリプトを覗いてみると…
・Interactible.cs

    void GazeEntered()
    {
        for (int i = 0; i < defaultMaterials.Length; i++)
        {
            // 2.d: Uncomment the below line to highlight the material when gaze enters.
            defaultMaterials[i].SetFloat("_Highlight", .25f);
        }
    }

    void GazeExited()
    {
        for (int i = 0; i < defaultMaterials.Length; i++)
        {
            // 2.d: Uncomment the below line to remove highlight on material when gaze exits.
            defaultMaterials[i].SetFloat("_Highlight", 0f);
        }
    }

Interactible.csが既に追加されており、マテリアルの発効を行うGazeEntered()関数を保持していました。

手動でAstroManに追加したInteractible.csは現状、何も行っていないようでした。
後々のチュートリアルで利用するか、実際の講演ではこの追加時にInteractible.csの役割を説明したのでしょうか。