Översikt över lösaren – MRTK2

Solver Main

Lösare är komponenter som gör det lättare att beräkna ett objekts position & orientering enligt en fördefinierad algoritm. Ett exempel kan vara att placera ett objekt på ytan som användarens blickstråle träffar för närvarande.

Dessutom definierar solversystemet deterministiskt en åtgärdsordning för dessa transformeringsberäkningar eftersom det inte finns något tillförlitligt sätt att ange uppdateringsordningen för komponenter för Unity.

Lösare erbjuder en rad beteenden för att koppla objekt till andra objekt eller system. Ett annat exempel är ett taggningsobjekt som hovrar framför användaren (baserat på kameran). En lösningslösare kan också kopplas till en kontrollant och ett objekt för att göra objektet tagga längs kontrollanten. Alla lösare kan staplas säkert, till exempel ett taggningsbeteende + ytmagnetism + momentum.

Så här använder du en lösare

Lösningssystemet består av tre kategorier av skript:

  • Solver: Den grundläggande abstrakta klassen som alla lösare härleds från. Den tillhandahåller tillståndsspårning, utjämning av parametrar och implementering, automatisk lösningssystemintegrering och uppdateringsordning.
  • SolverHandler: Anger referensobjektet som ska spåras mot (till exempel huvudkameratransformering, handstråle osv.), hanterar insamling av lösarkomponenter och kör uppdatering av dem i rätt ordning.

Den tredje kategorin är själva lösaren. Följande lösare tillhandahåller byggstenarna för grundläggande beteende:

  • Orbital: Låser till en angiven position och förskjuts från det refererade objektet.
  • ConstantViewSize: Skalar för att bibehålla en konstant storlek i förhållande till vyn för det refererade objektet.
  • RadialView: Håller objektet inom en vykonkon som är gjuten av det refererade objektet.
  • Follow: Håller objektet inom en uppsättning användardefinierade gränser för det refererade objektet.
  • InBetween: Håller ett objekt mellan två spårade objekt.
  • SurfaceMagnetism: kastar strålarna till ytor i världen och justerar objektet mot den ytan.
  • DirectionalIndicator: Bestämmer positionen och orienteringen för ett objekt som en riktningsindikator. Från referenspunkten för SolverHandler Tracked Target kommer den här indikatorn att orientera sig mot angiven DirectionalTarget.
  • Momentum: Använder acceleration/hastighet/friktion för att simulera momentum och springiness för ett objekt som flyttas av andra lösare/komponenter.
  • HandConstraint: Begränsar objektet så att det följer händer i en region som inte korsar GameObject med händerna. Användbart för handbegränsat interaktivt innehåll, till exempel menyer osv. Den här lösaren är avsedd att fungera med IMixedRealityHand men fungerar även med IMixedRealityController.
  • HandConstraintPalmUp: Härleds från HandConstraint men innehåller logik för att testa om handflatan är vänd mot användaren före aktiveringen. Den här lösaren fungerar bara med IMixedRealityHand-styrenheter , med andra kontrollanttyper som den här lösaren fungerar precis som basklassen.

Om du vill använda solversystemet lägger du helt enkelt till en av komponenterna som anges ovan i ett GameObject. Eftersom alla lösare kräver en SolverHandlerskapas en automatiskt av Unity.

Anteckning

Exempel på hur du använder solversystemet finns i filen SolverExamples.scene .

Så här ändrar du spårningsreferens

Egenskapen Spårad måltyp för komponenten SolverHandler definierar referenspunkten som alla lösare använder för att beräkna sina algoritmer. Till exempel resulterar en värdetyp av Head med en enkel SurfaceMagnetism komponent i en raycast från huvudet och i riktning mot användarens blick för att lösa vilken yta som träffar. Potentiella värden för TrackedTargetType egenskapen är:

  • Huvud : Referenspunkt är omvandlingen av huvudkameran
  • ControllerRay: Referenspunkten är transformen LinePointer på en styrenhet (dvs. pekarens ursprung på en rörelsekontrollant eller handstyrenhet) som pekar i linjestrålens riktning
    • Använd egenskapen TrackedHandedness för att välja handedness-inställningen (t.ex. vänster, höger, båda)
  • HandJoint: Referenspunkt är omvandlingen av en specifik handfog
    • Använd egenskapen TrackedHandedness för att välja handedness-inställningen (t.ex. vänster, höger, båda)
    • Använd egenskapen TrackedHandJoint för att fastställa den gemensamma transformering som ska användas
  • CustomOverride: Referenspunkt från den tilldelade TransformOverride

