共用方式為


眼支持目標選擇 — MRTK2

MRTK

本頁討論了在MRTK中選取目標的不同存取眼球凝視資料及眼球凝視特定事件的選項。 眼動追蹤結合使用者所看目標資訊,並結合手 部追蹤語音指令等額外輸入,使目標選擇快速且輕鬆:

  • 看 & 說 「選擇」 (預設語音指令)
  • & 說 「爆炸」「爆炸」 (自訂語音指令)
  • 看看 & 藍牙按鈕
  • 看 & 捏 (也就是把手舉到前面,拇指和食指合攏)

要利用眼神凝視選擇全息內容,有幾個選項:

1. 使用主要對焦指標:

這可以理解為你優先排序的游標。 預設情況下,如果手在視野內,那就是手部光線。 如果沒有手在視野內,那麼優先指標會是頭部或眼睛凝視。 因此請注意,根據目前的設計,若使用手部光線,頭部或眼睛凝視會被抑制為游標輸入。

例如:

使用者想選擇遠方的全息按鈕。 作為開發者,你希望提供一個靈活的解決方案,讓使用者能在各種條件下完成這些任務:

  • 走到按鈕前,輕按它
  • 從遠處看,然後說「選擇」
  • 用手射線鎖定按鈕並施壓。在這種情況下,最靈活的解決方案是使用主焦點處理器,因為它會在當前優先的主要焦點指標觸發事件時通知你。 請注意,如果啟用手部光線,頭部或眼睛凝視的對焦指標會在雙手進入視野時立即關閉。

重要事項

請注意,如果啟用手部光線,頭部或眼睛凝視的對焦指標會在雙手進入視野時立即關閉。 如果你想支援 「看了就捏」 的互動,你需要關閉手部射線。 在我們的眼動追蹤範例場景中,我們關閉了手部光線,以便透過眼睛+手部動作展現更豐富的互動——例如參見 眼部支持定位(Eye-Supported Positioning)。

2. 同時使用眼部聚焦與手部光線:

有些情況你可能想更具體說明哪種焦點指標能觸發特定事件,並允許同時使用多種遠距離互動技術。

舉例來說:在你的應用程式中,使用者可以用遠手射線來操控某些全息機械裝置——例如,抓取並持有一些遠處的全息引擎零件並將其固定在原位。 在此過程中,使用者必須完成多項指示,並透過勾選一些勾選框來記錄進度。 如果使用者 手不忙,通常會本能地輕觸勾選框或用手部光線選擇。 然而,如果使用者雙手忙碌,例如我們手中拿著全息引擎零件,你希望讓使用者能透過眼神無縫滑動說明,並只要看到勾選框說「勾選!」。

為實現此功能,您需要使用獨立於 MRTK FocusHandlers 核心的眼睛專用 EyeTrackingTarget 腳本,稍後會詳細說明。

1. 使用通用的焦點與指標處理器

如果眼動追蹤設定正確, (看到 基本MRTK設定使用眼動追蹤) ,使用者用眼睛選擇全息影像的操作方式與其他對焦輸入 (如頭部凝視或手部光線) 相同。這提供了一個靈活的互動方式,可以根據使用者需求在 MRTK 輸入指標設定檔中定義主要焦點類型,同時保持程式碼不變。 這讓人們可以在不更改程式碼的情況下切換頭部或眼睛凝視,也不必將手部光線換成眼睛目標鎖定,以進行遠距離互動。

聚焦全息影像

要偵測全息影像是否被聚焦,請使用「 IMixedRealityFocusHandler」 介面,該介面提供兩個介面成員: OnFocusEnterOnFocusExit

這裡有一個簡單的例子, ColorTap.cs 用來改變全息影像的顏色。

public class ColorTap : MonoBehaviour, IMixedRealityFocusHandler
{
    void IMixedRealityFocusHandler.OnFocusEnter(FocusEventData eventData)
    {
        material.color = color_OnHover;
    }

    void IMixedRealityFocusHandler.OnFocusExit(FocusEventData eventData)
    {
        material.color = color_IdleState;
    }
    ...
}

選擇聚焦全息影像

要選擇聚焦全息影像,請使用 PointerHandler 監聽輸入事件以確認選擇。 例如,加入 IMixedRealityPointerHandler 會讓他們對簡單的指標輸入做出反應。 IMixedRealityPointerHandler 介面需要實作以下三個介面成員:OnPointerUpOnPointerDownOnPointerClicked

