Tanoda
LeapEyeDislocator.cs
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) Ultraleap, Inc. 2011-2020. *
3 * *
4 * Use subject to the terms of the Apache License 2.0 available at *
5 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
6 * between Ultraleap and you, your company or other organization. *
7 ******************************************************************************/
8
9using UnityEngine;
10
11namespace Leap.Unity {
12 using Attributes;
13
18 [RequireComponent(typeof(LeapXRServiceProvider))]
19 public class LeapEyeDislocator : MonoBehaviour {
20
21 [SerializeField]
22 private bool _useCustomBaseline = false;
23
24 [MinValue(0), Units("MM"), InspectorName("Baseline")]
25 [SerializeField]
26 private float _customBaselineValue = 64;
27
28 [SerializeField]
29 private bool _showEyePositions = false;
30
31 private LeapServiceProvider _provider;
32 private Maybe<float> _deviceBaseline = Maybe.None;
33 private bool _hasVisitedPreCull = false;
34
35 private Camera _cachedCamera;
36 private Camera _camera {
37 get {
38 if (_cachedCamera == null) {
39 _cachedCamera = GetComponent<Camera>();
40 }
41 return _cachedCamera;
42 }
43 }
44
45 private void onDevice(Device device) {
46 _deviceBaseline = Maybe.Some(device.Baseline);
47 }
48
49 private void OnEnable() {
50 _provider = GetComponent<LeapServiceProvider>();
51 if (_provider == null) {
52 _provider = GetComponentInChildren<LeapServiceProvider>();
53 if (_provider == null) {
54 enabled = false;
55 return;
56 }
57 }
58
59 _provider.OnDeviceSafe += onDevice;
60 }
61
62 private void OnDisable() {
63 _camera.ResetStereoViewMatrices();
64
65 _provider.OnDeviceSafe -= onDevice;
66 }
67
68 private void Update() {
69 _camera.ResetStereoViewMatrices();
70 _hasVisitedPreCull = false;
71 }
72
73 private void OnPreCull() {
74 if (_hasVisitedPreCull) {
75 return;
76 }
77 _hasVisitedPreCull = true;
78
79 Maybe<float> baselineToUse = Maybe.None;
80 if (_useCustomBaseline) {
81 baselineToUse = Maybe.Some(_customBaselineValue);
82 } else {
83 baselineToUse = _deviceBaseline;
84 }
85
86 float baselineValue;
87 if (baselineToUse.TryGetValue(out baselineValue)) {
88 baselineValue *= 1e-3f;
89
90 Matrix4x4 leftMat = _camera.GetStereoViewMatrix(Camera.StereoscopicEye.Left);
91 Matrix4x4 rightMat = _camera.GetStereoViewMatrix(Camera.StereoscopicEye.Right);
92
93 Vector3 leftPos = leftMat.inverse.MultiplyPoint3x4(Vector3.zero);
94 Vector3 rightPos = rightMat.inverse.MultiplyPoint3x4(Vector3.zero);
95 float existingBaseline = Vector3.Distance(leftPos, rightPos);
96
97 float baselineAdjust = baselineValue - existingBaseline;
98
99 adjustViewMatrix(Camera.StereoscopicEye.Left, baselineAdjust);
100 adjustViewMatrix(Camera.StereoscopicEye.Right, baselineAdjust);
101 }
102 }
103
104 private void adjustViewMatrix(Camera.StereoscopicEye eye, float baselineAdjust) {
105 float eyeOffset = eye == Camera.StereoscopicEye.Left ? 1 : -1;
106 Vector3 ipdOffset = eyeOffset * Vector3.right * baselineAdjust * 0.5f;
107 Vector3 providerForwardOffset = Vector3.zero,
108 providerVerticalOffset = Vector3.zero;
109 Quaternion providerRotation = Quaternion.Euler(0f, 180f, 0f);
110 if (_provider is LeapXRServiceProvider) {
111 LeapXRServiceProvider _xrProvider = _provider as LeapXRServiceProvider;
112 providerForwardOffset = Vector3.forward * _xrProvider.deviceOffsetZAxis;
113 providerVerticalOffset = -Vector3.up * _xrProvider.deviceOffsetYAxis;
114 providerRotation = Quaternion.AngleAxis(_xrProvider.deviceTiltXAxis, Vector3.right);
115 } else {
116 Matrix4x4 imageMatWarp = _camera.projectionMatrix
117 * Matrix4x4.TRS(Vector3.zero, providerRotation, Vector3.one)
118 * _camera.projectionMatrix.inverse;
119 Shader.SetGlobalMatrix("_LeapGlobalWarpedOffset", imageMatWarp);
120 }
121
122 var existingMatrix = _camera.GetStereoViewMatrix(eye);
123 _camera.SetStereoViewMatrix(eye, Matrix4x4.TRS(Vector3.zero, providerRotation, Vector3.one) *
124 Matrix4x4.Translate(providerForwardOffset + ipdOffset) *
125 Matrix4x4.Translate(providerVerticalOffset) *
126 existingMatrix);
127 }
128
129 private void OnDrawGizmos() {
130 if (_showEyePositions && Application.isPlaying) {
131 Matrix4x4 leftMat = _camera.GetStereoViewMatrix(Camera.StereoscopicEye.Left);
132 Matrix4x4 rightMat = _camera.GetStereoViewMatrix(Camera.StereoscopicEye.Right);
133
134 Vector3 leftPos = leftMat.inverse.MultiplyPoint3x4(Vector3.zero);
135 Vector3 rightPos = rightMat.inverse.MultiplyPoint3x4(Vector3.zero);
136
137 Gizmos.color = Color.white;
138 Gizmos.DrawSphere(leftPos, 0.02f);
139 Gizmos.DrawSphere(rightPos, 0.02f);
140
141 Gizmos.color = Color.blue;
142 Gizmos.DrawLine(leftPos, rightPos);
143 }
144 }
145 }
146}
UnityEngine.Color Color
Definition: TestScript.cs:32
The Device class represents a physically connected device.
Definition: Device.cs:29
float Baseline
The distance in mm between the center points of the stereo sensors.
Definition: Device.cs:188
Moves the camera to each eye position on pre-render. Only necessary for image pass-through (IR viewer...
The LeapServiceProvider provides tracked Leap Hand data and images from the device via the Leap servi...
Action< Device > OnDeviceSafe
A utility event to get a callback whenever a new device is connected to the service....
The LeapXRServiceProvider expands on the standard LeapServiceProvider to account for the offset of th...
static readonly NoneType None
Definition: Maybe.cs:15
static Maybe< T > Some(T t)
Constructs a Maybe given a specific value. This value needs to always be non-null if the type is a re...
Definition: Maybe.cs:104
bool TryGetValue(out T t)
If this Maybe has a value, the out argument is filled with that value and this method returns true,...
Definition: Maybe.cs:116