Anteckning

För både ControllerRay - och HandJoint-typerna försöker lösaren först tillhandahålla den vänstra kontrollanten/handtransformen och sedan höger om den förstnämnda inte är tillgänglig eller om egenskapen inte TrackedHandedness anger något annat.

Exempel på spårat objekt för lösareav olika egenskaper som är associerade med varje TrackedTargetType

Viktigt

De flesta lösare använder framåtvektorn för det spårade transformeringsmålet som tillhandahålls av SolverHandler. Vid användning av en handled spårad måltyp, kan den främre vektorn i palmleden peka genom fingrarna och inte genom handflatan. Detta beror på vilken plattform som tillhandahåller gemensamma handdata. För indatasimulering och Windows Mixed Reality är det uppvektorn som pekar upp genom handflatan (dvs. den gröna vektorn är uppe, den blå vektorn är framåt).

Framåtriktad vektor

Du kan lösa detta genom att uppdatera egenskapen Ytterligare rotationSolverHandler till <90, 0, 0>. Detta säkerställer att den framåtriktade vektorn som levereras till lösare pekar genom handflatan och utåt bort från handen.

Ytterligare rotation

Du kan också använda den Controller Ray-spårade måltypen för att få liknande beteende för att peka med händerna.

Så här kedjar du lösare

Det är möjligt att lägga till flera Solver komponenter i samma GameObject och därmed länka sina algoritmer. Komponenterna SolverHandler hanterar uppdatering av alla lösare på samma GameObject. Som standard anropen SolverHandlerGetComponents<Solver>() på Start som returnerar Lösare i den ordning som de visas i inspektören.

Om du anger egenskapen Uppdaterad länkad transformering till true instrueras dessutom att Solver spara dess beräknade position, orientering & skala till en mellanliggande variabel som är tillgänglig för alla lösare (dvs GoalPosition. ). När det är falskt Solver uppdaterar gameobject-transformen direkt. Genom att spara transformeringsegenskaperna på en mellanliggande plats kan andra lösare utföra sina beräkningar från och med variabeln mellanhand. Det beror på att Unity inte tillåter att uppdateringar av gameObject.transform staplas inom samma ram.

Anteckning

Utvecklare kan ändra körningsordningen för lösare genom att ange SolverHandler.Solvers egenskapen direkt.

Så här skapar du en ny lösare

Alla lösare måste ärva från den abstrakta basklassen, Solver. De primära kraven för ett Solver-tillägg innebär att SolverUpdate åsidosätta metoden. I den här metoden bör utvecklare uppdatera de ärvda GoalPositionegenskaperna och GoalRotationGoalScale till önskade värden. Dessutom är det i allmänhet värdefullt att utnyttja SolverHandler.TransformTarget som referensram som konsumenten önskar.

Koden nedan ger ett exempel på en ny Solver-komponent med namnet InFront som placerar det bifogade objektet 2 m framför SolverHandler.TransformTarget. SolverHandler.TrackedTargetType Om anges av konsumenten som Head, då SolverHandler.TransformTarget kommer att vara kameran transform och därmed denna Solver kommer att placera den bifogade GameObject 2m framför användarnas blick varje bildruta.

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

Implementeringsguider för lösare

Vanliga lösningsegenskaper

Varje solverkomponent har en kärnuppsättning med identiska egenskaper som styr solvensens kärnbeteende.

Om utjämning är aktiverat uppdaterar lösaren gradvis transformeringen av GameObject med tiden till de beräknade värdena. Hastigheten för den här ändringen bestäms av varje transformeringskomponents LerpTime-egenskap . Ett högre MoveLerpTime-värde resulterar till exempel i långsammare steg i rörelse mellan bildrutor.

Om MaintainScale är aktiverat använder lösaren GameObjects lokala standardskala.

