13#if UNITY_2019_1_OR_NEWER
31 private const float DEFAULT_DEVICE_OFFSET_Y_AXIS = 0f;
32 private const float DEFAULT_DEVICE_OFFSET_Z_AXIS = 0.12f;
33 private const float DEFAULT_DEVICE_TILT_X_AXIS = 5f;
41 [Tooltip(
"Allow manual adjustment of the Leap device's virtual offset and tilt. These "
42 +
"settings can be used to match the physical position and orientation of the "
43 +
"Leap Motion sensor on a tracked device it is mounted on (such as a VR "
45 [SerializeField, OnEditorChange(
"deviceOffsetMode")]
48 get {
return _deviceOffsetMode; }
50 _deviceOffsetMode = value;
59 [Tooltip(
"Adjusts the Leap Motion device's virtual height offset from the tracked "
60 +
"headset position. This should match the vertical offset of the physical "
61 +
"device with respect to the headset in meters.")]
63 [Range(-0.50F, 0.50F)]
64 private float _deviceOffsetYAxis = DEFAULT_DEVICE_OFFSET_Y_AXIS;
66 get {
return _deviceOffsetYAxis; }
67 set { _deviceOffsetYAxis = value; }
70 [Tooltip(
"Adjusts the Leap Motion device's virtual depth offset from the tracked "
71 +
"headset position. This should match the forward offset of the physical "
72 +
"device with respect to the headset in meters.")]
74 [Range(-0.50F, 0.50F)]
75 private float _deviceOffsetZAxis = DEFAULT_DEVICE_OFFSET_Z_AXIS;
77 get {
return _deviceOffsetZAxis; }
78 set { _deviceOffsetZAxis = value; }
81 [Tooltip(
"Adjusts the Leap Motion device's virtual X axis tilt. This should match "
82 +
"the tilt of the physical device with respect to the headset in degrees.")]
84 [Range(-90.0F, 90.0F)]
85 private float _deviceTiltXAxis = DEFAULT_DEVICE_TILT_X_AXIS;
87 get {
return _deviceTiltXAxis; }
88 set { _deviceTiltXAxis = value; }
91 [Tooltip(
"Allows for the manual placement of the Leap Tracking Device." +
92 "This device offset mode is incompatible with Temporal Warping.")]
94 private Transform _deviceOrigin;
96 get {
return _deviceOrigin; }
97 set { _deviceOrigin = value; }
100 [Tooltip(
"This camera's PreCull time triggers pose data collection for "
101 +
"temporal warping. This needs to be set if the provider is not "
102 +
"on the same GameObject as the main Camera component.")]
104 private Camera _preCullCamera;
106 get {
return _preCullCamera; }
107 set { _preCullCamera = value; }
113 private const int DEFAULT_WARP_ADJUSTMENT = 17;
115 private const int DEFAULT_WARP_ADJUSTMENT = 45;
117 private const int DEFAULT_WARP_ADJUSTMENT = 17;
126 [Tooltip(
"Temporal warping prevents the hand coordinate system from 'swimming' or "
127 +
"'bouncing' when the headset moves and the user's hands stay still. "
128 +
"This phenomenon is caused by the differing amounts of latencies inherent "
129 +
"in the two systems. "
130 +
"For PC VR and Android VR, temporal warping should set to 'Auto', as the "
131 +
"correct value can be chosen automatically for these platforms. "
132 +
"Some non-standard platforms may use 'Manual' mode to adjust their "
133 +
"latency compensation amount for temporal warping. "
134 +
"Use 'Images' for scenarios that overlay Leap device images on tracked "
143 [Tooltip(
"The time in milliseconds between the current frame's headset position and "
144 +
"the time at which the Leap frame was captured.")]
146 private int _customWarpAdjustment = DEFAULT_WARP_ADJUSTMENT;
150 return _customWarpAdjustment;
152 return DEFAULT_WARP_ADJUSTMENT;
157 Debug.LogWarning(
"Setting custom warping adjustment amount, but the "
158 +
"temporal warping mode is not Manual, so the value will be "
161 _customWarpAdjustment = value;
167 [Tooltip(
"Pass updated transform matrices to hands with materials that utilize the "
168 +
"VertexOffsetShader. Won't have any effect on hands that don't take into "
169 +
"account shader-global vertex offsets in their material shaders.")]
182 #region Internal Memory
189 private Pose? _trackingBaseDeltaPose =
null;
191 private Camera _cachedCamera;
192 private Camera cachedCamera {
194 if (_cachedCamera ==
null) {
195 _cachedCamera = GetComponent<Camera>();
197 return _cachedCamera;
210 editTimePose = TestHandFactory.TestHandPose.HeadMountedB;
237 #if XR_LEGACY_INPUT_AVAILABLE
238 if (GetComponent<UnityEngine.SpatialTracking.TrackedPoseDriver>() ==
null) {
239 gameObject.AddComponent<
UnityEngine.SpatialTracking.TrackedPoseDriver>().UseRelativeTransform =
true;
243 #if UNITY_2019_1_OR_NEWER
244 if (GraphicsSettings.renderPipelineAsset !=
null) {
245 RenderPipelineManager.beginCameraRendering -= onBeginRendering;
246 RenderPipelineManager.beginCameraRendering += onBeginRendering;
260 #if UNITY_2019_1_OR_NEWER
261 if (GraphicsSettings.renderPipelineAsset !=
null) {
262 RenderPipelineManager.beginCameraRendering -= onBeginRendering;
273 _cachedCamera = GetComponent<Camera>();
274 if (_deviceOffsetMode ==
DeviceOffsetMode.Transform && _deviceOrigin ==
null) {
275 Debug.LogError(
"Cannot use the Transform device offset mode without " +
276 "specifying a Transform to use as the device origin.",
this);
282 Debug.LogError(
"Cannot perform temporal warping with no pre-cull camera.");
293 var projectionMatrix = _cachedCamera ==
null ? Matrix4x4.identity
294 : _cachedCamera.projectionMatrix;
295 switch (SystemInfo.graphicsDeviceType) {
296 #if !UNITY_2017_2_OR_NEWER
297 case UnityEngine.Rendering.GraphicsDeviceType.Direct3D9:
299 case UnityEngine.Rendering.GraphicsDeviceType.Direct3D11:
300 case UnityEngine.Rendering.GraphicsDeviceType.Direct3D12:
301 for (
int i = 0; i < 4; i++) {
302 projectionMatrix[1, i] = -projectionMatrix[1, i];
305 for (
int i = 0; i < 4; i++) {
306 projectionMatrix[2, i] = projectionMatrix[2, i] * 0.5f
307 + projectionMatrix[3, i] * 0.5f;
316 out pastPosition, out pastRotation);
319 var currCenterRotation = XRSupportUtil.GetXRNodeCenterEyeLocalRotation();
323 : currCenterRotation;
326 * imageReferenceRotation;
327 imageQuatWarp =
Quaternion.Euler(imageQuatWarp.eulerAngles.x,
328 imageQuatWarp.eulerAngles.y,
329 -imageQuatWarp.eulerAngles.z);
330 Matrix4x4 imageMatWarp = projectionMatrix
331 #if UNITY_2019_2_OR_NEWER
333 * Matrix4x4.TRS(
Vector3.zero, imageQuatWarp,
new Vector3(1f, -1f, 1f))
337 * projectionMatrix.inverse;
338 Shader.SetGlobalMatrix(
"_LeapGlobalWarpedOffset", imageMatWarp);
341 #if UNITY_2019_1_OR_NEWER
342 protected virtual void onBeginRendering(ScriptableRenderContext context, Camera camera) {
onPreCull(camera); }
345 protected virtual void onPreCull(Camera preCullingCamera) {
351 if (!Application.isPlaying) {
360 trackedPose =
new Pose(XRSupportUtil.GetXRNodeCenterEyeLocalPosition(),
361 XRSupportUtil.GetXRNodeCenterEyeLocalRotation());
366 if (!_trackingBaseDeltaPose.HasValue) {
367 _trackingBaseDeltaPose = _cachedCamera.transform.ToLocalPose()
371 trackedPose = _trackingBaseDeltaPose.Value * trackedPose;
377 Debug.LogError(
"Unsupported DeviceOffsetMode: " + _deviceOffsetMode);
388 #region LeapServiceProvider Overrides
398 (long)(Time.smoothDeltaTime *
S_TO_NS / Time.timeScale)
422 dest.CopyFrom(source).Transform(leapTransform);
427 #region Internal Methods
439 bool updateTemporalCompensation =
true) {
443 if (Application.isPlaying
444 && updateTemporalCompensation
449 - (_temporalWarpingMode ==
463 }
else if (!Application.isPlaying) {
468 currentPose = transform.ToLocalPose().Then(currentPose);
475 bool useCurrentPosition =
477 !Application.isPlaying;
482 if (Application.isPlaying) {
498 if (transform.parent !=
null
503 transform.lossyScale.ToVector() * 1e-3f
509 transform.lossyScale.ToVector() * 1e-3f
515 return leapTransform;
530 switch (camera.cameraType) {
531 case CameraType.Preview:
532#if UNITY_2017_1_OR_NEWER
533 case CameraType.Reflection:
535 case CameraType.SceneView:
539 if (Application.isPlaying
545 Hand leftHand =
null, rightHand =
null;
550 if (updateHand.
IsLeft && leftHand ==
null) {
551 leftHand = updateHand;
552 }
else if (updateHand.
IsRight && rightHand ==
null) {
553 rightHand = updateHand;
562 (leftHand !=
null ? leftHand.
Id : 0),
563 (rightHand !=
null ? rightHand.Id : 0),
565 out precullRightHand);
571 if (rightHand !=
null && rightValid) {
573 Matrix4x4.TRS(precullRightHand.
translation.ToVector3(),
574 precullRightHand.
rotation.ToQuaternion(),
576 * Matrix4x4.Inverse(Matrix4x4.TRS(rightHand.PalmPosition.ToVector3(),
577 rightHand.Rotation.ToQuaternion(),
580 if (leftHand !=
null && leftValid) {
582 Matrix4x4.TRS(precullLeftHand.
translation.ToVector3(),
583 precullLeftHand.
rotation.ToQuaternion(),
585 * Matrix4x4.Inverse(Matrix4x4.TRS(leftHand.
PalmPosition.ToVector3(),
The Controller class is your main interface to the Leap Motion Controller.
PolicyFlag
The supported controller policies.
void GetInterpolatedLeftRightTransform(Int64 time, Int64 sourceTime, int leftId, int rightId, out LeapTransform leftTransform, out LeapTransform rightTransform)
This is a special variant of GetInterpolatedFrameFromTime, for use with special features that only re...
long FrameTimestamp(int history=0)
Returns the timestamp of a recent tracking frame. Use the optional history parameter to specify how m...
long Now()
Returns a timestamp value as close as possible to the current time. Values are in microseconds,...
void ClearPolicy(PolicyFlag policy)
Requests clearing a policy.
void SetPolicy(PolicyFlag policy)
Requests setting a policy.
The Frame class represents a set of hand and finger tracking data detected in a single frame.
long Timestamp
The frame capture time in microseconds elapsed since an arbitrary point in time in the past.
List< Hand > Hands
The list of Hand objects detected in this frame, given in arbitrary order. The list can be empty if n...
The Hand class reports the physical characteristics of a detected hand.
bool IsLeft
Identifies whether this Hand is a left hand.
Vector PalmPosition
The center position of the palm.
int Id
A unique ID assigned to this Hand object, whose value remains the same across consecutive frames whil...
LeapQuaternion Rotation
The rotation of the hand as a quaternion.
bool IsRight
Identifies whether this Hand is a right hand.
TestHandPose editTimePose
The LeapServiceProvider provides tracked Leap Hand data and images from the device via the Leap servi...
SmoothedFloat _smoothedTrackingLatency
const double S_TO_NS
Converts seconds to nanoseconds.
Controller _leapController
override Frame CurrentFrame
const string HAND_ARRAY_GLOBAL_NAME
The transform array used for late-latching.
The LeapXRServiceProvider expands on the standard LeapServiceProvider to account for the offset of th...
DeviceOffsetMode deviceOffsetMode
virtual void onPreCull(Camera preCullingCamera)
override void transformFrame(Frame source, Frame dest)
Quaternion warpedRotation
bool _updateHandInPrecull
virtual LeapTransform GetWarpedMatrix(long timestamp, bool updateTemporalCompensation=true)
Matrix4x4[] _transformArray
void OnPreCullHandTransforms(Camera camera)
void resetShaderTransforms()
Resets shader globals for the Hand transforms.
override long CalculateInterpolationTime(bool endOfFrame=false)
bool manualUpdateHasBeenCalledSinceUpdate
TransformHistory transformHistory
void transformHands(ref LeapTransform LeftHand, ref LeapTransform RightHand)
override void initializeFlags()
Initializes the Leap Motion policy flags. The POLICY_OPTIMIZE_HMD flag improves tracking for head-mou...
Implements a resample-able transform history.
void SampleTransform(long timestamp, out Vector3 delayedPos, out Quaternion delayedRot)
RingBuffer< TransformData > history
void UpdateDelay(Pose curPose, long timestamp)
A position and rotation. You can multiply two poses; this acts like Matrix4x4 multiplication,...
static readonly Pose identity
The Vector struct represents a three-component mathematical vector or point such as a direction or po...
static readonly Vector Zero
The zero vector: (0, 0, 0)