|
|
- /************************************************************************************
- Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
-
- Licensed under the Oculus Utilities SDK License Version 1.31 (the "License"); you may not use
- the Utilities SDK except in compliance with the License, which is provided at the time of installation
- or download, or which otherwise accompanies this software in either electronic or hard copy form.
-
- You may obtain a copy of the License at
- https://developer.oculus.com/licenses/utilities-1.31
-
- Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
- under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
- ANY KIND, either express or implied. See the License for the specific language governing
- permissions and limitations under the License.
- ************************************************************************************/
-
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- [DefaultExecutionOrder(-80)]
- public class OVRSkeleton : MonoBehaviour
- {
- public interface IOVRSkeletonDataProvider
- {
- SkeletonType GetSkeletonType();
- SkeletonPoseData GetSkeletonPoseData();
- }
-
- public struct SkeletonPoseData
- {
- public OVRPlugin.Posef RootPose { get; set; }
- public float RootScale { get; set; }
- public OVRPlugin.Quatf[] BoneRotations { get; set; }
- public bool IsDataValid { get; set; }
- public bool IsDataHighConfidence { get; set; }
- }
-
- public enum SkeletonType
- {
- None = OVRPlugin.SkeletonType.None,
- HandLeft = OVRPlugin.SkeletonType.HandLeft,
- HandRight = OVRPlugin.SkeletonType.HandRight,
- }
-
- public enum BoneId
- {
- Invalid = OVRPlugin.BoneId.Invalid,
-
- Hand_Start = OVRPlugin.BoneId.Hand_Start,
- Hand_WristRoot = OVRPlugin.BoneId.Hand_WristRoot, // root frame of the hand, where the wrist is located
- Hand_ForearmStub = OVRPlugin.BoneId.Hand_ForearmStub, // frame for user's forearm
- Hand_Thumb0 = OVRPlugin.BoneId.Hand_Thumb0, // thumb trapezium bone
- Hand_Thumb1 = OVRPlugin.BoneId.Hand_Thumb1, // thumb metacarpal bone
- Hand_Thumb2 = OVRPlugin.BoneId.Hand_Thumb2, // thumb proximal phalange bone
- Hand_Thumb3 = OVRPlugin.BoneId.Hand_Thumb3, // thumb distal phalange bone
- Hand_Index1 = OVRPlugin.BoneId.Hand_Index1, // index proximal phalange bone
- Hand_Index2 = OVRPlugin.BoneId.Hand_Index2, // index intermediate phalange bone
- Hand_Index3 = OVRPlugin.BoneId.Hand_Index3, // index distal phalange bone
- Hand_Middle1 = OVRPlugin.BoneId.Hand_Middle1, // middle proximal phalange bone
- Hand_Middle2 = OVRPlugin.BoneId.Hand_Middle2, // middle intermediate phalange bone
- Hand_Middle3 = OVRPlugin.BoneId.Hand_Middle3, // middle distal phalange bone
- Hand_Ring1 = OVRPlugin.BoneId.Hand_Ring1, // ring proximal phalange bone
- Hand_Ring2 = OVRPlugin.BoneId.Hand_Ring2, // ring intermediate phalange bone
- Hand_Ring3 = OVRPlugin.BoneId.Hand_Ring3, // ring distal phalange bone
- Hand_Pinky0 = OVRPlugin.BoneId.Hand_Pinky0, // pinky metacarpal bone
- Hand_Pinky1 = OVRPlugin.BoneId.Hand_Pinky1, // pinky proximal phalange bone
- Hand_Pinky2 = OVRPlugin.BoneId.Hand_Pinky2, // pinky intermediate phalange bone
- Hand_Pinky3 = OVRPlugin.BoneId.Hand_Pinky3, // pinky distal phalange bone
- Hand_MaxSkinnable = OVRPlugin.BoneId.Hand_MaxSkinnable,
- // Bone tips are position only. They are not used for skinning but are useful for hit-testing.
- // NOTE: Hand_ThumbTip == Hand_MaxSkinnable since the extended tips need to be contiguous
- Hand_ThumbTip = OVRPlugin.BoneId.Hand_ThumbTip, // tip of the thumb
- Hand_IndexTip = OVRPlugin.BoneId.Hand_IndexTip, // tip of the index finger
- Hand_MiddleTip = OVRPlugin.BoneId.Hand_MiddleTip, // tip of the middle finger
- Hand_RingTip = OVRPlugin.BoneId.Hand_RingTip, // tip of the ring finger
- Hand_PinkyTip = OVRPlugin.BoneId.Hand_PinkyTip, // tip of the pinky
- Hand_End = OVRPlugin.BoneId.Hand_End,
-
- // add new bones here
-
- Max = OVRPlugin.BoneId.Max
- }
-
- [SerializeField]
- private SkeletonType _skeletonType = SkeletonType.None;
- [SerializeField]
- private IOVRSkeletonDataProvider _dataProvider;
-
- [SerializeField]
- private bool _updateRootPose = false;
- [SerializeField]
- private bool _updateRootScale = false;
- [SerializeField]
- private bool _enablePhysicsCapsules = false;
-
- private GameObject _bonesGO;
- private GameObject _bindPosesGO;
- private GameObject _capsulesGO;
-
- protected List<OVRBone> _bones;
- private List<OVRBone> _bindPoses;
- private List<OVRBoneCapsule> _capsules;
-
- private readonly Quaternion wristFixupRotation = new Quaternion(0.0f, 1.0f, 0.0f, 0.0f);
- public bool IsInitialized { get; private set; }
- public bool IsDataValid { get; private set; }
- public bool IsDataHighConfidence { get; private set; }
- public IList<OVRBone> Bones { get; protected set; }
- public IList<OVRBone> BindPoses { get; private set; }
- public IList<OVRBoneCapsule> Capsules { get; private set; }
- public SkeletonType GetSkeletonType() { return _skeletonType; }
-
- private void Awake()
- {
- if (_dataProvider == null)
- {
- _dataProvider = GetComponent<IOVRSkeletonDataProvider>();
- }
-
- _bones = new List<OVRBone>();
- Bones = _bones.AsReadOnly();
-
- _bindPoses = new List<OVRBone>();
- BindPoses = _bindPoses.AsReadOnly();
-
- _capsules = new List<OVRBoneCapsule>();
- Capsules = _capsules.AsReadOnly();
- }
-
- private void Start()
- {
- if (_skeletonType != SkeletonType.None)
- {
- Initialize();
- }
- }
-
- private void Initialize()
- {
- var skeleton = new OVRPlugin.Skeleton();
- if (OVRPlugin.GetSkeleton((OVRPlugin.SkeletonType)_skeletonType, out skeleton))
- {
- InitializeBones(skeleton);
- InitializeBindPose(skeleton);
- InitializeCapsules(skeleton);
-
- IsInitialized = true;
- }
- }
-
- virtual protected void InitializeBones(OVRPlugin.Skeleton skeleton)
- {
- _bones = new List<OVRBone>(new OVRBone[skeleton.NumBones]);
- Bones = _bones.AsReadOnly();
-
- if (!_bonesGO)
- {
- _bonesGO = new GameObject("Bones");
- _bonesGO.transform.SetParent(transform, false);
- _bonesGO.transform.localPosition = Vector3.zero;
- _bonesGO.transform.localRotation = Quaternion.identity;
- }
-
- // 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.FromFlippedXVector3f();
- Quaternion rot = skeleton.Bones[i].Pose.Orientation.FromFlippedXQuatf();
-
- var boneGO = new GameObject(id.ToString());
- boneGO.transform.localPosition = pos;
- boneGO.transform.localRotation = rot;
- _bones[i] = new OVRBone(id, parentIdx, boneGO.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);
- }
- else
- {
- _bones[i].Transform.SetParent(_bones[_bones[i].ParentBoneIndex].Transform, false);
- }
- }
- }
-
- private void InitializeBindPose(OVRPlugin.Skeleton skeleton)
- {
- _bindPoses = new List<OVRBone>(new OVRBone[skeleton.NumBones]);
- BindPoses = _bindPoses.AsReadOnly();
-
- if (!_bindPosesGO)
- {
- _bindPosesGO = new GameObject("BindPoses");
- _bindPosesGO.transform.SetParent(transform, false);
- _bindPosesGO.transform.localPosition = Vector3.zero;
- _bindPosesGO.transform.localRotation = Quaternion.identity;
- }
-
- for (int i = 0; i < skeleton.NumBones; ++i)
- {
- BoneId id = (OVRSkeleton.BoneId)skeleton.Bones[i].Id;
- short parentIdx = skeleton.Bones[i].ParentBoneIndex;
- var bindPoseGO = new GameObject(id.ToString());
- OVRBone bone = _bones[i];
-
- if (bone.Transform != null)
- {
- bindPoseGO.transform.localPosition = bone.Transform.localPosition;
- bindPoseGO.transform.localRotation = bone.Transform.localRotation;
- }
-
- _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)
- {
- _bindPoses[i].Transform.SetParent(_bindPosesGO.transform, false);
- }
- else
- {
- _bindPoses[i].Transform.SetParent(_bindPoses[_bones[i].ParentBoneIndex].Transform, false);
- }
- }
- }
-
- private void InitializeCapsules(OVRPlugin.Skeleton skeleton)
- {
- if (_enablePhysicsCapsules)
- {
- _capsules = new List<OVRBoneCapsule>(new OVRBoneCapsule[skeleton.NumBoneCapsules]);
- Capsules = _capsules.AsReadOnly();
-
- if (!_capsulesGO)
- {
- _capsulesGO = new GameObject("Capsules");
- _capsulesGO.transform.SetParent(transform, false);
- _capsulesGO.transform.localPosition = Vector3.zero;
- _capsulesGO.transform.localRotation = Quaternion.identity;
- }
-
- _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.position = bone.position;
- capsuleRigidBodyGO.transform.rotation = 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].FromFlippedXVector3f();
- var p1 = capsule.Points[1].FromFlippedXVector3f();
- var delta = p1 - p0;
- var mag = delta.magnitude;
- var rot = Quaternion.FromToRotation(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;
-
- _capsules[i] = new OVRBoneCapsule(capsule.BoneIndex, capsuleRigidBody, capsuleCollider);
- }
- }
- }
-
- private void Update()
- {
- if (!IsInitialized || _dataProvider == null)
- {
- IsDataValid = false;
- IsDataHighConfidence = false;
-
- return;
- }
-
- var data = _dataProvider.GetSkeletonPoseData();
-
- IsDataValid = data.IsDataValid;
- if (data.IsDataValid)
- {
- IsDataHighConfidence = data.IsDataHighConfidence;
-
- if (_updateRootPose)
- {
- transform.localPosition = data.RootPose.Position.FromFlippedZVector3f();
- transform.localRotation = data.RootPose.Orientation.FromFlippedZQuatf();
- }
-
- if (_updateRootScale)
- {
- transform.localScale = new Vector3(data.RootScale, data.RootScale, data.RootScale);
- }
-
- for (var i = 0; i < _bones.Count; ++i)
- {
- if (_bones[i].Transform != null)
- {
- _bones[i].Transform.localRotation = data.BoneRotations[i].FromFlippedXQuatf();
- if (_bones[i].Id == BoneId.Hand_WristRoot)
- {
- _bones[i].Transform.localRotation *= wristFixupRotation;
- }
- }
- }
- }
- }
-
- private void FixedUpdate()
- {
- if (!IsInitialized || _dataProvider == null)
- {
- IsDataValid = false;
- IsDataHighConfidence = false;
-
- return;
- }
-
- Update();
-
- if (_enablePhysicsCapsules)
- {
- var data = _dataProvider.GetSkeletonPoseData();
-
- IsDataValid = data.IsDataValid;
- IsDataHighConfidence = data.IsDataHighConfidence;
-
- for (int i = 0; i < _capsules.Count; ++i)
- {
- OVRBoneCapsule capsule = _capsules[i];
- var capsuleGO = capsule.CapsuleRigidbody.gameObject;
-
- if (data.IsDataValid && data.IsDataHighConfidence)
- {
- Transform bone = _bones[(int)capsule.BoneIndex].Transform;
-
- if (capsuleGO.activeSelf)
- {
- capsule.CapsuleRigidbody.MovePosition(bone.position);
- capsule.CapsuleRigidbody.MoveRotation(bone.rotation);
- }
- else
- {
- capsuleGO.SetActive(true);
- capsule.CapsuleRigidbody.position = bone.position;
- capsule.CapsuleRigidbody.rotation = bone.rotation;
- }
- }
- else
- {
- if (capsuleGO.activeSelf)
- {
- capsuleGO.SetActive(false);
- }
- }
- }
- }
- }
-
- public BoneId GetCurrentStartBoneId()
- {
- switch (_skeletonType)
- {
- case SkeletonType.HandLeft:
- case SkeletonType.HandRight:
- return BoneId.Hand_Start;
- case SkeletonType.None:
- default:
- return BoneId.Invalid;
- }
- }
-
- public BoneId GetCurrentEndBoneId()
- {
- switch (_skeletonType)
- {
- case SkeletonType.HandLeft:
- case SkeletonType.HandRight:
- return BoneId.Hand_End;
- case SkeletonType.None:
- default:
- return BoneId.Invalid;
- }
- }
-
- private BoneId GetCurrentMaxSkinnableBoneId()
- {
- switch (_skeletonType)
- {
- case SkeletonType.HandLeft:
- case SkeletonType.HandRight:
- return BoneId.Hand_MaxSkinnable;
- case SkeletonType.None:
- default:
- return BoneId.Invalid;
- }
- }
-
- public int GetCurrentNumBones()
- {
- switch (_skeletonType)
- {
- case SkeletonType.HandLeft:
- case SkeletonType.HandRight:
- return GetCurrentEndBoneId() - GetCurrentStartBoneId();
- case SkeletonType.None:
- default:
- return 0;
- }
- }
-
- public int GetCurrentNumSkinnableBones()
- {
- switch (_skeletonType)
- {
- case SkeletonType.HandLeft:
- case SkeletonType.HandRight:
- return GetCurrentMaxSkinnableBoneId() - GetCurrentStartBoneId();
- case SkeletonType.None:
- default:
- return 0;
- }
- }
- }
-
- public class OVRBone
- {
- public OVRSkeleton.BoneId Id { get; private set; }
- public short ParentBoneIndex { get; private set; }
- public Transform Transform { get; private set; }
-
- public OVRBone(OVRSkeleton.BoneId id, short parentBoneIndex, Transform trans)
- {
- Id = id;
- ParentBoneIndex = parentBoneIndex;
- Transform = trans;
- }
- }
-
- public class OVRBoneCapsule
- {
- public short BoneIndex { get; private set; }
- public Rigidbody CapsuleRigidbody { get; private set; }
- public CapsuleCollider CapsuleCollider { get; private set; }
-
- public OVRBoneCapsule(short boneIndex, Rigidbody capsuleRigidBody, CapsuleCollider capsuleCollider)
- {
- BoneIndex = boneIndex;
- CapsuleRigidbody = capsuleRigidBody;
- CapsuleCollider = capsuleCollider;
- }
- }
-
|