Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

479 lines
15 KiB

  1. /************************************************************************************
  2. Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
  3. Licensed under the Oculus Utilities SDK License Version 1.31 (the "License"); you may not use
  4. the Utilities SDK except in compliance with the License, which is provided at the time of installation
  5. or download, or which otherwise accompanies this software in either electronic or hard copy form.
  6. You may obtain a copy of the License at
  7. https://developer.oculus.com/licenses/utilities-1.31
  8. Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
  9. under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
  10. ANY KIND, either express or implied. See the License for the specific language governing
  11. permissions and limitations under the License.
  12. ************************************************************************************/
  13. using System.Collections;
  14. using System.Collections.Generic;
  15. using UnityEngine;
  16. [DefaultExecutionOrder(-80)]
  17. public class OVRSkeleton : MonoBehaviour
  18. {
  19. public interface IOVRSkeletonDataProvider
  20. {
  21. SkeletonType GetSkeletonType();
  22. SkeletonPoseData GetSkeletonPoseData();
  23. }
  24. public struct SkeletonPoseData
  25. {
  26. public OVRPlugin.Posef RootPose { get; set; }
  27. public float RootScale { get; set; }
  28. public OVRPlugin.Quatf[] BoneRotations { get; set; }
  29. public bool IsDataValid { get; set; }
  30. public bool IsDataHighConfidence { get; set; }
  31. }
  32. public enum SkeletonType
  33. {
  34. None = OVRPlugin.SkeletonType.None,
  35. HandLeft = OVRPlugin.SkeletonType.HandLeft,
  36. HandRight = OVRPlugin.SkeletonType.HandRight,
  37. }
  38. public enum BoneId
  39. {
  40. Invalid = OVRPlugin.BoneId.Invalid,
  41. Hand_Start = OVRPlugin.BoneId.Hand_Start,
  42. Hand_WristRoot = OVRPlugin.BoneId.Hand_WristRoot, // root frame of the hand, where the wrist is located
  43. Hand_ForearmStub = OVRPlugin.BoneId.Hand_ForearmStub, // frame for user's forearm
  44. Hand_Thumb0 = OVRPlugin.BoneId.Hand_Thumb0, // thumb trapezium bone
  45. Hand_Thumb1 = OVRPlugin.BoneId.Hand_Thumb1, // thumb metacarpal bone
  46. Hand_Thumb2 = OVRPlugin.BoneId.Hand_Thumb2, // thumb proximal phalange bone
  47. Hand_Thumb3 = OVRPlugin.BoneId.Hand_Thumb3, // thumb distal phalange bone
  48. Hand_Index1 = OVRPlugin.BoneId.Hand_Index1, // index proximal phalange bone
  49. Hand_Index2 = OVRPlugin.BoneId.Hand_Index2, // index intermediate phalange bone
  50. Hand_Index3 = OVRPlugin.BoneId.Hand_Index3, // index distal phalange bone
  51. Hand_Middle1 = OVRPlugin.BoneId.Hand_Middle1, // middle proximal phalange bone
  52. Hand_Middle2 = OVRPlugin.BoneId.Hand_Middle2, // middle intermediate phalange bone
  53. Hand_Middle3 = OVRPlugin.BoneId.Hand_Middle3, // middle distal phalange bone
  54. Hand_Ring1 = OVRPlugin.BoneId.Hand_Ring1, // ring proximal phalange bone
  55. Hand_Ring2 = OVRPlugin.BoneId.Hand_Ring2, // ring intermediate phalange bone
  56. Hand_Ring3 = OVRPlugin.BoneId.Hand_Ring3, // ring distal phalange bone
  57. Hand_Pinky0 = OVRPlugin.BoneId.Hand_Pinky0, // pinky metacarpal bone
  58. Hand_Pinky1 = OVRPlugin.BoneId.Hand_Pinky1, // pinky proximal phalange bone
  59. Hand_Pinky2 = OVRPlugin.BoneId.Hand_Pinky2, // pinky intermediate phalange bone
  60. Hand_Pinky3 = OVRPlugin.BoneId.Hand_Pinky3, // pinky distal phalange bone
  61. Hand_MaxSkinnable = OVRPlugin.BoneId.Hand_MaxSkinnable,
  62. // Bone tips are position only. They are not used for skinning but are useful for hit-testing.
  63. // NOTE: Hand_ThumbTip == Hand_MaxSkinnable since the extended tips need to be contiguous
  64. Hand_ThumbTip = OVRPlugin.BoneId.Hand_ThumbTip, // tip of the thumb
  65. Hand_IndexTip = OVRPlugin.BoneId.Hand_IndexTip, // tip of the index finger
  66. Hand_MiddleTip = OVRPlugin.BoneId.Hand_MiddleTip, // tip of the middle finger
  67. Hand_RingTip = OVRPlugin.BoneId.Hand_RingTip, // tip of the ring finger
  68. Hand_PinkyTip = OVRPlugin.BoneId.Hand_PinkyTip, // tip of the pinky
  69. Hand_End = OVRPlugin.BoneId.Hand_End,
  70. // add new bones here
  71. Max = OVRPlugin.BoneId.Max
  72. }
  73. [SerializeField]
  74. private SkeletonType _skeletonType = SkeletonType.None;
  75. [SerializeField]
  76. private IOVRSkeletonDataProvider _dataProvider;
  77. [SerializeField]
  78. private bool _updateRootPose = false;
  79. [SerializeField]
  80. private bool _updateRootScale = false;
  81. [SerializeField]
  82. private bool _enablePhysicsCapsules = false;
  83. private GameObject _bonesGO;
  84. private GameObject _bindPosesGO;
  85. private GameObject _capsulesGO;
  86. protected List<OVRBone> _bones;
  87. private List<OVRBone> _bindPoses;
  88. private List<OVRBoneCapsule> _capsules;
  89. private readonly Quaternion wristFixupRotation = new Quaternion(0.0f, 1.0f, 0.0f, 0.0f);
  90. public bool IsInitialized { get; private set; }
  91. public bool IsDataValid { get; private set; }
  92. public bool IsDataHighConfidence { get; private set; }
  93. public IList<OVRBone> Bones { get; protected set; }
  94. public IList<OVRBone> BindPoses { get; private set; }
  95. public IList<OVRBoneCapsule> Capsules { get; private set; }
  96. public SkeletonType GetSkeletonType() { return _skeletonType; }
  97. private void Awake()
  98. {
  99. if (_dataProvider == null)
  100. {
  101. _dataProvider = GetComponent<IOVRSkeletonDataProvider>();
  102. }
  103. _bones = new List<OVRBone>();
  104. Bones = _bones.AsReadOnly();
  105. _bindPoses = new List<OVRBone>();
  106. BindPoses = _bindPoses.AsReadOnly();
  107. _capsules = new List<OVRBoneCapsule>();
  108. Capsules = _capsules.AsReadOnly();
  109. }
  110. private void Start()
  111. {
  112. if (_skeletonType != SkeletonType.None)
  113. {
  114. Initialize();
  115. }
  116. }
  117. private void Initialize()
  118. {
  119. var skeleton = new OVRPlugin.Skeleton();
  120. if (OVRPlugin.GetSkeleton((OVRPlugin.SkeletonType)_skeletonType, out skeleton))
  121. {
  122. InitializeBones(skeleton);
  123. InitializeBindPose(skeleton);
  124. InitializeCapsules(skeleton);
  125. IsInitialized = true;
  126. }
  127. }
  128. virtual protected void InitializeBones(OVRPlugin.Skeleton skeleton)
  129. {
  130. _bones = new List<OVRBone>(new OVRBone[skeleton.NumBones]);
  131. Bones = _bones.AsReadOnly();
  132. if (!_bonesGO)
  133. {
  134. _bonesGO = new GameObject("Bones");
  135. _bonesGO.transform.SetParent(transform, false);
  136. _bonesGO.transform.localPosition = Vector3.zero;
  137. _bonesGO.transform.localRotation = Quaternion.identity;
  138. }
  139. // pre-populate bones list before attempting to apply bone hierarchy
  140. for (int i = 0; i < skeleton.NumBones; ++i)
  141. {
  142. BoneId id = (OVRSkeleton.BoneId)skeleton.Bones[i].Id;
  143. short parentIdx = skeleton.Bones[i].ParentBoneIndex;
  144. Vector3 pos = skeleton.Bones[i].Pose.Position.FromFlippedXVector3f();
  145. Quaternion rot = skeleton.Bones[i].Pose.Orientation.FromFlippedXQuatf();
  146. var boneGO = new GameObject(id.ToString());
  147. boneGO.transform.localPosition = pos;
  148. boneGO.transform.localRotation = rot;
  149. _bones[i] = new OVRBone(id, parentIdx, boneGO.transform);
  150. }
  151. for (int i = 0; i < skeleton.NumBones; ++i)
  152. {
  153. if (((OVRPlugin.BoneId)skeleton.Bones[i].ParentBoneIndex) == OVRPlugin.BoneId.Invalid)
  154. {
  155. _bones[i].Transform.SetParent(_bonesGO.transform, false);
  156. }
  157. else
  158. {
  159. _bones[i].Transform.SetParent(_bones[_bones[i].ParentBoneIndex].Transform, false);
  160. }
  161. }
  162. }
  163. private void InitializeBindPose(OVRPlugin.Skeleton skeleton)
  164. {
  165. _bindPoses = new List<OVRBone>(new OVRBone[skeleton.NumBones]);
  166. BindPoses = _bindPoses.AsReadOnly();
  167. if (!_bindPosesGO)
  168. {
  169. _bindPosesGO = new GameObject("BindPoses");
  170. _bindPosesGO.transform.SetParent(transform, false);
  171. _bindPosesGO.transform.localPosition = Vector3.zero;
  172. _bindPosesGO.transform.localRotation = Quaternion.identity;
  173. }
  174. for (int i = 0; i < skeleton.NumBones; ++i)
  175. {
  176. BoneId id = (OVRSkeleton.BoneId)skeleton.Bones[i].Id;
  177. short parentIdx = skeleton.Bones[i].ParentBoneIndex;
  178. var bindPoseGO = new GameObject(id.ToString());
  179. OVRBone bone = _bones[i];
  180. if (bone.Transform != null)
  181. {
  182. bindPoseGO.transform.localPosition = bone.Transform.localPosition;
  183. bindPoseGO.transform.localRotation = bone.Transform.localRotation;
  184. }
  185. _bindPoses[i] = new OVRBone(id, parentIdx, bindPoseGO.transform);
  186. }
  187. for (int i = 0; i < skeleton.NumBones; ++i)
  188. {
  189. if (((OVRPlugin.BoneId)skeleton.Bones[i].ParentBoneIndex) == OVRPlugin.BoneId.Invalid)
  190. {
  191. _bindPoses[i].Transform.SetParent(_bindPosesGO.transform, false);
  192. }
  193. else
  194. {
  195. _bindPoses[i].Transform.SetParent(_bindPoses[_bones[i].ParentBoneIndex].Transform, false);
  196. }
  197. }
  198. }
  199. private void InitializeCapsules(OVRPlugin.Skeleton skeleton)
  200. {
  201. if (_enablePhysicsCapsules)
  202. {
  203. _capsules = new List<OVRBoneCapsule>(new OVRBoneCapsule[skeleton.NumBoneCapsules]);
  204. Capsules = _capsules.AsReadOnly();
  205. if (!_capsulesGO)
  206. {
  207. _capsulesGO = new GameObject("Capsules");
  208. _capsulesGO.transform.SetParent(transform, false);
  209. _capsulesGO.transform.localPosition = Vector3.zero;
  210. _capsulesGO.transform.localRotation = Quaternion.identity;
  211. }
  212. _capsules = new List<OVRBoneCapsule>(new OVRBoneCapsule[skeleton.NumBoneCapsules]);
  213. Capsules = _capsules.AsReadOnly();
  214. for (int i = 0; i < skeleton.NumBoneCapsules; ++i)
  215. {
  216. var capsule = skeleton.BoneCapsules[i];
  217. Transform bone = Bones[capsule.BoneIndex].Transform;
  218. var capsuleRigidBodyGO = new GameObject((_bones[capsule.BoneIndex].Id).ToString() + "_CapsuleRigidBody");
  219. capsuleRigidBodyGO.transform.SetParent(_capsulesGO.transform, false);
  220. capsuleRigidBodyGO.transform.position = bone.position;
  221. capsuleRigidBodyGO.transform.rotation = bone.rotation;
  222. var capsuleRigidBody = capsuleRigidBodyGO.AddComponent<Rigidbody>();
  223. capsuleRigidBody.mass = 1.0f;
  224. capsuleRigidBody.isKinematic = true;
  225. capsuleRigidBody.useGravity = false;
  226. #if UNITY_2018_3_OR_NEWER
  227. capsuleRigidBody.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
  228. #else
  229. capsuleRigidBody.collisionDetectionMode = CollisionDetectionMode.Continuous;
  230. #endif
  231. var capsuleColliderGO = new GameObject((_bones[capsule.BoneIndex].Id).ToString() + "_CapsuleCollider");
  232. capsuleColliderGO.transform.SetParent(capsuleRigidBodyGO.transform, false);
  233. var capsuleCollider = capsuleColliderGO.AddComponent<CapsuleCollider>();
  234. var p0 = capsule.Points[0].FromFlippedXVector3f();
  235. var p1 = capsule.Points[1].FromFlippedXVector3f();
  236. var delta = p1 - p0;
  237. var mag = delta.magnitude;
  238. var rot = Quaternion.FromToRotation(Vector3.right, delta);
  239. capsuleCollider.radius = capsule.Radius;
  240. capsuleCollider.height = mag + capsule.Radius * 2.0f;
  241. capsuleCollider.isTrigger = false;
  242. capsuleCollider.direction = 0;
  243. capsuleColliderGO.transform.localPosition = p0;
  244. capsuleColliderGO.transform.localRotation = rot;
  245. capsuleCollider.center = Vector3.right * mag * 0.5f;
  246. _capsules[i] = new OVRBoneCapsule(capsule.BoneIndex, capsuleRigidBody, capsuleCollider);
  247. }
  248. }
  249. }
  250. private void Update()
  251. {
  252. if (!IsInitialized || _dataProvider == null)
  253. {
  254. IsDataValid = false;
  255. IsDataHighConfidence = false;
  256. return;
  257. }
  258. var data = _dataProvider.GetSkeletonPoseData();
  259. IsDataValid = data.IsDataValid;
  260. if (data.IsDataValid)
  261. {
  262. IsDataHighConfidence = data.IsDataHighConfidence;
  263. if (_updateRootPose)
  264. {
  265. transform.localPosition = data.RootPose.Position.FromFlippedZVector3f();
  266. transform.localRotation = data.RootPose.Orientation.FromFlippedZQuatf();
  267. }
  268. if (_updateRootScale)
  269. {
  270. transform.localScale = new Vector3(data.RootScale, data.RootScale, data.RootScale);
  271. }
  272. for (var i = 0; i < _bones.Count; ++i)
  273. {
  274. if (_bones[i].Transform != null)
  275. {
  276. _bones[i].Transform.localRotation = data.BoneRotations[i].FromFlippedXQuatf();
  277. if (_bones[i].Id == BoneId.Hand_WristRoot)
  278. {
  279. _bones[i].Transform.localRotation *= wristFixupRotation;
  280. }
  281. }
  282. }
  283. }
  284. }
  285. private void FixedUpdate()
  286. {
  287. if (!IsInitialized || _dataProvider == null)
  288. {
  289. IsDataValid = false;
  290. IsDataHighConfidence = false;
  291. return;
  292. }
  293. Update();
  294. if (_enablePhysicsCapsules)
  295. {
  296. var data = _dataProvider.GetSkeletonPoseData();
  297. IsDataValid = data.IsDataValid;
  298. IsDataHighConfidence = data.IsDataHighConfidence;
  299. for (int i = 0; i < _capsules.Count; ++i)
  300. {
  301. OVRBoneCapsule capsule = _capsules[i];
  302. var capsuleGO = capsule.CapsuleRigidbody.gameObject;
  303. if (data.IsDataValid && data.IsDataHighConfidence)
  304. {
  305. Transform bone = _bones[(int)capsule.BoneIndex].Transform;
  306. if (capsuleGO.activeSelf)
  307. {
  308. capsule.CapsuleRigidbody.MovePosition(bone.position);
  309. capsule.CapsuleRigidbody.MoveRotation(bone.rotation);
  310. }
  311. else
  312. {
  313. capsuleGO.SetActive(true);
  314. capsule.CapsuleRigidbody.position = bone.position;
  315. capsule.CapsuleRigidbody.rotation = bone.rotation;
  316. }
  317. }
  318. else
  319. {
  320. if (capsuleGO.activeSelf)
  321. {
  322. capsuleGO.SetActive(false);
  323. }
  324. }
  325. }
  326. }
  327. }
  328. public BoneId GetCurrentStartBoneId()
  329. {
  330. switch (_skeletonType)
  331. {
  332. case SkeletonType.HandLeft:
  333. case SkeletonType.HandRight:
  334. return BoneId.Hand_Start;
  335. case SkeletonType.None:
  336. default:
  337. return BoneId.Invalid;
  338. }
  339. }
  340. public BoneId GetCurrentEndBoneId()
  341. {
  342. switch (_skeletonType)
  343. {
  344. case SkeletonType.HandLeft:
  345. case SkeletonType.HandRight:
  346. return BoneId.Hand_End;
  347. case SkeletonType.None:
  348. default:
  349. return BoneId.Invalid;
  350. }
  351. }
  352. private BoneId GetCurrentMaxSkinnableBoneId()
  353. {
  354. switch (_skeletonType)
  355. {
  356. case SkeletonType.HandLeft:
  357. case SkeletonType.HandRight:
  358. return BoneId.Hand_MaxSkinnable;
  359. case SkeletonType.None:
  360. default:
  361. return BoneId.Invalid;
  362. }
  363. }
  364. public int GetCurrentNumBones()
  365. {
  366. switch (_skeletonType)
  367. {
  368. case SkeletonType.HandLeft:
  369. case SkeletonType.HandRight:
  370. return GetCurrentEndBoneId() - GetCurrentStartBoneId();
  371. case SkeletonType.None:
  372. default:
  373. return 0;
  374. }
  375. }
  376. public int GetCurrentNumSkinnableBones()
  377. {
  378. switch (_skeletonType)
  379. {
  380. case SkeletonType.HandLeft:
  381. case SkeletonType.HandRight:
  382. return GetCurrentMaxSkinnableBoneId() - GetCurrentStartBoneId();
  383. case SkeletonType.None:
  384. default:
  385. return 0;
  386. }
  387. }
  388. }
  389. public class OVRBone
  390. {
  391. public OVRSkeleton.BoneId Id { get; private set; }
  392. public short ParentBoneIndex { get; private set; }
  393. public Transform Transform { get; private set; }
  394. public OVRBone(OVRSkeleton.BoneId id, short parentBoneIndex, Transform trans)
  395. {
  396. Id = id;
  397. ParentBoneIndex = parentBoneIndex;
  398. Transform = trans;
  399. }
  400. }
  401. public class OVRBoneCapsule
  402. {
  403. public short BoneIndex { get; private set; }
  404. public Rigidbody CapsuleRigidbody { get; private set; }
  405. public CapsuleCollider CapsuleCollider { get; private set; }
  406. public OVRBoneCapsule(short boneIndex, Rigidbody capsuleRigidBody, CapsuleCollider capsuleCollider)
  407. {
  408. BoneIndex = boneIndex;
  409. CapsuleRigidbody = capsuleRigidBody;
  410. CapsuleCollider = capsuleCollider;
  411. }
  412. }