Oculus Connect 4 will feature more than 30 sessions across four tracks: Develop, Design, Distribute, and Future.

We kick things off with a keynote address on October 11!
New To The Forum? Click Here To Read The How To Guide. -- Developers Click Here.

New Unity UI + OVR Look-Based Input HOWTO

24

Comments

  • ccsccs Posts: 219
    Hiro Protagonist
    New version of project/code:

    https://www.dropbox.com/s/ncs8d9mwy192f99/LookInputSampleV3.zip?dl=0



    Changes:
    * more robust button handling
    * added ignoreInputsWhenLookAway option
    * added deselectWhenLookAway option

    New code:
    using UnityEngine;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    using System.Collections;
    
    public class LookInputModule : BaseInputModule {
    
    	// singleton makes it easy to access the instanced fields from other code without needing a pointer
    	// e.g.  if (LookInputModule.singleton != null && LookInputModule.singleton.controlAxisUsed) ...
    	private static LookInputModule _singleton;
    	public static LookInputModule singleton {
    		get {
    			return _singleton;
    		}
    	}
    
    	// name of button to use for click/submit
    	public string submitButtonName = "Fire1";
    
    	// name of axis to use for scrolling/sliders
    	public string controlAxisName = "Horizontal";
    
    	// smooth axis - default UI move handlers do things in steps, meaning you can smooth scroll a slider or scrollbar
    	// with axis control. This option allows setting value of scrollbar/slider directly as opposed to using move handler
    	// to avoid this
    	public bool useSmoothAxis = true;
    	// multiplier controls how fast slider/scrollbar moves with respect to input axis value
    	public float smoothAxisMultiplier = 0.01f;
    	// if useSmoothAxis is off, this next field controls how many steps per second are done when axis is on
    	public float steppedAxisStepsPerSecond = 10f;
    
    	// guiRaycastHit is helpful if you have other places you want to use look input outside of UI system
    	// you can use this to tell if the UI raycaster hit a UI element
    	private bool _guiRaycastHit;
    	public bool guiRaycastHit {
    		get {
    			return _guiRaycastHit;
    		}
    	}
    
    	// controlAxisUsed is helpful if you use same axis elsewhere
    	// you can use this boolean to see if the UI used the axis control or not
    	// if something is selected and takes move event, then this will be set
    	private bool _controlAxisUsed;
    	public bool controlAxisUsed {
    		get {
    			return _controlAxisUsed;
    		}
    	}
    
    	// buttonUsed is helpful if you use same button elsewhere
    	// you can use this boolean to see if the UI used the button press or not
    	private bool _buttonUsed;
    	public bool buttonUsed {
    		get {
    			return _buttonUsed;
    		}
    	}
    
    	public enum Mode {Pointer,Submit};
    	// LookInputModule supports 2 modes:
    	// 1 - Pointer
    	//     Module acts a lot like a mouse with pointer locked where you look. Where you look is where 
    	//     pointerDown/pointerUp/pointerClick events are used
    	//     useCursor is recommended for correct precision
    	//     axis control of sliders/scrollbars/etc. is optional
    	// 2 - Submit
    	//     controls are selected and manipulated with axis control only
    	//     submit/select events are used
    	//     in this mode you can't click along a slider/scrollbar to set the slider/scroll value
    	//     useLookDrag option is ignored
    	public Mode mode = Mode.Pointer;
    
    	// useLookDrag allows you to use look-based drag and drop (see example)
    	// and also drag sliders/scrollbars based on where you are looking
    	// only works if usePointerMethod is true
    	public bool useLookDrag = true;
    	public bool useLookDragSlider = true;
    	public bool useLookDragScrollbar = false;
    
    	// useCursor only applies when usePointerMethod is true
    	// the cursor works like a mouse pointer so you can see exactly where you are clicking
    	// not recommended to turn off
    	public bool useCursor = true;
    
    	// the UI element to use for the cursor
    	// the cursor will appear on the plane of the current UI element being looked at - so it adjusts to depth correctly
    	// recommended to use a simple Image component (typical mouse cursor works pretty well) and you MUST add the 
    	// Unity created IgnoreRaycast component (script included in example) so that the cursor will not be see by the UI
    	// event system
    	public RectTransform cursor;
    
    	// when UI element is selected this is the color it gets
    	// useful for when want to use axis input to control sliders/scrollbars so you can see what is being
    	// manipulated
    	public bool useSelectColor = true;
    	public bool useSelectColorOnButton = false;
    	public bool useSelectColorOnToggle = false;
    	public Color selectColor = Color.blue;
    
    	// ignore input when looking away from all UI elements
    	// useful if you want to use buttons/axis for other controls
    	public bool ignoreInputsWhenLookAway = true;
    
    	// deselect when looking away from all UI elements
    	// useful if you want to use axis for other controls
    	public bool deselectWhenLookAway = false;
    
    	// interal vars
    	private PointerEventData lookData;
    	private Color currentSelectedNormalColor;
    	private bool currentSelectedNormalColorValid;
    	private Color currentSelectedHighlightedColor;
    	private GameObject currentLook;
    	private GameObject currentPressed;
    	private GameObject currentDragging;
    	private float nextAxisActionTime;
    
    	// 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);
    		if (lookData.pointerCurrentRaycast.gameObject != null) {
    			_guiRaycastHit = true;
    		} else {
    			_guiRaycastHit = false;
    		}
    		m_RaycastResultCache.Clear();
    		return lookData;
    	}
    
    	// update the cursor location and whether it is enabled
    	// this code is based on Unity's DragMe.cs code provided in the UI drag and drop example
    	private void UpdateCursor(PointerEventData lookData) {
    		if (cursor != null) {
    			if (useCursor) {
    				if (lookData.pointerEnter != null) {
    					RectTransform draggingPlane = lookData.pointerEnter.GetComponent<RectTransform>();
    					Vector3 globalLookPos;
    					if (RectTransformUtility.ScreenPointToWorldPointInRectangle(draggingPlane, lookData.position, lookData.enterEventCamera, out globalLookPos)) {
    						cursor.gameObject.SetActive(true);
    						cursor.position = globalLookPos;
    						cursor.rotation = draggingPlane.rotation;
    					} else {
    						cursor.gameObject.SetActive(false);
    					}
    				} else {
    					cursor.gameObject.SetActive(false);
    				}
    			} else {
    				cursor.gameObject.SetActive(false);
    			}
    		}
    	}
    		
    	// sets color of selected UI element and saves current color so it can be restored on deselect
    	private void SetSelectedColor(GameObject go) {
    		if (useSelectColor) {
    			if (!useSelectColorOnButton && go.GetComponent<Button>()) {
    				currentSelectedNormalColorValid = false;
    				return;
    			}
    			if (!useSelectColorOnToggle && go.GetComponent<Toggle>()) {
    				currentSelectedNormalColorValid = false;
    				return;
    			}
    			Selectable s = go.GetComponent<Selectable>();
    			if (s != null) {
    				ColorBlock cb = s.colors;
    				currentSelectedNormalColor = cb.normalColor;
    				currentSelectedNormalColorValid = true;
    				currentSelectedHighlightedColor = cb.highlightedColor;
    				cb.normalColor = selectColor;
    				cb.highlightedColor = selectColor;
    				s.colors = cb;
    			}
    		}
    	}
    
    	// restore color of previously selected UI element
    	private void RestoreColor(GameObject go) {
    		if (useSelectColor && currentSelectedNormalColorValid) {
    			Selectable s = go.GetComponent<Selectable>();
    			if (s != null) {
    				ColorBlock cb = s.colors;
    				cb.normalColor = currentSelectedNormalColor;
    				cb.highlightedColor = currentSelectedHighlightedColor;
    				s.colors = cb;
    			}
    		}
    	}
    
    	// clear the current selection
    	private void ClearSelection() {
    		if (eventSystem.currentSelectedGameObject) {
    			RestoreColor(eventSystem.currentSelectedGameObject);
    			eventSystem.SetSelectedGameObject(null);
    		}
    	}
    
    	// select a game object
    	private void Select(GameObject go) {
    		ClearSelection();
    		if (ExecuteEvents.GetEventHandler<ISelectHandler> (go)) {
    			SetSelectedColor(go);
    			eventSystem.SetSelectedGameObject(go);
    		}
    	}
    
    	// send update event to selected object
    	// needed for InputField to receive keyboard input
    	private bool SendUpdateEventToSelectedObject() {
    		if (eventSystem.currentSelectedGameObject == null)
    			return false;
    		BaseEventData data = GetBaseEventData ();
    		ExecuteEvents.Execute (eventSystem.currentSelectedGameObject, data, ExecuteEvents.updateSelectedHandler);
    		return data.used;
    	}
    
    	// Process is called by UI system to process events
    	public override void Process() {
    		_singleton = this;
    
    		// send update events if there is a selected object - this is important for InputField to receive keyboard events
    		SendUpdateEventToSelectedObject();
    
    		// see if there is a UI element that is currently being looked at
    		PointerEventData lookData = GetLookPointerEventData();
    		currentLook = lookData.pointerCurrentRaycast.gameObject;
    
    		// deselect when look away
    		if (deselectWhenLookAway && currentLook == null) {
    			ClearSelection();
    		}
    
    		// handle enter and exit events (highlight)
    		// using the function that is already defined in BaseInputModule
    		HandlePointerExitAndEnter(lookData,currentLook);
    
    		// update cursor
    		UpdateCursor(lookData);
    
    		if (!ignoreInputsWhenLookAway || ignoreInputsWhenLookAway && currentLook != null) {
    			// button down handling
    			_buttonUsed = false;
    			if (Input.GetButtonDown (submitButtonName)) {
    				ClearSelection();
    				lookData.pressPosition = lookData.position;
    				lookData.pointerPressRaycast = lookData.pointerCurrentRaycast;
    				lookData.pointerPress = null;
    				if (currentLook != null) {
    					currentPressed = currentLook;
    					GameObject newPressed = null;
    					if (mode == Mode.Pointer) {
    						newPressed = ExecuteEvents.ExecuteHierarchy (currentPressed, lookData, ExecuteEvents.pointerDownHandler);
    						if (newPressed == null) {
    							// some UI elements might only have click handler and not pointer down handler
    							newPressed = ExecuteEvents.ExecuteHierarchy (currentPressed, lookData, ExecuteEvents.pointerClickHandler);
    							if (newPressed != null) {
    								currentPressed = newPressed;
    							}
    						} else {
    							currentPressed = newPressed;
    							// we want to do click on button down at same time, unlike regular mouse processing
    							// which does click when mouse goes up over same object it went down on
    							// reason to do this is head tracking might be jittery and this makes it easier to click buttons
    							ExecuteEvents.Execute (newPressed, lookData, ExecuteEvents.pointerClickHandler);
    						}
    					} else if (mode == Mode.Submit) {
    						newPressed = ExecuteEvents.ExecuteHierarchy (currentPressed, lookData, ExecuteEvents.submitHandler);
    						if (newPressed == null) {
    							// try select handler instead
    							newPressed = ExecuteEvents.ExecuteHierarchy (currentPressed, lookData, ExecuteEvents.selectHandler);
    						}
    					}
    					if (newPressed != null) {
    						lookData.pointerPress = newPressed;
    						currentPressed = newPressed;
    						Select(currentPressed);
    						_buttonUsed = true;
    					}
    					if (mode == Mode.Pointer) {
    						if (useLookDrag) {
    							bool useLookTest = true;
    							if (!useLookDragSlider && currentPressed.GetComponent<Slider>()) {
    								useLookTest = false;
    							} else if (!useLookDragScrollbar && currentPressed.GetComponent<Scrollbar>()) {
    								useLookTest = false;
    								// the following is for scrollbars to work right
    								// apparently they go into an odd drag mode when pointerDownHandler is called
    								// a begin/end drag fixes that
    								if (ExecuteEvents.Execute(currentPressed,lookData, ExecuteEvents.beginDragHandler)) {
    									ExecuteEvents.Execute(currentPressed,lookData,ExecuteEvents.endDragHandler);
    								}
    							} 
    							if (useLookTest) {
    								if (ExecuteEvents.Execute(currentPressed,lookData, ExecuteEvents.beginDragHandler)) {
    									lookData.pointerDrag = currentPressed;
    									currentDragging = currentPressed;
    								}
    							}
    						} else {
    							// the following is for scrollbars to work right
    							// apparently they go into an odd drag mode when pointerDownHandler is called
    							// a begin/end drag fixes that
    							if (ExecuteEvents.Execute(currentPressed,lookData, ExecuteEvents.beginDragHandler)) {
    								ExecuteEvents.Execute(currentPressed,lookData,ExecuteEvents.endDragHandler);
    							}
    						}
    					}
    				}
    			}
    		}
    
    		// have to handle button up even if looking away
    		if (Input.GetButtonUp(submitButtonName)) {
    			if (currentDragging) {
    				ExecuteEvents.Execute(currentDragging,lookData,ExecuteEvents.endDragHandler);
    				if (currentLook != null) {
    					ExecuteEvents.ExecuteHierarchy(currentLook,lookData,ExecuteEvents.dropHandler);
    				}
    				lookData.pointerDrag = null;
    				currentDragging = null;
    			}
    			if (currentPressed) {
    				ExecuteEvents.Execute(currentPressed,lookData,ExecuteEvents.pointerUpHandler);
    				lookData.rawPointerPress = null;
    				lookData.pointerPress = null;
    				currentPressed = null;
    			}
    		}
    
    		// drag handling
    		if (currentDragging != null) {
    			ExecuteEvents.Execute (currentDragging,lookData,ExecuteEvents.dragHandler);
    		}
    
    		if (!ignoreInputsWhenLookAway || ignoreInputsWhenLookAway && currentLook != null) {
    			// control axis handling
    			_controlAxisUsed = false;
    			if (eventSystem.currentSelectedGameObject && controlAxisName != null && controlAxisName != "") {
    				float newVal = Input.GetAxis (controlAxisName);
    				if (newVal > 0.01f || newVal < -0.01f) {
    					if (useSmoothAxis) {
    						Slider sl = eventSystem.currentSelectedGameObject.GetComponent<Slider>();
    						if (sl != null) {
    							float mult = sl.maxValue - sl.minValue;
    							sl.value += newVal*smoothAxisMultiplier*mult;
    							_controlAxisUsed = true;
    						} else {
    							Scrollbar sb = eventSystem.currentSelectedGameObject.GetComponent<Scrollbar>();
    							if (sb != null) {
    								sb.value += newVal*smoothAxisMultiplier;
    								_controlAxisUsed = true;
    							}
    						}
    					} else {
    						_controlAxisUsed = true;
    						float time = Time.unscaledTime;
    						if (time > nextAxisActionTime) {
    							nextAxisActionTime = time + 1f/steppedAxisStepsPerSecond;
    							AxisEventData axisData = GetAxisEventData(newVal,0.0f,0.0f);
    							if (!ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, axisData, ExecuteEvents.moveHandler)) {
    								_controlAxisUsed = false;
    							} 
    						}
    					}
    				}
    			}
    		}
    	}	
    }
    
    
  • Just curious, is there a way to use this OVR Look-Based Input to say, for example, pick up and drop a 3D object in the scene instead of just UI? Would greatly appreciate it if someone could point me in the right direction!
  • virrorvirror Posts: 402
    Lawnmower Man (or Woman)
    This way of distributing the code is a bit messy, dont get me wrong, really appreciate what you have done here!
    But could you please package this as a unity package instead so it can be imported with ease into existing projects?
  • AguaAgua Posts: 33
    Lawnmower Man (or Woman)
    Thanks again for sharing this.
    How would go about selecting GUI objects with just the raycast?
    For example, if you look at the button for more than 2 seconds it clicks the button. If you look at it for less than 2 seconds it is not clicked.
  • ccsccs Posts: 219
    Hiro Protagonist
    virror - I hear you on being messy. When I started this thread the code I shared was quite simple so it fit nicely within the forum post in a code section, and I hadn't intended to go further with it, but it kind of snowballed into a bigger project. :) Next time I share, I'll share as a unitypackage or I might even add it to the Unity Store as a free asset. If I go that route, I can't package it with the OVR stuff included, so that is a downside to going that way. Sharing the way I did ensured a complete working project without requiring any hookup with the OVR prefab.

    Since my last post, I have added a 2d slider component which allows setting x/y by dragging a button around within the 2d space. This is useful for a color picker, which I also made as a UI component. I also made a dropdown/popup list component/prefab which you use a set string list and connect it to another component using a delegate callback, or you can directly hook it to an enum field on another component. This has nothing to do with the Rift, but these are useful UI components, and you can control them easily with the same look methods as the other existing components. If I can find some time, I'll clean it all up and package it up to share.

    Agua-

    It wouldn't be too hard to add a time-based select/click. Basically in the GetLookPointerEventData() function in my LookInputModule, you should save the last looked at object into a private variable. When the last looked at object doesn't match the new looked at object, you start/reset a countdown timer for the length of time you want the delay to be. Then you add a check to see if that timer has gone below 0. If it has, and the looked at object is valid, you simply call the pointerDown or pointerClick handler on that object (look at the GetButtonDown(submitButtonName) code to see what it does and mimic that). This is an interesting concept, so if I get some time, I will add this to my LookInputModule as a feature. I can see using this in the GearVR apps I have in mind to develop. If I add this, I'll also add a little timer wheel or slider icon next to the red-dot pointer to show the timer progress. Thanks for sparking an idea! I don't really see how this will work with sliders/scrollbars though. For that I think you really need a button.

    ccs
  • CubicleNinjasCubicleNinjas Posts: 194
    Hiro Protagonist
    Simply wanted to thank you for the helpful sample files. Appreciate it and looking forward to updates!
  • itin513itin513 Posts: 6
    Virtual Boy (or Girl)
    kashen wrote:
    Just curious, is there a way to use this OVR Look-Based Input to say, for example, pick up and drop a 3D object in the scene instead of just UI? Would greatly appreciate it if someone could point me in the right direction!

    Hey kashen, I recently integrated this system into my project. While the method I use is not a 1:1 "pick up and drop a 3D object in the scene..." I do manipulate a GameObject once look based input has established a target-of-interest. So I imagine if you wanted to; you could essentially track the duration of time passed since target-established, and then force the target GameObject transform to 'follow' the LookCamera (used on the CenterEyeAnchor according to original creators instructions). I'm not sure I'm performing this in the best way possible, but solving the problem for my project required adding in a basic public function to access the private class variable that contains the raycasting look input taget obj.

    Let me know if I can help further.

    CaptainOculus
  • mknktmknkt Posts: 30
    Thank you so much, you have no idea how valuable this is to some people :D I finally have my first working GUI based off of this project. Keep up the great work :!:
    Vector Reboot Studio
  • Hey,

    I am pretty new to the unity + oculus topic so I am looking for some help. I would like to change the script so that looking at the button for some time (like, 1sec) will trigger some script (e.g. camera change). Fo camer changing via keyboard I was just using:
    #pragma strict
    
    public var camera1 : GameObject;
    public var camera2 : GameObject;
    public var camera3 : GameObject;
    var activeCamera : int;
           
    function Start () {}
    
    function Update () {
    
            if (Input.GetKeyDown(KeyCode.V))
            {
                switch(activeCamera){
    
                  case 1:
                      camera1.SetActive(false);
                      camera2.SetActive(true);
                      activeCamera = 2;
                      break;
                  case 2:
                     camera3.SetActive(true);
                     camera2.SetActive(false);
                     activeCamera = 3;
                     break;
                  case 3:
                     camera1.SetActive(true);
                     camera3.SetActive(false);
                     activeCamera = 1;
                     break;
              }
    
    
    
            }
    
    }
    

    Could You please give me some tips on how to do that?
  • p4blop4blo Posts: 8
    Virtual Boy (or Girl)
    Great solution, works perfectly :)

    Thanks so much for sharing
  • TomasRikerTomasRiker Posts: 1
    Virtual Boy (or Girl)
    First of all, thanks for posting this.

    There's a problem: I can't get dragging for the slider working, even though I checked "Use Look Drag Slider".
    The scrollbar works.

    Funnily, it works your pre-compiled version. So I guess something has changed in Unity since then.

    Any ideas what that might be?
  • Lifted, nailed in, awesome! - man you rock.
    Thanks for the share! :D
    Lupus, lone developer at Lupus Solus.
    Currently working on Push For Emor.
    http://www.indiedb.com/games/push-for-emor
    http://www.twitter.com/pushforemor
  • dignifiedwebdignifiedweb Posts: 273
    Art3mis
    Thanks for sharing this, it worked so perfectly! I was easily able to grab your one script, add my own cursor, and add a look-based input to my UI. I appreciate the hard work! The sample project was really well done too, by the way.
    Check out my Mobile VR Jam 2015 title Man Overboard! - Try the DK2 Version if you don't have a Gear VR
  • ccsccs Posts: 219
    Hiro Protagonist
    Glad others have found this useful!

    I'm sorry I haven't been able to respond to all the posts. I have my day job + trying to do a VR startup on the side, and I can barely keep up! I'll try to get back to this post at some point to see if I can correct any issues that have popped up.

    ccs
  • ccsccs Posts: 219
    Hiro Protagonist
    I don't know if anyone else encountered this, but I updated from 4.6.0f1 to 4.6.3f1 today and all my clicks and button presses stopped working. It seems that now the cursor canvas is winning the raycast and processing all the events so they are not getting to the underlying UI object. To remedy this, simply disable or remove the Graphic Raycaster component on the Cursor so it won't receive events. I'm not sure why the Graphic Raycaster on the Cursor didn't win the raycasts before, but perhaps that was a bug that Unity remedied which is why it is popping up now in 4.6.3f1. I will update the sample project and try to upload a new version. I also plan to take a stab at 5.0 before too long and I will try to make sure this works with that.

    ccs
  • ccsccs Posts: 219
    Hiro Protagonist
    I fixed up the issues others were seeing with drag issues and clicking with cursor and posted a new version of the project:

    https://www.dropbox.com/s/3bpz5rgimbxdk ... 4.zip?dl=0

    It looks like the previous version of my code broke in newer versions of unity because they removed the begin and end drag handlers from the slider component, and my code only enabled drag on slider if the call to begin drag actually executed. Now it tries to drag even if the component doesn't have a begin drag handler.

    The above was built with Unity 4.6.4f1.

    This version also adds a scaling cursor option which scales the size of the world cursor based on the distance it is being drawn at such that it should always appear the same size, but will always be at the right focal distance in the scene.

    ccs
  • HegarzHegarz Posts: 8
    Hey, firstly thanks a million for sharing this, however I'm having a bit of a problem.

    I downloaded the example you've uploaded and I have that working completely fine, so I stirpped it down to just the cursor and one canvas and it works fine.

    I've then tried to rebuild this in my project, seems to go fine in the sense that when I play the scene, the cursor gets centered, however from here on the cursor does not track with the headset and if I print our cursor.position in the UpdateCursor function in LookInputModule script the value does not change.

    Do you have any ideas what might be causing this? Note I do not have the very latest OVR controller instead it is the version just before, I'm quite close to a project deadline so I don't want to replace the previous controller unless absolutely necessary.

    Thanks again for the great work, and if you could get back to me that would be very much appreciated!

    Edit: To update/elaborate further, it's now detecting rotation of the headset on the Y-axis giving horizontal movement, but nothing on the x axis to give vertical movement
  • ccsccs Posts: 219
    Hiro Protagonist
    Do you have the Event Camera set on the Canvas point to a dummy camera that must be placed under the CenterEyeAnchor transform that OVR provides under the camera rig? It should be placed at 0,0,0 position with 0,0,0 rotation. The attached images illustrate what has to happen. This camera is what is used to get the point that you are looking at, so it is important that it be placed dead center of the OVR cameras. If you are using an older OVR SDK that doesn't have CenterEyeAnchor, you can create your own under the LeftEyeAnchor and just offset it a little bit to the right (+x). You will have to experiment to get it to feel right.



    Also make sure to set this dummy camera to Culling Mask = Nothing so it doesn't waste CPU/GPU rendering anything. Clear flags should also be set to Don't clear to prevent clearing any other rendering from other cameras.



    Lastly - the cursor will only appear when you are actually looking at a UI element. You should place a Panel under your Canvas in world space, and make sure the Canvas itself is set to World Space and is on the UI layer.

    ccs
  • evolvingtechevolvingtech Posts: 6
    Virtual Boy (or Girl)
    @CCS - Thank you very very much for you fine code example!

    I do have a question... I am running Unity 5.0.1f1 and I get the following deprecation warning:

    Assets/OVR/Scripts/Util/OVRGridCube.cs(146,35): warning CS0618: `UnityEngine.Renderer.castShadows' is obsolete: `Property castShadows has been deprecated. Use shadowCastingMode instead.'

    Any thoughts on how to fix this?
  • ccsccs Posts: 219
    Hiro Protagonist
    That is coming from the Oculus API. I'm still using 4.6.4 for my projects, although I have tinkered with 5.0 on the side. I think current OVR API is not 100% compatible with 5.0, but will still work. I know Unity just came out with the beta that integrates OVR support internally, but I haven't tried it so I don't know how well it works.

    Basically Oculus and Unity need to get this sorted out to have a cleaner solution for 5.* going forward.

    http://unity3d.com/unity/beta

    In the beta release notes:
    VR: Added integrated support for Oculus Rift in Editor and Standalone Players. Once Virtual Reality is enabled in Player Settings, pressing play in the editor will show your game view on the rift. It is recommended to "Maximize on Play" the game view in order to achieve smooth rendering. Be sure to remove any previous Oculus plugins from your project.
  • ndavidenndaviden Posts: 3
    Hi again css. Your work has been incredibly helpful!

    Would you be able to turn your demo into a package that could be imported into any project? That way it would be easy to tinker with all that you made for the demo.

    Thanks again!
  • ccsccs Posts: 219
    Hiro Protagonist
    Yeah, let me see about making a package. I agree that is cleaner. For the demo to work right I needed to add stuff on the OVR center eye anchor, so the package will include an OVR camera rig. You will have to be selective on import if you don't want that.

    ccs
  • CultorCultor Posts: 3
    Virtual Boy (or Girl)
    Hey, any news on this project ? It's pretty great ! Been playing with it in Unity 5.

    A great addition would be the ability to click buttons by looking at them for an X amount of seconds. Combined with some sort of animation to make it clear what is happening.
    I will dive in the code myself to see If i can manage it myself but I'm new to programming in Unity, all the tips are welcome :)
  • ZY1991ZY1991 Posts: 7
    Awesome work! But I have a question to ask. I am developing with Gear VR. I have trouble with calling a keyboard in Gear VR. Using your demo, I can click the InputField but it doesn't call a Android's mobile keyboard. Do you know how to call the keyboard so I can input using GearVR's touchPad? Thank you!
  • Hey ccs! Thx a lot for the program it seems to work pretty damn well... unless you turn the standard InputModule back on.
    I made a worldspace canvas that follows the player around and automatically selects the first button when you press p: a pauze menu (HUD style). However, this "automatically selecting the first button" doesnt work with the InputModule off, and when I turn the Module on all kinds of weird things start to happen. Do you know how to fix this? And/or can you tell me what piece of code I need to add to have that "automatically select the first button" feature?

    (PS: I understand this inputmodule is for pressing buttons on static world objects (and not in a HUD because you cant specifically look at a button when it follows you around) but i want to have both my pauze menu working AND use your script for selecting other UI elements within the world)
  • *Slow Clap*

    You gentlemen are the future. Thank you for this wonderful example.

    I wonder how much Unity is going to integrate when it comes to the uGUI and VR support. I haven't seen much news on that.
  • wazmackwazmack Posts: 3
    Would this work with gear VR?
    we want interactive videos, with hotspots that when you hover your crosshair over, 2d content pops up..

    anyone thing they can help my company out on this one?
  • ccsccs Posts: 219
    Hiro Protagonist
    I have trouble with calling a keyboard in Gear VR. Using your demo, I can click the InputField but it doesn't call a Android's mobile keyboard.

    On Android, the soft keyboard is an additional view that pops up on phone in 2d fashion which can't be displayed in a 3d app. You want all GearVR applications to disable the built-in soft keyboard, which is already taken care of for you by the setup that Oculus provides for GearVR. To solve this, you have to create your own world-space keyboard using UI Buttons arranged in a keyboard pattern, and have the buttons pass key events to the input field. It is quite a pain to rig all that up, but it works. I made a GearVR webbrowser (not released) that uses the UI shown in this post and can enter text input this way. Do note that bluetooth keyboards work with GearVR with no additional code.
    Would this work with gear VR?

    Yes this package works with GearVR. Just change Submit Button Name on the LookInputModule component to "Fire" and the GearVR touchpad will work here to click buttons and sliders. You can enable Use Look Drag to allow dragging sliders/scrollbars.

    For hover-over to trigger some action (submit or pop-up another UI element), you will need to add some code right after this part:
    		// see if there is a UI element that is currently being looked at
    		PointerEventData lookData = GetLookPointerEventData();
    		currentLook = lookData.pointerCurrentRaycast.gameObject;
    

    If currentLook is not null, it will be the currently looked-at UI game object. Here you could see if that currentLook object has a specific custom component, and if so, trigger it to do something, like this:
    		if (currentLook != null) {
    			FooComponent foo = currentLook.GetComponent<FooComponent>();
    			if (foo != null) {
    				foo.callCustomAction();
    			}
    		}
    
    And/or can you tell me what piece of code I need to add to have that "automatically select the first button" feature?

    Just use the Select(GameObject go) function provided in LookInputModule.cs. That function will deselect current selected UI object, if any, and select the passed UI object. In the code where you handle "p" to bring up your menu, add a call to this to select the button you want selected when the menu comes up.
  • OculusDevOculusDev Posts: 3
    Hey,

    Hope this thread is still active...I've just stumbled across this as the perfect example of what I'm trying to achieve. I've downloaded the dropbox code from post #1 and the UI works really well in Rift (Unity 5.1.1, Rift DK2 with runtime 6.0.0).

    I have an issue that I'm trying to solve with the UI button. If I look at the button and click on it then the button continues to be rendered in a "clicked" state even when I look away from it. I have to click on a non-UI element to deselect the button. I've tried changing the button's "Navigation" option from "Auto" to "None" but it still doesn't work as expected. I'm working through the BasicLookInputModule code to understand the behavior but if anybody else has seen (and preferably solved!) this then please let me know. Thanks in advance.
  • JagaHeeJagaHee Posts: 1
    Hello ccs
    Thank you for posting this code. Very useful. I have a question about BasicLookInputModule. As you wrote in instruction, i've attached the script to EventSystem object. And disabled touch input module and standalone. Then i need to deactivate lookInput and activate touch and standalone. But when i do this strage thing happens. Touch works only when by a second finger and Input system says it is the first finger. Do i need to clean something or stop any Input system somewhere?
    p.s. sorry for my english)
Sign In or Register to comment.