|
|
- /************************************************************************************
- Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
-
- Licensed under the Oculus Utilities SDK License Version 1.31 (the "License"); you may not use
- the Utilities SDK except in compliance with the License, which is provided at the time of installation
- or download, or which otherwise accompanies this software in either electronic or hard copy form.
-
- You may obtain a copy of the License at
- https://developer.oculus.com/licenses/utilities-1.31
-
- Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
- under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
- ANY KIND, either express or implied. See the License for the specific language governing
- permissions and limitations under the License.
-
- ************************************************************************************/
-
- using UnityEngine;
- using System.Collections;
- using UnityEngine.EventSystems;
- using UnityEngine.UI;
-
- /// <summary>
- /// UI pointer driven by gaze input.
- /// </summary>
- public class OVRGazePointer : OVRCursor {
- private Transform gazeIcon; //the transform that rotates according to our movement
-
- [Tooltip("Should the pointer be hidden when not over interactive objects.")]
- public bool hideByDefault = true;
-
- [Tooltip("Time after leaving interactive object before pointer fades.")]
- public float showTimeoutPeriod = 1;
-
- [Tooltip("Time after mouse pointer becoming inactive before pointer unfades.")]
- public float hideTimeoutPeriod = 0.1f;
-
- [Tooltip("Keep a faint version of the pointer visible while using a mouse")]
- public bool dimOnHideRequest = true;
-
- [Tooltip("Angular scale of pointer")]
- public float depthScaleMultiplier = 0.03f;
-
- public bool matchNormalOnPhysicsColliders;
-
- /// <summary>
- /// The gaze ray.
- /// </summary>
- public Transform rayTransform;
-
- /// <summary>
- /// Is gaze pointer current visible
- /// </summary>
- public bool hidden { get; private set; }
-
- /// <summary>
- /// Current scale applied to pointer
- /// </summary>
- public float currentScale { get; private set; }
-
- /// <summary>
- /// Current depth of pointer from camera
- /// </summary>
- private float depth;
- private float hideUntilTime;
- /// <summary>
- /// How many times position has been set this frame. Used to detect when there are no position sets in a frame.
- /// </summary>
- private int positionSetsThisFrame = 0;
- /// <summary>
- /// Last time code requested the pointer be shown. Usually when pointer passes over interactive elements.
- /// </summary>
- private float lastShowRequestTime;
- /// <summary>
- /// Last time pointer was requested to be hidden. Usually mouse pointer activity.
- /// </summary>
- private float lastHideRequestTime;
-
- // Optionally present GUI element displaying progress when using gaze-to-select mechanics
- private OVRProgressIndicator progressIndicator;
-
- private static OVRGazePointer _instance;
- public static OVRGazePointer instance
- {
- // If there's no GazePointer already in the scene, instanciate one now.
- get
- {
- if (_instance == null)
- {
- Debug.Log(string.Format("Instanciating GazePointer", 0));
- _instance = (OVRGazePointer)GameObject.Instantiate((OVRGazePointer)Resources.Load("Prefabs/GazePointerRing", typeof(OVRGazePointer)));
- }
- return _instance;
- }
-
- }
-
-
- /// <summary>
- /// Used to determine alpha level of gaze cursor. Could also be used to determine cursor size, for example, as the cursor fades out.
- /// </summary>
- public float visibilityStrength
- {
- get
- {
- // It's possible there are reasons to show the cursor - such as it hovering over some UI - and reasons to hide
- // the cursor - such as another input method (e.g. mouse) being used. We take both of these in to account.
-
-
- float strengthFromShowRequest;
- if (hideByDefault)
- {
- // fade the cursor out with time
- strengthFromShowRequest = Mathf.Clamp01(1 - (Time.time - lastShowRequestTime) / showTimeoutPeriod);
- }
- else
- {
- // keep it fully visible
- strengthFromShowRequest = 1;
- }
-
- // Now consider factors requesting pointer to be hidden
- float strengthFromHideRequest;
-
- strengthFromHideRequest = (lastHideRequestTime + hideTimeoutPeriod > Time.time) ? (dimOnHideRequest ? 0.1f : 0) : 1;
-
-
- // Hide requests take priority
- return Mathf.Min(strengthFromShowRequest, strengthFromHideRequest);
- }
- }
-
- public float SelectionProgress
- {
- get
- {
- return progressIndicator ? progressIndicator.currentProgress : 0;
- }
- set
- {
- if (progressIndicator)
- progressIndicator.currentProgress = value;
- }
- }
-
- public void Awake()
- {
- currentScale = 1;
- // Only allow one instance at runtime.
- if (_instance != null && _instance != this)
- {
- enabled = false;
- DestroyImmediate(this);
- return;
- }
-
- _instance = this;
-
- gazeIcon = transform.Find("GazeIcon");
- progressIndicator = transform.GetComponent<OVRProgressIndicator>();
- }
-
- void Update ()
- {
- if (rayTransform == null && Camera.main != null)
- rayTransform = Camera.main.transform;
-
- // Move the gaze cursor to keep it in the middle of the view
- transform.position = rayTransform.position + rayTransform.forward * depth;
-
- // Should we show or hide the gaze cursor?
- if (visibilityStrength == 0 && !hidden)
- {
- Hide();
- }
- else if (visibilityStrength > 0 && hidden)
- {
- Show();
- }
- }
-
- /// <summary>
- /// Set position and orientation of pointer
- /// </summary>
- /// <param name="pos"></param>
- /// <param name="normal"></param>
- public override void SetCursorStartDest(Vector3 _, Vector3 pos, Vector3 normal)
- {
- transform.position = pos;
-
- if (!matchNormalOnPhysicsColliders) normal = rayTransform.forward;
-
- // Set the rotation to match the normal of the surface it's on.
- Quaternion newRot = transform.rotation;
- newRot.SetLookRotation(normal, rayTransform.up);
- transform.rotation = newRot;
-
- // record depth so that distance doesn't pop when pointer leaves an object
- depth = (rayTransform.position - pos).magnitude;
-
- //set scale based on depth
- currentScale = depth * depthScaleMultiplier;
- transform.localScale = new Vector3(currentScale, currentScale, currentScale);
-
- positionSetsThisFrame++;
- RequestShow();
- }
-
- public override void SetCursorRay(Transform ray)
- {
- // We don't do anything here, because we already set this properly by default in Update.
- }
-
- void LateUpdate()
- {
- // This happens after all Updates so we know that if positionSetsThisFrame is zero then nothing set the position this frame
- if (positionSetsThisFrame == 0)
- {
- // No geometry intersections, so gazing into space. Make the cursor face directly at the camera
- Quaternion newRot = transform.rotation;
- newRot.SetLookRotation(rayTransform.forward, rayTransform.up);
- transform.rotation = newRot;
- }
-
- Quaternion iconRotation = gazeIcon.rotation;
- iconRotation.SetLookRotation(transform.rotation * new Vector3(0, 0, 1));
- gazeIcon.rotation = iconRotation;
-
- positionSetsThisFrame = 0;
- }
-
- /// <summary>
- /// Request the pointer be hidden
- /// </summary>
- public void RequestHide()
- {
- if (!dimOnHideRequest)
- {
- Hide();
- }
- lastHideRequestTime = Time.time;
- }
-
- /// <summary>
- /// Request the pointer be shown. Hide requests take priority
- /// </summary>
- public void RequestShow()
- {
- Show();
- lastShowRequestTime = Time.time;
- }
-
-
- // Disable/Enable child elements when we show/hide the cursor. For performance reasons.
- void Hide()
- {
- foreach (Transform child in transform)
- {
- child.gameObject.SetActive(false);
- }
- if (GetComponent<Renderer>())
- GetComponent<Renderer>().enabled = false;
- hidden = true;
- }
-
- void Show()
- {
- foreach (Transform child in transform)
- {
- child.gameObject.SetActive(true);
- }
- if (GetComponent<Renderer>())
- GetComponent<Renderer>().enabled = true;
- hidden = false;
- }
-
- }
|