Files
WhaleAdventure_VR/Assets/XRI Starter Kit/Assets/Features/Hand Poser/Scripts/HandReference.cs
2026-06-19 18:16:40 +09:00

100 lines
3.9 KiB
C#

using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
using UnityEngine.XR.Interaction.Toolkit.Interactors;
namespace MikeNspired.XRIStarterKit
{
public class HandReference : MonoBehaviour
{
[field: SerializeField] public HandAnimator Hand { get; private set; }
[field: SerializeField] public LeftRight LeftRight { get; private set; }
[field: SerializeField] public HandReference OtherHand { get; private set; }
[field: SerializeField] public NearFarInteractor NearFarInteractor { get; private set; }
private Transform handModelAttach; // Extra transform match hand model attach transform
private Transform attachTransform;
private Vector3 originalLocalPos;
private Quaternion originalLocalRot;
private HandPoser currentHandPoser;
private void OnValidate()
{
if (!Hand)
Hand = GetComponentInChildren<HandAnimator>();
if (!NearFarInteractor)
NearFarInteractor = GetComponent<NearFarInteractor>();
}
private void Awake()
{
NearFarInteractor.selectEntered.AddListener(OnGrab);
NearFarInteractor.selectExited.AddListener(_ => ResetAttachTransform());
attachTransform = NearFarInteractor.attachTransform;
originalLocalPos = attachTransform.localPosition;
originalLocalRot = attachTransform.localRotation;
// Create the dummy transform parented under the hand model
handModelAttach = new GameObject("HandModelAttach" + name).transform;
handModelAttach.SetParent(Hand.transform, false);
handModelAttach.localPosition = Vector3.zero;
handModelAttach.localRotation = Quaternion.identity;
}
private void OnGrab(SelectEnterEventArgs args)
{
// Skip if far interaction
if (NearFarInteractor.interactionAttachController.hasOffset)
return;
FindHandPoser(args);
if (!currentHandPoser)
return;
var interactableAttach = LeftRight == LeftRight.Left
? currentHandPoser.leftHandAttach
: currentHandPoser.rightHandAttach;
Vector3 finalPosition = interactableAttach.localPosition * -1;
Quaternion finalRotation = Quaternion.Inverse(interactableAttach.localRotation);
finalPosition = RotatePointAroundPivot(finalPosition, Vector3.zero, finalRotation.eulerAngles);
handModelAttach.localPosition = finalPosition;
handModelAttach.localRotation = finalRotation;
// We read out its *world* position/rotation, and apply that to the XR attach transform:
attachTransform.position = handModelAttach.position;
attachTransform.rotation = handModelAttach.rotation;
}
private void FindHandPoser(SelectEnterEventArgs args)
{
Transform interactableTransform = args.interactableObject.transform;
currentHandPoser =
interactableTransform.GetComponent<XRHandPoser>() ??
interactableTransform.GetComponentInChildren<XRHandPoser>(true) ??
interactableTransform.GetComponentInParent<XRHandPoser>();
if (!currentHandPoser && interactableTransform.parent)
currentHandPoser = interactableTransform.parent.GetComponentInChildren<XRHandPoser>(true);
}
public void ResetAttachTransform()
{
attachTransform.localPosition = originalLocalPos;
attachTransform.localRotation = originalLocalRot;
}
private static Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles)
{
var direction = point - pivot;
direction = Quaternion.Euler(angles) * direction;
return direction + pivot;
}
}
}