Egenskaper för kärnlösare
Vanliga egenskaper som ärvts av alla Solver-komponenter

Orbital

Klassen Orbital är en taggkomponent som beter sig som planeter i ett solsystem. Den här lösaren säkerställer de tillhörande GameObject-omloppsbanorna runt den spårade transformen. Om den spårade måltypenSolverHandler för är inställd på Head, kommer GameObject därför att kretsa runt användarens huvud med en fast förskjutning tillämpad.

Utvecklare kan ändra denna fasta offset för att hålla menyer eller andra scenkomponenter på ögonnivå eller i midjenivå etc. runt en användare. Detta görs genom att ändra egenskaperna Lokal förskjutning och Världsförskjutning . Egenskapen Orienteringstyp avgör vilken rotation som tillämpas på objektet om det ska behålla sin ursprungliga rotation eller alltid vända sig mot kameran eller ansiktet oavsett vilken transformering som driver dess position etc.

Omloppsexempel
Omloppsexempel

Radiell vy

RadialView är en annan taggningskomponent som håller en viss del av ett GameObject inom frustum för användarens vy.

Egenskaperna Min & Max View Degrees avgör hur stor del av GameObject som alltid måste visas.

Egenskaperna Min & Max Distance avgör hur långt GameObject ska hållas från användaren. Om du till exempel går mot GameObject med ett minsta avstånd på 1 m kommer GameObject att skjutas bort för att säkerställa att det aldrig är närmare än 1 miljon till användaren.

RadialView Vanligtvis används tillsammans med Spårad måltyp inställd på Head så att komponenten följer användarens blick. Den här komponenten kan dock fungera för att hållas i "vy" av valfri spårad måltyp.

RadialView-exempel
RadialView-exempel

Följ

Klassen Follow placerar ett element framför det spårade målet i förhållande till den lokala framåtaxeln. Elementet kan vara löst begränsat (t.ex. tagg-along) så att det inte följer förrän det spårade målet flyttas bortom användardefinierade gränser.

Det fungerar på samma sätt som RadialView-lösaren, med ytterligare kontroller för att hantera maximalt vågrätt & lodräta visningsgrader och mekanismer för att ändra objektets orientering .

Följ egenskaper
Följ egenskaper

Följ exempelscen
Följ exempelscen (Assets/MRTK/Examples/Demos/Solvers/Scenes/FollowSolverExample.unity)

Emellan

Klassen InBetween behåller det anslutna GameObject mellan två transformeringar. Dessa två transformeringsslutpunkter definieras av GameObjects egen SolverHandlerspårade måltyp och komponentens InBetween second tracked target type-egenskap . I allmänhet anges båda typerna till CustomOverride och de resulterande SolverHandler.TransformOverride värdena och InBetween.SecondTransformOverride värdena anges till de två spårade slutpunkterna.

Vid körning skapar komponenten InBetween en annan SolverHandler komponent baserat på egenskaperna Second Tracked Target Type och Second Transform Override .

Definierar PartwayOffset var längs linjen mellan två transformeringar objektet ska placeras med 0,5 som halvvägs, 1,0 vid den första transformen och 0,0 vid den andra transformen.

InBetween-exempel
Exempel på hur du använder InBetween-lösaren för att hålla objektet mellan två transformeringar

SurfaceMagnetism

Verken SurfaceMagnetism genom att utföra en raycast mot en uppsättning LayerMask av ytor och placera GameObject vid den kontaktpunkten.

Surface Normal Offset placerar GameObject ett angivet avstånd i meter från ytan i riktning mot det normala vid träffpunkten på ytan.

Omvänt kommer Surface Ray Offset placera GameObject ett angivet avstånd i meter från ytan men i motsatt riktning av raycast utförs. Således, om raycast är användarens blick, kommer GameObject att röra sig närmare längs linjen från träffpunkten på ytan till kameran.

Orienteringsläget avgör vilken typ av rotation som ska tillämpas i förhållande till det normala på ytan.

  • Ingen – Ingen rotation tillämpas
  • TrackedTarget – Objektet kommer att möta den spårade transformen som driver raycasten
  • SurfaceNormal – Objektet justeras baserat på det normala vid träffpunkten på ytan
  • Blandat – Objektet justeras baserat på det normala vid träffpunkten på ytan OCH baserat på den spårade transformen.

