Search Unity

Unity 5.2 VR Raycast? - solved

Discussion in 'AR/VR (XR) Discussion' started by RealoFoxtrot, Oct 15, 2015.

  1. RealoFoxtrot

    RealoFoxtrot

    Joined:
    Oct 2, 2015
    Posts:
    11
    Edit now that Solved:

    A massive thanks to Todd Wasson and DrBlort for being view patient with this, even though I went through a huge array of ideas until I actually did the first answer that was given. (Yeah, It's the simplest one, but different to what I had actually done)

    In the end, Unity now takes the input from the HMD and rotates the camera itself. aka where the headset is pointed is transform.forward.

    For anyone else who was in my position, this is the code which looks for collides in world tagged "button", and will print "this is a button" to the console

    Code (CSharp):
    1.     void Update () {
    2.  
    3.         RaycastHit seen;
    4.         Ray raydirection = new Ray(transform.position, transform.forward);
    5.         if (Physics.Raycast(raydirection, out seen, sightlength))
    6.         {
    7.             if (seen.collider.tag == "buttons") //in the editor, tag anything you want to interact with and use it here
    8.             {
    9.                 print("This is a button");
    10.             }
    11.  
    12.         }
    13.         Debug.DrawRay(transform.position, transform.forward, Color.black, 1); //unless you allow debug to be seen in game, this will only be viewable in the scene view
    14.     }
    15. }
    ==============================================================

    Okay, so.. I'm very new to coding, so please excuse any completely glaring errors.

    I am attempting to attach a Raycast which follows the rotation of the Oculus Rift.
    My test is to check if it is looking at a box collider on a world-space-ui and print some text.

    The problem i am having is that i can't seem to update the Raycast's direction based on the VR Devices rotation.

    Attaching code below. This code doesn't work at the commented line, and I really need someone to tell me what i've done wrong

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.VR;
    3.  
    4. public class CameraInteract : MonoBehaviour {
    5.  
    6.     public float sightlength;
    7.  
    8.     void Start () {
    9.  
    10.     }
    11.  
    12.     void Update () {
    13.  
    14.         RaycastHit seen;
    15.         Ray raydirection = new Ray(transform.position, InputTracking.GetLocalRotation(VRnode CenterEye); // This is the problem code, and i might just been using the wrong thing entirely
    16.         if (Physics.Raycast(raydirection, out seen, sightlength))
    17.         {
    18.             if (seen.collider.tag == "buttons")
    19.             {
    20.                 print("This is a button");
    21.             }
    22.  
    23.         }
    24.  
    25.     }
    26. }
     
    Last edited: Oct 20, 2015
  2. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    Looks like you're missing a right parenthesis there. Assuming that's just a "copy/paste into the forum" typo:

    What object is this script attached to? If it's on the camera game object you can probably just use the forward transform of that.

    Untested:
    Code (csharp):
    1.  
    2. //Instead of this:
    3. Ray raydirection =new Ray(transform.position, InputTracking.GetLocalRotation(VRnode CenterEye));
    4.  
    5. //Try this:
    6. Ray raydirection = new Ray(transform.position, transform.forward)
    7.  
     
  3. RealoFoxtrot

    RealoFoxtrot

    Joined:
    Oct 2, 2015
    Posts:
    11
    Yeah, I tried that first. It is attached to the camera, but the problem is, that because the Oculus Rift Camera in 5.2 is automatically changed when using a standard camera, the transform.forward doesn't work. It just points forward based on the original position.
    I need to be able to update the raycast to where the VRdevice is pointing
     
  4. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    Oh, right. That makes sense.

    I'm not sure because I don't use the InputTracking class or OVRPlayerRig/OVRCameraRig or whatever it is, I just used the default Unity cam. I wouldn't expect GetLocalRotation to do it though. Isn't that just the rotation relative to the parent object? I.e., if you turned your head to the right so many degrees, those numbers would stay the same even as the parent body spun around in circles?

    If so, maybe you need the world space forward vector instead? Is there a function in there like GetWorldRotation() or similar maybe?
     
  5. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    I see here that there isn't a world vector:

    http://docs.unity3d.com/ScriptReference/VR.InputTracking.html

    I don't know how it works with quaternions, but with matrices you multiply the parent world by the child local to get the child world. It's probably something similar with quats? Maybe you can try multiplying the local rotation by the parent's world rotation to get the child's world quaternion.
     
  6. RealoFoxtrot

    RealoFoxtrot

    Joined:
    Oct 2, 2015
    Posts:
    11
    That's the problem in a nutshell. All the advice is for the OVRCameraRig, which is now obsolete in the latest version. And as I'm not experienced in code at all, reading the documentation is a touch confusing.

    I am not sure what data type a .rotation is, but i presume a Ray needs (xx.position, xx.rotation)
    How can I turn a Quaternion into a type that can be accepted into the Ray?
     
  7. RealoFoxtrot

    RealoFoxtrot

    Joined:
    Oct 2, 2015
    Posts:
    11
  8. Xorxor

    Xorxor

    Joined:
    Oct 15, 2014
    Posts:
    24
    You probably want the Oculus Utilities for Unity 5. It includes the OVRCameraRig that you're more or less used to using.
     
  9. RealoFoxtrot

    RealoFoxtrot

    Joined:
    Oct 2, 2015
    Posts:
    11
    That makes sense, but I am concerned that Unity will just overwrite and go back to it's default camera... If i can use the default camera, it would be great as it'd work better as the project goes onwards

    I think I've got it. Updated my code to this:
    Code (CSharp):
    1.         Quaternion HMDRotation = InputTracking.GetLocalRotation(VRNode CenterEye);
    2.         Vector3 playerRotation = HMDRotation.eulerAngles;
    3.         Ray raydirection = new Ray(transform.position, playerRotation)
    Unfortunately, (VRNode CenterEye) is still giving problems. It says that enum VRNode isn't a valid type in the given context, and that CenterEye does not exist in the current context.
    This is really confusing when looking at http://docs.unity3d.com/ScriptReference/VR.VRNode.html and http://docs.unity3d.com/ScriptReference/VR.InputTracking.GetLocalRotation.html
     
  10. RealoFoxtrot

    RealoFoxtrot

    Joined:
    Oct 2, 2015
    Posts:
    11
  11. RealoFoxtrot

    RealoFoxtrot

    Joined:
    Oct 2, 2015
    Posts:
    11
    ..... Hello, I'm back again. The Raycast wasn't working, and so i used debug.drawray to see what the problem was. If anyone can watch this and tell me what the heck is going on, I'd be grateful:
     
  12. DrBlort

    DrBlort

    Joined:
    Nov 14, 2012
    Posts:
    72
    What if you put a child object on the camera, and use the forward direction of the object?

    EDIT: typo & grammar
     
  13. RealoFoxtrot

    RealoFoxtrot

    Joined:
    Oct 2, 2015
    Posts:
    11
    Sounds good. will try it once i get back.
    Just checking, How do you reference a child object, when the script is in a parent?
     
  14. DrBlort

    DrBlort

    Joined:
    Nov 14, 2012
    Posts:
    72
    I tried it myself and it seems to work.

    To reference a child object depending on the case I usually do two things:

    1. Make the member variable public, and add it via the inspector
    2. In Start(), use GetComponentInChild<MyScriptType>() and assign it to a member variable to cache it and avoid using the look up more than once.


    EDIT:
    I reread the thread, and I realized what you've been doing in post #9. I understand what you're trying to do, although it won't work like that.

    What you are confusing is that a rotation is not a direction. To convert from a rotation (as a quaternion) to a direction (as a Vector3) you need to multiply the rotation with the "original" direction, which I assume it's forward (could be another, but in this case seems to work).

    So, the code to convert that rotation to a direction would be:

    Code (CSharp):
    1. Quaternion HMDRotation = InputTracking.GetLocalRotation(VRNode.CenterEye);
    2. Vector3 playerDirection = HMDRotation * transform.forward;
    3. Ray raydirection = new Ray(transform.position, playerDirection)
    That transform is assuming it's the camera's, as you mentioned that your script is there. Otherwise modify it to point to the transform you want.

    Anyway, I did try your script, and in Unity 5.2.1p3 64 bits the forward of the camera follows the HMD, both using InputTracking (which I never used before) and just using transform.forward.

    In my test, I did directly this:

    Code (CSharp):
    1. Ray r = new Ray(transform.position, transform.forward);
    And the script worked both putting it on the camera, or on a child of the camera.
     
    Last edited: Oct 15, 2015
  15. RealoFoxtrot

    RealoFoxtrot

    Joined:
    Oct 2, 2015
    Posts:
    11
    Thank you! Worked Perfectly!


    ...except.. for some reason it's moving at twice the rate that the headset is. I.e. if you look to the left, the raycast is looking behind you. If you look behind you, the raycast has spun around to face the front.

    I tried to do transform.forward/2 but that just makes the Raycast shorter by half
     
  16. DrBlort

    DrBlort

    Joined:
    Nov 14, 2012
    Posts:
    72
    I have no idea of what could be happening there :|

    However, I'd suspect some kind of scale or hierarchy problem. Try making a new clean scene, use only the default camera, and try again with the minimum possible script.
     
  17. Kiesel

    Kiesel

    Joined:
    Nov 13, 2014
    Posts:
    6
    If you just want to check for UI Elements you can use a different approach.
    You can use the Eventsystem of the UI.
    Code (CSharp):
    1.     PointerEventData pointer = new PointerEventData(EventSystem.current);
    2.     List<RaycastResult> rcResult;
    3.  
    4.     void Update () {
    5.  
    6.         rcResult = new List<RaycastResult>();
    7.  
    8.         pointer.position = gameObject.GetComponent<Camera>().WorldToScreenPoint(transform.forward+transform.position);
    9.         EventSystem.current.RaycastAll(pointer, rcResult);
    10.         if(rcResult.Count > 0)
    11.         {
    12.                 //Your Code if something was hit goes in here
    13.         }
    14. }
     
  18. RealoFoxtrot

    RealoFoxtrot

    Joined:
    Oct 2, 2015
    Posts:
    11
    Kiesel, It's about using World-space UI really. I don't want it to detect the HUD, which is also worldspace

    Repost of my current updated code:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.VR;
    3.  
    4. public class CameraInteract : MonoBehaviour {
    5.  
    6.     public float sightlength;
    7.  
    8.     // Use this for initialization
    9.     void Start () {
    10.    
    11.     }
    12.    
    13.     // Update is called once per frame
    14.     void Update () {
    15.  
    16.         RaycastHit seen;
    17.         Quaternion HMDRotation = InputTracking.GetLocalRotation(VRNode.Head);
    18.         Vector3 playerRotation = HMDRotation * transform.forward;
    19.         //Quaternion camrot = transform.rotation;
    20.         //Vector3 playerRotation = camrot * transform.forward;
    21.         Ray raydirection = new Ray(transform.position, playerRotation);
    22.         if (Physics.Raycast(raydirection, out seen))
    23.         {
    24.             if (seen.collider.tag == "buttons")
    25.             {
    26.                 print("This is a button");
    27.             }
    28.  
    29.         }
    30.         Debug.DrawRay(transform.position, playerRotation, Color.black, 1);
    31.     }
    32. }
     
  19. RealoFoxtrot

    RealoFoxtrot

    Joined:
    Oct 2, 2015
    Posts:
    11
    I took DrBlorts Advice and did a new scene using just the starter camera and basic code. This was the result:


    Code (CSharp):
    1.     void Update ()
    2.     {
    3.         Quaternion camrot = transform.rotation;
    4.         Vector3 playerRotation = camrot * transform.forward;
    5.         Debug.DrawRay(transform.position, playerRotation, Color.black, 1);
    6.     }
    7. }
    The Result seems to be the same. It's still rotating at twice the speed of the headset.
    I am wondering what Transform.forward actually means now..


    Edit: SODS LAW!

    .... Okay. Do you want to know what the answer is? It's the answer given all the way back up there in post #2. Not sure what i was doing originally which i thought was the same, but doing exactly as Todd said works. Marking this as done.
     
    Last edited: Oct 20, 2015
    brad_81 likes this.