MR Input 213:運動控制器

注意

混合實境學院教學課程的設計是以 HoloLens (第 1 代) 和混合實境沉浸式頭戴裝置為準。 因此,對於仍在尋找這些裝置開發指引的開發人員而言,我們覺得這些教學課程很重要。 這些教學課程不會使用用於 HoloLens 2 的最新工具組或互動進行更新。 系統會保留這些資訊,以繼續在支援的裝置上運作。 已針對 HoloLens 2 公佈一系列新的教學課程

混合實境世界中的動作控制器會新增另一個互動層級。 透過 運動控制器,我們可以以更自然的方式直接與物件互動,類似于真實生活中的實體互動、增加您 app 體驗的沉浸式和快樂。

在 MR Input 213 中,我們將藉由建立簡單的空間繪製體驗來探索動作控制器的輸入事件。 透過此應用程式,使用者可以在三維空間中繪製各種筆刷和色彩。

本教學課程涵蓋的主題

MixedReality213 Topic1 MixedReality213 Topic2 MixedReality213 Topic3
控制器視覺效果 控制器輸入事件 自訂控制器和 UI
瞭解如何在 Unity 的遊戲模式和執行時間中轉譯動作控制器模型。 瞭解不同類型的按鈕事件及其應用程式。 瞭解如何在控制器上方重迭 UI 元素,或完全自訂它。

裝置支援

課程 HoloLens 沉浸式頭戴裝置
MR Input 213:運動控制器 ✔️

在您開始使用 Intune 之前

必要條件

請參閱此頁面上的沉浸式頭戴式裝置安裝檢查 清單

專案檔

  • 下載 專案所需的檔案,並將檔案解壓縮到桌面。

注意

如果您想要先查看原始程式碼再下載,GitHub即可使用

Unity 設定

目標

  • 將 Unity 優化以進行Windows Mixed Reality開發
  • 設定Mixed Reality相機
  • 設定環境

