Skip to main content
New Participant
September 11, 2013

[TIP] Detecting where the player looks at

Hi guys,

we came across this for our vrjam game "Sorcerer's Wrath", where the player fights things by just looking at them.

Here is a quick blog post how we did this, I have not seen this specific approach in the wild and thought it might be worth sharing. Happy to discuss pro's and con's.
    This topic has been closed for replies.

    18 replies

    Up and Coming
    September 12, 2013
    Thanks for writing that up :)
    Participant
    September 23, 2013
    Hi Nigrin,

    Thanks for sharing that. I tackled the same problem and decided to use the Physics.Raycast() approach. Your approach may be much faster I don't know, I've heard raycasting is slow, but in my situation it didn't matter and I've not seen any speed impact.

    I'm pretty new to Unity so my approach is probably poor but I thought I'd share it (written in C#) :-


    public class PlayerLookingAt : MonoBehaviour {

    Transform cameraTransform = null;

    void Awake() {
    cameraTransform = GameObject.FindWithTag("MainCamera").transform;
    }

    void Update() {
    float length = 10.0f;
    RaycastHit hit;
    Vector3 rayDirection = cameraTransform.TransformDirection(Vector3.forward);
    Vector3 rayStart = cameraTransform.position + rayDirection; // Start the ray away from the player to avoid hitting itself
    Debug.DrawRay(rayStart, rayDirection * length, Color.green);
    if (Physics.Raycast(rayStart, rayDirection, out hit, length)) {
    if (hit.collider.tag == "Tower") {
    // Do stuff
    }
    }
    }
    }


    That's the guts of the code. I've tagged the OVR camera controller as 'MainCamera' and put a collider with isTrigger ticked on the objects I want to know if the player is looking at.

    I hope that helps someone,
    Cheers,
    Mark
    Up and Coming
    September 24, 2013
    Another technique is to use dot product between to Vector3's. I found the information on it here http://forum.unity3d.com/threads/173707-Using-Vector3-Dot-for-Direction-Facing-Calculation

    I found that 0.72f < x <= 1 seemed to fit the Oculus field of vision to determine if it was in view or not. That was with the B cups, I believe the other cups would change the number you needed to use.
    Seeing is believing
    Up and Coming
    December 7, 2013
    "marky1124" wrote:
    Hi Nigrin,

    Thanks for sharing that. I tackled the same problem and decided to use the Physics.Raycast() approach. Your approach may be much faster I don't know, I've heard raycasting is slow, but in my situation it didn't matter and I've not seen any speed impact.

    I'm pretty new to Unity so my approach is probably poor but I thought I'd share it (written in C#) :-


    public class PlayerLookingAt : MonoBehaviour {

    Transform cameraTransform = null;

    void Awake() {
    cameraTransform = GameObject.FindWithTag("MainCamera").transform;
    }

    void Update() {
    float length = 10.0f;
    RaycastHit hit;
    Vector3 rayDirection = cameraTransform.TransformDirection(Vector3.forward);
    Vector3 rayStart = cameraTransform.position + rayDirection; // Start the ray away from the player to avoid hitting itself
    Debug.DrawRay(rayStart, rayDirection * length, Color.green);
    if (Physics.Raycast(rayStart, rayDirection, out hit, length)) {
    if (hit.collider.tag == "Tower") {
    // Do stuff
    }
    }
    }
    }


    That's the guts of the code. I've tagged the OVR camera controller as 'MainCamera' and put a collider with isTrigger ticked on the objects I want to know if the player is looking at.

    I hope that helps someone,
    Cheers,
    Mark


    Thanks for this, I ported it to JS and works like a charm.
    Up and Coming
    December 7, 2013
    Thanks for sharing this Mark... do you know if it casts a ray to the actual center of the view or is it slightly offset due to the OVR camera offset? I can't remember if I tried using Vector3.forward when I tackled this problem but this is what I ended up doing in order to compensate for the OVR's camera offset:


    var rayLength = 5.0;

    function Update () {

    var ray : Ray = camera.main.ViewportPointToRay (Vector3(0.59,0.5,0));
    var hit : RaycastHit;
    Debug.DrawRay (ray.origin, ray.direction * rayLength, Color.red);

    if (Physics.Raycast (ray, hit, rayLength)) {

    if(hit.collider.tag == "whateverObjectYouWant") {

    //Do Something...
    }
    }


    .. by adding .09 to the x it counters the offset and casts the ray to the center of the screen view. It works but I'm always interested in a better solution so I might have to give this a try and see if it works for me. Thanks!
    Up and Coming
    January 5, 2014
    Got a question about this type of stuff. How do you add a requirement that a "button" on screen must be looked at for x seconds? I want to add input like we see in many rift games like titans of space. But have no idea what to look for.
    http://daggasoft.com http://homeawesomation.com Check out vrTrek http://daggasoft.wordpress.com/2014/01/03/vrtrek-for-oculus-rift/ Check out Bricktastic - Beta Testers Wanted! http://daggasoft.wordpress.com/2014/02/12/bricktastic-beta-1/
    Inspiring
    January 6, 2014
    i'd create a timer that begins counting up when the player has a button in sight, if the raycast leaves the button before the set amount of time required to look at it then the timer resets. If the timer exceeds the time required then it becomes active
    January 9, 2014
    In the Unity tutorials, they use raycasting instead of a collider like Nigrin suggested.

    I think (and may be wrong) that the problem of the collider is that you can "look" at something through walls. Let's say you look forward, at a wall, and right behind this wall, an enemy enters the collider : the
    onColliderEnter(collider other){if(other == enemy){somecode();}}

    is true, even if you don't see the enemy, and somecode will be executed.

    With the raycast, you can put something like :
    raycasthit = hit ; 
    Physics.Raycast(transform.position, Vector3.forward, out hit);
    if(hit == enemy){somecode();}

    in your code and it will take the first thing the raycast hits. So, if it's a wall, the condition is false even if your raycast hits an enemy behind the wall.

    I personally use linecast instead of raycast if possible, because I had less problems with it, and because I think that it's faster (not having to calculate the ray to the infinite), but maybe am I wrong on this. The best way I found to do what we intend to do is to combine both approaches : use a box collider to see if there is an enemy in front of you (or near you), even if it's behind a wall, and if there is one, cast a raycast (or linecast) to see if there is something between you and the enemy. This way, you can avoid the "enemy behind wall" problem, and you don't use constantly raycasts / linecasts, and that should be better for the performance of the game.
    Participant
    January 14, 2014
    "nigrin" wrote:
    Hi guys,

    we came across this for our vrjam game "Sorcerer's Wrath", where the player fights things by just looking at them.

    Here is a quick blog post how we did this, I have not seen this specific approach in the wild and thought it might be worth sharing. Happy to discuss pro's and con's.


    Commenting out a.x fixed a huge issue for me - thanks!
    sh0v0r
    Up and Coming
    January 14, 2014
    Lunar Flight uses ray casts for the cockpit interaction. I placed and object between the eyes which is a child of the Right Camera as this is the camera that all other cameras reference for orientation information. I use it's forward vector for the raycast direction and cast just a bit further than the depth of the cockpit.

    Everything the player can interact with has a collider and an object that contains all it's information. When the ray cast hits one of them it then gets the info object to know what icon or string to display and it's interaction method. The raycast is also only done every 100ms.