Tanoda
Cursor3D.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;
10using Leap.Unity;
11using Leap;
12using System.Collections;
13
14namespace Leap.Unity.InputModule {
15 public class Cursor3D : MonoBehaviour {
16 [Tooltip("The current Leap Data Provider for the scene.")]
18 [Tooltip("The diameter of the visual sphere cursor.")]
19 public float RenderSphereDiameter = 0.1f;
20 [Tooltip("The diameter of the collider that checks for pinchable objects.")]
21 public float CollisionSphereDiameter = 0.1f;
22 [Tooltip("The amount of motion amplification for cursor movement.")]
23 public float MotionScalingFactor = 6f;
24 [Tooltip("The amount that the cursor is lerped to its previous position per frame.")]
25 public float CursorSmoothingFactor = 0.2f;
26
27 [Tooltip("The springiness of the spring joint.")]
28 public float Spring = 500.0f;
29 [Tooltip("The dampening of the spring joint.")]
30 public float Damper = 10.5f;
31 [Tooltip("The drag applied to the object while it is being dragged.")]
32 public float Drag = 10.0f;
33 [Tooltip("The angular drag applied to the object while it is being dragged.")]
34 public float AngularDrag = 5.0f;
35 [Tooltip("The amount of dead-zone in the spring joint.")]
36 public float Distance = 0f;
37
38 private Quaternion CurrentRotation;
39
40 #pragma warning disable 0649
41 [SerializeField]
42 private Mesh _sphereMesh;
43 [SerializeField]
44 private Material _sphereMaterial;
45 #pragma warning restore 0649
46
47 private GameObject[] Cursors;
48 private SpringJoint[,] SpringJoints;
49 private bool[] prevPinching;
50
51 // Use this for initialization
52 void Start() {
53 if (LeapDataProvider == null) {
54 LeapDataProvider = FindObjectOfType<LeapProvider>();
55 if (LeapDataProvider == null || !LeapDataProvider.isActiveAndEnabled) {
56 Debug.LogError("Cannot use LeapImageRetriever if there is no LeapProvider!");
57 enabled = false;
58 return;
59 }
60 }
61
62 Cursors = new GameObject[2];
63
64 for (int i = 0; i < Cursors.Length; i++) {
65 Cursors[i] = new GameObject("Cursor " + i);
66 Cursors[i].AddComponent<MeshFilter>().mesh = _sphereMesh;
67 Cursors[i].AddComponent<MeshRenderer>().sharedMaterial = _sphereMaterial;
68 Cursors[i].AddComponent<Rigidbody>().isKinematic = true;
69 Cursors[i].transform.parent = transform;
70 Cursors[i].transform.localScale = Vector3.one * RenderSphereDiameter;
71 }
72
73 prevPinching = new bool[2];
74 SpringJoints = new SpringJoint[2, 10];
75 }
76
77 //Update the Head Yaw for Calculating "Shoulder Positions"
78 void Update() {
79 Frame curFrame = LeapDataProvider.CurrentFrame.TransformedCopy(LeapTransform.Identity);
80
81
82
83 Quaternion HeadYaw = Quaternion.Euler(0f, XRSupportUtil.GetXRNodeHeadLocalRotation().eulerAngles.y, 0f);
84 CurrentRotation = Quaternion.Slerp(CurrentRotation, HeadYaw, 0.1f);
85
86 for (int whichHand = 0; whichHand < 2; whichHand++) {
87 if (whichHand > curFrame.Hands.Count - 1) {
88 if (Cursors[whichHand].activeInHierarchy) {
89 Cursors[whichHand].SetActive(false);
90 }
91 continue;
92 } else {
93 if (!Cursors[whichHand].activeInHierarchy) {
94 Cursors[whichHand].SetActive(true);
95 }
96 }
97
98 Vector3 ProjectionOrigin = Vector3.zero;
99 switch (curFrame.Hands[whichHand].IsRight) {
100 case true:
101 ProjectionOrigin = XRSupportUtil.GetXRNodeHeadLocalPosition() + CurrentRotation * new Vector3(0.15f, -0.13f, 0.1f);
102 break;
103 case false:
104 ProjectionOrigin = XRSupportUtil.GetXRNodeHeadLocalPosition() + CurrentRotation * new Vector3(-0.15f, -0.13f, 0.1f);
105 break;
106 }
107
108 Vector3 Offset = curFrame.Hands[whichHand].Fingers[1].Bone(Bone.BoneType.TYPE_METACARPAL).Center.ToVector3() - ProjectionOrigin;
109
110 Cursors[whichHand].transform.position = Vector3.Lerp(Cursors[whichHand].transform.position, ProjectionOrigin + (Offset * MotionScalingFactor), CursorSmoothingFactor);
111
112 if (curFrame.Hands[whichHand].PinchDistance < 30f) {
113 if (!prevPinching[whichHand]) {
114 prevPinching[whichHand] = true;
115 Cursors[whichHand].GetComponent<MeshRenderer>().material.color = Color.green;
116
117 Collider[] Colliders = Physics.OverlapSphere(Cursors[whichHand].transform.position, CollisionSphereDiameter);
118
119 for (int i = 0; i < Mathf.Min(10, Colliders.Length); i++) {
120 // We need to hit a rigidbody that is not kinematic
121 if (!Colliders[i].attachedRigidbody || Colliders[i].attachedRigidbody.isKinematic) {
122 return;
123 }
124
125 if (!SpringJoints[whichHand, i]) {
126 SpringJoints[whichHand, i] = Cursors[whichHand].AddComponent<SpringJoint>();
127 Cursors[whichHand].GetComponent<Rigidbody>().isKinematic = true;
128 }
129
130 SpringJoints[whichHand, i].transform.position = Cursors[whichHand].transform.position;
131 SpringJoints[whichHand, i].anchor = Vector3.zero;
132
133 SpringJoints[whichHand, i].spring = Spring;
134 SpringJoints[whichHand, i].damper = Damper;
135 SpringJoints[whichHand, i].maxDistance = Distance;
136 SpringJoints[whichHand, i].connectedBody = Colliders[i].attachedRigidbody;
137
138 StartCoroutine(DragObject(whichHand, i));
139 }
140 }
141 } else if (curFrame.Hands[whichHand].PinchDistance > 40f) {
142 if (prevPinching[whichHand]) {
143 prevPinching[whichHand] = false;
144 Cursors[whichHand].GetComponent<MeshRenderer>().material.color = Color.white;
145
146 //constraint breaks implicitly when prevPinching is set to false
147 }
148 }
149 }
150 }
151
152 private IEnumerator DragObject(int whichHand, int i) {
153 float oldDrag = SpringJoints[whichHand, i].connectedBody.drag;
154 float oldAngularDrag = SpringJoints[whichHand, i].connectedBody.angularDrag;
155 SpringJoints[whichHand, i].connectedBody.drag = Drag;
156 SpringJoints[whichHand, i].connectedBody.angularDrag = AngularDrag;
157
158 while (prevPinching[whichHand]) {
159 SpringJoints[whichHand, i].transform.position = Cursors[whichHand].transform.position;
160 yield return null;
161 }
162
163 if (SpringJoints[whichHand, i].connectedBody) {
164 SpringJoints[whichHand, i].connectedBody.drag = oldDrag;
165 SpringJoints[whichHand, i].connectedBody.angularDrag = oldAngularDrag;
166 SpringJoints[whichHand, i].connectedBody = null;
167 Destroy(SpringJoints[whichHand, i]);
168 }
169 }
170 }
171}
UnityEngine.Debug Debug
Definition: TanodaServer.cs:19
UnityEngine.Color Color
Definition: TestScript.cs:32
The Bone class represents a tracked bone.
Definition: Bone.cs:26
BoneType
Enumerates the type of bones.
Definition: Bone.cs:168
The Frame class represents a set of hand and finger tracking data detected in a single frame.
Definition: Frame.cs:24
List< Hand > Hands
The list of Hand objects detected in this frame, given in arbitrary order. The list can be empty if n...
Definition: Frame.cs:156
Provides Frame object data to the Unity application by firing events as soon as Frame data is availab...
Definition: LeapProvider.cs:21
abstract Frame CurrentFrame
The current frame for this update cycle, in world space.
Definition: LeapProvider.cs:37
The LeapTransform class represents a transform in three dimensional space.
static readonly LeapTransform Identity
The identity transform.