HoloLensでGaze, Click, Hold, Voiceイベントを拾う

(2017-02-05)

こんなの。SparitalMappingを有効にしているので球が床で止まっている。

こんなの

動画

HoloToolKit のインタフェースを実装することでイベントを拾えるようになっている。

IFocusable

Gazeしたとき。

public void OnFocusEnter()
{
    gazing = true;
}

public void OnFocusExit()
{
    gazing = false;
}

IInputClickHandler

クリックしたとき。

public void OnInputClicked(InputEventData eventData)
{
    if (!clicked)
    {
        clicked = true;
        clickedRotationFrame = 0;
    }
    countUp();
}

IHoldHandler

Hold(指を下げたまま維持する)したとき。 指を上げたときがCompletedで、Objectを外れたときCanceledになる。

public void OnHoldStarted(HoldEventData eventData)
{
    holding = true;
    clicked = true;
}

public void OnHoldCompleted(HoldEventData eventData)
{
    holding = false;
}

public void OnHoldCanceled(HoldEventData eventData)
{
    holding = false;
}

ISpeechHandler

声の入力。 InspectorからSpeech Input Source(Script)を追加して反応するキーワードを設定して使う。 MicrophoneのCapabilitiesが必要。

public void OnSpeechKeywordRecognized(SpeechKeywordRecognizedEventData eventData)
{
    switch (eventData.RecognizedText)
    {
        case "reset":
            count = 0;
            num.GetComponent<TextMesh>().text = count.ToString();
            break;
    }
}

全体。

using System;
using HoloToolkit.Unity.InputModule;
using UnityEngine;

public class CounterCube : MonoBehaviour, IFocusable, IInputClickHandler, IHoldHandler, ISpeechHandler
{
    // rotate ANIMATION_FRAME * ANIMATION_PER_FRAME degrees
    private const int ANIMATION_FRAME = 30;
    private const float ANIMATION_ROTATE_PER_FRAME = 60f / ANIMATION_FRAME;

    public GameObject cube;
    public GameObject num;

    private int count = 0;

    private bool gazing = false;
    private bool clicked = false;
    private int clickedRotationFrame = 0;
    private bool holding = false;
	
	// Update is called once per frame
	void Update ()
    {
        if(clicked)
        {
            if(clickedRotationFrame < ANIMATION_FRAME)
            {
                clickedRotationFrame++;
                cube.transform.localRotation = Quaternion.Euler(clickedRotationFrame * ANIMATION_ROTATE_PER_FRAME, clickedRotationFrame * ANIMATION_ROTATE_PER_FRAME, 0);
            }
            else if (holding)
            {
                // continue to count up
                clickedRotationFrame = 0;
                countUp();
            }
            else
            {
                clicked = false;
            }

        }

        if (holding)
        {
            cube.GetComponent<Renderer>().material.color = Color.green;
        }
        else if (gazing)
        {
            cube.GetComponent<Renderer>().material.color = Color.blue;
        }
        else
        {
            cube.GetComponent<Renderer>().material.color = Color.gray;
        }
    }

    public void OnFocusEnter()
    {
        gazing = true;
    }

    public void OnFocusExit()
    {
        gazing = false;
    }

    public void OnInputClicked(InputEventData eventData)
    {
        if (!clicked)
        {
            clicked = true;
            clickedRotationFrame = 0;
        }
        countUp();
    }

    public void OnHoldStarted(HoldEventData eventData)
    {
        holding = true;
        clicked = true;
    }

    public void OnHoldCompleted(HoldEventData eventData)
    {
        holding = false;
    }

    public void OnHoldCanceled(HoldEventData eventData)
    {
        holding = false;
    }

    private void countUp()
    {
        num.GetComponent<TextMesh>().text = (++count).ToString();
        var sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        sphere.transform.position = transform.position;
        sphere.transform.localScale = Vector3.one * 0.1f;
        sphere.AddComponent<Rigidbody>();
    }

    public void OnSpeechKeywordRecognized(SpeechKeywordRecognizedEventData eventData)
    {
        switch (eventData.RecognizedText)
        {
            case "reset":
                count = 0;
                num.GetComponent<TextMesh>().text = count.ToString();
                break;
        }
    }
}