在下面的範例中,我們透過觀察全息影像並捏住或說「選取」來改變它的顏色。 觸發事件所需的動作定義 eventData.MixedRealityInputAction == selectAction 為,我們可以在 Unity 編輯器中設定 的 selectAction 類型——預設是「Select」動作。 可用的 混合現實輸入動作 類型可透過 MRTK 配置檔 ->Input ->Input Actions 在 MRTK 設定檔中配置。

public class ColorTap : MonoBehaviour, IMixedRealityFocusHandler, IMixedRealityPointerHandler
{
    // Allow for editing the type of select action in the Unity Editor.
    [SerializeField]
    private MixedRealityInputAction selectAction = MixedRealityInputAction.None;
    ...

    void IMixedRealityPointerHandler.OnPointerUp(MixedRealityPointerEventData eventData)
    {
        if (eventData.MixedRealityInputAction == selectAction)
        {
            material.color = color_OnHover;
        }
    }

    void IMixedRealityPointerHandler.OnPointerDown(MixedRealityPointerEventData eventData)
    {
        if (eventData.MixedRealityInputAction == selectAction)
        {
            material.color = color_OnSelect;
        }
    }

    void IMixedRealityPointerHandler.OnPointerClicked(MixedRealityPointerEventData eventData) { }
}

專屬眼視 BaseEyeFocusHandler

考慮到眼睛凝視和其他指標輸入可能差異很大,你可能要確保只有在焦點輸入是 眼睛凝視 且目前是主要輸入指標時才反應。 為此,你會使用 專屬於眼動追蹤的 , BaseEyeFocusHandler 且 是從 BaseFocusHandler衍生出來的。 如前所述,只有當眼睛凝視目標是目前主要指標輸入 (也就是沒有手部光線啟動時,) 才會觸發。 欲了解更多資訊,請參閱 「如何支持眼神凝視+手勢」。

這裡有一個來自 EyeTrackingDemo-03-Navigation (Assets/MRTK/Examples/Demo/EyeTracking/Scenes) 的範例。 在這個示範中,有兩個 3D 全息影像會根據觀察物體的哪一部分而轉動:如果使用者看向全息圖的左側,該部分會慢慢向正面移動。 如果看右側,那部分會慢慢移到前面。 這種行為你可能不希望一直保持,也不想被手射線或頭部凝視意外觸發。 有了 連接後 OnLookAtRotateByEyeGaze ,遊戲物件會在被觀看時旋轉。

public class OnLookAtRotateByEyeGaze : BaseEyeFocusHandler
{
    ...

    protected override void OnEyeFocusStay()
    {
        // Update target rotation
        RotateHitTarget();
    }

    ...

    ///
    /// This function computes the rotation of the target to move the currently
    /// looked at aspect slowly to the front.
    ///
    private void RotateHitTarget()
    {
        // Example for querying the hit position of the eye gaze ray using EyeGazeProvider
        Vector3 TargetToHit = (this.gameObject.transform.position - InputSystem.EyeGazeProvider.HitPosition).normalized;

        ...
    }
}

請參閱 API 文件以獲取完整的可用事件清單:BaseEyeFocusHandler

  • OnEyeFocusStart: 當眼睛凝視 射線開始 與該目標的碰撞器相交時觸發。
  • OnEyeFocusStay:眼睛凝視射線與目標的碰撞器相交時觸發。
  • OnEyeFocusStop: 當眼睛凝視 射線停止 與該目標的碰撞器相交時觸發。
  • OnEyeFocusDwell: 當眼睛凝視射線與目標的碰撞器相交指定時間後觸發。

2. 獨立的眼球專屬眼球追蹤目標

最後,我們提供一個解決方案,讓你能完全獨立於腳本中對其他焦點指標 EyeTrackingTarget 的眼睛輸入處理。

這有三個 優點

  • 你可以確保全息影像只對使用者的眼神有反應。
  • 這與當前主要輸入無關。 因此,你可以同時處理多個輸入——例如,結合快速的眼睛瞄準與手勢。
  • 已經設置了多個 Unity 事件,讓在 Unity 編輯器內或程式碼中快速且方便地處理與重用現有行為。

但也有一些 缺點:

  • 要花更多力氣分別處理獨立輸入。
  • 沒有優雅的降級:它只支援眼睛瞄準。 如果眼動追蹤無法運作,你需要額外的備用方案。

