mixedreality/com.microsoft.mixedreality..../SDK/Features/UX/Scripts/PulseShader/PulseShaderHandMeshHandler.cs

222 lines
7.3 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Input;
using Microsoft.MixedReality.Toolkit.Utilities;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.UI.PulseShader
{
/// <summary>
/// Script for triggering the pulse shader effect on HoloLens 2 hand mesh.
/// </summary>
public class PulseShaderHandMeshHandler : PulseShaderHandler, IMixedRealityPointerHandler
{
[Space]
[SerializeField]
[Tooltip("Trigger the pulse shader visual if the palm of the left or right hand is facing the camera.")]
private bool pulseOnLookAtPalms = false;
/// <summary>
/// Trigger the pulse shader visual if the palm of the left or right hand is facing the camera.
/// </summary>
public bool PulseOnLookAtPalms
{
get => pulseOnLookAtPalms;
set => pulseOnLookAtPalms = value;
}
[SerializeField]
[Tooltip("Trigger the pulse shader visual if the hand is in the pinch/select gesture. ")]
private bool pulseFingerTipsOnPinch = false;
/// <summary>
/// Trigger the pulse shader visual if the hand is in the pinch/select gesture.
/// </summary>
public bool PulseFingerTipsOnPinch
{
get => pulseFingerTipsOnPinch;
set => pulseFingerTipsOnPinch = value;
}
[SerializeField]
[Tooltip("Trigger the pulse shader visual once if the left or right hand enters the frame and is tracked.")]
private bool pulseOnHandDetected = true;
/// <summary>
/// Trigger the pulse shader visual once if the left or right hand enters the frame and is tracked.
/// </summary>
public bool PulseOnHandDetected
{
get => pulseOnHandDetected;
set => pulseOnHandDetected = value;
}
[SerializeField]
[Tooltip("The length of time required for the palm to face the camera before the pulse shader visual is triggered. ")]
private float palmFacingTime = 0.25f;
/// <summary>
/// The length of time required for the palm to face the camera before the pulse shader visual is triggered.
/// </summary>
public float PalmFacingTime
{
get => palmFacingTime;
set => palmFacingTime = value;
}
[SerializeField]
[Tooltip("The local origin of the palms.")]
private Vector3 pulseOriginPalms = new Vector3(0.5f, 0.5f, 0);
/// <summary>
/// The local origin of the palms.
/// </summary>
public Vector3 PulseOriginPalms
{
get => pulseOriginPalms;
set => pulseOriginPalms = value;
}
[SerializeField]
[Tooltip("The local origin of the pulse shader visual for the finger tips. ")]
private Vector3 pulseOriginFingertips = new Vector3(0, 1f, 0);
/// <summary>
/// The local origin of the pulse shader visual for the finger tips.
/// </summary>
public Vector3 PulseOriginFingertips
{
get => pulseOriginFingertips;
set => pulseOriginFingertips = value;
}
private bool pulseTriggeredLeft = false;
private bool pulseTriggeredRight = false;
private float palmFacingTimer = 0;
protected override void Start()
{
base.Start();
CoreServices.InputSystem?.RegisterHandler<IMixedRealityPointerHandler>(this);
}
protected override void OnDestroy()
{
base.OnDestroy();
CoreServices.InputSystem?.UnregisterHandler<IMixedRealityPointerHandler>(this);
}
protected override void Update()
{
if (PulseOnLookAtPalms)
{
if (IsAPalmFacingCamera())
{
if (palmFacingTimer >= 0)
{
palmFacingTimer += Time.deltaTime;
if (palmFacingTimer > PalmFacingTime)
{
PulsePalms();
palmFacingTimer = -1;
}
}
}
else
{
palmFacingTimer = 0;
}
}
if (PulseOnHandDetected)
{
// If joints are detected then an articulated hand is present
bool isLeftHandDetected = HandJointUtils.TryGetJointPose(TrackedHandJoint.Palm, Handedness.Left, out MixedRealityPose leftPose);
bool isRightHandDetected = HandJointUtils.TryGetJointPose(TrackedHandJoint.Palm, Handedness.Right, out MixedRealityPose rightPose);
TriggerPulseOnHandDetected(isLeftHandDetected, isRightHandDetected);
}
}
private void TriggerPulseOnHandDetected(bool isLeftHandDetected, bool isRightHandDetected)
{
// Left Hand
if (isLeftHandDetected && !pulseTriggeredLeft)
{
pulseTriggeredLeft = true;
PulsePalms();
}
else if (!isLeftHandDetected && pulseTriggeredLeft)
{
pulseTriggeredLeft = false;
}
// Right Hand
if (isRightHandDetected && !pulseTriggeredRight)
{
pulseTriggeredRight = true;
PulsePalms();
}
else if (!isRightHandDetected && pulseTriggeredRight)
{
pulseTriggeredRight = false;
}
}
/// <summary>
/// Set the local origin of the pulse shader visual to the palms and trigger the animation.
/// </summary>
public void PulsePalms()
{
SetLocalOrigin(PulseOriginPalms);
PulseOnce();
}
/// <summary>
/// Set the local origin of the pulse shader visual to the finger tips and trigger the animation.
/// </summary>
public void PulseFingerTips()
{
SetLocalOrigin(PulseOriginFingertips);
PulseOnce();
}
// Check if the palm is facing the camera
private bool IsAPalmFacingCamera()
{
foreach (IMixedRealityController controller in CoreServices.InputSystem.DetectedControllers)
{
if (controller.ControllerHandedness.IsMatch(Handedness.Both)
&& controller is IMixedRealityHand jointedHand
&& jointedHand.TryGetJoint(TrackedHandJoint.Palm, out MixedRealityPose palmPose)
&& Vector3.Dot(palmPose.Up, CameraCache.Main.transform.forward) > 0.0f)
{
return true;
}
}
return false;
}
#region Pointer Handler
public void OnPointerDown(MixedRealityPointerEventData eventData)
{
if (PulseFingerTipsOnPinch)
{
PulseFingerTips();
}
}
public void OnPointerDragged(MixedRealityPointerEventData eventData) { }
public void OnPointerUp(MixedRealityPointerEventData eventData) { }
public void OnPointerClicked(MixedRealityPointerEventData eventData) { }
#endregion
}
}