Condividi tramite


Input MR 213: Controller del movimento

Nota

Le esercitazioni di Mixed Reality Academy sono state progettate in base a HoloLens (prima generazione) e ai visori VR immersive di realtà mista. Pertanto, riteniamo importante lasciarle a disposizione degli sviluppatori a cui serve ancora materiale sussidiario per lo sviluppo di questi dispositivi. Queste esercitazioni non verranno aggiornate con i set di strumenti o le interazioni più recenti usati per HoloLens 2. Rimarranno invariate per consentire di continuare a lavorare sui dispositivi supportati. Per HoloLens 2 è stata pubblicata una nuova serie di esercitazioni.

I controller di movimento nel mondo della realtà mista aggiungono un altro livello di interattività. Con i controller di movimento, è possibile interagire direttamente con gli oggetti in modo più naturale, simile alle interazioni fisiche nella vita reale, aumentando l'immersione e la gioia nell'esperienza dell'app.

In MR Input 213 si esamineranno gli eventi di input del controller di movimento creando un'esperienza di pittura spaziale semplice. Con questa app, gli utenti possono dipingere nello spazio tridimensionale con vari tipi di pennelli e colori.

Argomenti illustrati in questa esercitazione

Argomento MixedReality213 Argomento MixedReality213 Argomento MixedReality213
Visualizzazione controller Eventi di input del controller Controller e interfaccia utente personalizzati
Informazioni su come eseguire il rendering dei modelli del controller di movimento in modalità gioco e runtime di Unity. Informazioni su diversi tipi di eventi del pulsante e sulle relative applicazioni. Informazioni su come sovrapporre gli elementi dell'interfaccia utente sopra il controller o personalizzarlo completamente.

Supporto di dispositivi

Corso HoloLens Visori VR immersive
Input MR 213: Controller del movimento ✔️

Prima di iniziare

Prerequisiti

Vedere l'elenco di controllo per l'installazione per visori immersivi in questa pagina.

File di progetto

Nota

Se si vuole esaminare il codice sorgente prima di scaricare, è disponibile in GitHub.

Configurazione di Unity

Obiettivi

  • Ottimizzare Unity per lo sviluppo di Windows Mixed Reality
  • Configurare Realtà mista fotocamera
  • Configurare l'ambiente

Istruzioni

  • Riavviare Unity.

  • Selezionare Open (Apri).

  • Passare a Desktop e trovare la cartella MixedReality213-master precedentemente non crittografata.

  • Fare clic su Seleziona cartella.

  • Al termine del caricamento dei file di progetto di Unity, sarà possibile visualizzare l'editor unity.

  • In Unity selezionare Impostazioni compilazione file>.

    MR213_BuildSettings

  • Selezionare piattaforma UWP (Universal Windows Platform) nell'elenco Piattaforma e fare clic sul pulsante Cambia piattaforma.

  • Impostare Dispositivo di destinazione su Qualsiasi dispositivo

  • Impostare il tipo di compilazione su D3D

  • Impostare SDK su Più recente installato

  • Controllare i progetti C# di Unity

    • Ciò consente di modificare i file di script nel progetto Visual Studio senza ricompilare il progetto Unity.
  • Fare clic su Impostazioni lettore.

  • Nel pannello Controllo scorrere verso il basso

  • In Impostazioni XR selezionare Realtà virtuale supportata

  • In SDK di realtà virtuale selezionare Windows Mixed Reality

    MR213_XRSettings

  • Chiudere la finestra Impostazioni di compilazione .

Struttura del progetto

Questa esercitazione usa Realtà mista Toolkit - Unity. È possibile trovare le versioni in questa pagina.

ProjectStructure

Scene completate per il riferimento

  • Sono disponibili due scene di Unity completate nella cartella Scene .
    • MixedReality213: Scena completata con pennello singolo
    • MixedReality213Advanced: Scena completata per la progettazione avanzata con più pennelli