BaseFocusHandler 類似, EyeTrackingTarget 內建多個專屬的 Unity 視線事件,您可以透過 Unity 編輯器 (詳見) 下方範例,方便收聽,或使用 AddListener () 程式碼中:

  • 開始 ()
  • 在Target ()
  • 《望遠 ()
  • OnDwell ()
  • OnSelected ()

以下將帶你了解幾個如何使用 EyeTrackingTarget 的範例。

範例 #1:眼部支援的智慧通知

EyeTrackingDemo-02-TargetSelection (Assets/MRTK/Examples/Demo/EyeTracking/Scenes) ,你可以找到一個「 智慧專注通知」 的範例,這些通知會對你的眼神視線做出反應。 這些是可以放置在場景中的 3D 文字框,當使用者觀看時會平滑地放大並轉向,以提升可讀性。 當使用者閱讀通知時,資訊會持續清晰且清晰地顯示。 讀完後移開通知後,通知會自動被關閉並淡出。為了達成這些,有一些通用的行為腳本,這些腳本並非專屬於眼動追蹤,例如:

此方法的優點是相同的腳本可被不同事件重複使用。 例如,全息影像可能根據語音指令或按下虛擬按鈕後開始面向使用者。 要觸發這些事件,你可以參考綁定在 GameObject 的腳本中應該執行 EyeTrackingTarget 的方法。

「智慧專注通知」為例,會發生以下情況:

  • OnLookAtStart () :通知開始......

    • FaceUser。Engage: ...轉向使用者。
    • ChangeSize。Engage: ...尺寸增加 (至指定最大比例尺)
    • BlendOut。Engage: ... 在進入較微妙的閒置狀態後,開始融入更多 () 。
  • OnDwell () :通知 BlendOut 腳本已充分檢視該通知。

  • OnLookAway () :通知開始......

    • FaceUser.Disengage : ...回到原本的方向。
    • 改變大小。脫落: ...縮小回原本大小。
    • BlendOut.Disengage: ...開始混合——如果 OnDwell () 被觸發,請完全混合並摧毀,否則恢復閒置狀態。

設計考量: 這裡享受體驗的關鍵是謹慎調整這些行為的速度,避免因過度反應使用者的眼神而造成不適。 否則這很快就會讓人感到非常壓力山大。

目標通知

範例 #2:全息寶石在看著它時旋轉緩慢

類似範例 #1,我們可以輕鬆為 (Assets/MRTK/Examples/Demo/EyeTracking/Scenes) 場景中,為全息寶石 EyeTrackingDemo-02-TargetSelection 建立懸浮回饋,這些回饋會緩慢以恆定方向和恆定速度旋轉, (與上方的旋轉範例形成對比,) 觀看時。 你只需要觸發 EyeTrackingTargetWhileLookingAtTarget () 事件中全息寶石的旋轉。 以下是一些細節:

  1. 建立一個包含公開函式的通用腳本,用來旋轉它所附帶的 GameObject。 以下是 RotateWithConstSpeedDir.cs 的範例,我們可以從 Unity 編輯器中調整旋轉方向和速度。

    using UnityEngine;
    
    namespace Microsoft.MixedReality.Toolkit.Examples.Demos.EyeTracking
    {
        /// <summary>
        /// The associated GameObject will rotate when RotateTarget() is called based on a given direction and speed.
        /// </summary>
        public class RotateWithConstSpeedDir : MonoBehaviour
        {
            [Tooltip("Euler angles by which the object should be rotated by.")]
            [SerializeField]
            private Vector3 RotateByEulerAngles = Vector3.zero;
    
            [Tooltip("Rotation speed factor.")]
            [SerializeField]
            private float speed = 1f;
    
            /// <summary>
            /// Rotate game object based on specified rotation speed and Euler angles.
            /// </summary>
            public void RotateTarget()
            {
                transform.eulerAngles = transform.eulerAngles + RotateByEulerAngles * speed;
            }
        }
    }
    
  2. 將腳本加入 EyeTrackingTarget 你的目標 GameObject,並在 UnityEvent 觸發器中參考 RotateTarget () 函式,如下圖所示:

    EyeTrackingTarget 範例

範例 #3:戳破那些寶石,也就是 多模態眼神凝視支援的目標選擇

