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

ezRocket
Explorer
Has anyone managed to get the a UI component to properly follow the OVRcam?

Anonymous
Not applicable
What do you mean, follow the cam?

If you are using the OVRPlayerController, you can put the UI transforms under ForwardDirection transform and they will always be in front of the player, but you can still look around on the HUD, but I'm not sure that is what you mean.

If you want something that perfectly tracks the camera, just stick UI transforms under CenterEyeAnchor with a Z of about 0.6 and rotation 180. The UI transform will always be looking back at the camera. You won't be able to use look-based input though because the UI will be fixed on the cam.

ccs

ezRocket
Explorer
Ergh, that shouldv'e been obvious... :oops:
Thanks, whatever I was doing caused it to either show in only one eye or move in one axis.

Is there a way to make a world space canvas always render over everything else? Using a dummy cam and setting the culling mask to the layer of the canvas doesn't work with the rift. Using sorting layers also doesn't help.

It'd be kinda immersion breaking if your HUD just decided to clip through walls.

Anonymous
Not applicable
Sorting layer and order in layer is just for sorting between UI canvases themselves. This allows you to specify a render order for those if you have multiple canvases.

I haven't tried this yet, but it looks like you can use a custom material on the UI elements. For the material I'm guessing you will need a custom shader with render queue set as overlay and set ZTest Always. Then assign that material to all of your UI elements. Render queue of overlay makes sure material is rendered after normal geometry, and ztest always makes the shader ignore depth buffer and always render (so there will be no clipping). To make the shader, you'll have to find the built-in UI shader code, make a copy, and modify. I haven't looked into the new UI shaders yet, but you can download the source to all the built-in Unity shaders from unity3d:

http://netstorage.unity3d.com/unity/builtin_shaders-4.6.0f2.zip

Some docs on shader cull and depth syntax.
http://docs.unity3d.com/Manual/SL-CullAndDepth.html

weasel47
Heroic Explorer
I'm trying to update the OP's script to send all of the events that would be used for a Standalone Input Module as described here:http://docs.unity3d.com/460/Documentation/Manual/script-StandaloneInputModule.html

There are a lot of things I'm not sure about, but this is what I have so far:
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 cancelButtonName = "Fire2";
public string controlAxisName = "Horizontal";
private GameObject dragHandler;
public GameObject buttonPressed;
public 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;
//need to figure out how to detect movement for these deltas...
lookData.delta = new Vector2(0.005f,0.0f);//lookData.position - lookPosition;
lookData.scrollDelta = new Vector2(0.005f,0.0f);//lookData.position - lookPosition;
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.go);
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);
}
}
if (Input.GetButtonDown (submitButtonName)) {
eventSystem.SetSelectedGameObject (null);
if (lookData.pointerCurrentRaycast.go != null) {
GameObject go = lookData.pointerCurrentRaycast.go;
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);
}
ExecuteEvents.ExecuteHierarchy (go, lookData, ExecuteEvents.pointerEnterHandler);
buttonPressed = ExecuteEvents.ExecuteHierarchy (go, lookData, ExecuteEvents.pointerDownHandler);
GameObject tempDragHandler = ExecuteEvents.ExecuteHierarchy (go, lookData, ExecuteEvents.dragHandler);
if (tempDragHandler != null)
dragHandler = tempDragHandler;
ExecuteEvents.Execute (dragHandler, lookData, ExecuteEvents.beginDragHandler);

}
}
else if (Input.GetButton (submitButtonName)) {
if (dragHandler != null) {
ExecuteEvents.Execute (dragHandler, lookData, ExecuteEvents.dragHandler);
}
if (eventSystem.currentSelectedGameObject != lookData.pointerCurrentRaycast.go) {
ExecuteEvents.ExecuteHierarchy (eventSystem.currentSelectedGameObject, lookData, ExecuteEvents.pointerExitHandler);
ExecuteEvents.ExecuteHierarchy (lookData.pointerCurrentRaycast.go, lookData, ExecuteEvents.pointerExitHandler);
}
}
else if (Input.GetButtonUp (submitButtonName)) {
if (buttonPressed !=null)
{
ExecuteEvents.ExecuteHierarchy (buttonPressed, lookData, ExecuteEvents.pointerUpHandler);
if (lookData.pointerCurrentRaycast.go == buttonPressed)
{
ExecuteEvents.ExecuteHierarchy (buttonPressed, lookData, ExecuteEvents.pointerClickHandler);
}
}
if (dragHandler != null) {
ExecuteEvents.Execute (dragHandler, lookData, ExecuteEvents.endDragHandler);
ExecuteEvents.Execute (dragHandler, lookData, ExecuteEvents.dropHandler);
}
dragHandler = null;
}


