public abstract Transform GetBoneUnsafe(Hand hand, BoneId Id);
public override bool TryGetBone(Hand hand, BoneId Id, out Transform bone) { var bones = Hand.left == hand ? _bonesLeft : _bonesRight; return(bones.TryGetValue(Id, out bone)); }
public abstract bool TryGetBone(Hand hand, BoneId Id, out Transform bone);
public virtual bool IsFingerHighConfidence(BoneId bone) { return(true); }
private void Initialize() { var skeleton = new OVRPlugin.Skeleton(); if (OVRPlugin.GetSkeleton((OVRPlugin.SkeletonType)_skeletonType, out skeleton)) { if (!_bonesGO) { _bonesGO = new GameObject("Bones"); _bonesGO.transform.SetParent(transform, false); _bonesGO.transform.localPosition = Vector3.zero; _bonesGO.transform.localRotation = Quaternion.identity; } if (!_bindPosesGO) { _bindPosesGO = new GameObject("BindPoses"); _bindPosesGO.transform.SetParent(transform, false); _bindPosesGO.transform.localPosition = Vector3.zero; _bindPosesGO.transform.localRotation = Quaternion.identity; } if (_enablePhysicsCapsules) { if (!_capsulesGO) { _capsulesGO = new GameObject("Capsules"); _capsulesGO.transform.SetParent(transform, false); _capsulesGO.transform.localPosition = Vector3.zero; _capsulesGO.transform.localRotation = Quaternion.identity; } } _bones = new List <OVRBone>(new OVRBone[skeleton.NumBones]); Bones = _bones.AsReadOnly(); _bindPoses = new List <OVRBone>(new OVRBone[skeleton.NumBones]); BindPoses = _bindPoses.AsReadOnly(); // pre-populate bones list before attempting to apply bone hierarchy for (int i = 0; i < skeleton.NumBones; ++i) { BoneId id = (OVRSkeleton.BoneId)skeleton.Bones[i].Id; short parentIdx = skeleton.Bones[i].ParentBoneIndex; Vector3 pos = skeleton.Bones[i].Pose.Position.FromFlippedZVector3f(); Quaternion rot = skeleton.Bones[i].Pose.Orientation.FromFlippedZQuatf(); var boneGO = new GameObject(id.ToString()); boneGO.transform.localPosition = pos; boneGO.transform.localRotation = rot; _bones[i] = new OVRBone(id, parentIdx, boneGO.transform); var bindPoseGO = new GameObject(id.ToString()); bindPoseGO.transform.localPosition = pos; bindPoseGO.transform.localRotation = rot; _bindPoses[i] = new OVRBone(id, parentIdx, bindPoseGO.transform); } for (int i = 0; i < skeleton.NumBones; ++i) { if (((OVRPlugin.BoneId)skeleton.Bones[i].ParentBoneIndex) == OVRPlugin.BoneId.Invalid) { _bones[i].Transform.SetParent(_bonesGO.transform, false); _bindPoses[i].Transform.SetParent(_bindPosesGO.transform, false); } else { _bones[i].Transform.SetParent(_bones[_bones[i].ParentBoneIndex].Transform, false); _bindPoses[i].Transform.SetParent(_bindPoses[_bones[i].ParentBoneIndex].Transform, false); } } if (_enablePhysicsCapsules) { _capsules = new List <OVRBoneCapsule>(new OVRBoneCapsule[skeleton.NumBoneCapsules]); Capsules = _capsules.AsReadOnly(); for (int i = 0; i < skeleton.NumBoneCapsules; ++i) { var capsule = skeleton.BoneCapsules[i]; Transform bone = Bones[capsule.BoneIndex].Transform; var capsuleRigidBodyGO = new GameObject((_bones[capsule.BoneIndex].Id).ToString() + "_CapsuleRigidBody"); capsuleRigidBodyGO.transform.SetParent(_capsulesGO.transform, false); capsuleRigidBodyGO.transform.localPosition = bone.position; capsuleRigidBodyGO.transform.localRotation = bone.rotation; var capsuleRigidBody = capsuleRigidBodyGO.AddComponent <Rigidbody>(); capsuleRigidBody.mass = 1.0f; capsuleRigidBody.isKinematic = true; capsuleRigidBody.useGravity = false; #if UNITY_2018_3_OR_NEWER capsuleRigidBody.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative; #else capsuleRigidBody.collisionDetectionMode = CollisionDetectionMode.Continuous; #endif var capsuleColliderGO = new GameObject((_bones[capsule.BoneIndex].Id).ToString() + "_CapsuleCollider"); capsuleColliderGO.transform.SetParent(capsuleRigidBodyGO.transform, false); var capsuleCollider = capsuleColliderGO.AddComponent <CapsuleCollider>(); var p0 = capsule.Points[0].FromFlippedZVector3f(); var p1 = capsule.Points[1].FromFlippedZVector3f(); var delta = p1 - p0; var mag = delta.magnitude; var rot = Quaternion.FromToRotation(capsuleRigidBodyGO.transform.localRotation * Vector3.right, delta); capsuleCollider.radius = capsule.Radius; capsuleCollider.height = mag + capsule.Radius * 2.0f; capsuleCollider.isTrigger = false; capsuleCollider.direction = 0; capsuleColliderGO.transform.localPosition = p0; capsuleColliderGO.transform.localRotation = rot; capsuleCollider.center = Vector3.right * mag * 0.5f; capsuleColliderGO.layer = gameObject.layer; _capsules[i] = new OVRBoneCapsule(capsule.BoneIndex, capsuleRigidBody, capsuleCollider); } } _isInitialized = true; } }
private void SetTracked() { if (trackedRoot != null && handAnchor != null) { trackedRoot.position = handAnchor.position; trackedRoot.rotation = handAnchor.rotation; } if (boneRotationValues.bones != null && boneRotationValues.bones.Length > 0) { //string debugTips = ""; List <(BoneId, bool)> fingerTipTests = new List <(BoneId, bool)>(); //Adding this helps reduce the amount of raycasts done on each finger tip by around 3 times, since each finger has 3 or 4 bones var boneIds = (BoneId[])Enum.GetValues(typeof(BoneId)); for (int i = 0; i < boneIds.Length; i++) { var currentBoneId = boneIds[i]; var bonesWithId = boneRotationValues.bones.Where((bone) => bone.id == currentBoneId); if (bonesWithId.Count() > 0) { var currentBone = bones[(int)currentBoneId]; var boneRotValue = bonesWithId.First(); #region Getting the rotation value from given hand bone values Quaternion localRotation; if (!boneRotValue.IsOrientation) { Vector3 rotationAxis = -Vector3.forward; if (currentBoneId == BoneId.Hand_Thumb0) { rotationAxis = -Vector3.up; } float currentAngle = boneRotValue.value * 90; localRotation = Quaternion.AngleAxis(currentAngle, rotationAxis) * currentBone.startRotation; } else { localRotation = boneRotValue.localRotation; } #endregion #region Adjusting rotation based on collision (less rotation toward collider if tip colliding) BoneId currentFingerTip = GetTip(currentBoneId); if (currentFingerTip != BoneId.Invalid) { var fingerTipTransform = bones[(int)currentFingerTip].mesh; var fingerTipRay = new Ray(fingerTipTransform.position, fingerTipTransform.up * (flipTipRays ? -1 : 1)); //debugTips += currentBoneId + " => " + currentFingerTip + "\n"; (BoneId, bool)fingerTipTest; var matchingTests = fingerTipTests.Where(currentTest => { return(currentTest.Item1 == currentFingerTip); }); if (matchingTests.Count() <= 0) { bool tipCollided = Physics.Raycast(fingerTipRay, tipCollisionDistance); fingerTipTest = (currentFingerTip, tipCollided); fingerTipTests.Add(fingerTipTest); Debug.DrawRay(fingerTipRay.origin, fingerTipRay.direction * tipCollisionDistance, tipCollided ? Color.green : Color.red); } else { fingerTipTest = matchingTests.First(); } //Calculate the difference in rotation between the next tracked local rotation and the previous tracked local rotation Quaternion deltaRotation = currentBone.tracked.localRotation * Quaternion.Inverse(localRotation); //Convert the difference to an angle on an axis float angle; Vector3 axis; deltaRotation.ToAngleAxis(out angle, out axis); //Local to world of axis direction axis = currentBone.tracked.TransformDirection(axis); //Comparing the axis of the rotation with the forward axis of the current bone (the forward axis //of the bone is the one it uses to close and open) bool isClosing = Vector3.Dot(currentBone.tracked.forward, axis) > 0; //If finger tip is colliding with an object and the finger is closing then set the current joint's //rotation to be the previous frame's if (fingerTipTest.Item2 && isClosing) { //localRotation = currentBone.tracked.localRotation; Quaternion meshDelta = currentBone.mesh.localRotation * Quaternion.Inverse(currentBone.startRotation); float maxAngle = meshDelta.PollAxisAngle(currentBone.tracked.forward, currentBone.tracked.up); Quaternion preferredAxisRotation = Quaternion.AngleAxis(maxAngle, currentBone.tracked.forward); Quaternion trackedDelta = currentBone.tracked.localRotation * Quaternion.Inverse(currentBone.startRotation); float currentAngle = meshDelta.PollAxisAngle(currentBone.tracked.forward, currentBone.tracked.up); Quaternion currentAxisRotation = Quaternion.AngleAxis(currentAngle, currentBone.tracked.forward); Quaternion shiftDelta = currentAxisRotation * Quaternion.Inverse(preferredAxisRotation); localRotation = currentBone.tracked.localRotation * shiftDelta; } Debug.DrawRay(currentBone.mesh.position, currentBone.tracked.forward * 0.02f, fingerTipTest.Item2 && isClosing ? Color.red : Color.green); } #endregion currentBone.tracked.localRotation = localRotation; } } //Debug.Log(debugTips); } }
/// <summary> /// Checks whether the given bone id is part of a finger /// </summary> /// <param name="currentBoneId">The bone id to be checked</param> /// <returns>True if the given id is part of a finger, false otherwise</returns> private static bool IsFingerBone(BoneId currentBoneId) { return(currentBoneId != BoneId.Hand_End && currentBoneId != BoneId.Hand_ForearmStub && currentBoneId != BoneId.Hand_MaxSkinnable && currentBoneId != BoneId.Hand_Start && currentBoneId != BoneId.Hand_WristRoot && currentBoneId != BoneId.Invalid && currentBoneId != BoneId.Max); }