Risolutori - MRTK3
I risolutori sono componenti che facilitano il calcolo della posizione e dell'orientamento di un oggetto in base a un algoritmo predefinito. Esempio: posizionamento di un oggetto sulla superficie con cui interseca il raycast dello sguardo fisso dell'utente.
Il sistema risolutore definisce in modo deterministico un ordine di operazioni per questi calcoli di trasformazione perché non è possibile specificare in Unity l'ordine di aggiornamento per i componenti.
I risolutori offrono una gamma di comportamenti per collegare oggetti ad altri oggetti o sistemi. Un altro esempio è un oggetto tag-along che passa il puntatore 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 di tag-along più magnetismo superficiale più slancio.
Uso
Il sistema risolutore è costituito da tre categorie di script:
Solver
: classe di base astratta da cui derivano tutti i risolutori. Fornisce il rilevamento dello stato, i parametri di smoothing e l'implementazione, l'integrazione automatica del sistema del risolutore e l'ordine di aggiornamento.SolverHandler
: imposta il rilevamento degli oggetti di riferimento su (ad esempio: trasformazione della fotocamera principale, 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 specificata ed offset 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 cono di visualizzazione eseguito dal cast dell'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 sulle 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 dell'oggetto SolverHandler Tracked Target, questo indicatore si orienta verso l'oggetto DirectionalTarget fornito.Momentum
: applica accelerazione/velocità/attrito per simulare lo slancio e la molla per un oggetto spostato da altri risolutori/componenti.HandConstraint
: vincoli oggetto da seguire in un'area che non interseca GameObject con le mani. Utile per contenuti interattivi vincolati a mano, ad esempio menu e così via. Questo risolutore è progettato per funzionare conXRNode
.HandConstraintPalmUp
: deriva da HandConstraint, ma include la logica per verificare se il palmo è rivolto all'utente prima dell'attivazione. Questo risolutore funziona solo conXRNode
i controller e si comporta come la classe base con altri tipi di controller.Overlap
: sovrappone l'oggetto rilevato.
Per usare il sistema solver, aggiungere uno dei componenti elencati in precedenza a un GameObject. Poiché tutti i risolutori richiedono un SolverHandler
, ne verrà creato automaticamente uno da Unity.
Nota
Esempi di come usare il sistema risolutore sono disponibili nel file SolverExamples.scene .
Come fare riferimento al rilevamento delle modifiche
La proprietà Tracked Target Type del SolverHandler
componente definisce il punto di riferimento che tutti i risolutori useranno per calcolare i relativi algoritmi. Ad esempio, un tipo di valore di Head
con un componente semplice SurfaceMagnetism
genererà un cast di raggi dalla testa e nella direzione dello sguardo dell'utente per risolvere la superficie che viene raggiunta. I valori potenziali per la TrackedTargetType
proprietà sono:
- *Head: Il punto di riferimento è la trasformazione della fotocamera principale
- ControllerRay: il punto di riferimento è la
LinePointer
trasformazione su un controller (ovvero, l'origine del puntatore su un controller di movimento o un controller della mano) che punta nella direzione del raggio della linea- Usare la
TrackedHandedness
proprietà per selezionare la preferenza per la mano (ovvero Sinistra, Destra, Entrambe)
- Usare la
- HandJoint: il punto di riferimento è la trasformazione di un'articolazione della mano specifica
- Usare la
TrackedHandedness
proprietà per selezionare la preferenza per la mano (ovvero Sinistra, Destra, Entrambe) - Utilizzare la
TrackedHandJoint
proprietà per determinare la trasformazione congiunta da utilizzare
- Usare la
- CustomOverride: punto di riferimento dall'oggetto assegnato
TransformOverride
Nota
Per entrambi i tipi ControllerRay e HandJoint , il gestore del risolutore tenterà prima di tutto di fornire la trasformazione del controller/mano sinistra e quindi la destra se il primo non è disponibile o a meno che la TrackedHandedness
proprietà non specifichi diversamente.
Importante
La maggior parte dei risolutori usa il vettore forward della destinazione della trasformazione rilevata fornita da SolverHandler
. Quando si utilizza un tipo di bersaglio tracciato hand joint , il vettore in 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 su punta attraverso il palmo (in altre parole, vettore verde è su, vettore blu è avanti).
Per ovviare a questo problema, aggiornare la proprietà Additional Rotation su su SolverHandler
<90, 0, 0>. Ciò garantisce che il vettore in avanti fornito ai risolutori punti attraverso il palmo e verso l'esterno dalla mano.
In alternativa, usare il tipo di destinazione rilevato Controller Ray per ottenere un comportamento simile per puntare con le mani.
Come concatenare i risolutori
È possibile aggiungere più Solver
componenti allo stesso GameObject, concatenando così i propri algoritmi. I SolverHandler
componenti gestiscono l'aggiornamento di tutti i risolutori nello stesso GameObject. Per impostazione predefinita, le SolverHandler
chiamate GetComponents<Solver>()
in Start restituiranno i risolutori nell'ordine in cui vengono visualizzati nel controllo.
Inoltre, l'impostazione della proprietà Updated Linked Transform su true indicherà che Solver
per salvare la posizione calcolata, l'orientamento e la scalabilità in una variabile intermedia accessibile da tutti i risolutori , GoalPosition
ovvero . Se false, aggiornerà Solver
direttamente la trasformazione di GameObject. Salvando le proprietà di trasformazione in una posizione intermedia, altri risolutori possono eseguire i calcoli a partire dalla variabile intermedia. Questo perché 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 del Risolutore comportano l'override del SolverUpdate
metodo . In questo metodo gli sviluppatori devono aggiornare le proprietà ereditate GoalPosition
, GoalRotation
e GoalScale
ai valori desiderati. Inoltre, è utile sfruttare SolverHandler.TransformTarget
come frame di riferimento desiderato dal consumatore.
Il codice riportato di seguito fornisce un esempio di un nuovo componente risolutore denominato InFront
che posiziona l'oggetto associato 2 m davanti a SolverHandler.TransformTarget
. Il consumer imposta SolverHandler.TrackedTargetType
come Head
, quindi SolverHandler.TransformTarget
sarà la trasformazione della fotocamera, e quindi questo Risolutore posiziona il GameObject collegato 2 m davanti allo sguardo degli utenti ogni fotogramma.
/// <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 base di proprietà identiche che controllano il comportamento del risolutore principale.
Se Smoothing è abilitato, il risolutore aggiornerà gradualmente la trasformazione del GameObject nel tempo ai valori calcolati. La proprietà LerpTime di ogni componente di trasformazione determina la velocità di questa modifica. Ad esempio, un valore MoveLerpTime superiore comporterà incrementi più lenti nello spostamento tra i fotogrammi.
Se MaintainScale è abilitato, il Risolutore utilizzerà la scala locale predefinita del GameObject.
Orbitale
La Orbital
classe è un componente tag-along che si comporta come pianeti in un sistema solare. Questo Risolutore garantirà che il GameObject collegato orbita intorno alla trasformazione rilevata. Pertanto, se il tipo di destinazione rilevata di 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 vita, ecc., intorno a un utente. Questa operazione viene eseguita modificando le proprietà Offset locale e Offset globale . La proprietà Orientation Type determina la rotazione applicata all'oggetto se deve mantenere la rotazione originale o affrontare sempre la fotocamera o il viso qualsiasi trasformazione stia guidando la posizione.
RadialView
RadialView
è un altro componente tag-along che mantiene una parte specifica di un GameObject all'interno del frustum della visualizzazione dell'utente.
Le proprietà Min & Max View Degrees determinano la quantità di una parte del GameObject che deve essere sempre visualizzata.
Le proprietà Min & Max Distance determinano la distanza da cui deve essere mantenuto l'oggetto GameObject dall'utente. Ad esempio, camminare verso il GameObject con una distanza minima di 1 m spingerà il GameObject via per assicurarsi che non sia mai più vicino a 1 m all'utente.
In genere, viene RadialView
usato con il tipo di destinazione monitorato impostato su Head
in modo che il componente segua lo sguardo dell'utente. Tuttavia, questo componente può funzionare per essere mantenuto in "visualizzazione" di qualsiasi tipo di destinazione rilevata.
Segui
La Follow
classe posiziona un elemento davanti alla destinazione rilevata rispetto all'asse avanti locale. L'elemento può essere vincolato in modo libero (noto anche come "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 Gradi e meccanismi per modificare l'orientamento dell'oggetto.
Inbetween
La classe mantiene l'oggetto InBetween
GameObject collegato tra due trasformazioni. Il tipo di destinazione monitorato di GameObject e SolverHandler
la InBetween
proprietà Second Tracked Target Type del componente definiscono questi due endpoint di trasformazione. In genere, entrambi i tipi verranno impostati su CustomOverride
e i valori risultanti SolverHandler.TransformOverride
e InBetween.SecondTransformOverride
vengono impostati sui due endpoint rilevati.
Il InBetween
componente creerà un altro SolverHandler
componente in fase di esecuzione in base alle proprietà Second Tracked Target Type e Second Transform Override .
Lungo la linea tra due trasformazioni, l'oggetto PartwayOffset
definisce dove l'oggetto verrà posizionato con 0,5 come metà, 1,0 alla prima trasformazione e 0,0 alla seconda trasformazione.
SurfaceMagnetism
Le SurfaceMagnetism
opere eseguendo un raycast su un set di superfici LayerMask e posizionando GameObject in quel punto di contatto.
Surface Normal Offset posiziona il GameObject una distanza impostata in metri di distanza dalla superficie nella direzione della normale in corrispondenza del punto di attacco sulla superficie.
Al contrario, l'offset Surface Ray posiziona il GameObject una distanza impostata in metri dalla superficie, ma nella direzione opposta del raycast eseguito. Pertanto, se il raycast è lo sguardo dell'utente, GameObject si sposta più vicino lungo la linea dal punto di colpo sulla superficie alla fotocamera.
La modalità 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 alla normalità in corrispondenza del punto di attacco sulla superficie E in base alla trasformazione tracciata.
Per forzare l'oggetto GameObject associato a rimanere verticale in qualsiasi modalità diversa da Nessuno, abilitare Mantieni orientamento verticale.
Nota
Utilizzare la proprietà Orientation Blend per controllare l'equilibrio tra i fattori di rotazione quando la modalità orientamento è impostata su Blended. Un valore pari a 0,0 avrà un orientamento interamente guidato dalla modalità TrackedTarget e un valore pari a 1,0 avrà un orientamento guidato interamente da SurfaceNormal.
Overlap
È Overlap
un semplice risolutore che mantiene la trasformazione dell'oggetto nella stessa posizione e rotazione della SolverHandler's
destinazione di trasformazione.
Determinazione delle superfici che possono essere colpite
Quando si aggiunge un SurfaceMagnetism
componente a un GameObject, è importante considerare il livello di GameObject e i relativi figli, se presenti collider. Il componente funziona eseguendo vari raycast per determinare la superficie da "magnete" su se stessa. Si supponga che il risolutore GameObject abbia un collider su uno dei livelli elencati nella MagneticSurfaces
proprietà di SurfaceMagnetism
. In questo caso, il raycast avrà probabilmente colpito se stesso, causando l'associazione di GameObject al proprio punto di collisore. Questo comportamento strano può essere evitato impostando il gameObject principale e tutti gli elementi figlio sul livello di cast Ignore Ray o modificando in modo appropriato la MagneticSurfaces
matrice LayerMask.
Al contrario, un SurfaceMagnetism
GameObject non si confronterà con le superfici su un livello non elencato nella MagneticSurfaces
proprietà. È consigliabile posizionare tutte le superfici desiderate su un livello dedicato , ovvero Surface, e impostare la MagneticSurfaces
proprietà su solo questo livello. Usando il valore predefinito o tutto ciò che 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-lungo che si orienta verso la direzione del punto desiderato nello spazio. Viene usato più comunemente quando il tipo di destinazione monitorato dell'oggetto SolverHandler
è impostato su Head
. In questo modo, un componente UX con il DirectionalIndicator
risolutore indirizza un utente a esaminare il punto desiderato nello spazio. Questo punto è determinato dalla proprietà Target direzionale .
Se la destinazione direzionale è visualizzabile dall'utente o dal frame di riferimento impostato in SolverHandler
, questo risolutore disabilita tutti i Renderer
componenti sotto di esso. Se non è visualizzabile, tutto verrà abilitato sull'indicatore.
Le dimensioni dell'indicatore compattano più vicino l'utente consiste nell'acquisire la destinazione direzionale nel foV.
Scala indicatore min - Scala minima per l'oggetto indicatore
Scala indicatore max - Scala massima per l'oggetto indicatore
Fattore di scalabilità di visibilità - Moltiplicatore per aumentare o ridurre il FOV che determina se il punto di destinazione direzionale è visualizzabile o meno
Offset di visualizzazione: dal punto di vista del fotogramma di riferimento (ovvero la fotocamera eventualmente) e nella direzione dell'indicatore, questa proprietà definisce la distanza dell'oggetto dal centro del viewport.
Scena di esempio di indicatore direzionale (Asset/MRTK/Examples/Demos/Solvers/Scenes/DirectionalIndicatorSolverExample.unity)
Menu a mano con HandConstraint e HandConstraintPalmUp
Il HandConstraint
comportamento fornisce un risolutore che limita l'oggetto monitorato a un'area sicura per il contenuto vincolato a mano (ad esempio interfaccia utente, menu e così via) Le aree sicure sono considerate aree che non si intersecano con la mano. Una classe derivata di HandConstraint
chiamata HandConstraintPalmUp
è inclusa anche per illustrare un comportamento comune dell'attivazione dell'oggetto risolutore quando il palmo è rivolto all'utente.
Per esempi di uso del risolutore vincolo mano per creare menu a mano, vedere la documentazione di Menu a mano.