Om du vill tvinga den associerade GameObject att förbli lodrät i något annat läge än Ingen aktiverar du Håll orienteringen lodrät.

Anteckning

Använd egenskapen Orienteringsblandning för att styra balansen mellan rotationsfaktorer när Orienteringsläge är inställt på Blandat. Värdet 0,0 kommer att ha orientering helt och hållet drivet av TrackedTarget-läget och värdet 1,0 kommer att ha orientering som drivs helt av SurfaceNormal.

SurfaceMagnetism-exempel

Fastställa vilka ytor som kan träffas

När du lägger till en SurfaceMagnetism komponent i en GameObject är det viktigt att överväga lagret av GameObject och dess underordnade, om det finns några som har kolliderare. Komponenten fungerar genom att utföra olika typer av raycasts för att avgöra vilken yta att "magnet" sig mot. Om lösaren GameObject har en collider på ett av de lager som anges i MagneticSurfaces egenskapen för SurfaceMagnetism, kommer raycast sannolikt att träffa sig själv, vilket resulterar i att GameObject ansluter till sin egen kolliderarpunkt. Det här udda beteendet kan undvikas genom att ange huvud-GameObject och alla underordnade till Ignorera Raycast-lagret eller ändra LayerMask-matrisen MagneticSurfaces på lämpligt sätt.

Omvänt kolliderar inte en SurfaceMagnetism GameObject med ytor på ett lager som inte anges i egenskapen MagneticSurfaces . Vi rekommenderar vanligtvis att du placerar alla önskade ytor på ett dedikerat lager (dvs . ytor) och ställer in MagneticSurfaces egenskapen på just det här lagret. Om du använder standardinställningen eller så kan allt resultera i att gränssnittskomponenter eller markörer bidrar till lösaren.

Slutligen ignoreras ytor längre än egenskapsinställningen MaxRaycastDistanceSurfaceMagnetism av raycasts.

DirectionalIndicator

Klassen DirectionalIndicator är en tag-along-komponent som orienterar sig mot riktningen för en önskad punkt i rymden.

Används oftast när den spårade måltypen för SolverHandler är inställd på Head. På det här sättet instruerar en UX-komponent med DirectionalIndicator lösaren en användare att titta på önskad punkt i utrymmet.

Önskad punkt i utrymmet bestäms via egenskapen Riktningsmål .

Om riktningsmålet kan visas av användaren, eller vilken referensram som anges i SolverHandler, inaktiverar den här lösaren alla Renderer komponenter under den. Om det inte går att visa aktiveras allt på indikatorn.

Indikatorns storlek krymper desto närmare registrerar användaren riktningsmålet i sin FOV.

  • Minsta indikatorskala – minsta skala för indikatorobjektet

  • Maximal indikatorskala – den maximala skalan för indikatorobjektet

  • Synlighetsskalningsfaktor – Multiplikator för att öka eller minska den FOV som avgör om riktningsmålpunkten kan visas eller inte

  • Visa förskjutning – Från referensramens synvinkel (t.ex. kamera möjligen) definierar den här egenskapen hur långt i indikatorriktningen objektet ska vara från mitten av visningsplatsen.

Egenskaper för riktningsindikator
Egenskaper för riktningsindikator

Exempelscen för riktningsindikator
Exempelscen för directional indicator (Assets/MRTK/Examples/Demos/Solvers/Scenes/DirectionalIndicatorSolverExample.unity)

Handmeny med HandConstraint och HandConstraintPalmUp

UX-exempel på handmeny

Beteendet HandConstraint ger en lösning som begränsar det spårade objektet till en region som är säker för handbegränsat innehåll (till exempel handgränssnitt, menyer osv.). Säkra regioner betraktas som områden som inte korsar handen. En härledd klass med HandConstraint anropad HandConstraintPalmUp ingår också för att demonstrera ett vanligt beteende för att aktivera det lösenlösarspårade objektet när handflatan är riktad mot användaren.

På sidan Handmeny finns exempel på hur du använder handbegränsningslösare för att skapa handmenyer.

Se även