using UnityEngine; namespace Passer.Humanoid { using Passer.Tracking; [System.Serializable] public class UnityXRHand : ArmController { #if pUNITYXR public override string name => "Unity XR"; protected UnityXRTracker unityXR => humanoid.unityXR; #region Manage public override void CheckSensor(HandTarget handTarget) { #if pUNITYXR if (this.handTarget == null) this.target = handTarget; if (this.handTarget == null) return; if (unityXR.trackerComponent == null && enabled) unityXR.CheckTracker(handTarget.humanoid); if (enabled && unityXR.trackerComponent != null && unityXR.trackerComponent.enabled) { if (controller == null) { Vector3 position = handTarget.transform.TransformPoint(handTarget.isLeft ? -0.1F : 0.1F, -0.05F, 0.04F); Quaternion localRotation = handTarget.isLeft ? Quaternion.Euler(180, 90, 90) : Quaternion.Euler(180, -90, -90); Quaternion rotation = handTarget.transform.rotation * localRotation; #if hSTEAMVR if (UnityXRDevice.xrDevice == UnityXRDevice.XRDeviceType.OpenVR) { SteamVR steamVR = unityXR.trackerComponent as SteamVR; controller = steamVR.GetController(handTarget.isLeft, position, rotation); } else #endif { UnityXR unityXRcomponent = unityXR.trackerComponent as UnityXR; controller = unityXRcomponent.GetController(handTarget.isLeft, position, rotation); } } if (controller != null) sensorTransform = controller.transform; if (!Application.isPlaying) SetSensor2Target(); } else { #if UNITY_EDITOR if (!Application.isPlaying) { if (controller != null) Object.DestroyImmediate(controller.gameObject, true); } #endif controller = null; sensorTransform = null; } #endif } #endregion Manage #region Init public override void Start(HumanoidControl _humanoid, Transform targetTransform) { base.Start(_humanoid, targetTransform); tracker = handTarget.humanoid.unityXR; if (tracker == null || tracker.enabled == false) return; Vector3 position = handTarget.transform.TransformPoint(handTarget.isLeft ? -0.1F : 0.1F, -0.05F, 0.04F); Quaternion localRotation = handTarget.isLeft ? Quaternion.Euler(180, 90, 90) : Quaternion.Euler(180, -90, -90); Quaternion rotation = handTarget.transform.rotation * localRotation; UnityXR unityXRcomponent = unityXR.trackerComponent as UnityXR; if (unityXRcomponent != null) controller = unityXRcomponent.GetController(handTarget.isLeft, position, rotation); if (controller != null) { controller.show = handTarget.humanoid.showRealObjects && handTarget.showRealObjects; sensorTransform = controller.transform; } SetSensor2Target(); #if UNITY_ANDROID && hOCHAND if (unityXR.oculusHandTracking) handSkeleton = OculusHandSkeleton.Get(unityXR.trackerComponent.transform, handTarget.isLeft); #endif #if hVIVEHAND if (unityXR.viveHandTracking) handSkeleton = ViveHandSkeleton.Get(unityXR.trackerComponent.transform, handTarget.isLeft); #endif } #endregion Init #region Update public override void Update() { status = Tracker.Status.Unavailable; if (tracker == null || tracker.enabled == false || !enabled) return; if (controller != null) { controller.UpdateComponent(); UpdateInput(); } if (handSkeleton != null) { handSkeleton.show = humanoid.showSkeletons; handSkeleton.UpdateComponent(); } if (controller != null && controller.status == Tracker.Status.Tracking) UpdateTarget(handTarget.hand.target, controller); else if (handSkeleton != null && handSkeleton.status == Tracker.Status.Tracking) UpdateHandFromSkeleton(); } #region Controller private void UpdateInput() { if (controllerInput == null) return; if (handTarget.isLeft) UpdateInputSide(controllerInput.left); else UpdateInputSide(controllerInput.right); } private void UpdateInputSide(ControllerSide controllerInputSide) { if (controllerInputSide == null || controller == null) return; controllerInputSide.stickHorizontal += controller.primaryAxis.x; controllerInputSide.stickVertical += controller.primaryAxis.y; controllerInputSide.stickButton |= (controller.primaryAxis.z > 0.5F); controllerInputSide.stickTouch |= (controller.primaryAxis.z > -0.5F); controllerInputSide.touchpadHorizontal += controller.secondaryAxis.x; controllerInputSide.touchpadVertical += controller.secondaryAxis.y; controllerInputSide.touchpadPress |= (controller.secondaryAxis.z > 0.5F); controllerInputSide.touchpadTouch |= (controller.secondaryAxis.z > -0.5F); controllerInputSide.buttons[0] |= (controller.button1 > 0.5F); controllerInputSide.buttons[1] |= (controller.button2 > 0.5F); controllerInputSide.trigger1 += controller.trigger1; controllerInputSide.trigger2 += controller.trigger2; controllerInputSide.option |= controller.option > 0; } // arm model for 3DOF tracking: position is calculated from rotation static public Vector3 CalculateHandPosition(HandTarget handTarget, Vector3 sensor2TargetPosition) { Quaternion hipsYRotation = Quaternion.AngleAxis(handTarget.humanoid.hipsTarget.transform.eulerAngles.y, handTarget.humanoid.up); Vector3 pivotPoint = handTarget.humanoid.hipsTarget.transform.position + hipsYRotation * (handTarget.isLeft ? new Vector3(-0.25F, 0.15F, -0.05F) : new Vector3(0.25F, 0.15F, -0.05F)); Quaternion forearmRotation = handTarget.hand.target.transform.rotation * (handTarget.isLeft ? Quaternion.Euler(0, -90, 0) : Quaternion.Euler(0, 90, 0)); Vector3 localForearmDirection = handTarget.humanoid.hipsTarget.transform.InverseTransformDirection(forearmRotation * Vector3.forward); if (localForearmDirection.x < 0 || localForearmDirection.y > 0) { pivotPoint += hipsYRotation * Vector3.forward * Mathf.Lerp(0, 0.15F, -localForearmDirection.x * 3 + localForearmDirection.y); } if (localForearmDirection.y > 0) { pivotPoint += hipsYRotation * Vector3.up * Mathf.Lerp(0, 0.2F, localForearmDirection.y); } if (localForearmDirection.z < 0.2F) { localForearmDirection = new Vector3(localForearmDirection.x, localForearmDirection.y, 0.2F); forearmRotation = Quaternion.LookRotation(handTarget.humanoid.hipsTarget.transform.TransformDirection(localForearmDirection), forearmRotation * Vector3.up); } handTarget.hand.target.transform.position = pivotPoint + forearmRotation * Vector3.forward * handTarget.forearm.bone.length; Vector3 handPosition = handTarget.hand.target.transform.TransformPoint(-sensor2TargetPosition); return handPosition; } #endregion Controller #region Skeleton protected override void UpdateHandFromSkeleton() { Transform wristBone = handSkeleton.GetWristBone(); handTarget.hand.target.transform.position = wristBone.transform.position; if (handTarget.isLeft) handTarget.hand.target.transform.rotation = wristBone.transform.rotation * Quaternion.Euler(180, 180, 0); else handTarget.hand.target.transform.rotation = wristBone.transform.rotation * Quaternion.Euler(0, 180, 0); UpdateThumbFromSkeleton(); UpdateIndexFingerFromSkeleton(); UpdateMiddleFingerFromSkeleton(); UpdateRingFingerFromSkeleton(); UpdateLittleFingerFromSkeleton(); } protected override void UpdateFingerBoneFromSkeleton(Transform targetTransform, Tracking.Finger finger, Tracking.FingerBone fingerBone) { if (handSkeleton == null) return; Transform thisBoneTransform = handSkeleton.GetBone(finger, fingerBone); if (thisBoneTransform == null) { Debug.Log(finger + " " + fingerBone + " " + thisBoneTransform); return; } Transform nextBoneTransform = handSkeleton.GetBone(finger, fingerBone + 1); if (thisBoneTransform == null || nextBoneTransform == null) return; Vector3 direction = nextBoneTransform.position - thisBoneTransform.position; if (handTarget.isLeft) targetTransform.rotation = Quaternion.LookRotation(direction, handTarget.hand.target.transform.forward) * Quaternion.Euler(-90, 0, 90); else targetTransform.rotation = Quaternion.LookRotation(direction, handTarget.hand.target.transform.forward) * Quaternion.Euler(-90, 0, -90); } #endregion #endregion #endif } }