Nuova configurazione della scena per l'esercitazione

  • In Unity fare clic su Nuova scena file >

  • Eliminare la fotocamera principale e la luce direzionale

  • Nel pannello Progetto cercare e trascinare i prefab seguenti nel pannello Gerarchia :

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

    Fotocamera e ambiente

  • Esistono due prefab della fotocamera in Realtà mista Toolkit:

    • MixedRealityCamera.prefab: solo fotocamera
    • MixedRealityCameraParent.prefab: Fotocamera + Teleportazione + Limite
    • In questa esercitazione verrà usata la funzionalità MixedRealityCamera senza teleportazione. A causa di questo, è stato aggiunto un semplice prefab Ambiente che contiene un piano di base per rendere l'utente a terra.
    • Per altre informazioni sulla teleportazione con MixedRealityCameraParent, vedere Progettazione avanzata - Teleportazione e locomozione

Configurazione di Skybox

  • Fare clic su Impostazioni di illuminazione > finestra >

  • Fare clic sul cerchio sul lato destro del campo Skybox Material

  • Digitare "grigio" e selezionare SkyboxGray (Asset/AppPrefabs/Supporto/Materiali/SkyboxGray.mat)

    Impostazione di skybox

  • Selezionare l'opzione Skybox per poter visualizzare skybox sfumatura grigia assegnata

    Opzione Disattiva skybox

  • La scena con MixedRealityCamera, Ambiente e skybox grigio sarà simile a questa.

    Ambiente MixedReality213

  • Fare clic su Salva scena file > come

  • Salvare la scena nella cartella Scene con qualsiasi nome

Capitolo 1 - Visualizzazione controller

Obiettivi

  • Informazioni su come eseguire il rendering dei modelli del controller di movimento in modalità gioco di Unity e in fase di esecuzione.

Windows Mixed Reality fornisce un modello di controller animato per la visualizzazione del controller. Esistono diversi approcci che è possibile adottare per la visualizzazione del controller nell'app:

  • Impostazione predefinita: uso del controller predefinito senza modifiche
  • Ibrido: uso del controller predefinito, ma personalizzazione di alcuni dei relativi elementi o componenti dell'interfaccia utente sovrapposti
  • Sostituzione: uso del modello 3D personalizzato per il controller

In questo capitolo verranno illustrati gli esempi di queste personalizzazioni del controller.

Istruzioni

  • Nel pannello Progetto digitare MotionControllers nella casella di ricerca . È anche possibile trovarlo in Assets/HoloToolkit/Input/Prefabs/.
  • Trascinare il prefab MotionControllers nel pannello Hierarchy (Gerarchia ).
  • Fare clic sul prefab MotionControllers nel pannello Gerarchia .

Prefab MotionControllers

Il prefab MotionControllers ha uno script MotionControllerVisualizer che fornisce gli slot per i modelli di controller alternativi. Se si assegnano modelli 3D personalizzati, ad esempio una mano o una spada e si seleziona "Usa sempre modello alternativo a sinistra/destra", verranno visualizzati anziché il modello predefinito. Questo slot verrà usato nel capitolo 4 per sostituire il modello di controller con un pennello.

MR213_ControllerVisualizer

Istruzioni

  • Nel pannello Inspector (Controllo ) fare doppio clic su MotionControllerVisualizer script (Script MotionControllerVisualizer ) per visualizzare il codice in Visual Studio

Script MotionControllerVisualizer

Le classi MotionControllerVisualizer e MotionControllerInfo forniscono i mezzi per accedere & modificare i modelli di controller predefiniti. MotionControllerVisualizer sottoscrive l'evento InteractionSourceDetected di Unity e crea automaticamente istanze dei modelli controller quando vengono trovati.

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

I modelli controller vengono forniti in base alla specifica glTF. Questo formato è stato creato per fornire un formato comune, migliorando al tempo stesso il processo di trasmissione e decompressione degli asset 3D. In questo caso, è necessario recuperare e caricare i modelli controller in fase di esecuzione, in quanto si vuole rendere l'esperienza dell'utente il più facile possibile e non è garantita quale versione dei controller di movimento l'utente potrebbe usare. Questo corso, tramite Realtà mista Toolkit, usa una versione del progetto UnityGLTF del gruppo Khronos.

Dopo aver recapitato il controller, gli script possono usare MotionControllerInfo per trovare le trasformazioni per elementi controller specifici in modo che possano posizionarsi correttamente.

