10using System.Collections;
11using System.Collections.Generic;
17 private const int TOTAL_JOINT_COUNT = 4 * 5;
18 private const float CYLINDER_MESH_RESOLUTION = 0.1f;
22 private static int _leftColorIndex = 0;
23 private static int _rightColorIndex = 0;
24 private static Color[] _leftColorList = {
new Color(0.0f, 0.0f, 1.0f),
new Color(0.2f, 0.0f, 0.4f),
new Color(0.0f, 0.2f, 0.2f) };
25 private static Color[] _rightColorList = {
new Color(1.0f, 0.0f, 0.0f),
new Color(1.0f, 1.0f, 0.0f),
new Color(1.0f, 0.5f, 0.0f) };
27 #pragma warning disable 0649
32 private bool _showArm =
true;
35 private bool _castShadows =
true;
38 private Material _material;
39 private Material _backing_material;
42 private Mesh _sphereMesh;
44 private Mesh _cylinderMesh;
48 private int _cylinderResolution = 12;
52 private float _jointRadius = 0.008f;
56 private float _cylinderRadius = 0.006f;
60 private float _palmRadius = 0.015f;
61 #pragma warning restore 0649
63 private Material _sphereMat;
65 private Vector3[] _spherePositions;
66 private Matrix4x4[] _sphereMatrices =
new Matrix4x4[32],
67 _cylinderMatrices =
new Matrix4x4[32];
68 private int _curSphereIndex = 0, _curCylinderIndex = 0;
96 if (_material !=
null && (_backing_material ==
null || !_backing_material.enableInstancing)) {
97 _backing_material =
new Material(_material);
98 _backing_material.hideFlags = HideFlags.DontSaveInEditor;
99 if(!Application.isEditor && !_backing_material.enableInstancing) {
100 Debug.LogError(
"Capsule Hand Material needs Instancing Enabled to render in builds!",
this);
102 _backing_material.enableInstancing =
true;
103 _sphereMat =
new Material(_backing_material);
104 _sphereMat.hideFlags = HideFlags.DontSaveInEditor;
109 private void OnValidate() {
111 if (_material ==
null || !_material.enableInstancing) {
112 Debug.LogWarning(
"CapsuleHand's Material must have " +
113 "instancing enabled in order to work in builds! Replacing " +
114 "Material with a Default Material now...",
this);
115 _material = (Material)
UnityEditor.AssetDatabase.LoadAssetAtPath(
116 System.IO.Path.Combine(
"Assets",
"Plugins",
"LeapMotion",
117 "Core",
"Materials",
"InstancedCapsuleHand.mat"), typeof(Material));
126 _sphereMat.color = _leftColorList[_leftColorIndex];
127 _leftColorIndex = (_leftColorIndex + 1) % _leftColorList.Length;
129 _sphereMat.color = _rightColorList[_rightColorIndex];
130 _rightColorIndex = (_rightColorIndex + 1) % _rightColorList.Length;
136 _curCylinderIndex = 0;
138 if (_spherePositions ==
null || _spherePositions.Length != TOTAL_JOINT_COUNT) {
139 _spherePositions =
new Vector3[TOTAL_JOINT_COUNT];
142 if (_material !=
null && (_backing_material ==
null || !_backing_material.enableInstancing)) {
143 _backing_material =
new Material(_material);
144 _backing_material.hideFlags = HideFlags.DontSaveInEditor;
145 _backing_material.enableInstancing =
true;
146 _sphereMat =
new Material(_backing_material);
147 _sphereMat.hideFlags = HideFlags.DontSaveInEditor;
151 foreach (var finger
in _hand.
Fingers) {
152 for (
int j = 0; j < 4; j++) {
153 int key = getFingerJointIndex((
int)finger.Type, j);
155 Vector3 position = finger.Bone((
Bone.
BoneType)j).NextJoint.ToVector3();
156 _spherePositions[key] = position;
158 drawSphere(position);
166 drawSphere(palmPosition, _palmRadius);
168 Vector3 thumbBaseToPalm = _spherePositions[THUMB_BASE_INDEX] - _hand.
PalmPosition.ToVector3();
169 Vector3 mockThumbJointPos = _hand.
PalmPosition.ToVector3() + Vector3.Reflect(thumbBaseToPalm, _hand.
Basis.
xBasis.ToVector3());
170 drawSphere(mockThumbJointPos);
176 Vector3 right = arm.Basis.xBasis.ToVector3() * arm.Width * 0.7f * 0.5f;
177 Vector3 wrist = arm.WristPosition.ToVector3();
178 Vector3 elbow = arm.ElbowPosition.ToVector3();
180 float armLength = Vector3.Distance(wrist, elbow);
181 wrist -= arm.Direction.ToVector3() * armLength * 0.05f;
183 Vector3 armFrontRight = wrist + right;
184 Vector3 armFrontLeft = wrist - right;
185 Vector3 armBackRight = elbow + right;
186 Vector3 armBackLeft = elbow - right;
188 drawSphere(armFrontRight);
189 drawSphere(armFrontLeft);
190 drawSphere(armBackLeft);
191 drawSphere(armBackRight);
193 drawCylinder(armFrontLeft, armFrontRight);
194 drawCylinder(armBackLeft, armBackRight);
195 drawCylinder(armFrontLeft, armBackLeft);
196 drawCylinder(armFrontRight, armBackRight);
200 for (
int i = 0; i < 5; i++) {
201 for (
int j = 0; j < 3; j++) {
202 int keyA = getFingerJointIndex(i, j);
203 int keyB = getFingerJointIndex(i, j + 1);
205 Vector3 posA = _spherePositions[keyA];
206 Vector3 posB = _spherePositions[keyB];
208 drawCylinder(posA, posB);
213 for (
int i = 0; i < 4; i++) {
214 int keyA = getFingerJointIndex(i, 0);
215 int keyB = getFingerJointIndex(i + 1, 0);
217 Vector3 posA = _spherePositions[keyA];
218 Vector3 posB = _spherePositions[keyB];
220 drawCylinder(posA, posB);
224 drawCylinder(mockThumbJointPos, THUMB_BASE_INDEX);
225 drawCylinder(mockThumbJointPos, PINKY_BASE_INDEX);
228 Graphics.DrawMeshInstanced(_sphereMesh, 0, _sphereMat, _sphereMatrices, _curSphereIndex,
null,
229 _castShadows?
UnityEngine.Rendering.ShadowCastingMode.On:
UnityEngine.Rendering.ShadowCastingMode.Off,
true, gameObject.layer);
232 if(_cylinderMesh ==
null) { _cylinderMesh = getCylinderMesh(1f); }
233 Graphics.DrawMeshInstanced(_cylinderMesh, 0, _backing_material, _cylinderMatrices, _curCylinderIndex,
null,
234 _castShadows ?
UnityEngine.Rendering.ShadowCastingMode.On :
UnityEngine.Rendering.ShadowCastingMode.Off,
true, gameObject.layer);
237 private void drawSphere(Vector3 position) {
238 drawSphere(position, _jointRadius);
241 private void drawSphere(Vector3 position,
float radius) {
242 if (isNaN(position)) {
return; }
245 _sphereMatrices[_curSphereIndex++] = Matrix4x4.TRS(position,
246 Quaternion.identity, Vector3.one * radius * 2.0f * transform.lossyScale.x);
249 private void drawCylinder(Vector3 a, Vector3 b) {
250 if (isNaN(a) || isNaN(b)) {
return; }
252 float length = (a - b).magnitude;
254 if ((a - b).magnitude > 0.001f) {
255 _cylinderMatrices[_curCylinderIndex++] = Matrix4x4.TRS(a,
256 Quaternion.LookRotation(b - a),
new Vector3(transform.lossyScale.x, transform.lossyScale.x, length));
260 private bool isNaN(Vector3 v) {
261 return float.IsNaN(v.x) ||
float.IsNaN(v.y) ||
float.IsNaN(v.z);
264 private void drawCylinder(
int a,
int b) {
265 drawCylinder(_spherePositions[a], _spherePositions[b]);
268 private void drawCylinder(Vector3 a,
int b) {
269 drawCylinder(a, _spherePositions[b]);
272 private int getFingerJointIndex(
int fingerIndex,
int jointIndex) {
273 return fingerIndex * 4 + jointIndex;
276 private Dictionary<int, Mesh> _meshMap =
new Dictionary<int, Mesh>();
277 private Mesh getCylinderMesh(
float length) {
278 int lengthKey = Mathf.RoundToInt(length * 100 / CYLINDER_MESH_RESOLUTION);
281 if (_meshMap.TryGetValue(lengthKey, out mesh)) {
286 mesh.name =
"GeneratedCylinder";
287 mesh.hideFlags = HideFlags.DontSave;
289 List<Vector3> verts =
new List<Vector3>();
290 List<Color> colors =
new List<Color>();
291 List<int> tris =
new List<int>();
295 for (
int i = 0; i < _cylinderResolution; i++) {
296 float angle = (Mathf.PI * 2.0f * i) / _cylinderResolution;
297 float dx = _cylinderRadius * Mathf.Cos(angle);
298 float dy = _cylinderRadius * Mathf.Sin(angle);
302 verts.Add(p0 + spoke);
303 verts.Add(p1 + spoke);
305 colors.Add(
Color.white);
306 colors.Add(
Color.white);
308 int triStart = verts.Count;
309 int triCap = _cylinderResolution * 2;
311 tris.Add((triStart + 0) % triCap);
312 tris.Add((triStart + 2) % triCap);
313 tris.Add((triStart + 1) % triCap);
315 tris.Add((triStart + 2) % triCap);
316 tris.Add((triStart + 3) % triCap);
317 tris.Add((triStart + 1) % triCap);
320 mesh.SetVertices(verts);
321 mesh.SetIndices(tris.ToArray(), MeshTopology.Triangles, 0);
322 mesh.RecalculateBounds();
323 mesh.RecalculateNormals();
324 mesh.UploadMeshData(
true);
326 _meshMap[lengthKey] = mesh;
The Bone class represents a tracked bone.
BoneType
Enumerates the type of bones.
The Finger class represents a tracked finger.
FingerType
Enumerates the names of the fingers.
The Hand class reports the physical characteristics of a detected hand.
LeapTransform Basis
The transform of the hand.
bool IsLeft
Identifies whether this Hand is a left hand.
Arm Arm
The arm to which this hand is attached.
Vector PalmPosition
The center position of the palm.
List< Finger > Fingers
The list of Finger objects detected in this frame that are attached to this hand, given in order from...
override Chirality Handedness
override void SetLeapHand(Hand hand)
override void UpdateHand()
override Hand GetLeapHand()
override void BeginHand()
override ModelType HandModelType
override bool SupportsEditorPersistence()
Returns whether or not this hand model supports editor persistence. This is false by default and must...