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
    September 25, 2015
    Hi, great work!
    Did you had a time to check the new Unity 5.2 version with your code and example . As it support 0.7 runtime now.
    Thanks for the share :)
    Up and Coming
    November 9, 2015
    Hey there,

    This work is awesome, but it won't run properly on Unity 5.2.2 . I get all sorts of weird behaviours (flickering, no image, etc.) and the interactions won't work.

    Anyone else managed to get it working under Unity 5.2.2?
    November 10, 2015
    Here is an updated version of the project that works with 5.2.1p2 (5.2.2 should work as well) and uses Native VR + 0.1.2 Oculus Utils so it is compatible with latest Oculus runtimes (0.7 or 0.8):

    https://www.dropbox.com/s/g8ptl7w9xdewp ... 5.zip?dl=0

    I'll update the 1st post as well. I'll leave the old version linked there in case anyone wants to still use the old Oculus integration.

    ccs
    Inspiring
    November 10, 2015
    Does it use uGUI and does it work on Gear VR ?
    November 10, 2015
    Yes it uses uGUI and yes it works with GearVR with a bluetooth controller and limited function with the touchpad. If you want to get fancier with the GearVR touchpad to add scrolling of scrollbars or use it to control the cursor beyond just center look position, that is something you would have to add. Currently scrolling is mapped to right stick y-axis and trigger axis (on an xbox 360 controller on desktop). The touchpad, however, will work as equivalent button press/release and allow you to control everything in this scene with look based scroll or submit.

    ccs
    Up and Coming
    November 11, 2015
    "ccs" wrote:
    Here is an updated version of the project that works with 5.2.1p2 (5.2.2 should work as well) and uses Native VR + 0.1.2 Oculus Utils so it is compatible with latest Oculus runtimes (0.7 or 0.8):

    https://www.dropbox.com/s/g8ptl7w9xdewp ... 5.zip?dl=0

    I'll update the 1st post as well. I'll leave the old version linked there in case anyone wants to still use the old Oculus integration.

    ccs


    It's working like a charm now on Unity 2.2.2. Great work my friend ;)
    Up and Coming
    December 2, 2015
    Hi guys, so I'm trying to make a Gear VR app that showcases some various models with different animations on each model, using various button they press on the wall in VR. I have about 10 of these models, all with animator controllers attached. I'm using the button script from this post (with the gaze based looking/selection).

    The issue is I have no idea how to make so after I click the button it spawns one of the models I specify from my assets folder, plays the animation in the model (fbx models with animator controller that is attached to the model too) and plays the sound for that animation. I tried messing with the on click () stuff that was included, it was directed to a testevents script but I didn't know what to do with that.

    I feel like what I'm trying to do is a very simple concept but I have been spending over a week now! Any help would be greatly appreciated. I really want to make this Gear VR app happen. Do I need a special script to replace the testevents script to make this happen?
    Up and Coming
    December 3, 2015
    What you can do is, create a prefab for your animation, then instantiate the prefab when they click the button.

    Firstly, create a game object at 0,0,0 and add your animation as a child. Add your audio source and set it to play automatically (so if you hit PLAY in editor you hear the sound immeadiately). Add your animation and set it to play automatically (in your FBX import animations).

    OK, if you hit play and everything looks good you are 3/4 of the way there.

    Now, drag that game object into the project to save it as a prefab.

    Now, create a script to add to each button that has a variable for a prefab and a location to spawn it. Give it a script to handle the click. Then drag your prefab onto the variable, and your spawn location, and also tell your button's click event to call that method.

    Here's some rough pseudo code:

    class SpawnAnimation : MonoBehaviour
    {
    public GameObject prefab;
    public Transform spawnTransform;

    public void Spawn()
    {
    GameObject go = (GameObject)Instantiate(prefab, spawnTransform.position, Quaternion.identity);
    go.SetParent(spawnTransform);
    }
    }
    Check out my Unity VR development blog: http://talesfromtherift.com @peterept
    Up and Coming
    December 3, 2015
    Thank you peterept. this gives me some hope to finally figure this out. I'll be back tomorrow (posting from my phone) and let you know if it worked!
    Up and Coming
    December 3, 2015
    Hey peterrept, so I tried it today but having issues still. Just to give you an example of how I have the models laid out, one is named "guy.fbx" inside the fbx I can expand it and there is an animation in there called "walk.vmd" (I use MMD4mechanim to make these) There is also a walk animation in the audio folder called "walk.wav" that syncs with the animation.

    I right clicked the walk.vmd and created a prefab called "guywalk" then I replaced the testevent with this:

    using UnityEngine;
    using System.Collections;

    class SpawnAnimation : MonoBehaviour
    {
    public GameObject guywalk;
    public Transform spawnTransform;

    public void Spawn()
    {
    GameObject go = (GameObject)Instantiate(guywalk, spawnTransform.position, Quaternion.identity);
    go.SetParent(guywalk);
    }
    }


    I seem to be getting an error when I try to launch. I am so bad with C# I'm sorry, I'm a lot better with the art stuff really. I made 3 separate grey buttons on the wall that link to the testevents script copies, but when I tried to make the buttons go to a copy the on click () changes to "no function" so that's a separate issues I'm having also. Any help with my "total noobness" would be greatly appreciated.