Files
dungeons/Assets/ThirdParty/UltimateXR/Runtime/Scripts/Devices/UxrTrackingDevice.cs

254 lines
8.8 KiB
C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrTrackingDevice.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using UltimateXR.Avatar;
using UltimateXR.Core.Components.Composite;
using UnityEngine;
using UnityEngine.XR;
namespace UltimateXR.Devices
{
/// <summary>
/// Base class for tracking devices.
/// </summary>
public abstract class UxrTrackingDevice : UxrAvatarComponent<UxrTrackingDevice>, IUxrTrackingDevice, IUxrTrackingUpdater
{
#region Inspector Properties/Serialized Fields
[Header("Mixed Reality:")] [SerializeField] private bool _hideAvatarInPassthrough = true;
#endregion
#region Public Types & Data
/// <summary>
/// Default update order.
/// </summary>
public const int OrderStandard = 0;
/// <summary>
/// Default update order for post-process tracking devices such as hand-tracking.
/// </summary>
public const int OrderPostprocess = 10;
/// <summary>
/// Gets the headset device name.
/// </summary>
public static string HeadsetDeviceName
{
get
{
var inputDevices = new List<InputDevice>();
InputDevices.GetDevices(inputDevices);
foreach (var device in inputDevices)
{
if (device.characteristics.HasFlag(InputDeviceCharacteristics.HeadMounted))
{
return device.name;
}
}
return string.Empty;
}
}
/// <summary>
/// Gets the tracking update order.
/// There are cases where more than one tracking device might be active. We use TrackingUpdateOrder
/// for cases where there is one that should be applied after the other(s). For example an Oculus Rift
/// together with a Leap Motion setup has one tracking component for each. But Leap Motion should
/// override the tracking values of the rift controllers if the Leap Motion component is active.
/// In this case Oculus, like most tracking devices, has a value of <see cref="OrderStandard" />
/// while Leap Motion has a value of <see cref="OrderPostprocess" /> so that the tracking
/// devices update the avatar in the correct order.
/// </summary>
public virtual int TrackingUpdateOrder => OrderStandard;
/// <summary>
/// Gets whether the device headset renders on top of the real world.
/// </summary>
public virtual bool IsMixedRealityDevice => false;
#endregion
#region Implicit IUxrDevice
/// <inheritdoc />
public abstract string SDKDependency { get; }
/// <inheritdoc />
public event EventHandler<UxrDeviceConnectEventArgs> DeviceConnected;
#endregion
#region Implicit IUxrTrackingDevice
/// <inheritdoc />
public event EventHandler SensorsUpdating;
/// <inheritdoc />
public event EventHandler SensorsUpdated;
/// <inheritdoc />
public event EventHandler AvatarUpdating;
/// <inheritdoc />
public event EventHandler AvatarUpdated;
#endregion
#region Explicit IUxrTrackingUpdater
/// <inheritdoc />
void IUxrTrackingUpdater.UpdateAvatar()
{
OnAvatarUpdating();
UpdateAvatar();
OnAvatarUpdated();
}
/// <inheritdoc />
void IUxrTrackingUpdater.UpdateSensors()
{
OnSensorsUpdating();
UpdateSensors();
OnSensorsUpdated();
}
#endregion
#region Public Methods
/// <summary>
/// Tries to get the connected headset device.
/// </summary>
/// <param name="inputDevice">Returns the headset device if found</param>
/// <returns>Whether the device was found</returns>
public static bool GetHeadsetDevice(out InputDevice inputDevice)
{
var inputDevices = new List<InputDevice>();
InputDevices.GetDevices(inputDevices);
foreach (var device in inputDevices)
{
if (device.characteristics.HasFlag(InputDeviceCharacteristics.HeadMounted))
{
inputDevice = device;
return true;
}
}
inputDevice = new InputDevice();
return false;
}
#endregion
#region Unity
/// <summary>
/// Sets events to null in order to help remove unused references.
/// </summary>
protected override void OnDestroy()
{
base.OnDestroy();
DeviceConnected = null;
SensorsUpdating = null;
SensorsUpdated = null;
AvatarUpdating = null;
AvatarUpdated = null;
}
#endregion
#region Event Trigger Methods
/// <summary>
/// Event trigger for the <see cref="DeviceConnected" /> event. Can be used to override in child classes in order to
/// use the event without subscribing to the parent.
/// </summary>
/// <param name="e">Event parameters</param>
/// <remarks>Calling the base implementation is required in child classes in order for the event to propagate correctly.</remarks>
protected virtual void OnDeviceConnected(UxrDeviceConnectEventArgs e)
{
// Hide the avatar renderers in passthrough mode for mixed reality devices?
if (e.IsConnected && IsMixedRealityDevice && _hideAvatarInPassthrough)
{
Avatar.RenderMode = UxrAvatarRenderModes.None;
}
DeviceConnected?.Invoke(this, e);
}
/// <summary>
/// Event trigger for the <see cref="AvatarUpdating" /> event. Can be used to override in child classes in order to use
/// the event without subscribing to the parent.
/// </summary>
/// <param name="e">Event parameters</param>
/// <remarks>Calling the base implementation is required in child classes in order for the event to propagate correctly.</remarks>
protected virtual void OnAvatarUpdating()
{
AvatarUpdating?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Event trigger for the <see cref="AvatarUpdated" /> event. Can be used to override in child classes in order to use
/// the event without subscribing to the parent.
/// </summary>
/// <param name="e">Event parameters</param>
/// <remarks>Calling the base implementation is required in child classes in order for the event to propagate correctly.</remarks>
protected virtual void OnAvatarUpdated()
{
AvatarUpdated?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Event trigger for the <see cref="SensorsUpdating" /> event. Can be used to override in child classes in order to
/// use the event without subscribing to the parent.
/// </summary>
/// <param name="e">Event parameters</param>
/// <remarks>Calling the base implementation is required in child classes in order for the event to propagate correctly.</remarks>
protected virtual void OnSensorsUpdating()
{
SensorsUpdating?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Event trigger for the <see cref="SensorsUpdated" /> event. Can be used to override in child classes in order to use
/// the event without subscribing to the parent.
/// </summary>
/// <param name="e">Event parameters</param>
/// <remarks>Calling the base implementation is required in child classes in order for the event to propagate correctly.</remarks>
protected virtual void OnSensorsUpdated()
{
SensorsUpdated?.Invoke(this, EventArgs.Empty);
}
#endregion
#region Protected Methods
/// <summary>
/// Overriden in child classes to implement the update of the current sensor data.
/// </summary>
protected virtual void UpdateSensors()
{
}
/// <summary>
/// Overriden in child classes to implement the update of the avatar using the current sensor data.
/// </summary>
protected virtual void UpdateAvatar()
{
}
#endregion
}
}