In un capitolo successivo si apprenderà come usare questi script per collegare gli elementi dell'interfaccia utente ai controller.

In alcuni script sono disponibili blocchi di codice con #if ! UNITY_EDITOR o UNITY_WSA. Questi blocchi di codice vengono eseguiti solo nel runtime UWP quando si esegue la distribuzione in Windows. Questo avviene perché il set di API usate dall'editor unity e dal runtime dell'app UWP sono diversi.

  • Salvare la scena e fare clic sul pulsante Riproduci .

Sarai in grado di vedere la scena con i controller del movimento nel visore VR. Puoi visualizzare animazioni dettagliate per i clic sui pulsanti, il movimento della levetta e l'evidenziazione del tocco del touchpad.

impostazione predefinita visualizzazione MR213_Controller

Capitolo 2 - Collegamento di elementi dell'interfaccia utente al controller

Obiettivi

  • Informazioni sugli elementi dei controller del movimento
  • Informazioni su come collegare oggetti a parti specifiche dei controller

In questo capitolo si apprenderà come aggiungere elementi dell'interfaccia utente al controller a cui l'utente può accedere e manipolare facilmente in qualsiasi momento. Si apprenderà anche come aggiungere un'interfaccia utente di selezione colori semplice usando l'input del touchpad.

Istruzioni

  • Nel pannello Progetto cercare lo script MotionControllerInfo .
  • Nel risultato della ricerca fare doppio clic su MotionControllerInfo script per visualizzare il codice in Visual Studio.

Script MotionControllerInfo

Il primo passaggio consiste nel scegliere l'elemento del controller a cui si vuole collegare l'interfaccia utente. Questi elementi sono definiti in ControllerElementEnum in MotionControllerInfo.cs.

MR213 MotionControllerElements

  • Casa
  • Menu
  • Afferrare
  • Levetta
  • Select
  • Touchpad
  • Posizione puntante : questo elemento rappresenta la punta del controller che punta verso la direzione in avanti.

Istruzioni

  • Nel pannello Progetto cercare Script AttachToController .
  • Nel risultato della ricerca fare doppio clic su AttachToController script (Script AttachToController ) per visualizzare il codice in Visual Studio.

Script AttachToController

Lo script AttachToController offre un modo semplice per collegare tutti gli oggetti a una mano e a un elemento controller specificati.

In AttachElementToController(),

  • Controllo della mano con MotionControllerInfo.Handedness
  • Ottenere un elemento specifico del controller usando MotionControllerInfo.TryGetElement()
  • Dopo aver recuperato la trasformazione dell'elemento dal modello controller, padre l'oggetto sotto di esso e impostare la posizione locale dell'oggetto & rotazione su zero.
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;
     }
}

Il modo più semplice per usare lo script AttachToController consiste nell'ereditare da esso, come è stato fatto nel caso di ColorPickerWheel. È sufficiente eseguire l'override delle funzioni OnAttachToController e OnDetachFromController per eseguire la configurazione/suddivisione quando il controller viene rilevato/disconnesso.

Istruzioni

  • Nel pannello Progetto digitare nella casella di ricerca ColorPickerWheel. È anche possibile trovarlo in Asset/AppPrefabs/.
  • Trascinare il prefab ColorPickerWheel nel pannello Hierarchy (Gerarchia ).
  • Fare clic sul prefab ColorPickerWheel nel pannello Gerarchia .
  • Nel pannello Inspector (Controllo ) fare doppio clic su ColorPickerWheel Script (Script ColorPickerWheel ) per visualizzare il codice in Visual Studio.

Prefab ColorPickerWheel

Script ColorPickerWheel

Poiché ColorPickerWheel eredita AttachToController, mostra Handedness e Element nel pannello Inspector . L'interfaccia utente verrà collegata all'elemento Touchpad sul controller sinistro.

Script ColorPickerWheel

ColorPickerWheel esegue l'override di OnAttachToController e OnDetachFromController per sottoscrivere l'evento di input che verrà usato nel capitolo successivo per la selezione dei colori con input del touchpad.

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;
    }
    ...
}
  • Salvare la scena e fare clic sul pulsante Riproduci .

