Search Unity

  1. New Unity Live Help updates. Check them out here!

    Dismiss Notice

Grab/Rotate/Pull/Push Objects with XR Ray Interactor?

Discussion in 'AR/VR (XR) Discussion' started by bftvtech, Mar 13, 2020.

  1. bftvtech

    bftvtech

    Joined:
    Feb 11, 2020
    Posts:
    10
    I'm trying to setup a grab interaction like the one in the Oculus Rift Home environment - where you can use the ray interactor to grab an object at a distance, pull it towards you or away from you, rotate around an axis.

    In Unity's new VR XR tutorial there is a prefab XR Rig with a Magic Tractor Beam, which is almost what I want, but you can only pull the object toward you, not away from you, and you can't rotate it.

    Has anyone tried something like this yet?
     
  2. xtr33me

    xtr33me

    Joined:
    Nov 2, 2011
    Posts:
    90
    Just curious if you have found if there is a built in way of doing this or is it something that will have to be written? I've seen drag functionality for AR but nothing for VR. Been through aPI docs and doesn't seem to be anything from what I can find, but thought I'd see if you had any luck yet.
     
  3. bftvtech

    bftvtech

    Joined:
    Feb 11, 2020
    Posts:
    10
    No luck yet, probably because I'm very new to C#. I did see that as part of the new VR Beginner Tutorial on learn.unity.com that they also had an AxisDragInteractable script, that I didn't see before. I haven't tested it out yet though as I've been busy failing at other tasks as well :)
     
  4. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    620
  5. bftvtech

    bftvtech

    Joined:
    Feb 11, 2020
    Posts:
    10
  6. bftvtech

    bftvtech

    Joined:
    Feb 11, 2020
    Posts:
    10
    So with your snippet of code from this link - is this a new script that you then attach to the game object which you want to grab, in addition to adding the XRGrabInteractable script?
     
  7. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    620
    Almost. It's attached to the controller, not to the grabbables (I wanted to attach it once only, in one place :)). The dependencies in the code snippet are right at the top: it expects that its on a GameObject with an XRController and an XRBaseInteractor (i.e. any of the XRIT interactors - they all extend that class).

    But you could easily attach a similar script to the grabbles with only small changes. Instead of:

    Code (CSharp):
    1. interactor.selectTarget
    to get the Grabbable from the Interactor, you would use:

    Code (CSharp):
    1. (XRGrabInteractable).selectingInteractor
    to get the Interactor from the Grabbable.
     
  8. bftvtech

    bftvtech

    Joined:
    Feb 11, 2020
    Posts:
    10
    I like your idea better - I'd prefer to keep it one of my XRController GameObjects. I'm getting an error in the script with 'IntelligentXRExtensions - it says the name does not exist in the current context. Do you know what I may have done wrong? Here's what I've got...

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using UnityEngine.XR;
    4. using UnityEngine.XR.Interaction.Toolkit;
    5. using System.Reflection;
    6.  
    7. public class AdjustOffset : MonoBehaviour
    8. {
    9.     public void Update()
    10.     {
    11.         var interactor = GetComponent<XRBaseInteractor>();
    12.         var controller = GetComponent<XRController>();
    13.  
    14.         XRGrabInteractable grabbable = interactor.selectTarget as XRGrabInteractable;
    15.         if (grabbable != null && grabbable.attachTransform != null)
    16.         {
    17.             InputDevice device = InputDevices.GetDeviceAtXRNode(controller.controllerNode);
    18.  
    19.             Vector2 thumbDirection = IntelligentXRExtensions.AmountMoved(device, CommonUsages.primary2DAxis);
    20.             float moveAwayAmount = thumbDirection.y;
    21.  
    22.             Vector3 vectorToMoveObjectAlong = grabbable.attachTransform.parent.InverseTransformVector(controller.transform.forward);
    23.             grabbable.attachTransform.localPosition += moveAwayAmount * vectorToMoveObjectAlong;
    24.  
    25.             MethodInfo unity_UpdateInteractorLocalPose = typeof(XRGrabInteractable).GetMethod("UpdateInteractorLocalPose", BindingFlags.NonPublic | BindingFlags.Instance);
    26.             unity_UpdateInteractorLocalPose.Invoke(grabbable, new object[] { interactor });
    27.         }
    28.  
    29.     }
    30. }
    31.  
     
  9. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    620
    IntelligentXRExtensions is one of my local classes - I'm away from desktop rgight now but will copy paste it here later
     
  10. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    620
    It was at the end of the original post, easy to miss, but:

     
  11. bftvtech

    bftvtech

    Joined:
    Feb 11, 2020
    Posts:
    10
    I'm not sure what bits of code I'm supposed to cut out and how exactly (InputDevice obj).TryGetFeatureValue(moveable, out Vector2 movement) is supposed to be inserted.

    Sorry to keep asking, I'm very new to C# and programming languages in general.
     
  12. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    620
    It's OK. I was using shorthand. So, for the start, I put brackets round the first two words as a semi-conventional thing to say "this is the type that goes here" (because brackets are used for type-casting in C#, Java, etc).

    i.e. in longhand:

    1. Whatever-your-Input-Device-object is (in the code you pasted, it's named "device"
    2. ... invoke the method TryGetFeatureValue( ... )
    3. ... and for the parameters/arguments, I assumed you'd guess this: use the CommonUsages value from Unity's API that is the thing you want to react to. In my case, I wanted to track the thumb-joystick, so I used: "CommonUsages.primary2DAxis"

    As per Unity's docs (https://docs.unity3d.com/Manual/xr_input.html#AccessingInputFeatures), TryGetFeatureValue has multiple versions, which automatically send out the right data based on context.

    If you pass in CommonUsages.primary2DAxis, you will get a Vector2 back from Unity.

    So, overall, something like this:

    Code (CSharp):
    1. device.TryGetFeatureValue( CommonUsages.primary2DAxis, out Vector2 movement );
    2.  
    3. // this will read the value of the thumbstick, and output it as a new Vector2 variable called 'movement'
     
  13. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    620
    Although ... in the code snippet above, the line of code that comes after is expecting a variable called "thumbDirection", so you'd want to have the replacement line end in "out Vector2 thumbDireciton );" instead :)
     
  14. bftvtech

    bftvtech

    Joined:
    Feb 11, 2020
    Posts:
    10
    I think my problem is trying to learn C# for VR Apps before starting in traditional keyboard/mouse 3d games and the difficulty I'm having just trying to access the buttons and thumbsticks on the Oculus Quest is making it hard to move forward and get more experience in C#. I've tried reading the docs that you mentioned but nothing seems to work, I think I'm just missing really obvious bits. This is what I tried to do with your response;

    Code (CSharp):
    1.             Vector2 thumbDirection = device.TryGetFeatureValue( CommonUsages.primary2DAxis, out Vector2 thumbDirection );
    2.             float moveAwayAmount = thumbDirection.y;
    And I didn't make anymore changes to the previous code I posted. There error I get is "Can't implicitly convert type bool to UnityEngine.Vector2. I'm guessing the error might be that I just wrote "device" but I'm not sure what I'm supposed to have there, am I supposed to direct the code to the oculus controller? Isn't that what you already had in the previous line of code, which came before what I wrote above, which is;

    Code (CSharp):
    1.  InputDevice device = InputDevices.GetDeviceAtXRNode(controller.controllerNode);
     
  15. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    620
    The keyword "out" in C# means "this variable is being created by the method I'm calling, and it will provide a value".

    The idea is that normally you send data "in" to a method (that's your parameters/arguments). In some programming langauges, every parameter has to be explicitly marked "in". But sometimes you can send data "out" from a method. Before the "return" statement was invented, this was the only way methods could return data: by having one or more of their arugments marked as "out".

    So ... you are currently trying to declare the same variable twice in that line. If you fixed your current bug, the next one would be something about how you can't declare the same variable because you've already declared it.

    Separately: the error message tells you exactly what it means. You are trying to convert something of type bool to something of type Vector2. Look in that line and see where that's happening (if you're using VSCode or Rider, you can hover the mouse over a method name or a variable name and it should popup a thing telling you what type that is, or what type it returns).
     
unityunity