ARPoseDriver.cs
5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.XR;
namespace UnityEngine.XR.ARFoundation
{
/// <summary>
/// The ARPoseDriver component applies the current Pose value of an AR device to the transform of the GameObject.
/// </summary>
[HelpURL(HelpUrls.ApiWithNamespace + nameof(ARPoseDriver) + ".html")]
public class ARPoseDriver : MonoBehaviour
{
internal struct NullablePose
{
internal Vector3? position;
internal Quaternion? rotation;
}
void OnEnable()
{
Application.onBeforeRender += OnBeforeRender;
#if UNITY_2020_1_OR_NEWER
List<InputDevice> devices = new List<InputDevice>();
InputDevices.GetDevicesWithCharacteristics(InputDeviceCharacteristics.TrackedDevice, devices);
foreach (var device in devices)
{
if (device.characteristics.HasFlag(InputDeviceCharacteristics.TrackedDevice))
{
CheckConnectedDevice(device, false);
}
}
InputDevices.deviceConnected += OnInputDeviceConnected;
#endif // UNITY_UNITY_2020_1_OR_NEWER
}
void OnDisable()
{
Application.onBeforeRender -= OnBeforeRender;
#if UNITY_2020_1_OR_NEWER
InputDevices.deviceConnected -= OnInputDeviceConnected;
#endif // UNITY_UNITY_2020_1_OR_NEWER
}
void Update() => PerformUpdate();
void OnBeforeRender() => PerformUpdate();
void PerformUpdate()
{
if (!enabled)
return;
var updatedPose = GetPoseData();
if (updatedPose.position.HasValue)
transform.localPosition = updatedPose.position.Value;
if (updatedPose.rotation.HasValue)
transform.localRotation = updatedPose.rotation.Value;
}
#if UNITY_2020_1_OR_NEWER
static internal InputDevice? s_InputTrackingDevice = null;
void OnInputDeviceConnected(InputDevice device) => CheckConnectedDevice(device);
void CheckConnectedDevice(InputDevice device, bool displayWarning = true)
{
var positionSuccess = false;
var rotationSuccess = false;
if (!(positionSuccess = device.TryGetFeatureValue(CommonUsages.centerEyePosition, out Vector3 position)))
positionSuccess = device.TryGetFeatureValue(CommonUsages.colorCameraPosition, out position);
if (!(rotationSuccess = device.TryGetFeatureValue(CommonUsages.centerEyeRotation, out Quaternion rotation)))
rotationSuccess = device.TryGetFeatureValue(CommonUsages.colorCameraRotation, out rotation);
if (positionSuccess && rotationSuccess)
{
if (s_InputTrackingDevice == null)
{
s_InputTrackingDevice = device;
}
else
{
Debug.LogWarning($"An input device {device.name} with the TrackedDevice characteristic was registered but the ARPoseDriver is already consuming data from {s_InputTrackingDevice.Value.name}.");
}
}
}
#else
static internal List<XR.XRNodeState> nodeStates = new List<XR.XRNodeState>();
#endif // UNITY_2020_1_OR_NEWER
static internal NullablePose GetPoseData()
{
NullablePose resultPose = new NullablePose();
#if UNITY_2020_1_OR_NEWER
if (s_InputTrackingDevice != null)
{
var pose = Pose.identity;
var positionSuccess = false;
var rotationSuccess = false;
if (!(positionSuccess = s_InputTrackingDevice.Value.TryGetFeatureValue(CommonUsages.centerEyePosition, out pose.position)))
positionSuccess = s_InputTrackingDevice.Value.TryGetFeatureValue(CommonUsages.colorCameraPosition, out pose.position);
if (!(rotationSuccess = s_InputTrackingDevice.Value.TryGetFeatureValue(CommonUsages.centerEyeRotation, out pose.rotation)))
rotationSuccess = s_InputTrackingDevice.Value.TryGetFeatureValue(CommonUsages.colorCameraRotation, out pose.rotation);
if (positionSuccess)
resultPose.position = pose.position;
if (rotationSuccess)
resultPose.rotation = pose.rotation;
if (positionSuccess || rotationSuccess)
return resultPose;
}
#else
XR.InputTracking.GetNodeStates(nodeStates);
foreach (var nodeState in nodeStates)
{
if (nodeState.nodeType == XR.XRNode.CenterEye)
{
var pose = Pose.identity;
var positionSuccess = nodeState.TryGetPosition(out pose.position);
var rotationSuccess = nodeState.TryGetRotation(out pose.rotation);
if (positionSuccess)
resultPose.position = pose.position;
if (rotationSuccess)
resultPose.rotation = pose.rotation;
return resultPose;
}
}
#endif // UNITY_2020_1_OR_NEWER
return resultPose;
}
}
}