MRが楽しい

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

公式チュートリアル「MR and Azure 305 9章」を試してみる

本日はチュートリアルの実施枠です。
Academyの「MR and Azure 305: Functions and storage」の実施内容をまとめます。
docs.microsoft.com
前回記事の続きです。
bluebirdofoz.hatenablog.com
今回は「Chapter 9」です。

Chapter 9:Create the Gaze class

最後に作成するスクリプトは、Gazeクラスです。
このクラスは、メインカメラから前方に Raycast を作成し、ユーザーがどのオブジェクトを見ているかを検出します。
Raycast は、ユーザがシーン内の GazeButton オブジェクトを見ているかどうかを識別し、動作をトリガします。

1.Script フォルダを開きます。
2.フォルダ内で右クリックして、Creapte -> C# Script を選択します。
Script の名称は ShapeFactory に設定します。
f:id:bluebirdofoz:20181010084346j:plain

3.新しいスクリプトをダブルクリックしてVisual Studioで開きます。
4-9.以下の通り、スクリプトを編集します。
・Gaze.cs

// 名前空間の追加
using UnityEngine;

public class Gaze : MonoBehaviour {
    // メンバ変数の追加
    /// <summary>
    /// Provides Singleton-like behavior to this class.
    /// このクラスをシングルトンと同じように動作させます
    /// </summary>
    public static Gaze instance;

    /// <summary>
    /// The Tag which the Gaze will use to interact with objects. Can also be set in editor.
    /// 視線がオブジェクトに作用するために使用するタグ。エディタでも設定できます
    /// </summary>
    public string InteractibleTag = "GazeButton";

    /// <summary>
    /// The layer which will be detected by the Gaze ('~0' equals everything).
    /// 注視によって検出されるレイヤー('~0'は全て)
    /// </summary>
    public LayerMask LayerMask = ~0;

    /// <summary>
    /// The Max Distance the gaze should travel, if it has not hit anything.
    /// 何も衝突していない場合、注視が働くの最大距離
    /// </summary>
    public float GazeMaxDistance = 300;

    /// <summary>
    /// The size of the cursor, which will be created.
    /// 作成されるカーソルのサイズ
    /// </summary>
    public Vector3 CursorSize = new Vector3(0.05f, 0.05f, 0.05f);

    /// <summary>
    /// The color of the cursor - can be set in editor.
    /// カーソルの色はエディタで設定できます
    /// </summary>
    public Color CursorColour = Color.HSVToRGB(0.0223f, 0.7922f, 1.000f);

    /// <summary>
    /// Provides when the gaze is ready to start working (based upon whether
    /// Azure connects successfully).
    /// 注視が機能を開始する準備が整ったときを通知します
    /// (Azureが正常に接続されたかどうかに基づきます)
    /// </summary>
    internal bool GazeEnabled = false;

    /// <summary>
    /// The currently focused object.
    /// 現在フォーカスされているオブジェクト
    /// </summary>
    internal GameObject FocusedObject { get; private set; }

    /// <summary>
    /// The object which was last focused on.
    /// 最後に焦点を合わせたオブジェクト
    /// </summary>
    internal GameObject _oldFocusedObject { get; private set; }

    /// <summary>
    /// The info taken from the last hit.
    /// 最後のヒットから得た情報
    /// </summary>
    internal RaycastHit HitInfo { get; private set; }

    /// <summary>
    /// The cursor object.
    /// カーソルオブジェクト
    /// </summary>
    internal GameObject Cursor { get; private set; }

    /// <summary>
    /// Provides whether the raycast has hit something.
    /// レイキャストが何かにヒットしたかどうかを示します
    /// </summary>
    internal bool Hit { get; private set; }

    /// <summary>
    /// This will store the position which the ray last hit.
    /// レイキャストが最後に当たった位置が保存されます。
    /// </summary>
    internal Vector3 Position { get; private set; }

    /// <summary>
    /// This will store the normal, of the ray from its last hit.
    /// 最後のヒットのレイキャストの法線を保存します。
    /// </summary>
    internal Vector3 Normal { get; private set; }

    /// <summary>
    /// The start point of the gaze ray cast.
    /// 注視線のキャストの開始点
    /// </summary>
    private Vector3 _gazeOrigin;

    /// <summary>
    /// The direction in which the gaze should be.
    /// 凝視するべき方向
    /// </summary>
    private Vector3 _gazeDirection;

    /// <summary>
    /// The method used after initialization of the scene, though before Start().
    /// Start()の前、シーンの初期化後に使用されるメソッド
    /// </summary>
    private void Awake()
    {
        // Set this class to behave similar to singleton
        // このクラスをシングルトンと同じように動作させます
        instance = this;
    }

    /// <summary>
    /// Start method used upon initialization.
    /// 初期化時に使用されるStartメソッド
    /// </summary>
    private void Start()
    {
        FocusedObject = null;
        Cursor = CreateCursor();
    }

