本日はオリジナルUIを作成します。
今回は今まで作成してきた腕輪型UIをまとめさらに使いやすくしました。
〇腕輪型UIとは?
筆者が作成したオリジナルのUIで、HoloLens 2のHandTrackingを使用してユーザーの手首に表示されるHandMenuです。
MRTKではユーザーの手に沿って表示を行うHandMenuと呼ばれるUIが提供されています。
HoloLens の場合、アプリケーション起動時のデバイスの位置がUnityでの原点(0,0,0)になります。
そのため、HoloLensアプリではオブジェクトを配置する座標によってSpatialMeshに埋もれてしまう現象が発生する可能性があります。また、配置する場所によってはユーザーの移動を求めることになる場合もあります。
HandMenuはユーザーの手に対して表示されるUIのため、ユーザーがどのような環境にあろうが使用することができるUIです。
・HandMenuの問題
HandMenuを使用する場合HoloLens 2のHomeボタン(アプリを終了するボタン)を誤って触ってしまうことがあります。
これはHandMenuを使用する際、HandMenuの仕組みからメニューだけではなく同時にHomeボタンも表示されてしまうことが原因でした。
この問題を解消するために腕輪型UIを作成しました。
〇腕輪型UIを作る
・環境
・Unity 2019.3.9f1
・MRTK v2.51
・HoloLens 2(※)
※HandMenuはHoloLens(初代)では動作しません。
・実装
MRTK導入が完了しているシーンを使用します。
①hierarchyウィンドウに空のゲームオブジェクトを作成し[HandWatch]と名付けます。
このオブジェクトが親オブジェクトになります。
②[HandWatch]オブジェクトに以下のコンポーネントを[Add Component]から追加します。
・SolverHandler
手の検知を行うために追加します。
・HandConstraint
手を検知した際のイベントを提供するコンポーネントです。
・HandBounds
このコンポーネントはMRTKで提供される手の関節やその他のデータへのアクセスを行うためのユーティリティを提供します。
③[HandConstraint]を次のように設定します。
・[Tracked Target Type]を[Hand Joint]に設定します。
これはどの部位を検知するのかを指定します。今回は腕輪型のUIを作成したいのでHand Jointを選択します。
・[Tracked Handness]は右手左手のどちらを検知するかの設定です。筆者の場合右手を選択しています。[Both]を選択することで両手を検知することができます。
・[Tracked Hand Joint]を[Wrist]に設定します。これはHandJointのうちどの部分を検知するかという設定で、手首を選択しました。
④腕輪のオブジェクトを[HandWatch]オブジェクトの子オブジェクトに配置します。ここでは[HandRing]と名付けています。
今回は次のようなオブジェクトを配置しました。
これが手に追随するオブジェクトになります。
⑤Unityエディタ上でシーンを再生します。
[Tracked Handness]で指定した手に沿ってリングが追随することを確認できます。
ですが、このままでは手首の位置とずれた位置にリングが表示されてしまっています。
オブジェクトの位置を調整します。
⑥[HandWatch]オブジェクトの[HandConstraint]から[Safe Zone]を[Below Wrist]に変更します。
この[Safe Zone]は検知したオブジェクトをどのように追随させるか?を設定しまう。
[Below Wrist]に変更したことで手首からのずれがなくなりました。
しかし位置は追随するようになりましたが、回転が追随しません。
⑦[HandWatch]オブジェクトの[HandConstraint]から[Rotation Behavior]を[None]に変更します。
これは追随するオブジェクトの回転をどのようにするかの制限を与える設定です。デフォルトではカメラ(ユーザーの顔)に対して回転が向くようになっています。
これを解除することで腕輪が完成します。
〇ボタンの機能
手首にリングが表示されるようになりました。次にボタンの機能を実装します。
①[HandRing]の子オブジェクトにCubeを配置してスケールを調整します。
ここではCubeに[EyeTrachingButtonON]という名前を付けました。
②[EyeTrachingButtonON]オブジェクトに[EyeTrackingTarget]コンポーネントを追加します。
[EyeTrackingTarget]コンポーネントはユーザーの目線を使用したイベントを起こすことができます。
③[EyeTrachingButtonON]オブジェクトを複製し[EyeTrachingButtonOFF]オブジェクトを作成します。
④[EyeTrachingButtonON]オブジェクトの[EyeTrackingTarget]コンポーネントを次のように設定します。
・[On Dwell()]のイベントに[EyeTrachingButtonON]と[EyeTrachingButtonOFF]二つのイベントを作成し、[EyeTrachingButtonON]をディアクティブに、[EyeTrachingButtonOFF]をアクティブにするように設定します。
⑤[EyeTrachingButtonOFF]オブジェクトの[EyeTrackingTarget]コンポーネントを次のように設定します。
・[On Dwell()]のイベントに[EyeTrachingButtonON]と[EyeTrachingButtonOFF]二つのイベントを作成し、[EyeTrachingButtonOFF]をディアクティブに、[EyeTrachingButtonON]をアクティブにするように設定します。
また[EyeTrachingButtonOFF]オブジェクトを非表示(ディアクティブ)にします。
⑥この状態で実行します。(UnityEditor上での動きはわかりづらかったためここでは割愛します。)
これで視線が合うことで[EyeTrachingButtonON]オブジェクト[EyeTrachingButtonOFF]オブジェクトがON、OFFするようになります。
EyeTrackingを使用するためにはEyeTracking用の設定が必要です。これは以前の記事を参考にしてください
⑦メニューの実装
[HandRing]オブジェクトの子オブジェクトに任意のボタンを配置します。
⑧配置した任意のボタンを非表示にして、[EyeTrachingButtonON]オブジェクトの[EyeTrackingTarget]にボタンをアクティブにするイベントを加えます。
⑨[EyeTrachingButtonOFF]オブジェクトの[EyeTrackingTarget]にボタンをディアクティブにするイベントを加えます。
これで腕輪に視線を当てた場合ボタンが表示され、もう一度腕輪を見つめたときボタンが非表示になる仕組みができました。
〇仕上げ1
①[EyeTrachingButtonON][EyeTrachingButtonOFF]オブジェクトのinspectorウィンドウから[MeshRendere]を無効化します。
これによってCubeがその機能を残して非表示になります。
②[HandWatch]オブジェクトの[HandConstraint]から次の設定を行います。
・[On First Hand Detected()]のイベントに[HandRing]を追加し、オブジェクトをアクティブにするようにします。
・[On Last Hand Lost()]のイベントに[HandRing]を追加しオブジェクトをディアクティブにするようにします。
[On First Hand Detected()]は手を検知した際に発火するイベントです。対して[On Last Hand Lost()]は手をLostした際に発火するイベントです。
つまり手が認識できている状態の場合のみ[HandRing]を表示する設定にしました。
最後に[HandRing]のゲームオブジェクトをディアクティブにします。
〇仕上げ2
次にただ手首にリングが表示されているだけではインパクトがありません。
腕輪ではなく腕時計にしましょう。
①次のスクリプトを作成しました。
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using TMPro; public class watch : MonoBehaviour { [SerializeField] TextMeshPro _dayText; [SerializeField] TextMeshPro _timeText; // Update is called once per frame void Update() { _dayText.text = (DateTime.Now.Month.ToString() +"/"+DateTime.Now.Day.ToString()); _timeText.text = (DateTime.Now.Hour.ToString() + ":" + DateTime.Now.Minute.ToString()+":"+DateTime.Now.Second.ToString()); } }
このスクリプトを[HandRing]オブジェクトに加えます。
②[HandRing]オブジェクトの子オブジェクトにTextMeshProを二つ追加します。
③[HandRing]オブジェクトに加えた[watch]コンポーネントの[DayText][TimeText]にそれぞれ加えます。
以上で腕時計型UIが完成しました。
〇実機
作成したUIを実機で確認します。
実機でも確認できるはずでしたが…なんとEyeTracingを当てるとオブジェクトが逃げてしまいました。
Unityに戻りエディタ上でMRTKで提供されているHandMenuを参考に実験してみました。
まるでEyeTrackingの周辺にコライダーがあるかのようにオブジェクトが裂けてしまいました。
これはSolberHandlerに問題がありそうです。
後日改めて調査したいと思います。(もし改善法などご存じの方いたらコメントください)
EyeTrakicngを使用しない場合きちんと動作するため、しばらくは調査が必要です。
〇HoloLensアドベントカレンダーとは?
冒頭でもお知らせしましたが、本日の記事はHoloLensアドベントカレンダー三日目の記事になります。
昨日は筆者ホロ元がHoloLens 2のSpatialAwarenessに関する調査記事を紹介しました。
明日は私の師であるガチ本さんの記事になります。