指示

  • 啟動 Unity。

  • 選取 [開啟] 。

  • 流覽至您的桌面,並尋找您先前未架構的 MixedReality213-master 資料夾。

  • 按一下 [選擇資料夾]

  • Unity 完成載入專案檔之後,您將可以看到 Unity 編輯器。

  • 在 Unity 中,選取[檔案 > 建置] 設定

    MR213_BuildSettings

  • 在 [平臺] 清單中選取 [通用 Windows 平臺],然後按一下 [切換平臺]按鈕。

  • 將 [目標裝置] 設定為 [任何裝置]

  • 將組建類型設定為 D3D

  • 將 SDK 設定為 最新安裝

  • 檢查 Unity C# 專案

    • 這可讓您修改Visual Studio專案中的腳本檔案,而不需重建 Unity 專案。
  • 按一下[播放程式] 設定

  • [偵測器] 面板中,向下捲動至底部

  • 在 XR 設定中,檢查支援的虛擬實境

  • 在 [虛擬實境 SDK] 底下,選取[Windows Mixed Reality

    MR213_XRSettings

  • 關閉[建置設定] 視窗。

專案結構

本教學課程使用 Mixed Reality Toolkit - Unity。 您可以在 此頁面找到版本。

ProjectStructure

您參考的已完成場景

  • 您會在 Scenes 資料夾下找到兩個已完成的 Unity 場景。
    • MixedReality213:具有單一筆刷的已完成場景
    • MixedReality213Advanced:使用多個筆刷進行進階設計的已完成場景

教學課程的新場景設定

  • 在 Unity 中,按一下 [ 檔案 > 新增場景]

  • 刪除 主要相機方向光線

  • [Project] 面板中,搜尋下列預製專案並將其拖曳至 [階層] 面板:

    • Assets/HoloToolkit/Input/Prefabs/MixedRealityCamera
    • Assets/AppPrefabs/Environment

    Camera and Environment

  • Mixed Reality工具組中有兩個相機預製專案:

    • MixedRealityCamera.prefab:僅限相機
    • MixedRealityCameraParent.prefab:Camera + Teleportation + Boundary
    • 在本教學課程中,我們將使用 MixedRealityCamera 而不需遠端傳送功能。 因此,我們新增了簡單的 環境 預製專案,其中包含基本樓層,讓使用者感覺很基礎。
    • 若要深入瞭解 使用 MixedRealityCameraParent進行遠端傳送,請參閱 進階設計 - Teleportation 和 locomotion

Skybox 設定

  • 按一下[視窗 > 光源 > ] 設定

  • 按一下Skybox 材質欄位右側的圓形

  • 輸入 'gray',然後選取 [SkyboxGray (Assets/AppPrefabs/Support/Materials/SkyboxGray.mat)

    Setting skybox

  • 核取 [Skybox ] 選項,以查看指派的灰色漸層 Skybox

    Toggle skybox option

  • 使用 MixedRealityCamera、環境和灰色 skybox 的場景看起來會像這樣。

    MixedReality213 Environment

  • 按一下 [檔案 > 儲存場景] 作為

  • 使用任何名稱將場景儲存在 Scenes 資料夾下

第 1 章 - 控制器視覺效果

目標

  • 瞭解如何在 Unity 的遊戲模式和執行時間轉譯動作控制器模型。

Windows Mixed Reality提供控制器視覺效果的動畫控制器模型。 有數種方法可讓您在應用程式中取得控制器視覺效果:

  • 預設值 - 使用預設控制器而不修改
  • 混合式 - 使用預設控制器,但自訂部分元素或重迭 UI 元件
  • 取代 - 針對控制器使用您自己的自訂 3D 模型

在本章中,我們將瞭解這些控制器自訂的範例。

指示

  • [Project] 面板中,在搜尋方塊中輸入MotionControllers。 您也可以在 Assets/HoloToolkit/Input/Prefabs/下找到它。
  • MotionControllers 預製專案拖曳到 [階層 ] 面板。
  • 按一下 [階層] 面板中的MotionControllers預製專案。

MotionControllers 預製專案

MotionControllers 預製專案具有 MotionControllerVisualizer 腳本,可提供替代控制器模型的位置。 如果您指派自己的自訂 3D 模型,例如手部或字組,並檢查 [一律使用替代左/右模型],您會看到它們,而不是預設模型。 我們將在第 4 章中使用這個位置,以筆刷取代控制器模型。

MR213_ControllerVisualizer

指示

  • [偵測器] 面板中,按兩下MotionControllerVisualizer腳本以查看Visual Studio

MotionControllerVisualizer 腳本

MotionControllerVisualizerMotionControllerInfo類別提供存取 & 修改預設控制器模型的方法。 MotionControllerVisualizer 訂閱 Unity 的 InteractionSourceDetected 事件,並在找到控制器模型時自動具現化。

protected override void Awake()
{
    ...
    InteractionManager.InteractionSourceDetected += InteractionManager_InteractionSourceDetected;
    InteractionManager.InteractionSourceLost += InteractionManager_InteractionSourceLost;
    ...
}

控制器模型會根據 glTF 規格來傳遞。 已建立此格式以提供通用格式,同時改善傳輸和解壓縮 3D 資產背後的程式。 在此情況下,我們需要在執行時間擷取和載入控制器模型,因為我們想要盡可能讓使用者體驗順暢,而且不保證使用者可能使用的動作控制器版本。 本課程透過Mixed Reality工具組使用 Khronos 群組的UnityGLTF 專案版本。

一旦傳遞控制器之後,腳本就可以使用 MotionControllerInfo 來尋找特定控制器元素的轉換,以便正確定位它們本身。

在稍後的章節中,我們將瞭解如何使用這些腳本將 UI 元素附加至控制器。

在某些腳本中,您會找到具有 #if 的程式碼區塊 !UNITY_EDITORUNITY_WSA。 當您部署至 Windows 時,這些程式碼區塊只會在 UWP 執行時間上執行。 這是因為 Unity 編輯器和 UWP 應用程式執行時間所使用的 API 集合不同。

  • 儲存 場景,然後按一下 播放 按鈕。

您將能夠在頭戴式裝置中看到具有動作控制器的場景。 您可以看到按鈕點選、搖桿移動和觸控板觸控醒目提示的詳細動畫。

MR213_Controller Visualization Default

第 2 章 - 將 UI 元素附加至控制器

目標

  • 瞭解動作控制器的元素
  • 瞭解如何將物件附加至控制器的特定部分

在本章中,您將瞭解如何將使用者介面元素新增至使用者隨時可以輕鬆地存取及操作的控制器。 您也將瞭解如何使用觸控板輸入來新增簡單的色彩選擇器 UI。

指示

  • [Project]面板中,搜尋MotionControllerInfo腳本。
  • 從搜尋結果中,按兩下MotionControllerInfo腳本以查看Visual Studio中的程式碼。

MotionControllerInfo 腳本

第一個步驟是選擇要附加 UI 之控制器的哪個元素。 這些專案定義于MotionControllerInfo.csControllerElementEnum中。

MR213 MotionControllerElements

  • 首頁
  • 功能表
  • 把握
  • 搖桿
  • 選取
  • 觸控板
  • 指向姿勢 – 這個專案代表指向正向的控制器提示。

指示

  • [Project]面板中,搜尋AttachToController腳本。
  • 在搜尋結果中,按兩下[AttachToController] 腳本,以查看Visual Studio中的程式碼。

AttachToController 腳本

AttachToController腳本提供簡單的方法,將任何物件附加至指定的控制器手部和元素。

AttachElementToController () 中,

  • 使用MotionControllerInfo.Handedness檢查手部
  • 使用MotionControllerInfo.TryGetElement () 取得控制器的特定元素
  • 從控制器模型擷取專案的轉換之後,將物件下的物件父代,並將物件的本機位置 & 旋轉設定為零。
public MotionControllerInfo.ControllerElementEnum Element { get { return element; } }

private void AttachElementToController(MotionControllerInfo newController)
{
     if (!IsAttached && newController.Handedness == handedness)
     {
          if (!newController.TryGetElement(element, out elementTransform))
          {
               Debug.LogError("Unable to find element of type " + element + " under controller " + newController.ControllerParent.name + "; not attaching.");
               return;
          }

          controller = newController;

          SetChildrenActive(true);

          // Parent ourselves under the element and set our offsets
          transform.parent = elementTransform;
          transform.localPosition = positionOffset;
          transform.localEulerAngles = rotationOffset;
          if (setScaleOnAttach)
          {
               transform.localScale = scale;
          }

          // Announce that we're attached
          OnAttachToController();
          IsAttached = true;
     }
}

使用 AttachToController 腳本最簡單的方式是繼承自它,因為我們在 ColorPickerWheel 的情況下已完成。只要覆寫 OnAttachToControllerOnDetachFromController 函式,即可在偵測到控制器/中斷連線時執行您的設定/分解。

指示

  • [Project]面板中,輸入搜尋方塊ColorPickerWheel。 您也可以在 [資產/AppPrefabs/] 底下找到它。
  • ColorPickerWheel 預製專案拖曳至 [階層 ] 面板。
  • 按一下 [階層] 面板中的ColorPickerWheel預製專案。
  • [偵測器] 面板中,按兩下ColorPickerWheel腳本以查看Visual Studio中的程式碼。

ColorPickerWheel prefab

ColorPickerWheel 腳本

由於ColorPickerWheel繼承AttachToController,因此它會在偵測器面板中顯示HandednessElement。 我們會將 UI 附加至左側控制器上的 Touchpad 元素。

ColorPickerWheel script

ColorPickerWheel 會覆寫 OnAttachToControllerOnDetachFromController 來訂閱輸入事件,在下一章中將用於使用觸控板輸入的色彩選取。

public class ColorPickerWheel : AttachToController, IPointerTarget
{
    protected override void OnAttachToController()
    {
        // Subscribe to input now that we're parented under the controller
        InteractionManager.InteractionSourceUpdated += InteractionSourceUpdated;
    }

    protected override void OnDetachFromController()
    {
        Visible = false;

        // Unsubscribe from input now that we've detached from the controller
        InteractionManager.InteractionSourceUpdated -= InteractionSourceUpdated;
    }
    ...
}
  • 儲存 場景,然後按一下 播放 按鈕。

將物件附加至控制器的替代方法

我們建議您的腳本繼承自 AttachToController ,並覆寫 OnAttachToController。 不過,這不一定可行。 替代方式是使用它作為獨立元件。 當您想要將現有的預製專案附加至控制器而不重構腳本時,這非常有用。 只要讓類別等候 IsAttached 設定為 true,再執行任何設定。 最簡單的做法是使用 'Start' 的協同程式。

private IEnumerator Start() {
    AttachToController attach = gameObject.GetComponent<AttachToController>();

    while (!attach.IsAttached) {
        yield return null;
    }

    // Perform setup here
}

第 3 章 - 使用觸控板輸入

目標

  • 瞭解如何取得觸控板輸入資料事件
  • 瞭解如何使用觸控板座標軸位置資訊,以取得您的應用程式體驗

指示

  • 在 [ 階層] 面板中,按一下 [ColorPickerWheel]
  • [偵測器] 面板的 [動畫]底下,按兩下 ColorPickerWheelController
  • 您將可以看到已開啟 動畫工具 索引標籤

使用 Unity 的動畫控制器顯示/隱藏 UI

為了顯示並隱藏具有動畫的 ColorPickerWheel UI,我們使用 Unity 的動畫系統。 將 ColorPickerWheelVisible 屬性設定為 true 或 false 觸發程式 顯示隱藏 動畫觸發程式。 ShowHide 參數定義于 ColorPickerWheelController 動畫控制器中。

Unity Animation Controller

指示

  • 在 [ 階層] 面板中,選取 [ColorPickerWheel prefab]
  • [偵測器] 面板中,按兩下ColorPickerWheel腳本以查看Visual Studio

ColorPickerWheel 腳本

ColorPickerWheel 訂閱 Unity 的 InteractionSourceUpdated 事件,以接聽觸控板事件。

InteractionSourceUpdated () 中,腳本會先檢查以確保它:

  • 實際上是觸控板事件 (obj.state。touchpadTouched)
  • 源自左側控制器 (obj.state.source。手部)

如果兩者都成立,則觸控板位置 (obj.state。touchpadPosition) 指派給 selectorPosition

private void InteractionSourceUpdated(InteractionSourceUpdatedEventArgs obj)
{
    if (obj.state.source.handedness == handedness && obj.state.touchpadTouched)
    {
        Visible = true;
        selectorPosition = obj.state.touchpadPosition;
    }
}

Update () 中,根據 可見 屬性,它會觸發色彩選擇器動畫元件中的顯示和隱藏動畫觸發程式

if (visible != visibleLastFrame)
{
    if (visible)
    {
        animator.SetTrigger("Show");
    }
    else
    {
        animator.SetTrigger("Hide");
    }
}

Update () 中, selectorPosition 用來在色彩滾輪的網格碰撞器上轉換光線,這會傳回 UV 位置。 接著,這個位置可用來尋找色彩滾輪紋理的圖元座標和色彩值。 這個值可透過 SelectedColor 屬性存取其他腳本。

Color Picker Wheel Raycasting

...
    // Clamp selector position to a radius of 1
    Vector3 localPosition = new Vector3(selectorPosition.x * inputScale, 0.15f, selectorPosition.y * inputScale);
    if (localPosition.magnitude > 1)
    {
        localPosition = localPosition.normalized;
    }
    selectorTransform.localPosition = localPosition;

    // Raycast the wheel mesh and get its UV coordinates
    Vector3 raycastStart = selectorTransform.position + selectorTransform.up * 0.15f;
    RaycastHit hit;
    Debug.DrawLine(raycastStart, raycastStart - (selectorTransform.up * 0.25f));

    if (Physics.Raycast(raycastStart, -selectorTransform.up, out hit, 0.25f, 1 << colorWheelObject.layer, QueryTriggerInteraction.Ignore))
    {
        // Get pixel from the color wheel texture using UV coordinates
        Vector2 uv = hit.textureCoord;
        int pixelX = Mathf.FloorToInt(colorWheelTexture.width * uv.x);
        int pixelY = Mathf.FloorToInt(colorWheelTexture.height * uv.y);
        selectedColor = colorWheelTexture.GetPixel(pixelX, pixelY);
        selectedColor.a = 1f;
    }
    // Set the selector's color and blend it with white to make it visible on top of the wheel
    selectorRenderer.material.color = Color.Lerp (selectedColor, Color.white, 0.5f);
}

第 4 章 - 覆寫控制器模型

目標

  • 瞭解如何使用自訂 3D 模型覆寫控制器模型。

MR213_BrushToolOverride

指示

  • 按一下 [階層] 面板中的[動作][控制器]。
  • 按一下 [ 替代右控制器 ] 欄位右側的圓形。
  • 輸入 'BrushController',然後從結果中選取預製專案。 您可以在 Assets/AppPrefabs/BrushController下找到它。
  • 檢查 [一律使用替代右方模型]

MR213_BrushToolOverrideSlot

BrushController預製物件不需要包含在[階層] 面板中。 不過,若要簽出其子元件:

  • [Project]面板中,輸入BrushController,然後將BrushController預製專案拖曳至 [階層] 面板。

MR213_BrushTool_Prefab2

您會在BrushController中找到Tip元件。 我們將使用其轉換來啟動/停止繪圖線。

  • [階層] 面板刪除BrushController
  • 儲存 場景,然後按一下 播放 按鈕。 您將可以看到筆刷模型已取代右手動作控制器。

第 5 章 - 使用選取輸入繪製

目標

  • 瞭解如何使用 [選取] 按鈕事件來啟動和停止線條繪圖

指示

  • Project面板中搜尋BrushController預製專案。
  • [偵測器] 面板中,按兩下BrushController腳本以查看Visual Studio

BrushController 腳本

BrushController 訂閱 InteractionManager 的 InteractionSourcePressedInteractionSourceReleased 事件。 觸發 InteractionSourcePressed 事件時,筆刷的 Draw 屬性會設定為 true;觸發 InteractionSourceReleased 事件時,筆刷的 Draw 屬性會設定為 false。

private void InteractionSourcePressed(InteractionSourcePressedEventArgs obj)
{
    if (obj.state.source.handedness == InteractionSourceHandedness.Right && obj.pressType == InteractionSourcePressType.Select)
    {
        Draw = true;
    }
}

private void InteractionSourceReleased(InteractionSourceReleasedEventArgs obj)
{
    if (obj.state.source.handedness == InteractionSourceHandedness.Right && obj.pressType == InteractionSourcePressType.Select)
    {
        Draw = false;
    }
}

Draw 設為 true 時,筆刷會在具現化的 Unity LineRenderer中產生點。 此預製專案的參考會保留在筆刷的 Stroke Prefab 欄位中。

private IEnumerator DrawOverTime()
{
    // Get the position of the tip
    Vector3 lastPointPosition = tip.position;

    ...

    // Create a new brush stroke
    GameObject newStroke = Instantiate(strokePrefab);
    LineRenderer line = newStroke.GetComponent<LineRenderer>();
    newStroke.transform.position = startPosition;
    line.SetPosition(0, tip.position);
    float initialWidth = line.widthMultiplier;

    // Generate points in an instantiated Unity LineRenderer
    while (draw)
    {
        // Move the last point to the draw point position
        line.SetPosition(line.positionCount - 1, tip.position);
        line.material.color = colorPicker.SelectedColor;
        brushRenderer.material.color = colorPicker.SelectedColor;
        lastPointAddedTime = Time.unscaledTime;
        // Adjust the width between 1x and 2x width based on strength of trigger pull
        line.widthMultiplier = Mathf.Lerp(initialWidth, initialWidth * 2, width);

        if (Vector3.Distance(lastPointPosition, tip.position) > minPositionDelta || Time.unscaledTime > lastPointAddedTime + maxTimeDelta)
        {
            // Spawn a new point
            lastPointAddedTime = Time.unscaledTime;
            lastPointPosition = tip.position;
            line.positionCount += 1;
            line.SetPosition(line.positionCount - 1, lastPointPosition);
        }
        yield return null;
    }
}

若要使用色彩選擇器滾輪 UI 中目前選取的色彩, BrushController 必須具有 ColorPickerWheel 物件的參考。 因為 BrushController prefab 會在執行時間具現化為取代控制器,所以場景中的任何物件參考都必須在執行時間設定。 在此情況下,我們使用 GameObject.FindObjectOfType 來尋找 ColorPickerWheel

private void OnEnable()
{
    // Locate the ColorPickerWheel
    colorPicker = FindObjectOfType<ColorPickerWheel>();

    // Assign currently selected color to the brush’s material color
    brushRenderer.material.color = colorPicker.SelectedColor;
    ...
}
  • 儲存 場景,然後按一下 播放 按鈕。 您將能夠使用右側控制器上的 [選取] 按鈕繪製線條並繪製。

第 6 章 - 使用 Select 輸入繁衍物件

目標

  • 瞭解如何使用選取和掌握按鈕輸入事件
  • 瞭解如何具現化物件

指示

  • [Project]面板中,在搜尋方塊中輸入ObjectSpawner。 您也可以在 Assets/AppPrefabs/ 下找到它

  • ObjectSpawner 預製專案拖曳至 [階層 ] 面板。

  • 按一下[階層] 面板中的[ObjectSpawner]。

  • ObjectSpawner 有一個名為 Color Source的欄位。

  • 從 [ 階層] 面板,將 ColorPickerWheel 參考拖曳至此欄位。

    Object Spawner Inspector

  • 按一下[階層] 面板中的[ObjectSpawner預製專案]。

  • [偵測器] 面板中,按兩下[ObjectSpawner腳本] 以查看Visual Studio中的程式碼。

ObjectSpawner 腳本

ObjectSpawner會將基本網格 (立方體、球體、圓柱) 的複本具現化到空間中。 偵測到 InteractionSourcePressed 時,它會檢查手部是否為 InteractionSourcePressType.GraspInteractionSourcePressType.Select 事件。

對於 擷取 事件,它會遞增目前網格類型的索引 (球體、立方體、圓柱)

private void InteractionSourcePressed(InteractionSourcePressedEventArgs obj)
{
    // Check handedness, see if it is left controller
    if (obj.state.source.handedness == handedness)
    {
        switch (obj.pressType)
        {
            // If it is Select button event, spawn object
            case InteractionSourcePressType.Select:
                if (state == StateEnum.Idle)
                {
                    // We've pressed the grasp - enter spawning state
                    state = StateEnum.Spawning;
                    SpawnObject();
                }
                break;

            // If it is Grasp button event
            case InteractionSourcePressType.Grasp:

                // Increment the index of current mesh type (sphere, cube, cylinder)
                meshIndex++;
                if (meshIndex >= NumAvailableMeshes)
                {
                    meshIndex = 0;
                }
                break;

            default:
                break;
        }
    }
}

針對 Select 事件,在 SpawnObject () 中,新的物件會具現化、未父代並釋放到世界。

private void SpawnObject()
{
    // Instantiate the spawned object
    GameObject newObject = Instantiate(displayObject.gameObject, spawnParent);
    // Detach the newly spawned object
    newObject.transform.parent = null;
    // Reset the scale transform to 1
    scaleParent.localScale = Vector3.one;
    // Set its material color so its material gets instantiated
    newObject.GetComponent<Renderer>().material.color = colorSource.SelectedColor;
}

ObjectSpawner會使用ColorPickerWheel來設定顯示物件材質的色彩。 繁衍的物件會提供此材質的實例,以便保留其色彩。

  • 儲存 場景,然後按一下 播放 按鈕。

您將能夠使用 [擷取] 按鈕來變更物件,並使用 [選取] 按鈕繁衍物件。

建置應用程式並將其部署至Mixed Reality入口網站

  • 在 Unity 中,選取[檔案 > 建置] 設定
  • 按一下 [新增開啟場景 ] 將目前的場景新增至 [建置中的場景]。
  • 按一下 [建置]
  • 建立名為 「App」 的新資料夾
  • 按一下 [ 應用程式 ] 資料夾。
  • 按一下 [選擇資料夾]
  • 當 Unity 完成時,會出現檔案總管視窗。
  • 開啟 [應用程式 ] 資料夾。
  • 按兩下YourSceneName.sln Visual Studio [方案檔案]。
  • 使用Visual Studio中的頂端工具列,將目標從 [偵錯] 變更為[發行],並將目標從 ARM 變更為X64
  • 按一下 [裝置] 按鈕旁的下拉式箭號,然後選取 [ 本機電腦]。
  • 按一下 [ 偵錯 - 啟動但不 > 偵錯] 功能表,或按 Ctrl + F5

現在,應用程式會建置並安裝在Mixed Reality入口網站中。 您可以在Mixed Reality入口網站中透過[開始] 功能表再次啟動它。

進階設計 - 使用星形配置筆刷工具

MixedReality213 Main

在本章中,您將瞭解如何使用自訂筆刷工具集合取代預設動作控制器模型。 如需參考,您可以在Scenes資料夾下找到已完成的場景MixedReality213Advanced

指示

  • [Project]面板中,在搜尋方塊中輸入BrushSelector。 您也可以在 Assets/AppPrefabs/ 下找到它

  • BrushSelector 預製專案拖曳到 [階層 ] 面板。

  • 針對組織,建立名為Brushes的空白 GameObject

  • 將下列預製專案從Project面板拖曳到筆刷

    • Assets/AppPrefabs/BrushFat
    • Assets/AppPrefabs/BrushThin
    • Assets/AppPrefabs/Eraser
    • Assets/AppPrefabs/MarkerFat
    • Assets/AppPrefabs/MarkerThin
    • Assets/AppPrefabs/Pencil

    Brushes

  • 按一下 [階層] 面板中的[動作][控制器預製專案]。

  • [偵測器]面板中,取消核取[動作控制器視覺化檢視] 上的 [一律使用替代右方模型]

  • 在 [ 階層] 面板中,按一下 [BrushSelector]

  • BrushSelector有一個名為ColorPicker的欄位

  • 從 [階層]面板,將ColorPickerWheel拖曳至[偵測器] 面板中的ColorPicker欄位。

    Assign ColorPickerWheel to Brush Selector

  • 在 [ 階層] 面板的 [BrushSelector prefab] 底下,選取 [功能表 ] 物件。

  • [偵測器] 面板的 [LineObjectCollection ] 元件下,開啟 [物件 ] 陣列下拉式清單。 您會看到 6 個空白位置。

  • 從 [ 階層] 面板,依任何順序將 [ 筆刷 GameObject] 底下的每個預製專案拖曳到這些位置。 (確定您要從場景拖曳預製專案,而不是專案資料夾中的預製專案。)

Brush Selector

BrushSelector prefab

由於BrushSelector繼承AttachToController,因此它會在[偵測器] 面板中顯示[手部]和 [元素] 選項。 我們選取 了 [向 右] 和 [ 指向姿勢 ],以將筆刷工具附加至右手控制器,並具有正向方向。

BrushSelector會使用兩個公用程式:

  • 橢圓形:用來在空間中沿著橢圓形產生點。
  • LineObjectCollection:使用任何 Line 類別所產生的點來散發物件 (,例如 Ellipse) 。 這是我們將用來沿著橢圓形放置筆刷的內容。

結合時,這些公用程式可用來建立星形功能表。

LineObjectCollection 腳本

LineObjectCollection 具有沿著其線條散佈之物件的大小、位置和旋轉控制項。 這適用于建立星形功能表,例如筆刷選取器。 若要建立筆刷的外觀,當筆刷接近中央選取的位置時相應增加, ObjectScale 曲線會尖峰在中央,並點選邊緣的點選。

BrushSelector 腳本

BrushSelector的情況下,我們選擇使用程式動畫。 首先,筆刷模型會以 LineObjectCollection 腳本的省略號散發。 然後,每個筆刷都會根據 使用者的 DisplayMode 值,負責維護使用者手上的位置,這會根據選取範圍而變更。 由於使用者選取筆刷時,筆刷位置轉換的機率很高,因此我們選擇了程式性方法。 Mecanim 動畫可以正常處理中斷,但通常比簡單的 Lerp 作業更複雜。

BrushSelector 使用兩者的組合。 偵測到觸控板輸入時,筆刷選項會變成可見,並沿著星形功能表相應增加。 逾時期間之後 (,表示使用者已) 筆刷選項再次縮小選取範圍,只保留選取的筆刷。

視覺化觸控板輸入

即使控制器模型已完全取代,在原始模型輸入上顯示輸入也很有説明。 這有助於實作使用者的實際動作。 針對 BrushSelector ,我們選擇在收到輸入時,讓觸控板短暫顯示。 這是藉由從控制器擷取 Touchpad 元素、將其材質取代為自訂材質,然後根據上次收到觸控板輸入的時間,將漸層套用至該材質的色彩來完成。

protected override void OnAttachToController()
{
    // Turn off the default controller's renderers
    controller.SetRenderersVisible(false);

    // Get the touchpad and assign our custom material to it
    Transform touchpad;
    if (controller.TryGetElement(MotionControllerInfo.ControllerElementEnum.Touchpad, out touchpad))
    {
        touchpadRenderer = touchpad.GetComponentInChildren<MeshRenderer>();
        originalTouchpadMaterial = touchpadRenderer.material;
        touchpadRenderer.material = touchpadMaterial;
        touchpadRenderer.enabled = true;
    }

    // Subscribe to input now that we're parented under the controller
    InteractionManager.InteractionSourceUpdated += InteractionSourceUpdated;
}

private void Update()
{
    ...
    // Update our touchpad material
    Color glowColor = touchpadColor.Evaluate((Time.unscaledTime - touchpadTouchTime) / touchpadGlowLossTime);
    touchpadMaterial.SetColor("_EmissionColor", glowColor);
    touchpadMaterial.SetColor("_Color", glowColor);
    ...
}

使用觸控板輸入進行筆刷工具選取

當筆刷選取器偵測到觸控板按下的輸入時,它會檢查輸入的位置,以判斷它是否位於左側或右邊。

具有 selectPressedAmount 的筆劃粗細

您可以在InteractionSourcePressed () 中取得按下金額的類比值,而不是InteractionSourcePressType.Select事件。 此值可以在 InteractionSourceUpdated () 中擷 取。

private void InteractionSourceUpdated(InteractionSourceUpdatedEventArgs obj)
{
    if (obj.state.source.handedness == handedness)
    {
        if (obj.state.touchpadPressed)
        {
            // Check which side we clicked
            if (obj.state.touchpadPosition.x < 0)
            {
                currentAction = SwipeEnum.Left;
            }
            else
            {
                currentAction = SwipeEnum.Right;
            }

            // Ping the touchpad material so it gets bright
            touchpadTouchTime = Time.unscaledTime;
        }

        if (activeBrush != null)
        {
            // If the pressed amount is greater than our threshold, draw
            if (obj.state.selectPressedAmount >= selectPressedDrawThreshold)
            {
                activeBrush.Draw = true;
                activeBrush.Width = ProcessSelectPressedAmount(obj.state.selectPressedAmount);
            }
            else
            {
                // Otherwise, stop drawing
                activeBrush.Draw = false;
                selectPressedSmooth = 0f;
            }
        }
    }
}

橡皮擦腳本

Eraser 是一種特殊的筆刷類型,可覆寫基底 BrushDrawOverTime () 函式。 當 Draw 為 true 時,橡皮擦會檢查其提示是否與任何現有的筆刷筆劃交集。 如果這樣做,則會將它們新增至佇列,以縮小並刪除。

進階設計 - Teleportation 和 locomotion

如果您想要允許使用者使用搖桿來移動場景,請使用 MixedRealityCameraParent ,而不是 MixedRealityCamera。 您也需要新增 InputManagerDefaultCursor。 由於 MixedRealityCameraParent 已經包含 MotionControllersBoundary 作為子元件,因此您應該移除現有的 MotionControllers和環境預 制專案。

指示

  • 在 [ 階層] 面板中,刪除 MixedRealityCameraEnvironmentMotionControllers

  • [Project] 面板中,搜尋下列預製專案並將其拖曳至 [階層] 面板:

    • Assets/AppPrefabs/Input/Prefabs/MixedRealityCameraParent
    • Assets/AppPrefabs/Input/Prefabs/InputManager
    • Assets/AppPrefabs/Input/Prefabs/Cursor/DefaultCursor

    Mixed Reality Camera Parent

  • 在 [ 階層] 面板中,按一下 [ 輸入管理員]

  • [偵測器] 面板中,向下捲動至 [簡單單一指標選取器 ] 區段

  • 從 [ 階層] 面板,將 DefaultCursor 拖曳至 [資料指標 ] 欄位

    Assigning DefaultCursor

  • 儲存 場景,然後按一下 播放 按鈕。 您將能夠使用搖桿來向左/向右或電匯旋轉。

結束

這就是本教學課程的結尾! 您已了解︰

  • 如何在 Unity 的遊戲模式和執行時間中使用動作控制器模型。
  • 如何使用不同類型的按鈕事件及其應用程式。
  • 如何在控制器頂端重迭 UI 元素,或完全自訂它。

您現在已準備好開始使用運動控制器建立自己的沉浸式體驗!

已完成的場景

  • 在 Unity 的[Project]面板中,按一下[場景]資料夾。
  • 您會發現兩個 Unity 場景 MixedReality213MixedReality213Advanced
    • MixedReality213:具有單一筆刷的已完成場景
    • MixedReality213Advanced:具有多個筆刷的已完成場景,具有選取按鈕的按下數量範例

另請參閱