Metodo alternativo per il collegamento di oggetti ai controller

È consigliabile che gli script ereditino da AttachToController ed eseseguono l'override di OnAttachToController. Tuttavia, questo potrebbe non essere sempre possibile. Un'alternativa consiste nell'usarlo come componente autonomo. Ciò può essere utile quando si vuole collegare un prefab esistente a un controller senza effettuare il refactoring degli script. È sufficiente che la classe attenda che IsAttached sia impostata su true prima di eseguire qualsiasi configurazione. Il modo più semplice per eseguire questa operazione consiste nell'usare una coroutine per "Start".

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

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

    // Perform setup here
}

Capitolo 3 - Uso dell'input del touchpad

Obiettivi

  • Informazioni su come ottenere eventi di dati di input del touchpad
  • Informazioni su come usare le informazioni sulla posizione dell'asse del touchpad per l'esperienza dell'app

Istruzioni

  • Nel pannello Hierarchy (Gerarchia ) fare clic su ColorPickerWheel
  • Nel pannello Inspector (Controllo ) in Animator fare doppio clic su ColorPickerWheelController
  • Sarà possibile visualizzare la scheda Animatore aperta

Visualizzazione/nascondere l'interfaccia utente con il controller di animazione di Unity

Per mostrare e nascondere l'interfaccia utente ColorPickerWheel con l'animazione, viene usato il sistema di animazione di Unity. Impostando la proprietà Visible di ColorPickerWheel su true o false trigger Mostra e nascondi trigger di animazione. I parametri Show e Hide sono definiti nel controller di animazione ColorPickerWheelController .

Controller di animazione Unity

Istruzioni

  • Nel pannello Hierarchy (Gerarchia ) selezionare ColorPickerWheel prefab (Prefab ColorPickerWheel )
  • Nel pannello Inspector (Controllo ) fare doppio clic su ColorPickerWheel script (Script ColorPickerWheel ) per visualizzare il codice in Visual Studio

Script ColorPickerWheel

ColorPickerWheel sottoscrive l'evento InteractionSourceUpdated di Unity per ascoltare gli eventi del touchpad.

In InteractionSourceUpdated(), lo script controlla per prima cosa:

  • è effettivamente un evento touchpad (obj.state).touchpadTouched)
  • proviene dal controller a sinistra (obj.state.source).mano)

Se entrambi sono true, la posizione del touchpad (obj.state).touchpadPosition) viene assegnato a selectorPosition.

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

In Update(), in base alla proprietà visibile , attiva i trigger Mostra e Nascondi animazioni nel componente animatore del selettore colori

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

In Update(), selectorPosition viene usato per eseguire il cast di un raggio in corrispondenza del collisore mesh della ruota del colore, che restituisce una posizione UV. Questa posizione può quindi essere usata per trovare la coordinata pixel e il valore del colore della trama della ruota del colore. Questo valore è accessibile ad altri script tramite la proprietà 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);
}

Capitolo 4 - Override del modello del controller

Obiettivi

  • Informazioni su come eseguire l'override del modello controller con un modello 3D personalizzato.

MR213_BrushToolOverride

Istruzioni

  • Fare clic su MotionController nel pannello Gerarchia .
  • Fare clic sul cerchio sul lato destro del campo Controller alternativo destro .
  • Digitare "BrushController" e selezionare il prefab dal risultato. È possibile trovarlo in Asset/AppPrefabs/BrushController.
  • Selezionare Usa sempre un modello alternativo a destra

MR213_BrushToolOverrideSlot

Il prefab BrushController non deve essere incluso nel pannello Gerarchia . Tuttavia, per controllare i componenti figlio:

  • Nel pannello Progetto digitare In BrushController e trascinare il prefab BrushController nel pannello Gerarchia .

MR213_BrushTool_Prefab2

Troverai il componente Tip in BrushController. Verrà usata la trasformazione per avviare/arrestare le linee di disegno.

  • Eliminare BrushController dal pannello Gerarchia .
  • Salvare la scena e fare clic sul pulsante play . Sarà possibile visualizzare il modello di pennello sostituito dal controller di movimento destro.

Capitolo 5 - Pittura con Selezione input

Obiettivi

  • Informazioni su come usare l'evento Select button per avviare e arrestare un disegno a linee

Istruzioni

  • Cercare il prefab BrushController nel pannello Progetto .
  • Nel pannello Controllo fare doppio clic su BrushController Script per visualizzare il codice in Visual Studio

Script BrushController

BrushController sottoscrive gli eventi InteractionSourcePressed e InteractionSourceReleased di InteractionManager . Quando viene attivato l'evento InteractionSourcePressed , la proprietà Draw del pennello è impostata su true; quando viene attivato l'evento InteractionSourceReleased , la proprietà Draw del pennello è impostata su 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;
    }
}

Mentre Draw è impostato su true, il pennello genererà punti in un'istanza di Unity LineRenderer. Un riferimento a questo prefab viene mantenuto nel campo Prefab del pennello.

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;
    }
}

Per usare il colore attualmente selezionato dall'interfaccia utente della rotellina del selettore colori, BrushController deve avere un riferimento all'oggetto ColorPickerWheel . Poiché il prefab BrushController viene creata un'istanza in fase di esecuzione come controller sostitutivo, tutti i riferimenti agli oggetti nella scena dovranno essere impostati in fase di esecuzione. In questo caso si usa GameObject.FindObjectOfType per individuare 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;
    ...
}
  • Salvare la scena e fare clic sul pulsante play . Sarà possibile disegnare le linee e disegnare usando il pulsante select sul controller a destra.

Capitolo 6 - Creazione di oggetti con Selezione input

Obiettivi

  • Informazioni su come usare gli eventi di input del pulsante Select and Grasp
  • Informazioni su come creare un'istanza di oggetti

Istruzioni

  • Nel pannello Progetto digitare ObjectSpawner nella casella di ricerca. È anche possibile trovarlo in Asset/AppPrefabs/

  • Trascinare il prefab ObjectSpawner nel pannello Gerarchia .

  • Fare clic su ObjectSpawner nel pannello Gerarchia .

  • ObjectSpawner ha un campo denominato Origine colori.

  • Nel pannello Gerarchia trascinare il riferimento ColorPickerWheel in questo campo.

    Controllo spawner oggetto

  • Fare clic sul prefab ObjectSpawner nel pannello Gerarchia .

  • Nel pannello Controllo fare doppio clic su ObjectSpawner Script per visualizzare il codice in Visual Studio.

Script ObjectSpawner

L'istanza di ObjectSpawner crea un'istanza di una mesh primitiva (cubo, sfera, cilindro) nello spazio. Quando viene rilevato un oggetto InteractionSourcePressed, controlla la mano e se è un evento InteractionSourcePressType.Grasp o InteractionSourcePressType.Select.

Per un evento Grasp, incrementa l'indice del tipo mesh corrente (sphere, cube, cylinder)

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;
        }
    }
}

Per un evento Select , in SpawnObject(), viene creata un'istanza di un nuovo oggetto, non padre e rilasciato nel mondo.

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 usa ColorPickerWheel per impostare il colore del materiale dell'oggetto visualizzato. Gli oggetti generati vengono assegnati a un'istanza di questo materiale in modo da conservarne il colore.

  • Salvare la scena e fare clic sul pulsante play .

Sarà possibile modificare gli oggetti con il pulsante Grasp e generare oggetti con il pulsante Seleziona.

Compilare e distribuire l'app nel portale di Realtà mista

  • In Unity selezionare Impostazioni compilazione file>.
  • Fare clic su Aggiungi scene aperte per aggiungere la scena corrente alle scene in compilazione.
  • Fare clic su Compila.
  • Creare una nuova cartella denominata "App".
  • Fare clic sulla cartella App .
  • Fare clic su Seleziona cartella.
  • Al termine di Unity, verrà visualizzata una finestra Esplora file.
  • Aprire la cartella App .
  • Fare doppio clic su YourSceneName.sln Visual Studio Solution file.
  • Usando la barra degli strumenti superiore in Visual Studio, modificare la destinazione da Debug a Versione e da ARM a X64.
  • Fare clic sulla freccia a discesa accanto al pulsante Dispositivo e selezionare Computer locale.
  • Fare clic su Debug -> Avvia senza eseguire il debug nel menu o premere CTRL + F5.

