MRが楽しい

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

HoloLens2でホロモンアプリを作る その41(プレイヤーが首を傾げたことを検出する)

本日はアプリ作成枠です。
HoloLens2でホロモンアプリを作る進捗を書き留めていきます。
f:id:bluebirdofoz:20210530230934j:plain

今回はプレイヤーが首を傾げたことを検出するロジックを実装します。

首傾げの判定ロジック

プレイヤーの首傾げを判定するにはメインカメラのZ軸のローカル回転を取得します。

以下のように首を傾げた回転を判定し、状態を更新するスクリプトを作成しました。
敷居値での切り替わりが頻発することを避けるため、UniRxによる丸め込み処理も実装しています。
・HeadObjectFeaturesSetter.cs

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

using System;

using UniRx;
using UniRx.Triggers;

using HMProject.HoloMon;

namespace HMProject.Player
{
    /// <summary>
    /// 顔の状態識別
    /// </summary>
    [Serializable]
    public enum HeadStatus
    {
        Normal,           // 通常
        Nod,              // 頷く
        Swing,            // 首振り
        Tilt,             // 首を傾げる
    }

    [RequireComponent(typeof(ObjectFeatures))]
    public class HeadObjectFeaturesSetter : MonoBehaviour
    {
        [SerializeField, Tooltip("顔の通常状態のオブジェクト名")]
        private HoloMonKnownObjectFeatures p_NormalHeadName;

        [SerializeField, Tooltip("顔を傾げた状態のオブジェクト名")]
        private HoloMonKnownObjectFeatures p_TiltHeadName;

        [SerializeField, Tooltip("丸め込みフレーム数")]
        private int p_RoundingFrameCount = 100;

        [SerializeField, Tooltip("首傾げの判定角度")]
        private float p_TiltAngle = 20.0f;


        [SerializeField, Tooltip("現在の顔の状態")]
        private HeadStatus p_CurrentHeadStatus;


        // オブジェクトの特徴の設定参照
        private ObjectFeatures p_ObjectFeatures;


        /// <summary>
        /// 起動処理
        /// </summary>
        void Start()
        {
            // オブジェクトの特徴の参照を取得する
            p_ObjectFeatures = this.gameObject.GetComponent<ObjectFeatures>();

            // 初期状態は通常状態
            SettingNormal();

            // 定期処理
            this.LateUpdateAsObservable()              // 毎フレームの最後に処理する
                .Select(_ => CheckCurrentHeadStatus()) // 現在のカメラ状態を判定する
                .DistinctUntilChanged()                // 状態に変化があった場合のみ通知する
                .ThrottleFrame(p_RoundingFrameCount)   // 指定フレームの間に変化がない場合のみ通知する
                .DistinctUntilChanged()                // 丸め込み結果に対して変化があったかチェックする
                .Subscribe(status =>
                {
                    SettingHeadStatus(status);
                })
                .AddTo(this);
        }

        /// <summary>
        /// 現在の顔の状態を判定する
        /// </summary>
        /// <returns></returns>
        private HeadStatus CheckCurrentHeadStatus()
        {
            HeadStatus status = HeadStatus.Normal;

            // 頭の横方向の傾き(Z軸方向回転)を判定する
            float headLocakTiltRotation = this.transform.eulerAngles.z;

            // 判定角度を満たすか否か
            if (headLocakTiltRotation > p_TiltAngle)
            {
                status = HeadStatus.Tilt;
            }

            return status;
        }

        /// <summary>
        /// 顔の状態を設定する
        /// </summary>
        /// <param name="a_HeadStatus"></param>
        private void SettingHeadStatus(HeadStatus a_HeadStatus)
        {
            switch (a_HeadStatus)
            {
                // 通常状態
                case HeadStatus.Normal:
                    SettingNormal();
                    break;
                // 首を傾げた状態
                case HeadStatus.Tilt:
                    SettingTilt();
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 顔の状態を通常状態に設定する
        /// </summary>
        private void SettingNormal()
        {
            p_ObjectFeatures.Features = p_NormalHeadName;
            p_CurrentHeadStatus = HeadStatus.Normal;
        }

        /// <summary>
        /// 顔の状態を首を傾げた状態に設定する
        /// </summary>
        private void SettingTilt()
        {
            p_ObjectFeatures.Features = p_TiltHeadName;
            p_CurrentHeadStatus = HeadStatus.Tilt;
        }
    }
}

f:id:bluebirdofoz:20210530230952j:plain

後は以下の記事で実装したホロモンの視界判定のロジックを通じて、プレイヤーが首を傾げたことをホロモンに検出させます。
bluebirdofoz.hatenablog.com

動作確認

アプリを起動し、ホロモンがこちらを注目している状態で首を傾げてみます。
ホロモンも同じように首を傾げてくれました。
f:id:bluebirdofoz:20210530231017j:plain