cancel
Showing results for 
Search instead for 
Did you mean: 

New Unity UI + OVR Look-Based Input HOWTO

Anonymous
Not applicable
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
105 REPLIES 105

vrguy2
Protege
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.

peterept
Protege
Hey, I'm not at my dev computer right now, but I'll help you later on.

But for now here some steps: there is 2 pieces to the puzzle:

1. Spawning your guy (and probably destroying also)

2. Make your guy prefab

You can test step 1 above with a simple prefab:

- Create an empty game object (name it "guy" and then create a simple 3d cube as it's child.
- Drag the guy game object into your project hierarchy and it will now be a prefab.
- Delete the guy from your scene.
- Assuming you have your UI button in the scene with the spawn script attached:
- Drag the guy prefab onto guywalk property
- Create an empty game object in the scene for your spawn spot, then drag it onto the script at spawnTransform prop.

Now run the scene, when you press the button your cube should appear. If you press again, you'll actually get another cube over the old one. You could use this code to remove any children before you spawn a new one:

foreach (Transform child in spawnTransform) {
GameObject.Destroy(child.gameObject);
}

So if that all works, now it's a matter of working on your prefab guy to slowly add in the animated character, sounds, etc.

HTH

SvenViking
Protege
I don't know if this matters or helps anyone, but a related tutorial and example project was recently posted on the Oculus Blog.

vrguy2
Protege
Thank you peterept and sven, I did just try that second project sven linked to but it seemed really complicated. I could not get an OVRplayercontroller to work with it at all, even after following the blog step by step, I couldn't figure out how to link the model to the buttons they had either. It seems I'm not able to get this going still.

I am definitely doing something silly I know it. I have re-read your instructions about 20 times try to do it step by step. Is there any simple modifications I could make to the script you gave me earlier that would accomplish the same thing, where I could just drag one script for guy.fbx to the button and one for girl.fbx to the other button.. doing all the sound, destruction, spawning? Or maybe there is a Unity asset store project I could purchase that I could just drag and drop my model to replace what they have, if they have UI buttons ready to go? I have a guy.fbx that's ready to go and girl.fbx, with the VMD animations inside the fbx and the sounds in the assets folder.

I would gladly paypal someone to help me figure this out at this point. I am basically trying to make something similar to that old "Miku Entertainment Sphere" demo, but for Gear VR utilizing my models and sounds. I feel like this is Unity 101 and I can't even do something as simple as make a model spawn with an animation and sound playing when press various buttons on a UI button in VR. Using the Oculus Audio SDK will complicate this even further I am guessing.

Edit: I just realized it might be easier to describe what I am trying to accomplish as a VR character selection screen. To be more specific I am getting stuck here on your instructions:

- Assuming you have your UI button in the scene with the spawn script attached:
- Drag the guy prefab onto guywalk property

dignifiedweb
Protege
Hi ccs,

I really appreciate the work you've done here. I am experiencing a weird problem, hoping you had an idea what's going on. I used your code in Unity 4.5x and it worked great, but now with the new runtime, I wanted to use Unity 5, naturally upgrading. I upgraded no problem with the new Unity Oculus Integration, everything was pretty easy and straightforward. So, as a metric, I ran your sample and it works great, so the issue is definitely not with your code.

With my old project I made a "look camera" as you described. In my new project, the cursor moves using this look camera, but it now has a really strange drifting problem, where it'll drift away from the center, so it ends up being away from where you're looking. Again, your sample doesn't have this issue, I even imported the latest 0.1.3.0 OculusUtilities package to make sure.

Comparing your sample and my old project, you don't seem to have a "look camera" anymore, but rather use the "CenterEyeAncher" for the "Event Camrea" on the cursor GameObject. Also, you seem to add the oculus supplied prefab "OVRTrackerBounds" as a child object. I am creating a simple OVRCameraRig setup, so I butchered your sample and dragged the "OVRCameraRig" out and it still works, I can't seem to break your code in the same way. I've copied over your latest code to my project, no luck so far. If I use the "CenterEyeAncher" the same as you, my cursor doesn't move, it just sits there. Any hints or idea what I could be doing wrong? It seems like I'm missing something simple. After sleeping on it, I may figure it out tomorrow night, but any ideas would be much appreciated. Thanks.

Anonymous
Not applicable
The only thing I can think of is the cursor object you are pointing to is not at 0,0,0 position on the canvas the cursor is a part of. The code moves the cursor canvas transform where the look raycast hit occurs. Then the code scales the cursor based on distance. If for some reason the cursor sprite was not perfectly centered, the scaling could make the cursor appear to float away from center based on distance. You could test this theory by turning off "Scale Cursor With Distance" option on LookInputModule to see if that changes anything.

One other possibility. Perhaps you don't have the Graphic Raycaster component disabled on the cursor itself. If you don't, what could happen is the screen raycast into the scene could actually be hitting the cursor, and then adjusting the cursor position based on the raycast hit. I would think this would cause the cursor to readjust position and move and keep doing that in a loop.

Good luck.

ccs

dignifiedweb
Protege
"ccs" wrote:
The only thing I can think of is ...


Those were good suggestions, but none of them worked unfortunately. If I figure it out, I'll let you know, but for now I am going to try the Oculus one to see if it works by swapping it in. Thanks again!

lchawkins
Honored Guest
hi! im trying to load different scenes for each button of your tutorial, and when i add the script for every button, only works at the first one. Any idea?
thanks!!

load scene code
using UnityEngine;
using System.Collections;

public class ButtonNextLevel : MonoBehaviour
{
public void NextLevelButton(int index)
{
Application.LoadLevel(index);
}

public void NextLevelButton(string level2)
{
Application.LoadLevel("level2");
}
}

Anonymous
Not applicable
Assuming you are passing the level's string to NextLevelButton from the Button On Click () event (in the inspector), it looks like you have a bug in the code. You are passing the string "level2" to Application.LoadLevel instead of the variable level2:


Application.LoadLevel("level2");


Should be:


Application.LoadLevel(level2);


Then in inspector assign the level name to the On Click action call string entry.

muraliv
Honored Guest
Hello,
How do I make a scroll of the scroll rect component when i swipe on the GearVR touchpad. This is not working currently.
Please let me know. Thanks