Ora l'app viene compilata e installata nel portale di Realtà mista. È possibile avviarlo di nuovo tramite il menu Start in Realtà mista Portale.

Progettazione avanzata - Strumenti di pennello con layout radiale

MixedReality213 Main

In questo capitolo si apprenderà come sostituire il modello di controller di movimento predefinito con una raccolta di strumenti pennello personalizzata. Per il riferimento, è possibile trovare la scena completata MixedReality213Advanced nella cartella Scene .

Istruzioni

  • Nel pannello Progetto digitare BrushSelector nella casella di ricerca . È anche possibile trovarlo in Asset/AppPrefabs/

  • Trascinare il prefab BrushSelector nel pannello Gerarchia .

  • Per l'organizzazione, creare un GameObject vuoto denominato Brushes

  • Trascinare i prefab seguenti dal pannello Progetto in Pennelli

    • Asset/AppPrefabs/BrushFat
    • Asset/AppPrefabs/BrushThin
    • Asset/AppPrefabs/Eraser
    • Asset/AppPrefabs/MarkerFat
    • Asset/AppPrefabs/MarkerThin
    • Asset/AppPrefabs/Matita

    Pennelli

  • Fare clic su MotionControllers prefab nel pannello Hierarchy (Gerarchia ).

  • Nel pannello Inspector (Controllo ) deselezionare Always Use Alternate Right Model (Usa sempre modello a destra alternativo ) nel visualizzatore del controller di movimento

  • Nel pannello Gerarchia fare clic su BrushSelector

  • BrushSelector ha un campo denominato ColorPicker

  • Dal pannello Hierarchy (Gerarchia ) trascinare il campo ColorPickerWheel nel campo ColorPicker nel pannello Inspector (Controllo ).

    Assegnare ColorPickerWheel al selettore pennello

  • Nel pannello Hierarchy (Gerarchia ) in BrushSelector prefab (Prefab BrushSelector ) selezionare l'oggetto Menu .

  • Nel pannello Inspector (Controllo ) nel componente LineObjectCollection aprire l'elenco a discesa Matrice oggetti . Verranno visualizzati 6 slot vuoti.

  • Dal pannello Hierarchy (Gerarchia ) trascinare ognuno dei prefab padre sotto Brushes GameObject in questi slot in qualsiasi ordine. Assicurarsi di trascinare i prefab dalla scena, non i prefab nella cartella del progetto.

Selettore pennello

Prefab BrushSelector

Poiché BrushSelector eredita AttachToController, mostra le opzioni Handedness e Element nel pannello Inspector . Abbiamo selezionato Right e Pointing Pose per collegare gli strumenti pennello al controller di destra con direzione in avanti.

BrushSelector usa due utilità:

  • Ellisse: consente di generare punti nello spazio lungo una forma ellisse.
  • LineObjectCollection: distribuisce gli oggetti usando i punti generati da qualsiasi classe Line (ad esempio, Ellipse). Questo è ciò che verrà usato per posizionare i pennelli lungo la forma Ellipse.

In combinazione, queste utilità possono essere usate per creare un menu radiale.

Script LineObjectCollection

LineObjectCollection include controlli per le dimensioni, la posizione e la rotazione degli oggetti distribuiti lungo la linea. Ciò è utile per la creazione di menu radiali come il selettore di pennello. Per creare l'aspetto dei pennelli che aumentano da nulla quando si avvicinano alla posizione selezionata al centro, la curva ObjectScale raggiunge il centro e tocca i bordi.

Script BrushSelector

Nel caso di BrushSelector, abbiamo scelto di usare l'animazione procedurale. Per prima cosa, i modelli pennello vengono distribuiti in un'ellisse dallo script LineObjectCollection . Ogni pennello è quindi responsabile della gestione della posizione nella mano dell'utente in base al relativo valore DisplayMode , che cambia in base alla selezione. È stato scelto un approccio procedurale a causa dell'elevata probabilità di interruzione delle transizioni di posizione del pennello quando l'utente seleziona i pennelli. Le animazioni mecanim possono gestire normalmente le interruzioni, ma tende a essere più complicate di una semplice operazione Lerp.