    /// <summary>
    /// Method to create a cursor object.
    /// カーソルオブジェクトを作成するメソッド
    /// </summary>
    /// <returns></returns>
    private GameObject CreateCursor()
    {
        GameObject newCursor = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        newCursor.SetActive(false);

        // Remove the collider, so it doesn't block raycast.
        // コライダーを取り外すので、レイキャストはブロックされません
        Destroy(newCursor.GetComponent<SphereCollider>());
        newCursor.transform.localScale = CursorSize;

        newCursor.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Diffuse"))
        {
            color = CursorColour
        };

        newCursor.name = "Cursor";

        newCursor.SetActive(true);

        return newCursor;
    }

    /// <summary>
    /// Called every frame
    /// フレームごとに呼び出されます
    /// </summary>
    private void Update()
    {
        if (GazeEnabled == true)
        {
            _gazeOrigin = Camera.main.transform.position;

            _gazeDirection = Camera.main.transform.forward;

            UpdateRaycast();
        }
    }

    /// <summary>
    /// Raycastを投影し、ヒットターゲットを検出します
    /// </summary>
    private void UpdateRaycast()
    {
        // Set the old focused gameobject.
        // 古い焦点を合わせたゲームオブジェクトを設定します
        _oldFocusedObject = FocusedObject;

        RaycastHit hitInfo;

        // Initialise Raycasting.
        // レイキャストを初期化する。
        Hit = Physics.Raycast(_gazeOrigin,
            _gazeDirection,
            out hitInfo,
            GazeMaxDistance, LayerMask);

        HitInfo = hitInfo;

        // Check whether raycast has hit.
        // レイキャストがヒットしたかどうかを確認します
        if (Hit == true)
        {
            Position = hitInfo.point;

            Normal = hitInfo.normal;

            // Check whether the hit has a collider.
            // ヒットしたコライダーがあるかどうかを確認します
            if (hitInfo.collider != null)
            {
                // Set the focused object with what the user just looked at.
                // フォーカスオブジェクトを、ユーザーが見たものに設定します
                FocusedObject = hitInfo.collider.gameObject;
            }
            else
            {
                // Object looked on is not valid, set focused gameobject to null.
                // 見つかったオブジェクトが有効でない場合、フォーカスオブジェクトをnullに設定します
                FocusedObject = null;
            }
        }
        else
        {
            // No object looked upon, set focused gameobject to null.
            // オブジェクトが見つからない場合、フォーカスオブジェクトをnullに設定します
            FocusedObject = null;

            // Provide default position for cursor.
            // カーソルのデフォルト位置を指定します
            Position = _gazeOrigin + (_gazeDirection * GazeMaxDistance);

            // Provide a default normal.
            // デフォルトの法線を指定します
            Normal = _gazeDirection;
        }

        // Lerp the cursor to the given position, which helps to stabilize the gaze.
        // レイキャストが当たった位置にカーソルを移動させます。注視を安定させるのに役立ちます
        Cursor.transform.position = Vector3.Lerp(Cursor.transform.position, Position, 0.6f);

        // Check whether the previous focused object is this same 
        //    object. If so, reset the focused object.
        // 前回のフォーカスされたオブジェクトが同じオブジェクトであるかどうかを確認します
        // その場合は、フォーカスされたオブジェクトをリセットします
        if (FocusedObject != _oldFocusedObject)
        {
            ResetFocusedObject();

            if (FocusedObject != null)
            {
                if (FocusedObject.CompareTag(InteractibleTag.ToString()))
                {
                    // Set the Focused object to green - success!
                    // フォーカスされたオブジェクトを緑色に設定します
                    FocusedObject.GetComponent<Renderer>().material.color = Color.green;

                    // Start the Azure Function, to provide the next shape!
                    // 次の図形を提供するためにAzure関数を開始してください
                    AzureServices.instance.CallAzureFunctionForNextShape();
                }
            }
        }
    }

    /// <summary>
    /// Reset the old focused object, stop the gaze timer, and send data if it
    /// is greater than one.
    /// 古いフォーカスされたオブジェクトをリセットし、視線タイマーを停止します
    /// データが 1 より大きい場合はデータを送信します
    /// </summary>
    private void ResetFocusedObject()
    {
        // Ensure the old focused object is not null.
        // 古いフォーカスオブジェクトがnullでないことを確認します
        if (_oldFocusedObject != null)
        {
            if (_oldFocusedObject.CompareTag(InteractibleTag.ToString()))
            {
                // Set the old focused object to red - its original state.
                // 古いフォーカスされたオブジェクトを赤色(元の状態)に設定します
                _oldFocusedObject.GetComponent<Renderer>().material.color = Color.red;
            }
        }
    }
}

f:id:bluebirdofoz:20181010084401j:plain

10.Visual Studio で変更を保存して Unity に戻ります。
f:id:bluebirdofoz:20181010084412j:plain

11.Hierarchy パネルの MixedRealityCameraParent を開くと、直下に MixedRealityCamera オブジェクトがあります。
Gaze スクリプトをこの MixedRealityCamera オブジェクトにドラッグして追加します。
f:id:bluebirdofoz:20181010084421j:plain

Chapter 9 はここまでです。
次回は Chapter 10 を実施します。
bluebirdofoz.hatenablog.com