if (Input.GetButtonDown (cancelButtonName)) {
eventSystem.SetSelectedGameObject(null);
if (lookData.pointerCurrentRaycast.go != null) {
GameObject go = lookData.pointerCurrentRaycast.go;
GameObject newPressed = ExecuteEvents.ExecuteHierarchy (go, lookData, ExecuteEvents.cancelHandler);
if (newPressed == null) {
// submit handler not found, try select handler instead
newPressed = ExecuteEvents.ExecuteHierarchy (go, lookData, ExecuteEvents.selectHandler);
}
if (newPressed != null) {
eventSystem.SetSelectedGameObject(newPressed);
}
}
}
}
}


I'm not sure what the difference between "Submit button pressed" and "pointer button pressed" should be if they're both the same button. The script doesn't wait for a full down-up click for the Submit button, but that doesn't seem ideal.

Sliders are sort of working, but they jump to their max value as soon as they're touched. They do not respond to dragging, but I think that's because the method of using the center of the screen on a dedicated camera will never result in a position delta. That would have to be calculated with some other method (I tried to set the deltas to low values for testing purposes, but that didn't seem to change anything). I would think that a slider would jump to whatever position is clicked even without the delta, but that doesn't seem to be working.

Anyone have any thoughts or suggestions on this?

Anonymous
Not applicable
I have drag and drop working. It required some more changes not captured in my earlier posts and package I posted. I used Unity's own drag and drop sample to test it. I'll have to see if head drag of scrollbars works as well, although I'm not sure you would want to use that in reality so I will make it an option. I'll clean up the code a bit, and package up a new demo with a drag and drop sample in addition to the existing samples, and I'll post the code as well. Shouldn't be too long...

weasel47
Heroic Explorer
"ccs" wrote:
I have drag and drop working. It required some more changes not captured in my earlier posts and package I posted. I used Unity's own drag and drop sample to test it. I'll have to see if head drag of scrollbars works as well, although I'm not sure you would want to use that in reality so I will make it an option. I'll clean up the code a bit, and package up a new demo with a drag and drop sample in addition to the existing samples, and I'll post the code as well. Shouldn't be too long...


Awesome! I look forward to seeing it!
I do agree that using one's head to drag scrollbars would probably be weird, but I thought it might be nice to have the option anyway. Options are never bad.

Anonymous
Not applicable
Here is the updated example project and code that supports head drag and several other options, including a world space cursor when you are looking at UI elements. Comments are in the code to explain each option. I added Unity's own drag and drop UI sample that works with head drag and drop here.

Full project including source code (used 4.6.0b21 - still need to try with 4.6.0RC2):
https://www.dropbox.com/s/3oafblrsk4amuvg/LookInputSampleV2.zip?dl=0

Code (although I recommend just trying the project above to see how it all works together):

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;

// 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();
if (lookData.pointerCurrentRaycast.gameObject) {
currentLook = lookData.pointerCurrentRaycast.gameObject;
}

// handle enter and exit events (highlight)
// using the function that is already defined in BaseInputModule
HandlePointerExitAndEnter(lookData,currentLook);

// update cursor
UpdateCursor(lookData);

// button 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);
}
}
}
}
} else 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);
}

// 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;
}
}
}
}
}
}
}

ezRocket
Explorer
"ccs" wrote:

http://netstorage.unity3d.com/unity/builtin_shaders-4.6.0f2.zip

Some docs on shader cull and depth syntax.
http://docs.unity3d.com/Manual/SL-CullAndDepth.html



Awesome, didn't know that with the materials. Just changed one of the default shaders, kinda hacky but works.

I noticed that there's an "OVRGUIShader" that comes with the Oculus package, but it overwrites the (GUI) text's properties. There's also a handy "GUIHUD" material.

Although, having said that, the GUI/Text Shader works perfectly! No messing around needed.

For now, I just made a copy of the GUIHUD material and put the GUI/Text Shader on that.
That saved me some serious time.

weasel47
Heroic Explorer
"ccs" wrote:
Here is the updated example project and code that supports head drag and several other options, including a world space cursor when you are looking at UI elements. Comments are in the code to explain each option. I added Unity's own drag and drop UI sample that works with head drag and drop here.

Full project including source code (used 4.6.0b21 - still need to try with 4.6.0RC2):
https://www.dropbox.com/s/3oafblrsk4amuvg/LookInputSampleV2.zip?dl=0


Thanks for doing this. I tested it out and it works pretty well. I'm using head movement for sliders. I encountered weird bugs twice, but was unable to reproduce them:
Once, I got "stuck" on a slider and couldn't interact with anything else afterwards. The slider kept responding to my head movement and wouldn't respond to the fire1 button.
The next time, while trying to reproduce that bug, I ended up with two different sliders recolored with the "select color." Everything still functioned fine, and I could still only interact with one slider at a time.

Another issue which I think is inherited from the way GUI elements are supposed to work by default, and I haven't looked into how to deal with it yet: selected elements can still be interacted with when the cursor is outside of the canvas. This is problematic for me because I have a 3D cursor that will be used to interact with other objects besides the gui. I appreciate the extra functions that you put in to deal with the opposite (detecting when input is going to the gui)!