BrushSelector usa una combinazione di entrambe. Quando viene rilevato l'input del touchpad, le opzioni del pennello diventano visibili e aumentano lungo il menu radiale. Dopo un periodo di timeout (che indica che l'utente ha effettuato una selezione) le opzioni del pennello vengono ridimensionate di nuovo, lasciando solo il pennello selezionato.

Visualizzazione dell'input del touchpad

Anche nei casi in cui il modello controller è stato completamente sostituito, può essere utile visualizzare l'input sugli input del modello originale. Ciò consente di mettere a terra le azioni dell'utente in realtà.This helps to ground the user's actions in reality. Per BrushSelector abbiamo scelto di rendere visibile brevemente il touchpad quando viene ricevuto l'input. Questa operazione è stata eseguita recuperando l'elemento Touchpad dal controller, sostituendo il materiale con un materiale personalizzato, quindi applicando una sfumatura al colore del materiale in base all'ultimo input del touchpad ricevuto.

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);
    ...
}

Selezione degli strumenti pennello con input touchpad

Quando il selettore di pennello rileva l'input premuto del touchpad, controlla la posizione dell'input per determinare se si trovava a sinistra o a destra.

Spessore tratto con selectPressedAmount

Anziché l'evento InteractionSourcePressType.Selectnell'oggetto InteractionSourcePressed(), è possibile ottenere il valore analogico della quantità premuta tramite selectPressedAmount. Questo valore può essere recuperato in 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;
            }
        }
    }
}

Script gomma

Eraser è un tipo speciale di pennello che esegue l'override della funzione DrawOverTime() di Base Brush. Mentre Draw è true, la gomma controlla se la punta interseca con qualsiasi tratto pennello esistente. In caso affermativo, vengono aggiunti a una coda per essere compattati ed eliminati.

Progettazione avanzata - Teleportazione e locomozione

Se si vuole consentire all'utente di spostarsi all'interno della scena con teletrasporto usando la levetta, usare MixedRealityCameraParent anziché MixedRealityCamera. È anche necessario aggiungere InputManager e DefaultCursor. Poiché MixedRealityCameraParent include già MotionControllers e Boundary come componenti figlio, è necessario rimuovere i prefab MotionController e Environment esistenti.

Istruzioni

  • Nel pannello Hierarchy (Gerarchia ) eliminare MixedRealityCamera, Environment e MotionControllers

  • Nel pannello Progetto cercare e trascinare i prefab seguenti nel pannello Hierarchy (Gerarchia ):

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

    Realtà mista elemento padre della fotocamera

  • Nel pannello Gerarchia fare clic su Gestione input

  • Nel pannello Inspector (Controllo) scorrere verso il basso fino alla sezione Simple Single Pointer Selector (Selettore puntatore singolo semplice)

  • Dal pannello Hierarchy (Gerarchia) trascinare DefaultCursor nel campo Cursor

    Assegnazione di DefaultCursor

  • Salvare la scena e fare clic sul pulsante Riproduci . Sarà possibile usare la levetta per ruotare a sinistra/destra o teletrasportare.

La fine

E questa è la fine di questa esercitazione! Sono stati appresi i concetti seguenti:

  • Come usare i modelli di controller di movimento nella modalità di gioco e nel runtime di Unity.
  • Come usare diversi tipi di eventi pulsante e le relative applicazioni.
  • Come sovrapporre gli elementi dell'interfaccia utente sopra il controller o personalizzarlo completamente.

A questo punto è possibile iniziare a creare un'esperienza immersiva con i controller del movimento.

Scene completate

  • Nel pannello Progetto di Unity fare clic sulla cartella Scene .
  • Sono disponibili due scene di Unity MixedReality213 e MixedReality213Advanced.
    • MixedReality213: scena completata con un singolo pennello
    • MixedReality213Advanced: Scena completata con più pennelli con l'esempio di pressione del pulsante di selezione

Vedi anche