在前一個例子中,我們展示了如何判斷目標是否被注視,以及如何觸發反應是多麼容易。 接著,讓我們利用 OnSelected () 事件 EyeTrackingTarget讓寶石爆炸。 有趣的是選擇 是如何 觸發的。 此方法 EyeTrackingTarget 允許快速指派不同的方式來呼叫選擇:

  • 捏合手勢:將「選擇動作」設為「選擇」會使用預設的手勢來觸發選擇。 這表示使用者只需舉起手,並用拇指和食指夾在一起即可確認選擇。

  • 「選擇」:使用預設語音指令 「選擇」 來選擇全息影像。

  • 「爆炸」「爆炸」:要使用自訂語音指令,你需要遵循兩個步驟:

    1. 設定自訂動作,例如 「DestroyTarget」

      • 導航至 MRTK -> 輸入 -> 輸入動作
      • 點擊「新增動作」
    2. 設定觸發此動作的語音指令,例如 「爆炸」「爆炸」

      • 導航到 MRTK -> 輸入 -> 語音
      • 點選「新增語音指令」
        • 將你剛建立的動作關聯起來
        • 指定 一個按鍵代碼 ,允許透過按鍵觸發動作

語音指令 EyeTrackingTarget 範例

當選擇寶石時,寶石會爆炸並發出聲音後消失。 這由 HitBehaviorDestroyOnSelect 劇本處理。 您有兩種選擇:

  • 在 Unity 編輯器中: 你只要把每個寶石範本附帶的腳本連結到 Unity 編輯器中的 OnSelected () Unity 事件。
  • 密碼中: 如果你不想拖放 GameObjects,也可以直接在腳本中加入事件監聽器。
    以下是我們在劇本中做 HitBehaviorDestroyOnSelect 的例子:
/// <summary>
/// Destroys the game object when selected and optionally plays a sound or animation when destroyed.
/// </summary>
[RequireComponent(typeof(EyeTrackingTarget))] // This helps to ensure that the EyeTrackingTarget is attached
public class HitBehaviorDestroyOnSelect : MonoBehaviour
{
    ...
    private EyeTrackingTarget myEyeTrackingTarget = null;

    private void Start()
    {
        myEyeTrackingTarget = this.GetComponent<EyeTrackingTarget>();

        if (myEyeTrackingTarget != null)
        {
            myEyeTrackingTarget.OnSelected.AddListener(TargetSelected);
        }
    }

    ...

    ///
    /// This is called once the EyeTrackingTarget detected a selection.
    ///
    public void TargetSelected()
    {
        // Play some animation
        // Play some audio effect
        // Handle destroying the target appropriately
    }
}

範例 #4:同時使用手部光線和眼神凝視輸入

手部光線優先於頭部和眼睛凝視的鎖定。 這表示,如果啟用手部光線,當手部進入視野的那一刻,手部光線就會成為主要指標。 不過,有些情況下你可能想用手部光線,同時偵測使用者是否在看某個全息影像。 慢點! 基本上你需要兩個步驟:

1. 啟用手部光線:要啟用手部光線,請前往 Mixed Reality 工具包 -> 輸入 -> 指標。 在 EyeTrackingDemo-00-RootScene 中,Mixed Reality Toolkit 只設定一次所有眼動追蹤示範場景,你應該會看到 EyeTrackingDemoPointerProfile。 你可以從零開始建立新的 輸入設定檔 ,或是改裝目前的眼動追蹤設定檔:

  • 從零開始:指標 標籤中,從右鍵選單選擇 DefaultMixedRealityInputPointerProfile 。 這是預設的指標設定檔,已經啟用了手部射線! 要將預設游標 (不透明白點) ,只要複製該設定檔並建立自訂指標設定檔即可。 接著在凝視游標預製件下,將 DefaultCursor 替換成 EyeGazeCursor
  • 根據現有 的 EyeTrackingDemoPointerProfile 雙擊 EyeTrackingDemoPointerProfile ,並在 指標選項中新增以下條目:
    • 控制器類型:「關節手」、「Windows Mixed Reality」
    • 慣用手: 任何
    • Pointer 預製件: DefaultControllerPointer

2. 偵測到有人在看全息影像: 使用 EyeTrackingTarget 腳本來偵測到有人在看全息影像,如上所述。 你也可以參考 FollowEyeGaze 範例腳本作為靈感,因為裡面會顯示一個全息影像跟隨你的視線,例如 (游標) 是否啟用手部射線。

現在,當你開始進行眼動追蹤的示範場景時,你應該會看到手中射出光線。 例如,在眼動追蹤目標選擇示範中,半透明的圓圈仍會跟隨你的眼睛,寶石會根據是否被看而回應,而頂部場景選單按鈕則使用手 () 的主要輸入指標。


回到「混合現實工具包中的眼動追蹤」