Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Teleportation on complicated meshes

Discussion in 'XR Interaction Toolkit and Input' started by raynorzs, Jan 24, 2022.

  1. raynorzs

    raynorzs

    Joined:
    Aug 29, 2018
    Posts:
    2
    Hello, every XR Interaction Toolkit tutorial shows how to use teleportation with Teleportation Area/Anchor compoment on a simple plane. My question is, how to create teleportation area on more complicated meshes than simple plane. For example I have a stairs and I want to detect only faces that are upwards (shown on screenshot). Or I have complicated environment like it is in Walkabout Mini Golf. How can I achieve that? Thank you
     

    Attached Files:

  2. Freakish

    Freakish

    Joined:
    Jun 3, 2015
    Posts:
    75
    I would likely just generate a quad and apply a teleport anchor to it, hide the quad (disable it's mesh renderer) and place it where the upward faces are. (Just duplicate it however many times you want it).

    Having said that I'd imagine most players would just teleport to the top step anyway.

    Hope it helps.
     
  3. unity_andrewc

    unity_andrewc

    Unity Technologies

    Joined:
    Dec 14, 2015
    Posts:
    201
    One way to do this would be to create another Collider mesh that only contains the top faces of the stair steps, and assign that to the Colliders list on the Interactable area - if you don't have access to the mesh, you would need to create it with a bunch of Colliders. This is the "expected" way to do it.

    Another way you could achieve this is to create a new type that derives from TeleportationArea to override the method GenerateTeleportRequest. This method is passed a RaycastHit, which you could use to dot the normal of what was hit with world up (Vector3.up) - if the result of the dot product is close to 1, that must mean the surface flat and facing up, so any other result you could return false from GenerateTeleportRequest to prevent the teleport from happening. The downside to this approach is that the reticle will then "lie" about the visual feedback for whether the player can teleport there without also similarly modifying CanSelect/CanHover.
     
  4. PatHightreeXVR

    PatHightreeXVR

    Joined:
    Dec 10, 2018
    Posts:
    19
    Is there a way to deny vertical surfaces without having a false positive for the arc visuals ?
    I tried subclassing XRRayInteractor and overriding GetValidTargets(), but it uses private variables :\
    (changing the collision geometry is not an option because we have a huge number of environments)
     
  5. JonathanCel

    JonathanCel

    Joined:
    Feb 17, 2021
    Posts:
    22

    So it's easy enough to turn the ray caster red to indicate an invalid teleport location:

    1: Override the interactor:

    Code (CSharp):
    1.  
    2. public class XRInteractorOverride : XRRayInteractor{}
    3.  
    2: A function to work out valid teleport angles:

    Code (CSharp):
    1.  
    2.         public bool ValidTeleportAngle()
    3.         {
    4.  
    5.             Vector3 hitPos;
    6.             Vector3 hitNormal;
    7.             bool isValidTarget;
    8.        
    9.             bool didHit = TryGetHitInfo( out hitPos, out hitNormal, out _, out isValidTarget );
    10.  
    11.             if ( didHit )
    12.             {
    13.                 float ang = Vector3.Angle( hitNormal, Vector3.up );
    14.  
    15.                 if ( ang <= maxTeleportAngle )
    16.                 {
    17.                     return true;
    18.                 }
    19.  
    20. #if UNITY_EDITOR
    21.                 //Debug.Log( "HitNormal " + hitNormal + " at " + hitPos + " with angle " + ang );
    22.                 //Debug.DrawLine( hitPos, hitPos + ( hitNormal * 5 ), Color.white, 1.0f );
    23. #endif
    24.             }
    25.  
    26.             return false;
    27.  
    28.         }
    29.  

    3: Override OnHoverEntering to update the reticle/line renderer:

    Code (CSharp):
    1.  
    2.         protected override void OnHoverEntering(HoverEnterEventArgs args)
    3.         {
    4.  
    5.             if ( !ValidTeleportAngle() )
    6.             {
    7.                 args.manager.CancelInteractorHover( args.interactorObject );
    8.                 return;
    9.             }
    10.         }
    11.  

    This gets you half way.
    The problem now is that you're able to select valid ground then slide the (still 'valid') reticle up a hill.

    The fix is to check on update like:

    Code (CSharp):
    1.  
    2. void Update(){
    3.  
    4.     if ( isHoverActive && !ValidTeleportAngle() )
    5.     {
    6.         // update the line renderer
    7.         this.interactionManager.CancelInteractorHover( (IXRHoverInteractor)this );
    8.         cancelNextNextTeleport = true;
    9.     } else {
    10.         cancelNextNextTeleport = false;
    11.     }
    12.  
    13. }
    14.  
    and finally cancel the teleport as it exits:

    Code (CSharp):
    1.  
    2. protected override void OnSelectExiting( SelectExitEventArgs args ){
    3.     if ( cancelNextTeleport ){
    4.         cancelNextTeleport = true;
    5.         args.isCanceled = true;
    6.     }
    7. }
    8.  
    A couple of extra steps, but not too hacky at least.
    @unity_andrewc : a built in solution to this would be pretty nice :)