Skip to main content
November 4, 2014

New Unity UI + OVR Look-Based Input HOWTO

LookInputModule.jpg

Edit6: version 5 of example project/code:
https://www.dropbox.com/s/g8ptl7w9xdewp ... 5.zip?dl=0
Version removed old Oculus integration and uses Native VR support + 0.1.2 utils so it works with latest runtimes (0.7 or 0.8).

Edit5: version 4 of example project/code (fixed for and tested with Unity 4.6.4f1):
https://www.dropbox.com/s/3bpz5rgimbxdk ... 4.zip?dl=0
This version also adds support for a cursor that scales size with distance so it will always appear the same size but be at the right depth.

Edit4: version 3 of example project/code:
[removed - see updated example above]

Edit3: New version of example project and code posted:
[removed - see updated example above]

Edit2: If you don't have time to read all of this thread and just want the code and a sample project, I uploaded one here:
[removed - see updated example above]

Edit: fixed some issues with the code to handle InputField and also was selecting wrong game object in some cases.

I have been messing around with the new Unity GUI stuff in 4.6 release, and I figured I would share a basic solution to get up and running quickly with a look-based input system. Here is how to get a basic look UI working:

1. Add some kind of UI element to your scene. This will also add a Canvas object and an EventSystem object if you don't already have them in your scene. All UI elements must be parented by a Canvas.

2. On the UI Canvas object, set the Render Mode to World Space

3. Arrange your Canvas in world space and add more UI elements as you would like. To get started, I would just add some buttons.

4. Under the OVRCameraRig->CenterEyeAnchor object, add a regular Unity Camera at position and rotation 0,0,0, and set this camera's Culling Mask to "Nothing" so it won't actually bother rendering anything and waste CPU/GPU cycles. I named it "Look Camera". This camera is just for use by the UI event system. By putting it under the CenterEyeAnchor object, it tracks perfectly with the head. The OVR cameras don't seem to work with the UI system, probably because they utilize render textures and not screen space rendering. This dummy look camera solves that problem.

5. For every UI Canvas object you have in the scene, drag this "Look Camera" object into the "Event Camera" field.

6. create a new script called BasicLookInputModule.cs. Copy in this code:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using System.Collections;

public class BasicLookInputModule : BaseInputModule {

public const int kLookId = -3;
public string submitButtonName = "Fire1";
public string controlAxisName = "Horizontal";
private PointerEventData lookData;

// use screen midpoint as locked pointer location, enabling look location to be the "mouse"
private PointerEventData GetLookPointerEventData() {
Vector2 lookPosition;
lookPosition.x = Screen.width/2;
lookPosition.y = Screen.height/2;
if (lookData == null) {
lookData = new PointerEventData(eventSystem);
}
lookData.Reset();
lookData.delta = Vector2.zero;
lookData.position = lookPosition;
lookData.scrollDelta = Vector2.zero;
eventSystem.RaycastAll(lookData, m_RaycastResultCache);
lookData.pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache);
m_RaycastResultCache.Clear();
return lookData;
}

private bool SendUpdateEventToSelectedObject() {
if (eventSystem.currentSelectedGameObject == null)
return false;
BaseEventData data = GetBaseEventData ();
ExecuteEvents.Execute (eventSystem.currentSelectedGameObject, data, ExecuteEvents.updateSelectedHandler);
return data.used;
}

public override void Process() {
// send update events if there is a selected object - this is important for InputField to receive keyboard events
SendUpdateEventToSelectedObject();
PointerEventData lookData = GetLookPointerEventData();
// use built-in enter/exit highlight handler
HandlePointerExitAndEnter(lookData,lookData.pointerCurrentRaycast.gameObject);
if (Input.GetButtonDown (submitButtonName)) {
eventSystem.SetSelectedGameObject(null);
if (lookData.pointerCurrentRaycast.gameObject != null) {
GameObject go = lookData.pointerCurrentRaycast.gameObject;
GameObject newPressed = ExecuteEvents.ExecuteHierarchy (go, lookData, ExecuteEvents.submitHandler);
if (newPressed == null) {
// submit handler not found, try select handler instead
newPressed = ExecuteEvents.ExecuteHierarchy (go, lookData, ExecuteEvents.selectHandler);
}
if (newPressed != null) {
eventSystem.SetSelectedGameObject(newPressed);
}
}
}
if (eventSystem.currentSelectedGameObject && controlAxisName != null && controlAxisName != "") {
float newVal = Input.GetAxis (controlAxisName);
if (newVal > 0.01f || newVal < -0.01f) {
AxisEventData axisData = GetAxisEventData(newVal,0.0f,0.0f);
ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, axisData, ExecuteEvents.moveHandler);
}
}
}
}



