// Headset Controller Aware|Presence|70040
|
|
namespace VRTK
|
|
{
|
|
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// Event Payload
|
|
/// </summary>
|
|
/// <param name="raycastHit">The Raycast Hit struct of item that is obscuring the path to the controller.</param>
|
|
/// <param name="controllerReference">The reference to the controller that is being or has been obscured or being or has been glanced.</param>
|
|
public struct HeadsetControllerAwareEventArgs
|
|
{
|
|
public RaycastHit raycastHit;
|
|
public VRTK_ControllerReference controllerReference;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Event Payload
|
|
/// </summary>
|
|
/// <param name="sender">this object</param>
|
|
/// <param name="e"><see cref="HeadsetControllerAwareEventArgs"/></param>
|
|
public delegate void HeadsetControllerAwareEventHandler(object sender, HeadsetControllerAwareEventArgs e);
|
|
|
|
/// <summary>
|
|
/// Determines whether the HMD is in line of sight to the controllers or if the headset is directly looking at one of the controllers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// **Script Usage:**
|
|
/// * Place the `VRTK_HeadsetControllerAware` script on any active scene GameObject.
|
|
/// </remarks>
|
|
/// <example>
|
|
/// `VRTK/Examples/029_Controller_Tooltips` displays tooltips that have been added to the controllers and are only visible when the controller is being looked at.
|
|
/// </example>
|
|
[AddComponentMenu("VRTK/Scripts/Presence/VRTK_HeadsetControllerAware")]
|
|
public class VRTK_HeadsetControllerAware : MonoBehaviour
|
|
{
|
|
[Tooltip("If this is checked then the left controller will be checked if items obscure it's path from the headset.")]
|
|
public bool trackLeftController = true;
|
|
[Tooltip("If this is checked then the right controller will be checked if items obscure it's path from the headset.")]
|
|
public bool trackRightController = true;
|
|
[Tooltip("The radius of the accepted distance from the controller origin point to determine if the controller is being looked at.")]
|
|
public float controllerGlanceRadius = 0.15f;
|
|
[Tooltip("A custom transform to provide the world space position of the right controller.")]
|
|
public Transform customRightControllerOrigin;
|
|
[Tooltip("A custom transform to provide the world space position of the left controller.")]
|
|
public Transform customLeftControllerOrigin;
|
|
[Tooltip("A custom raycaster to use when raycasting to find controllers.")]
|
|
public VRTK_CustomRaycast customRaycast;
|
|
|
|
/// <summary>
|
|
/// Emitted when the controller is obscured by another object.
|
|
/// </summary>
|
|
public event HeadsetControllerAwareEventHandler ControllerObscured;
|
|
/// <summary>
|
|
/// Emitted when the controller is no longer obscured by an object.
|
|
/// </summary>
|
|
public event HeadsetControllerAwareEventHandler ControllerUnobscured;
|
|
|
|
/// <summary>
|
|
/// Emitted when the controller is seen by the headset view.
|
|
/// </summary>
|
|
public event HeadsetControllerAwareEventHandler ControllerGlanceEnter;
|
|
/// <summary>
|
|
/// Emitted when the controller is no longer seen by the headset view.
|
|
/// </summary>
|
|
public event HeadsetControllerAwareEventHandler ControllerGlanceExit;
|
|
|
|
protected GameObject leftController;
|
|
protected GameObject rightController;
|
|
protected Transform headset;
|
|
|
|
protected bool leftControllerObscured = false;
|
|
protected bool rightControllerObscured = false;
|
|
protected bool leftControllerLastState = false;
|
|
protected bool rightControllerLastState = false;
|
|
|
|
protected bool leftControllerGlance = false;
|
|
protected bool rightControllerGlance = false;
|
|
protected bool leftControllerGlanceLastState = false;
|
|
protected bool rightControllerGlanceLastState = false;
|
|
|
|
public virtual void OnControllerObscured(HeadsetControllerAwareEventArgs e)
|
|
{
|
|
if (ControllerObscured != null)
|
|
{
|
|
ControllerObscured(this, e);
|
|
}
|
|
}
|
|
|
|
public virtual void OnControllerUnobscured(HeadsetControllerAwareEventArgs e)
|
|
{
|
|
if (ControllerUnobscured != null)
|
|
{
|
|
ControllerUnobscured(this, e);
|
|
}
|
|
}
|
|
|
|
public virtual void OnControllerGlanceEnter(HeadsetControllerAwareEventArgs e)
|
|
{
|
|
if (ControllerGlanceEnter != null)
|
|
{
|
|
ControllerGlanceEnter(this, e);
|
|
}
|
|
}
|
|
|
|
public virtual void OnControllerGlanceExit(HeadsetControllerAwareEventArgs e)
|
|
{
|
|
if (ControllerGlanceExit != null)
|
|
{
|
|
ControllerGlanceExit(this, e);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The LeftControllerObscured method returns the state of if the left controller is being obscured from the path of the headset.
|
|
/// </summary>
|
|
/// <returns>Returns `true` if the path between the headset and the controller is obscured.</returns>
|
|
public virtual bool LeftControllerObscured()
|
|
{
|
|
return leftControllerObscured;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The RightControllerObscured method returns the state of if the right controller is being obscured from the path of the headset.
|
|
/// </summary>
|
|
/// <returns>Returns `true` if the path between the headset and the controller is obscured.</returns>
|
|
public virtual bool RightControllerObscured()
|
|
{
|
|
return rightControllerObscured;
|
|
}
|
|
|
|
/// <summary>
|
|
/// the LeftControllerGlanced method returns the state of if the headset is currently looking at the left controller or not.
|
|
/// </summary>
|
|
/// <returns>Returns `true` if the headset can currently see the controller within the given radius threshold.</returns>
|
|
public virtual bool LeftControllerGlanced()
|
|
{
|
|
return leftControllerGlance;
|
|
}
|
|
|
|
/// <summary>
|
|
/// the RightControllerGlanced method returns the state of if the headset is currently looking at the right controller or not.
|
|
/// </summary>
|
|
/// <returns>Returns `true` if the headset can currently see the controller within the given radius threshold.</returns>
|
|
public virtual bool RightControllerGlanced()
|
|
{
|
|
return rightControllerGlance;
|
|
}
|
|
|
|
protected virtual void Awake()
|
|
{
|
|
VRTK_SDKManager.AttemptAddBehaviourToToggleOnLoadedSetupChange(this);
|
|
}
|
|
|
|
protected virtual void OnEnable()
|
|
{
|
|
headset = VRTK_DeviceFinder.HeadsetTransform();
|
|
leftController = VRTK_DeviceFinder.GetControllerLeftHand();
|
|
rightController = VRTK_DeviceFinder.GetControllerRightHand();
|
|
}
|
|
|
|
protected virtual void OnDisable()
|
|
{
|
|
leftController = null;
|
|
rightController = null;
|
|
}
|
|
|
|
protected virtual void OnDestroy()
|
|
{
|
|
VRTK_SDKManager.AttemptRemoveBehaviourToToggleOnLoadedSetupChange(this);
|
|
}
|
|
|
|
protected virtual void Update()
|
|
{
|
|
if (trackLeftController)
|
|
{
|
|
RayCastToController(leftController, customLeftControllerOrigin, ref leftControllerObscured, ref leftControllerLastState);
|
|
}
|
|
if (trackRightController)
|
|
{
|
|
RayCastToController(rightController, customRightControllerOrigin, ref rightControllerObscured, ref rightControllerLastState);
|
|
}
|
|
|
|
CheckHeadsetView(leftController, customLeftControllerOrigin, ref leftControllerGlance, ref leftControllerGlanceLastState);
|
|
CheckHeadsetView(rightController, customRightControllerOrigin, ref rightControllerGlance, ref rightControllerGlanceLastState);
|
|
}
|
|
|
|
protected virtual HeadsetControllerAwareEventArgs SetHeadsetControllerAwareEvent(RaycastHit raycastHit, VRTK_ControllerReference controllerReference)
|
|
{
|
|
HeadsetControllerAwareEventArgs e;
|
|
e.raycastHit = raycastHit;
|
|
e.controllerReference = controllerReference;
|
|
return e;
|
|
}
|
|
|
|
protected virtual void RayCastToController(GameObject controller, Transform customDestination, ref bool obscured, ref bool lastState)
|
|
{
|
|
obscured = false;
|
|
if (controller != null && controller.gameObject.activeInHierarchy)
|
|
{
|
|
Vector3 destination = (customDestination ? customDestination.position : controller.transform.position);
|
|
RaycastHit hitInfo;
|
|
if (VRTK_CustomRaycast.Linecast(customRaycast, headset.position, destination, out hitInfo, Physics.IgnoreRaycastLayer, QueryTriggerInteraction.Ignore))
|
|
{
|
|
obscured = true;
|
|
}
|
|
|
|
if (lastState != obscured)
|
|
{
|
|
ObscuredStateChanged(controller.gameObject, obscured, hitInfo);
|
|
}
|
|
|
|
lastState = obscured;
|
|
}
|
|
}
|
|
|
|
protected virtual void ObscuredStateChanged(GameObject controller, bool obscured, RaycastHit hitInfo)
|
|
{
|
|
VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(controller);
|
|
if (obscured)
|
|
{
|
|
OnControllerObscured(SetHeadsetControllerAwareEvent(hitInfo, controllerReference));
|
|
}
|
|
else
|
|
{
|
|
OnControllerUnobscured(SetHeadsetControllerAwareEvent(hitInfo, controllerReference));
|
|
}
|
|
}
|
|
|
|
protected virtual void CheckHeadsetView(GameObject controller, Transform customDestination, ref bool controllerGlance, ref bool controllerGlanceLastState)
|
|
{
|
|
controllerGlance = false;
|
|
if (controller != null && controller.gameObject.activeInHierarchy)
|
|
{
|
|
Vector3 controllerPosition = (customDestination ? customDestination.position : controller.transform.position);
|
|
float distanceFromHeadsetToController = Vector3.Distance(headset.position, controllerPosition);
|
|
Vector3 lookPoint = headset.position + (headset.forward * distanceFromHeadsetToController);
|
|
|
|
if (Vector3.Distance(controllerPosition, lookPoint) <= controllerGlanceRadius)
|
|
{
|
|
controllerGlance = true;
|
|
}
|
|
|
|
if (controllerGlanceLastState != controllerGlance)
|
|
{
|
|
GlanceStateChanged(controller.gameObject, controllerGlance);
|
|
}
|
|
|
|
controllerGlanceLastState = controllerGlance;
|
|
}
|
|
}
|
|
|
|
protected virtual void GlanceStateChanged(GameObject controller, bool glance)
|
|
{
|
|
RaycastHit emptyHit = new RaycastHit();
|
|
VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(controller);
|
|
if (glance)
|
|
{
|
|
OnControllerGlanceEnter(SetHeadsetControllerAwareEvent(emptyHit, controllerReference));
|
|
}
|
|
else
|
|
{
|
|
OnControllerGlanceExit(SetHeadsetControllerAwareEvent(emptyHit, controllerReference));
|
|
}
|
|
}
|
|
}
|
|
}
|