Panoramica del risolutore - MRTK2

Risolutore principale

I risolutori sono componenti che facilitano il calcolo della posizione di un oggetto & orientamento in base a un algoritmo predefinito. Un esempio può posizionare un oggetto sulla superficie in cui è attualmente raggiunto il raycast dello sguardo dell'utente.

Inoltre, il sistema risolutore definisce in modo deterministico un ordine di operazioni per questi calcoli di trasformazione perché non esiste alcun modo affidabile per specificare l'ordine di aggiornamento di Unity per i componenti.

I risolutori offrono un intervallo di comportamenti per collegare oggetti ad altri oggetti o sistemi. Un altro esempio sarebbe un oggetto tag-lungo che passa il puntatore del mouse davanti all'utente (in base alla fotocamera). Un risolutore può anche essere collegato a un controller e a un oggetto per rendere il tag dell'oggetto lungo il controller. Tutti i risolutori possono essere impilati in modo sicuro, ad esempio un comportamento tag-lungo + magnetismo di superficie + momento.

Come usare un risolutore

Il sistema risolutore è costituito da tre categorie di script:

  • Solver: classe astratta di base da cui derivano tutti i risolutori. Fornisce il rilevamento dello stato, i parametri di smoothing e l'implementazione, l'integrazione automatica del sistema risolutore e l'ordine di aggiornamento.
  • SolverHandler: imposta l'oggetto di riferimento su (ad esempio: la trasformazione principale della fotocamera, il raggio della mano e così via), gestisce la raccolta dei componenti del risolutore ed esegue l'aggiornamento nell'ordine appropriato.

La terza categoria è il risolutore stesso. I risolutori seguenti forniscono i blocchi predefiniti per il comportamento di base:

  • Orbital: blocca in una posizione e un offset specificati dall'oggetto a cui si fa riferimento.
  • ConstantViewSize: ridimensiona per mantenere una dimensione costante rispetto alla visualizzazione dell'oggetto a cui si fa riferimento.
  • RadialView: mantiene l'oggetto all'interno di un cast di viste in base all'oggetto a cui si fa riferimento.
  • Follow: mantiene l'oggetto all'interno di un set di limiti definiti dall'utente dell'oggetto a cui si fa riferimento.
  • InBetween: mantiene un oggetto tra due oggetti rilevati.
  • SurfaceMagnetism: esegue il cast dei raggi alle superfici del mondo e allinea l'oggetto a tale superficie.
  • DirectionalIndicator: determina la posizione e l'orientamento di un oggetto come indicatore direzionale. Dal punto di riferimento della destinazione tracciata risolutore, questo indicatore si orienta verso l'oggetto DirectionalTarget fornito.
  • Momentum: applica accelerazione/velocità/attrito per simulare il momento e la primavera per un oggetto spostato da altri risolutori/componenti.
  • HandConstraint: vincola l'oggetto a seguire le mani in un'area che non interseca GameObject con le mani. Utile per il contenuto interattivo vincolato a mano, ad esempio menu e così via. Questo risolutore è destinato a lavorare con IMixedRealityHand , ma funziona anche con IMixedRealityController.
  • HandConstraintPalmUp: deriva da HandConstraint, ma include la logica per testare se il palmo è rivolto all'utente prima dell'attivazione. Questo risolutore funziona solo con i controller IMixedRealityHand , con altri tipi di controller che questo risolutore si comporta esattamente come la sua classe di base.

Per usare il sistema risolutore, è sufficiente aggiungere uno dei componenti elencati sopra a un GameObject. Poiché tutti i risolutori richiedono , SolverHandleruno verrà creato automaticamente da Unity.

Nota

Esempi di come usare il sistema risolutori sono disponibili nel file SolverExamples.scene .

Informazioni di riferimento sul rilevamento delle modifiche

La proprietà Tracked Target Type del SolverHandler componente definisce il punto di riferimento che tutti i risolutori useranno per calcolare gli algoritmi. Ad esempio, un tipo di valore di Head con un componente semplice SurfaceMagnetism genererà un raycast dalla testa e nella direzione dello sguardo dell'utente per risolvere la superficie colpita. I valori potenziali per la TrackedTargetType proprietà sono:

  • Head : Punto di riferimento è la trasformazione della fotocamera principale
  • ControllerRay: punto di riferimento è la LinePointer trasformazione su un controller (ad esempio l'origine del puntatore su un controller di movimento o un controller di mano) che punta nella direzione del raggio linea
    • Utilizzare la TrackedHandedness proprietà per selezionare la preferenza di mano (ad esempio Sinistra, Destra, Entrambi)
  • HandJoint: punto di riferimento è la trasformazione di una mano specifica
    • Utilizzare la TrackedHandedness proprietà per selezionare la preferenza di mano (ad esempio Sinistra, Destra, Entrambi)
    • Usare la TrackedHandJoint proprietà per determinare la trasformazione congiunta da utilizzare
  • CustomOverride: punto di riferimento dall'oggetto assegnato TransformOverride

Nota

Per entrambi i tipi ControllerRay e HandJoint , il gestore del risolutore tenterà di fornire prima il controller/trasformazione a sinistra e quindi a destra se l'ex non è disponibile o a meno che la TrackedHandedness proprietà non specifica altrimenti.

Esempio di oggetto monitorato del risolutoredi varie proprietà associate a ogni TrackedTargetType

Importante

La maggior parte dei risolutori usa il vettore di inoltro della destinazione trasformazione tracciata fornita da SolverHandler. Quando si usa un tipo di destinazione a mano tracciata, il vettore avanti dell'articolazione del palmo può puntare attraverso le dita e non attraverso il palmo. Ciò dipende dalla piattaforma che fornisce i dati comuni della mano. Per la simulazione di input e Windows Mixed Reality, è il vettore up che punta attraverso il palmo (ad esempio il vettore verde è su, il vettore blu è avanti).

Vettore Forward Up

Per superare questo problema, aggiornare la proprietà Rotazione aggiuntiva su SolverHandler<90, 0, 0>. In questo modo il vettore di inoltro fornito ai risolutori punta attraverso il palmo e verso l'esterno dalla mano.

Rotazione aggiuntiva

In alternativa, usare il tipo di destinazione del raggio controller per ottenere un comportamento simile per puntare con le mani.

Come concatenare i risolutori

È possibile aggiungere più Solver componenti allo stesso GameObject, concatenando così gli algoritmi. I SolverHandler componenti gestiscono l'aggiornamento di tutti i risolutori nello stesso GameObject. Per impostazione predefinita, le chiamate GetComponents<Solver>() su Start restituiranno i SolverHandler risolutori nell'ordine in cui vengono visualizzati nel controllo.

Inoltre, impostando la proprietà Update Linked Transform su true, verrà indicato che Solver per salvare la posizione calcolata, l'orientamento, & la scala su una variabile intermediaria accessibile da tutti i risolutori (ad esempio GoalPosition). Quando false, l'oggetto Solver aggiornerà direttamente la trasformazione di GameObject. Salvando le proprietà di trasformazione in una posizione intermedia, altri risolutori sono in grado di eseguire i calcoli a partire dalla variabile intermediaria. Questo è dovuto al fatto che Unity non consente aggiornamenti a gameObject.transform di eseguire lo stack all'interno dello stesso frame.

Nota

Gli sviluppatori possono modificare l'ordine di esecuzione dei risolutori impostando direttamente la SolverHandler.Solvers proprietà.

Come creare un nuovo risolutore

Tutti i risolutori devono ereditare dalla classe base astratta, Solver. I requisiti principali di un'estensione risolutore comportano l'override del SolverUpdate metodo. In questo metodo gli sviluppatori devono aggiornare le proprietà ereditate e GoalScale ai valori desiderati.GoalPositionGoalRotation Inoltre, è generalmente utile sfruttare SolverHandler.TransformTarget come cornice di riferimento desiderata dal consumer.

Il codice fornito di seguito fornisce un esempio di un nuovo componente risolutore denominato InFront che inserisce l'oggetto collegato 2m davanti a SolverHandler.TransformTarget. Se l'oggetto SolverHandler.TrackedTargetType è impostato dal consumer come Head, l'oggetto SolverHandler.TransformTarget sarà la trasformazione della fotocamera e quindi questo risolutore posiziona il GameObject 2m collegato davanti allo sguardo degli utenti ogni cornice.

/// <summary>
/// InFront solver positions an object 2m in front of the tracked transform target
/// </summary>
public class InFront : Solver
{
    ...

    public override void SolverUpdate()
    {
        if (SolverHandler != null && SolverHandler.TransformTarget != null)
        {
            var target = SolverHandler.TransformTarget;
            GoalPosition = target.position + target.forward * 2.0f;
        }
    }
}

Guide all'implementazione del risolutore

Proprietà comuni del risolutore

Ogni componente risolutore ha un set di core di proprietà identiche che controllano il comportamento principale del risolutore.

Se Smoothing è abilitato, il risolutore aggiornerà gradualmente la trasformazione del GameObject nel tempo ai valori calcolati. La velocità di questa modifica è determinata dalla proprietà LerpTime di ogni componente di trasformazione. Ad esempio, un valore MoveLerpTime più elevato comporterà incrementi più lenti in movimento tra fotogrammi.

Se MaintainScale è abilitato, il risolutore utilizzerà la scala locale predefinita di GameObject.

Proprietà del risolutore di base
Proprietà comuni ereditate da tutti i componenti del risolutore

Orbitale

La Orbital classe è un componente tag-lungo che si comporta come pianeti in un sistema solare. Questo risolutore garantirà l'orbita del GameObject collegato intorno alla trasformazione tracciata. Pertanto, se il tipo di destinazione monitorato dell'oggetto SolverHandler è impostato su Head, il GameObject orbita intorno alla testa dell'utente con un offset fisso applicato.

Gli sviluppatori possono modificare questo offset fisso per mantenere i menu o altri componenti della scena a livello di occhio o a livello di vita e così via. Questa operazione viene eseguita modificando le proprietà Offset locale e Offset mondiale . La proprietà Orientation Type determina la rotazione applicata all'oggetto se deve mantenere la rotazione originale o visi sempre la fotocamera o la faccia qualsiasi trasformazione stia guidando la sua posizione ecc.

Esempio orbitale
Esempio orbitale

RadialView

È RadialView un altro componente tag-along che mantiene una particolare parte di un GameObject all'interno del frustum della visualizzazione dell'utente.

Le proprietà Min & Max View Degrees determinano la quantità di una parte di GameObject da visualizzare sempre.

Le proprietà Min & Max Distance determinano la distanza da cui l'oggetto GameObject deve essere mantenuto dall'utente. Ad esempio, camminare verso GameObject con una distanza minima di 1m spingerà il GameObject via per assicurarsi che non sia mai più vicino a 1m all'utente.

In genere, viene RadialView usato insieme al tipo di destinazione tracciato impostato su Head in modo che il componente segua lo sguardo fisso dell'utente. Tuttavia, questo componente può funzionare per essere mantenuto in "visualizzazione" di qualsiasi tipo di destinazione rilevata.

Esempio di RadialView
Esempio radialView

Segui

La Follow classe posiziona un elemento davanti all'oggetto della destinazione tracciata rispetto all'asse in avanti locale. L'elemento può essere vincolato in modo libero (ad esempio tag-along) in modo che non segua fino a quando la destinazione rilevata non si sposta oltre i limiti definiti dall'utente.

Funziona in modo analogo al risolutore RadialView, con controlli aggiuntivi per gestire Max Horizontal & Vertical View Degrees e i meccanismi per modificare l'orientamento dell'oggetto.

Seguire le proprietà
Seguire le proprietà

Seguire la scena di esempio
Seguire la scena di esempio (Assets/MRTK/Examples/Demos/Solvers/Scenes/FollowSolverExample.unity)

Inbetween

La InBetween classe manterrà il GameObject associato tra due trasformazioni. Questi due endpoint di trasformazione sono definiti dal tipo SolverHandlerdi destinazione tracciato del GameObject e dalla InBetween proprietà Second Tracked Target Type del componente. In genere, entrambi i tipi verranno impostati su CustomOverride e i valori risultanti SolverHandler.TransformOverride e InBetween.SecondTransformOverride impostati sui due endpoint rilevati.

In fase di esecuzione, il InBetween componente creerà un altro SolverHandler componente in base alle proprietà Second Tracked Target Type e Second Transform Override .

Definisce PartwayOffset dove lungo la linea tra due trasformazioni l'oggetto deve essere posizionato con 0,5 a metà strada, 1,0 alla prima trasformazione e 0,0 alla seconda trasformazione.

Esempio di InBetween
Esempio di utilizzo del risolutore InBetween per mantenere l'oggetto tra due trasformazioni

SurfaceMagnetism

L'oggetto SurfaceMagnetism funziona eseguendo un raycast su un set LayerMask di superfici e posizionando il GameObject in quel punto di contatto.

L'offset normale della superficie posiziona il GameObject a una distanza impostata in metri dalla superficie nella direzione della normale in corrispondenza del punto di attacco sulla superficie.

Viceversa, l'offset del raggio di superficie posiziona il GameObject a una distanza impostata in metri dalla superficie, ma nella direzione opposta del raycast eseguito. Pertanto, se il raycast è lo sguardo dell'utente, il GameObject si sposta più vicino lungo la linea dal punto di hit sulla superficie alla fotocamera.

La modalità di orientamento determina il tipo di rotazione da applicare in relazione alla normale sulla superficie.

  • Nessuno - Nessuna rotazione applicata
  • TrackedTarget : l'oggetto affronterà la trasformazione tracciata che guida il raycast
  • SurfaceNormal : l'oggetto verrà allineato in base alla normale in corrispondenza del punto di attacco sulla superficie
  • Blended : l'oggetto verrà allineato in base al normale in corrispondenza del punto di attacco sulla superficie E in base alla trasformazione rilevata.

Per forzare il GameObject associato a rimanere verticale in qualsiasi modalità diversa da Nessuno, abilitare Mantieniorientamento verticale.

Nota

Utilizzare la proprietà Orientation Blend per controllare il bilanciamento tra i fattori di rotazione quando la modalità di orientamento è impostata su Blended. Il valore 0,0 avrà un orientamento interamente guidato dalla modalità TrackedTarget e il valore 1,0 avrà un orientamento interamente basato su SurfaceNormal.

Esempio di SurfaceMagnetism

Determinazione delle superfici che possono essere colpite

Quando si aggiunge un componente a un SurfaceMagnetism GameObject, è importante considerare il livello del GameObject e dei relativi elementi figlio, se presenti collisori. Il componente funziona eseguendo vari tipi di raycast per determinare quale superficie "magnete" contro. Se il gameobject del risolutore ha un collisore su uno dei livelli elencati nella MagneticSurfaces proprietà di SurfaceMagnetism, il raycast probabilmente si raggiungerà con conseguente collegamento del GameObject al proprio punto di collisore. Questo comportamento dispari può essere evitato impostando il GameObject principale e tutti gli elementi figlio sul livello Ignore Raycast o modificando la MagneticSurfaces matrice LayerMask in modo appropriato.

Al contrario, un SurfaceMagnetism GameObject non sarà in conflitto con superfici su un livello non elencato nella MagneticSurfaces proprietà . È in genere consigliabile posizionare tutte le superfici desiderate su un livello dedicato (ad esempio Superfici) e impostare la MagneticSurfaces proprietà su solo questo livello. L'uso dell'impostazione predefinita o di tutti gli elementi può comportare componenti o cursori dell'interfaccia utente che contribuiscono al risolutore.

Infine, le superfici più lontane dell'impostazione della MaxRaycastDistance proprietà verranno ignorate dai SurfaceMagnetism raycast.

DirectionalIndicator

La DirectionalIndicator classe è un componente tag-along che si orienta verso la direzione di un punto desiderato nello spazio.

Usato più comunemente quando il tipo di destinazione monitorato di SolverHandler è impostato su Head. In questo modo, un componente dell'esperienza utente con il DirectionalIndicator risolutore indirizza un utente a esaminare il punto desiderato nello spazio.

Il punto desiderato nello spazio viene determinato tramite la proprietà Target direzionale .

Se la destinazione direzionale è visualizzabile dall'utente o da qualsiasi frame di riferimento impostato in SolverHandler, questo risolutore disabiliterà tutti i Renderer componenti sottostanti. Se non è visualizzabile, tutto verrà abilitato sull'indicatore.

La dimensione dell'indicatore ridurrà il valore più vicino all'utente consiste nell'acquisire la destinazione direzionale nella foV.

  • Scala indicatore min - Scala minima per l'oggetto indicatore

  • Scala indicatore massima - Scala massima per l'oggetto indicatore

  • Fattore di scala di visibilità - Moltiplicatore per aumentare o diminuire la FOV che determina se il punto di destinazione direzionale è visualizzabile o meno

  • Offset di visualizzazione: dal punto di vista del fotogramma di riferimento (ad esempio, la fotocamera possibilmente), questa proprietà definisce quanto lontano nella direzione dell'indicatore deve essere dall'oggetto al centro del riquadro di visualizzazione.

Proprietà indicatore direzionale
Proprietà indicatore direzionale

Scena di esempio indicatore direzionale
Scena di esempio di indicatore direzionale (Assets/MRTK/Examples/Demos/Solvers/Scenes/DirectionalIndicatorSolverExample.unity)

Menu a mano con HandConstraint e HandConstraintPalmUp

Esempio di esperienza utente del menu a mano

Il HandConstraint comportamento fornisce un risolutore che vincola l'oggetto monitorato a un'area sicura per il contenuto limitato a mano ,ad esempio interfaccia utente a mano, menu e così via. Le aree sicure sono considerate aree che non si intersecano con la mano. Viene inclusa anche una classe derivata di HandConstraint chiamata HandConstraintPalmUp per illustrare un comportamento comune dell'attivazione dell'oggetto rilevato del risolutore quando il palmo è rivolto all'utente.

Per gli esempi relativi all'uso del risolutore vincolo manuale per creare menu a mano, vedere la pagina Menu a mano.

Vedi anche