7. Drag this script onto the EventSystem object in the scene.

8. fix Submit Button Name and Control Axis Name to match what you use in the Input Settings if you don't use Unity defaults.

9. disable or remove Standalone Input Module and Touch Input Module on the Event System object.

That's it. Push play. Look around with headset and you should see it highlight the buttons/sliders/etc. as you are looking around. When you hit the submit button it will trigger that UI element (buttons On Value Changed operations will be called if you set any of those up). Sliders get selected when you click them and can then be manipulated with the axis that was chosen on the BasicLookInputModule component.

I hope someone finds this useful since there isn't much out there on how to do this yet.

ccs
    This topic has been closed for replies.

    105 replies

    New Participant
    February 21, 2016
    Thank you so much, I've been trying to implement this myself but found it kinda hard to do. Great work :)
    New Participant
    February 22, 2016
    Very nice :)
    Come visit me at http://www.dantecampbell.org
    New Participant
    April 5, 2016
    Hello and thanks for sharing,

    I have problem. Everithing works fine with WR enabled without oculus connected. But i cant click on buttons when oculus is connected. I thing there is issue with:

    lookPosition.x = Screen.width/2;
    lookPosition.y = Screen.height/2;

    I think the reason is in lookPosition is Vector2 with
    centre of Screen instead of some reference of camera direction centre. I
    have upgraded raycast im my project to camera instead of screen and it
    works perfectly. Is there any simple way to do something similar forlookPosition  ?
    I am using Unity 5.4.0b10

    Thank you for any advice.

    New Participant
    April 22, 2016
    As I am a noob, I have created a few UI buttons but each of them does not have an Event Camera field? How do I drag the 'Look Camera' into each of them as you describe in Step 5?

    "5. For every UI Canvas object you have in the scene, drag this "Look Camera" object into the "Event Camera" field."

    Thanks for the help guys and sorry to be the noob asking nooby questions! :-)
    April 23, 2016
    Only the Canvas component has an Event Camera field, and you don't actually have to set it anymore as it defaults to the Main Camera which is a unified, both-eye VR camera nowadays. A while back the Oculus integration was 2 separate cameras for each eye, and in that case it helped to have a "center" eye fake camera so the cursor/look point would be dead center.
    May 1, 2016
    I just updated to 5.4 beta and I see this is no longer working. I'll try to figure out what is broken.
    May 1, 2016
    I can no longer edit original post, but here is an update that works with 5.4beta (version 16 as of this post).

    https://www.dropbox.com/s/q8zcylzs1ggt24n/LookInputSampleV6.zip?dl=0
    1. Completely removed OVR utils and OVR integration. Switched to native VR including adding OpenVR as supported platform
    2. Changes from using Screen.width and Screen.height to using UnityEngine.VR.VRSettings.eyeTextureWidth and eyeTextureHeight to get center point accurately. 
    For those that don't want to re-download, here is the quick fix in LookInputModule.cs that fixes the raycast point:

    @Budlog take note! :smile: 

            lookPosition.x = UnityEngine.VR.VRSettings.eyeTextureWidth/2;
            lookPosition.y = UnityEngine.VR.VRSettings.eyeTextureHeight/2;
            //lookPosition.x = Screen.width/2;
            //lookPosition.y = Screen.height/2;

    ccs

    Up and Coming
    May 2, 2016
    Very Helpful :smiley: 
    Up and Coming
    May 2, 2016
    Yesterday I tried out this demo scene and it worked... I then started to incorporate this info into my own scene but I can not get the look at cursor to operate when I push a button on controller...

    Pulled my hair out for a while then went back to the demo script and now there is no button press detection in that now either.

    I checked Oculus Home and all is well so I can't figure out what is going on?
    Up and Coming
    May 2, 2016
    Okay it fixed itself somehow.. :cold_sweat: