using System; using System.Collections.Generic; using UnityEngine; namespace Leap.Unity { public class CapsuleHand : IHandModel { public override ModelType HandModelType { get { return ModelType.Graphics; } } public override Chirality Handedness { get { return this.handedness; } set { } } public override bool SupportsEditorPersistence() { return true; } public override Hand GetLeapHand() { return this.hand_; } public override void SetLeapHand(Hand hand) { this.hand_ = hand; } private void OnValidate() { this._cylinderResolution = Mathf.Max(3, this._cylinderResolution); if (this._armRenderers != null) { this.updateArmVisibility(); } } public override void InitHand() { if (this._material != null) { this.jointMat = new Material(this._material); this.jointMat.hideFlags = HideFlags.DontSaveInEditor; } if (this._serializedTransforms != null) { for (int i = 0; i < this._serializedTransforms.Count; i++) { Transform transform = this._serializedTransforms[i]; if (transform != null) { UnityEngine.Object.DestroyImmediate(transform.gameObject); } } this._serializedTransforms.Clear(); } else { this._serializedTransforms = new List(); } this._jointSpheres = new Transform[20]; this._armRenderers = new List(); this._cylinderTransforms = new List(); this._sphereATransforms = new List(); this._sphereBTransforms = new List(); this.createSpheres(); this.createCylinders(); this.updateArmVisibility(); this._hasGeneratedMeshes = false; } public override void BeginHand() { base.BeginHand(); if (this.hand_.IsLeft) { this.jointMat.color = CapsuleHand._leftColorList[CapsuleHand._leftColorIndex]; CapsuleHand._leftColorIndex = (CapsuleHand._leftColorIndex + 1) % CapsuleHand._leftColorList.Length; } else { this.jointMat.color = CapsuleHand._rightColorList[CapsuleHand._rightColorIndex]; CapsuleHand._rightColorIndex = (CapsuleHand._rightColorIndex + 1) % CapsuleHand._rightColorList.Length; } } public override void UpdateHand() { this.updateSpheres(); if (this._showArm) { this.updateArm(); } this.updateCylinders(); } private void updateSpheres() { List fingers = this.hand_.Fingers; for (int i = 0; i < fingers.Count; i++) { Finger finger = fingers[i]; for (int j = 0; j < 4; j++) { int fingerJointIndex = this.getFingerJointIndex((int)finger.Type, j); Transform transform = this._jointSpheres[fingerJointIndex]; transform.position = finger.Bone((Bone.BoneType)j).NextJoint.ToVector3(); } } this.palmPositionSphere.position = this.hand_.PalmPosition.ToVector3(); Vector3 position = this.hand_.PalmPosition.ToVector3(); this.wristPositionSphere.position = position; Transform transform2 = this._jointSpheres[0]; Vector3 inDirection = transform2.position - this.hand_.PalmPosition.ToVector3(); this.mockThumbJointSphere.position = this.hand_.PalmPosition.ToVector3() + Vector3.Reflect(inDirection, this.hand_.Basis.xBasis.ToVector3()); } private void updateArm() { Arm arm = this.hand_.Arm; Vector3 b = arm.Basis.xBasis.ToVector3() * arm.Width * 0.7f * 0.5f; Vector3 a = arm.WristPosition.ToVector3(); Vector3 vector = arm.ElbowPosition.ToVector3(); float d = Vector3.Distance(a, vector); a -= arm.Direction.ToVector3() * d * 0.05f; this.armFrontRight.position = a + b; this.armFrontLeft.position = a - b; this.armBackRight.position = vector + b; this.armBackLeft.position = vector - b; } private void updateCylinders() { for (int i = 0; i < this._cylinderTransforms.Count; i++) { Transform transform = this._cylinderTransforms[i]; Transform transform2 = this._sphereATransforms[i]; Transform transform3 = this._sphereBTransforms[i]; Vector3 vector = transform2.position - transform3.position; if (!this._hasGeneratedMeshes) { MeshFilter component = transform.GetComponent(); component.sharedMesh = this.generateCylinderMesh(vector.magnitude / base.transform.lossyScale.x); } transform.position = transform2.position; if (vector.sqrMagnitude > Mathf.Epsilon) { transform.LookAt(transform3); } } this._hasGeneratedMeshes = true; } private void updateArmVisibility() { for (int i = 0; i < this._armRenderers.Count; i++) { this._armRenderers[i].enabled = this._showArm; } } private void createSpheres() { List fingers = this.hand_.Fingers; for (int i = 0; i < fingers.Count; i++) { Finger finger = fingers[i]; for (int j = 0; j < 4; j++) { int fingerJointIndex = this.getFingerJointIndex((int)finger.Type, j); this._jointSpheres[fingerJointIndex] = this.createSphere("Joint", 0.008f, false); } } this.mockThumbJointSphere = this.createSphere("MockJoint", 0.008f, false); this.palmPositionSphere = this.createSphere("PalmPosition", 0.015f, false); this.wristPositionSphere = this.createSphere("WristPosition", 0.008f, false); this.armFrontLeft = this.createSphere("ArmFrontLeft", 0.008f, true); this.armFrontRight = this.createSphere("ArmFrontRight", 0.008f, true); this.armBackLeft = this.createSphere("ArmBackLeft", 0.008f, true); this.armBackRight = this.createSphere("ArmBackRight", 0.008f, true); } private void createCylinders() { for (int i = 0; i < 5; i++) { for (int j = 0; j < 3; j++) { int fingerJointIndex = this.getFingerJointIndex(i, j); int fingerJointIndex2 = this.getFingerJointIndex(i, j + 1); Transform jointA = this._jointSpheres[fingerJointIndex]; Transform jointB = this._jointSpheres[fingerJointIndex2]; this.createCylinder("Finger Joint", jointA, jointB, false); } } for (int k = 0; k < 4; k++) { int fingerJointIndex3 = this.getFingerJointIndex(k, 0); int fingerJointIndex4 = this.getFingerJointIndex(k + 1, 0); Transform jointA2 = this._jointSpheres[fingerJointIndex3]; Transform jointB2 = this._jointSpheres[fingerJointIndex4]; this.createCylinder("Hand Joints", jointA2, jointB2, false); } Transform jointA3 = this._jointSpheres[0]; Transform jointA4 = this._jointSpheres[16]; this.createCylinder("Hand Bottom", jointA3, this.mockThumbJointSphere, false); this.createCylinder("Hand Side", jointA4, this.mockThumbJointSphere, false); this.createCylinder("ArmFront", this.armFrontLeft, this.armFrontRight, true); this.createCylinder("ArmBack", this.armBackLeft, this.armBackRight, true); this.createCylinder("ArmLeft", this.armFrontLeft, this.armBackLeft, true); this.createCylinder("ArmRight", this.armFrontRight, this.armBackRight, true); } private int getFingerJointIndex(int fingerIndex, int jointIndex) { return fingerIndex * 4 + jointIndex; } private Transform createSphere(string name, float radius, bool isPartOfArm = false) { GameObject gameObject = new GameObject(name); this._serializedTransforms.Add(gameObject.transform); gameObject.AddComponent().mesh = this._sphereMesh; gameObject.AddComponent().sharedMaterial = this.jointMat; gameObject.transform.parent = base.transform; gameObject.transform.localScale = Vector3.one * radius * 2f; gameObject.hideFlags = (HideFlags.HideInHierarchy | HideFlags.HideInInspector | HideFlags.DontSaveInEditor | HideFlags.DontSaveInBuild | HideFlags.DontUnloadUnusedAsset); gameObject.layer = base.gameObject.layer; if (isPartOfArm) { this._armRenderers.Add(gameObject.GetComponent()); } return gameObject.transform; } private void createCylinder(string name, Transform jointA, Transform jointB, bool isPartOfArm = false) { GameObject gameObject = new GameObject(name); this._serializedTransforms.Add(gameObject.transform); gameObject.AddComponent(); gameObject.AddComponent().sharedMaterial = this._material; gameObject.transform.parent = base.transform; this._cylinderTransforms.Add(gameObject.transform); this._sphereATransforms.Add(jointA); this._sphereBTransforms.Add(jointB); gameObject.gameObject.layer = base.gameObject.layer; gameObject.hideFlags = (HideFlags.HideInHierarchy | HideFlags.HideInInspector | HideFlags.DontSaveInEditor | HideFlags.DontSaveInBuild | HideFlags.DontUnloadUnusedAsset); if (isPartOfArm) { this._armRenderers.Add(gameObject.GetComponent()); } } private Mesh generateCylinderMesh(float length) { Mesh mesh = new Mesh(); mesh.name = "GeneratedCylinder"; mesh.hideFlags = HideFlags.DontSave; List list = new List(); List list2 = new List(); List list3 = new List(); Vector3 zero = Vector3.zero; Vector3 a = Vector3.forward * length; for (int i = 0; i < this._cylinderResolution; i++) { float f = 6.2831855f * (float)i / (float)this._cylinderResolution; float x = 0.006f * Mathf.Cos(f); float y = 0.006f * Mathf.Sin(f); Vector3 b = new Vector3(x, y, 0f); list.Add((zero + b) * base.transform.lossyScale.x); list.Add((a + b) * base.transform.lossyScale.x); list2.Add(Color.white); list2.Add(Color.white); int count = list.Count; int num = this._cylinderResolution * 2; list3.Add(count % num); list3.Add((count + 2) % num); list3.Add((count + 1) % num); list3.Add((count + 2) % num); list3.Add((count + 3) % num); list3.Add((count + 1) % num); } mesh.SetVertices(list); mesh.SetIndices(list3.ToArray(), MeshTopology.Triangles, 0); mesh.RecalculateBounds(); mesh.RecalculateNormals(); mesh.UploadMeshData(true); return mesh; } private const int THUMB_BASE_INDEX = 0; private const int PINKY_BASE_INDEX = 16; private const float SPHERE_RADIUS = 0.008f; private const float CYLINDER_RADIUS = 0.006f; private const float PALM_RADIUS = 0.015f; private static int _leftColorIndex = 0; private static int _rightColorIndex = 0; private static Color[] _leftColorList = new Color[] { new Color(0f, 0f, 1f), new Color(0.2f, 0f, 0.4f), new Color(0f, 0.2f, 0.2f) }; private static Color[] _rightColorList = new Color[] { new Color(1f, 0f, 0f), new Color(1f, 1f, 0f), new Color(1f, 0.5f, 0f) }; [SerializeField] private Chirality handedness; [SerializeField] private bool _showArm = true; [SerializeField] private Material _material; [SerializeField] private Mesh _sphereMesh; [SerializeField] private int _cylinderResolution = 12; private bool _hasGeneratedMeshes; private Material jointMat; [SerializeField] [HideInInspector] private List _serializedTransforms; private Transform[] _jointSpheres; private Transform mockThumbJointSphere; private Transform palmPositionSphere; private Transform wristPositionSphere; private List _armRenderers; private List _cylinderTransforms; private List _sphereATransforms; private List _sphereBTransforms; private Transform armFrontLeft; private Transform armFrontRight; private Transform armBackLeft; private Transform armBackRight; private Hand hand_; } }