Files
2025-07-21 09:11:14 +02:00

968 lines
38 KiB
C#

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* Licensed under the Oculus SDK License Agreement (the "License");
* you may not use the Oculus 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/oculussdk/
*
* Unless required by applicable law or agreed to in writing, the Oculus 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.Generic;
using UnityEngine;
using UnityEngine.Assertions;
public class OVRSkeleton : MonoBehaviour
{
public interface IOVRSkeletonDataProvider
{
SkeletonType GetSkeletonType();
SkeletonPoseData GetSkeletonPoseData();
bool enabled { get; }
}
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 OVRPlugin.Vector3f[] BoneTranslations { get; set; }
public int SkeletonChangedCount { get; set; }
}
public enum SkeletonType
{
None = OVRPlugin.SkeletonType.None,
HandLeft = OVRPlugin.SkeletonType.HandLeft,
HandRight = OVRPlugin.SkeletonType.HandRight,
Body = OVRPlugin.SkeletonType.Body,
}
public enum BoneId
{
Invalid = OVRPlugin.BoneId.Invalid,
// hand bones
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,
// body bones
Body_Start = OVRPlugin.BoneId.Body_Start,
Body_Root = OVRPlugin.BoneId.Body_Root,
Body_Hips = OVRPlugin.BoneId.Body_Hips,
Body_SpineLower = OVRPlugin.BoneId.Body_SpineLower,
Body_SpineMiddle = OVRPlugin.BoneId.Body_SpineMiddle,
Body_SpineUpper = OVRPlugin.BoneId.Body_SpineUpper,
Body_Chest = OVRPlugin.BoneId.Body_Chest,
Body_Neck = OVRPlugin.BoneId.Body_Neck,
Body_Head = OVRPlugin.BoneId.Body_Head,
Body_LeftShoulder = OVRPlugin.BoneId.Body_LeftShoulder,
Body_LeftScapula = OVRPlugin.BoneId.Body_LeftScapula,
Body_LeftArmUpper = OVRPlugin.BoneId.Body_LeftArmUpper,
Body_LeftArmLower = OVRPlugin.BoneId.Body_LeftArmLower,
Body_LeftHandWristTwist = OVRPlugin.BoneId.Body_LeftHandWristTwist,
Body_RightShoulder = OVRPlugin.BoneId.Body_RightShoulder,
Body_RightScapula = OVRPlugin.BoneId.Body_RightScapula,
Body_RightArmUpper = OVRPlugin.BoneId.Body_RightArmUpper,
Body_RightArmLower = OVRPlugin.BoneId.Body_RightArmLower,
Body_RightHandWristTwist = OVRPlugin.BoneId.Body_RightHandWristTwist,
Body_LeftHandPalm = OVRPlugin.BoneId.Body_LeftHandPalm,
Body_LeftHandWrist = OVRPlugin.BoneId.Body_LeftHandWrist,
Body_LeftHandThumbMetacarpal = OVRPlugin.BoneId.Body_LeftHandThumbMetacarpal,
Body_LeftHandThumbProximal = OVRPlugin.BoneId.Body_LeftHandThumbProximal,
Body_LeftHandThumbDistal = OVRPlugin.BoneId.Body_LeftHandThumbDistal,
Body_LeftHandThumbTip = OVRPlugin.BoneId.Body_LeftHandThumbTip,
Body_LeftHandIndexMetacarpal = OVRPlugin.BoneId.Body_LeftHandIndexMetacarpal,
Body_LeftHandIndexProximal = OVRPlugin.BoneId.Body_LeftHandIndexProximal,
Body_LeftHandIndexIntermediate = OVRPlugin.BoneId.Body_LeftHandIndexIntermediate,
Body_LeftHandIndexDistal = OVRPlugin.BoneId.Body_LeftHandIndexDistal,
Body_LeftHandIndexTip = OVRPlugin.BoneId.Body_LeftHandIndexTip,
Body_LeftHandMiddleMetacarpal = OVRPlugin.BoneId.Body_LeftHandMiddleMetacarpal,
Body_LeftHandMiddleProximal = OVRPlugin.BoneId.Body_LeftHandMiddleProximal,
Body_LeftHandMiddleIntermediate = OVRPlugin.BoneId.Body_LeftHandMiddleIntermediate,
Body_LeftHandMiddleDistal = OVRPlugin.BoneId.Body_LeftHandMiddleDistal,
Body_LeftHandMiddleTip = OVRPlugin.BoneId.Body_LeftHandMiddleTip,
Body_LeftHandRingMetacarpal = OVRPlugin.BoneId.Body_LeftHandRingMetacarpal,
Body_LeftHandRingProximal = OVRPlugin.BoneId.Body_LeftHandRingProximal,
Body_LeftHandRingIntermediate = OVRPlugin.BoneId.Body_LeftHandRingIntermediate,
Body_LeftHandRingDistal = OVRPlugin.BoneId.Body_LeftHandRingDistal,
Body_LeftHandRingTip = OVRPlugin.BoneId.Body_LeftHandRingTip,
Body_LeftHandLittleMetacarpal = OVRPlugin.BoneId.Body_LeftHandLittleMetacarpal,
Body_LeftHandLittleProximal = OVRPlugin.BoneId.Body_LeftHandLittleProximal,
Body_LeftHandLittleIntermediate = OVRPlugin.BoneId.Body_LeftHandLittleIntermediate,
Body_LeftHandLittleDistal = OVRPlugin.BoneId.Body_LeftHandLittleDistal,
Body_LeftHandLittleTip = OVRPlugin.BoneId.Body_LeftHandLittleTip,
Body_RightHandPalm = OVRPlugin.BoneId.Body_RightHandPalm,
Body_RightHandWrist = OVRPlugin.BoneId.Body_RightHandWrist,
Body_RightHandThumbMetacarpal = OVRPlugin.BoneId.Body_RightHandThumbMetacarpal,
Body_RightHandThumbProximal = OVRPlugin.BoneId.Body_RightHandThumbProximal,
Body_RightHandThumbDistal = OVRPlugin.BoneId.Body_RightHandThumbDistal,
Body_RightHandThumbTip = OVRPlugin.BoneId.Body_RightHandThumbTip,
Body_RightHandIndexMetacarpal = OVRPlugin.BoneId.Body_RightHandIndexMetacarpal,
Body_RightHandIndexProximal = OVRPlugin.BoneId.Body_RightHandIndexProximal,
Body_RightHandIndexIntermediate = OVRPlugin.BoneId.Body_RightHandIndexIntermediate,
Body_RightHandIndexDistal = OVRPlugin.BoneId.Body_RightHandIndexDistal,
Body_RightHandIndexTip = OVRPlugin.BoneId.Body_RightHandIndexTip,
Body_RightHandMiddleMetacarpal = OVRPlugin.BoneId.Body_RightHandMiddleMetacarpal,
Body_RightHandMiddleProximal = OVRPlugin.BoneId.Body_RightHandMiddleProximal,
Body_RightHandMiddleIntermediate = OVRPlugin.BoneId.Body_RightHandMiddleIntermediate,
Body_RightHandMiddleDistal = OVRPlugin.BoneId.Body_RightHandMiddleDistal,
Body_RightHandMiddleTip = OVRPlugin.BoneId.Body_RightHandMiddleTip,
Body_RightHandRingMetacarpal = OVRPlugin.BoneId.Body_RightHandRingMetacarpal,
Body_RightHandRingProximal = OVRPlugin.BoneId.Body_RightHandRingProximal,
Body_RightHandRingIntermediate = OVRPlugin.BoneId.Body_RightHandRingIntermediate,
Body_RightHandRingDistal = OVRPlugin.BoneId.Body_RightHandRingDistal,
Body_RightHandRingTip = OVRPlugin.BoneId.Body_RightHandRingTip,
Body_RightHandLittleMetacarpal = OVRPlugin.BoneId.Body_RightHandLittleMetacarpal,
Body_RightHandLittleProximal = OVRPlugin.BoneId.Body_RightHandLittleProximal,
Body_RightHandLittleIntermediate = OVRPlugin.BoneId.Body_RightHandLittleIntermediate,
Body_RightHandLittleDistal = OVRPlugin.BoneId.Body_RightHandLittleDistal,
Body_RightHandLittleTip = OVRPlugin.BoneId.Body_RightHandLittleTip,
Body_End = OVRPlugin.BoneId.Body_End,
// add new bones here
Max = OVRPlugin.BoneId.Max,
}
[SerializeField]
protected SkeletonType _skeletonType = SkeletonType.None;
[SerializeField]
private IOVRSkeletonDataProvider _dataProvider;
[SerializeField]
private bool _updateRootPose = false;
[SerializeField]
private bool _updateRootScale = false;
[SerializeField]
private bool _enablePhysicsCapsules = false;
[SerializeField]
private bool _applyBoneTranslations = true;
private GameObject _bonesGO;
private GameObject _bindPosesGO;
private GameObject _capsulesGO;
protected List<OVRBone> _bones;
private List<OVRBone> _bindPoses;
private List<OVRBoneCapsule> _capsules;
protected OVRPlugin.Skeleton2 _skeleton = new OVRPlugin.Skeleton2();
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;
}
internal virtual void SetSkeletonType(SkeletonType type)
{
_skeletonType = type;
}
public bool IsValidBone(BoneId bone)
{
return OVRPlugin.IsValidBone((OVRPlugin.BoneId)bone, (OVRPlugin.SkeletonType)_skeletonType);
}
public int SkeletonChangedCount { get; private set; }
protected virtual void Awake()
{
if (_dataProvider == null)
{
var foundDataProvider = SearchSkeletonDataProvider();
if (foundDataProvider != null)
{
_dataProvider = foundDataProvider;
if (_dataProvider is MonoBehaviour mb)
{
Debug.Log($"Found IOVRSkeletonDataProvider reference in {mb.name} due to unassigned field.");
}
}
}
_bones = new List<OVRBone>();
Bones = _bones.AsReadOnly();
_bindPoses = new List<OVRBone>();
BindPoses = _bindPoses.AsReadOnly();
_capsules = new List<OVRBoneCapsule>();
Capsules = _capsules.AsReadOnly();
}
internal IOVRSkeletonDataProvider SearchSkeletonDataProvider()
{
var dataProviders = gameObject.GetComponentsInParent<IOVRSkeletonDataProvider>();
foreach (var dataProvider in dataProviders)
{
if (dataProvider.GetSkeletonType() == _skeletonType)
{
return dataProvider;
}
}
return null;
}
/// <summary>
/// Start this instance.
/// Initialize data structures.
/// </summary>
protected virtual void Start()
{
if (_dataProvider == null && _skeletonType == SkeletonType.Body)
{
Debug.LogWarning("OVRSkeleton and its subclasses requires OVRBody to function.");
}
if (ShouldInitialize())
{
Initialize();
}
}
private bool ShouldInitialize()
{
if (IsInitialized)
{
return false;
}
if (_dataProvider != null && !_dataProvider.enabled)
{
return false;
}
if (_skeletonType == SkeletonType.None)
{
return false;
}
else if (IsHandSkeleton(_skeletonType))
{
#if UNITY_EDITOR
return OVRInput.IsControllerConnected(OVRInput.Controller.Hands);
#else
return true;
#endif
}
else
{
return true;
}
}
private void Initialize()
{
if (OVRPlugin.GetSkeleton2((OVRPlugin.SkeletonType)_skeletonType, ref _skeleton))
{
InitializeBones();
InitializeBindPose();
InitializeCapsules();
IsInitialized = true;
}
}
protected virtual Transform GetBoneTransform(BoneId boneId) => null;
protected virtual void InitializeBones()
{
bool flipX = IsHandSkeleton(_skeletonType);
if (!_bonesGO)
{
_bonesGO = new GameObject("Bones");
_bonesGO.transform.SetParent(transform, false);
_bonesGO.transform.localPosition = Vector3.zero;
_bonesGO.transform.localRotation = Quaternion.identity;
}
if (_bones == null || _bones.Count != _skeleton.NumBones)
{
_bones = new List<OVRBone>(new OVRBone[_skeleton.NumBones]);
Bones = _bones.AsReadOnly();
}
bool newBonesCreated = false;
// pre-populate bones list before attempting to apply bone hierarchy
for (int i = 0; i < _bones.Count; ++i)
{
OVRBone bone = _bones[i] ?? (_bones[i] = new OVRBone());
bone.Id = (OVRSkeleton.BoneId)_skeleton.Bones[i].Id;
bone.ParentBoneIndex = _skeleton.Bones[i].ParentBoneIndex;
Assert.IsTrue((int)bone.Id >= 0 && bone.Id <= BoneId.Max);
// don't create new bones each time; rely on
// pre-existing bone transforms.
if (bone.Transform == null)
{
newBonesCreated = true;
bone.Transform = GetBoneTransform(bone.Id);
if (bone.Transform == null)
{
bone.Transform = new GameObject(BoneLabelFromBoneId(_skeletonType, bone.Id)).transform;
}
}
// if allocated bone here before, make sure the name is correct.
if (GetBoneTransform(bone.Id) == null)
{
bone.Transform.name = BoneLabelFromBoneId(_skeletonType, bone.Id);
}
var pose = _skeleton.Bones[i].Pose;
if (_applyBoneTranslations)
{
bone.Transform.localPosition = flipX
? pose.Position.FromFlippedXVector3f()
: pose.Position.FromFlippedZVector3f();
}
bone.Transform.localRotation = flipX
? pose.Orientation.FromFlippedXQuatf()
: pose.Orientation.FromFlippedZQuatf();
}
if (newBonesCreated)
{
for (int i = 0; i < _bones.Count; ++i)
{
if (!IsValidBone((BoneId)_bones[i].ParentBoneIndex) ||
IsBodySkeleton(_skeletonType)) // Body bones are always in tracking space
{
_bones[i].Transform.SetParent(_bonesGO.transform, false);
}
else
{
_bones[i].Transform.SetParent(_bones[_bones[i].ParentBoneIndex].Transform, false);
}
}
}
}
private void InitializeBindPose()
{
if (!_bindPosesGO)
{
_bindPosesGO = new GameObject("BindPoses");
_bindPosesGO.transform.SetParent(transform, false);
_bindPosesGO.transform.localPosition = Vector3.zero;
_bindPosesGO.transform.localRotation = Quaternion.identity;
}
if (_bindPoses == null || _bindPoses.Count != _bones.Count)
{
_bindPoses = new List<OVRBone>(new OVRBone[_bones.Count]);
BindPoses = _bindPoses.AsReadOnly();
}
// pre-populate bones list before attempting to apply bone hierarchy
for (int i = 0; i < _bindPoses.Count; ++i)
{
OVRBone bone = _bones[i];
OVRBone bindPoseBone = _bindPoses[i] ?? (_bindPoses[i] = new OVRBone());
bindPoseBone.Id = bone.Id;
bindPoseBone.ParentBoneIndex = bone.ParentBoneIndex;
Transform trans = bindPoseBone.Transform
? bindPoseBone.Transform
: (bindPoseBone.Transform =
new GameObject(BoneLabelFromBoneId(_skeletonType, bindPoseBone.Id)).transform);
trans.localPosition = bone.Transform.localPosition;
trans.localRotation = bone.Transform.localRotation;
}
for (int i = 0; i < _bindPoses.Count; ++i)
{
if (!IsValidBone((BoneId)_bindPoses[i].ParentBoneIndex) ||
IsBodySkeleton(_skeletonType)) // Body bones are always in tracking space
{
_bindPoses[i].Transform.SetParent(_bindPosesGO.transform, false);
}
else
{
_bindPoses[i].Transform.SetParent(_bindPoses[_bindPoses[i].ParentBoneIndex].Transform, false);
}
}
}
private void InitializeCapsules()
{
bool flipX = IsHandSkeleton(_skeletonType);
if (_enablePhysicsCapsules)
{
if (!_capsulesGO)
{
_capsulesGO = new GameObject("Capsules");
_capsulesGO.transform.SetParent(transform, false);
_capsulesGO.transform.localPosition = Vector3.zero;
_capsulesGO.transform.localRotation = Quaternion.identity;
}
if (_capsules == null || _capsules.Count != _skeleton.NumBoneCapsules)
{
_capsules = new List<OVRBoneCapsule>(new OVRBoneCapsule[_skeleton.NumBoneCapsules]);
Capsules = _capsules.AsReadOnly();
}
for (int i = 0; i < _capsules.Count; ++i)
{
OVRBone bone = _bones[_skeleton.BoneCapsules[i].BoneIndex];
OVRBoneCapsule capsule = _capsules[i] ?? (_capsules[i] = new OVRBoneCapsule());
capsule.BoneIndex = _skeleton.BoneCapsules[i].BoneIndex;
if (capsule.CapsuleRigidbody == null)
{
capsule.CapsuleRigidbody =
new GameObject(BoneLabelFromBoneId(_skeletonType, bone.Id) + "_CapsuleRigidbody")
.AddComponent<Rigidbody>();
capsule.CapsuleRigidbody.mass = 1.0f;
capsule.CapsuleRigidbody.isKinematic = true;
capsule.CapsuleRigidbody.useGravity = false;
capsule.CapsuleRigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
}
GameObject rbGO = capsule.CapsuleRigidbody.gameObject;
rbGO.transform.SetParent(_capsulesGO.transform, false);
rbGO.transform.position = bone.Transform.position;
rbGO.transform.rotation = bone.Transform.rotation;
if (capsule.CapsuleCollider == null)
{
capsule.CapsuleCollider =
new GameObject(BoneLabelFromBoneId(_skeletonType, bone.Id) + "_CapsuleCollider")
.AddComponent<CapsuleCollider>();
capsule.CapsuleCollider.isTrigger = false;
}
var p0 = flipX
? _skeleton.BoneCapsules[i].StartPoint.FromFlippedXVector3f()
: _skeleton.BoneCapsules[i].StartPoint.FromFlippedZVector3f();
var p1 = flipX
? _skeleton.BoneCapsules[i].EndPoint.FromFlippedXVector3f()
: _skeleton.BoneCapsules[i].EndPoint.FromFlippedZVector3f();
var delta = p1 - p0;
var mag = delta.magnitude;
var rot = Quaternion.FromToRotation(Vector3.right, delta);
capsule.CapsuleCollider.radius = _skeleton.BoneCapsules[i].Radius;
capsule.CapsuleCollider.height = mag + _skeleton.BoneCapsules[i].Radius * 2.0f;
capsule.CapsuleCollider.direction = 0;
capsule.CapsuleCollider.center = Vector3.right * mag * 0.5f;
GameObject ccGO = capsule.CapsuleCollider.gameObject;
ccGO.transform.SetParent(rbGO.transform, false);
ccGO.transform.localPosition = p0;
ccGO.transform.localRotation = rot;
}
}
}
protected virtual void Update()
{
UpdateSkeleton();
}
protected void UpdateSkeleton()
{
if (ShouldInitialize())
{
Initialize();
}
if (!IsInitialized || _dataProvider == null)
{
IsDataValid = false;
IsDataHighConfidence = false;
return;
}
var data = _dataProvider.GetSkeletonPoseData();
IsDataValid = data.IsDataValid;
if (!data.IsDataValid)
{
return;
}
if (SkeletonChangedCount != data.SkeletonChangedCount)
{
SkeletonChangedCount = data.SkeletonChangedCount;
IsInitialized = false;
Initialize();
}
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)
{
var boneTransform = _bones[i].Transform;
if (boneTransform == null) continue;
if (IsBodySkeleton(_skeletonType))
{
boneTransform.localPosition = data.BoneTranslations[i].FromFlippedZVector3f();
boneTransform.localRotation = data.BoneRotations[i].FromFlippedZQuatf();
}
else if (IsHandSkeleton(_skeletonType))
{
boneTransform.localRotation = data.BoneRotations[i].FromFlippedXQuatf();
if (_bones[i].Id == BoneId.Hand_WristRoot)
{
boneTransform.localRotation *= wristFixupRotation;
}
}
else
{
boneTransform.localRotation = data.BoneRotations[i].FromFlippedZQuatf();
}
}
}
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.Body:
return BoneId.Body_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.Body:
return BoneId.Body_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.Body:
return BoneId.Body_End;
case SkeletonType.None:
default:
return BoneId.Invalid;
}
}
public int GetCurrentNumBones()
{
switch (_skeletonType)
{
case SkeletonType.HandLeft:
case SkeletonType.HandRight:
case SkeletonType.Body:
return GetCurrentEndBoneId() - GetCurrentStartBoneId();
case SkeletonType.None:
default:
return 0;
}
}
public int GetCurrentNumSkinnableBones()
{
switch (_skeletonType)
{
case SkeletonType.HandLeft:
case SkeletonType.HandRight:
case SkeletonType.Body:
return GetCurrentMaxSkinnableBoneId() - GetCurrentStartBoneId();
case SkeletonType.None:
default:
return 0;
}
}
// force aliased enum values to the more appropriate value
public static string BoneLabelFromBoneId(OVRSkeleton.SkeletonType skeletonType, BoneId boneId)
{
if (skeletonType == OVRSkeleton.SkeletonType.Body)
{
switch (boneId)
{
case BoneId.Body_Root:
return "Body_Root";
case BoneId.Body_Hips:
return "Body_Hips";
case BoneId.Body_SpineLower:
return "Body_SpineLower";
case BoneId.Body_SpineMiddle:
return "Body_SpineMiddle";
case BoneId.Body_SpineUpper:
return "Body_SpineUpper";
case BoneId.Body_Chest:
return "Body_Chest";
case BoneId.Body_Neck:
return "Body_Neck";
case BoneId.Body_Head:
return "Body_Head";
case BoneId.Body_LeftShoulder:
return "Body_LeftShoulder";
case BoneId.Body_LeftScapula:
return "Body_LeftScapula";
case BoneId.Body_LeftArmUpper:
return "Body_LeftArmUpper";
case BoneId.Body_LeftArmLower:
return "Body_LeftArmLower";
case BoneId.Body_LeftHandWristTwist:
return "Body_LeftHandWristTwist";
case BoneId.Body_RightShoulder:
return "Body_RightShoulder";
case BoneId.Body_RightScapula:
return "Body_RightScapula";
case BoneId.Body_RightArmUpper:
return "Body_RightArmUpper";
case BoneId.Body_RightArmLower:
return "Body_RightArmLower";
case BoneId.Body_RightHandWristTwist:
return "Body_RightHandWristTwist";
case BoneId.Body_LeftHandPalm:
return "Body_LeftHandPalm";
case BoneId.Body_LeftHandWrist:
return "Body_LeftHandWrist";
case BoneId.Body_LeftHandThumbMetacarpal:
return "Body_LeftHandThumbMetacarpal";
case BoneId.Body_LeftHandThumbProximal:
return "Body_LeftHandThumbProximal";
case BoneId.Body_LeftHandThumbDistal:
return "Body_LeftHandThumbDistal";
case BoneId.Body_LeftHandThumbTip:
return "Body_LeftHandThumbTip";
case BoneId.Body_LeftHandIndexMetacarpal:
return "Body_LeftHandIndexMetacarpal";
case BoneId.Body_LeftHandIndexProximal:
return "Body_LeftHandIndexProximal";
case BoneId.Body_LeftHandIndexIntermediate:
return "Body_LeftHandIndexIntermediate";
case BoneId.Body_LeftHandIndexDistal:
return "Body_LeftHandIndexDistal";
case BoneId.Body_LeftHandIndexTip:
return "Body_LeftHandIndexTip";
case BoneId.Body_LeftHandMiddleMetacarpal:
return "Body_LeftHandMiddleMetacarpal";
case BoneId.Body_LeftHandMiddleProximal:
return "Body_LeftHandMiddleProximal";
case BoneId.Body_LeftHandMiddleIntermediate:
return "Body_LeftHandMiddleIntermediate";
case BoneId.Body_LeftHandMiddleDistal:
return "Body_LeftHandMiddleDistal";
case BoneId.Body_LeftHandMiddleTip:
return "Body_LeftHandMiddleTip";
case BoneId.Body_LeftHandRingMetacarpal:
return "Body_LeftHandRingMetacarpal";
case BoneId.Body_LeftHandRingProximal:
return "Body_LeftHandRingProximal";
case BoneId.Body_LeftHandRingIntermediate:
return "Body_LeftHandRingIntermediate";
case BoneId.Body_LeftHandRingDistal:
return "Body_LeftHandRingDistal";
case BoneId.Body_LeftHandRingTip:
return "Body_LeftHandRingTip";
case BoneId.Body_LeftHandLittleMetacarpal:
return "Body_LeftHandLittleMetacarpal";
case BoneId.Body_LeftHandLittleProximal:
return "Body_LeftHandLittleProximal";
case BoneId.Body_LeftHandLittleIntermediate:
return "Body_LeftHandLittleIntermediate";
case BoneId.Body_LeftHandLittleDistal:
return "Body_LeftHandLittleDistal";
case BoneId.Body_LeftHandLittleTip:
return "Body_LeftHandLittleTip";
case BoneId.Body_RightHandPalm:
return "Body_RightHandPalm";
case BoneId.Body_RightHandWrist:
return "Body_RightHandWrist";
case BoneId.Body_RightHandThumbMetacarpal:
return "Body_RightHandThumbMetacarpal";
case BoneId.Body_RightHandThumbProximal:
return "Body_RightHandThumbProximal";
case BoneId.Body_RightHandThumbDistal:
return "Body_RightHandThumbDistal";
case BoneId.Body_RightHandThumbTip:
return "Body_RightHandThumbTip";
case BoneId.Body_RightHandIndexMetacarpal:
return "Body_RightHandIndexMetacarpal";
case BoneId.Body_RightHandIndexProximal:
return "Body_RightHandIndexProximal";
case BoneId.Body_RightHandIndexIntermediate:
return "Body_RightHandIndexIntermediate";
case BoneId.Body_RightHandIndexDistal:
return "Body_RightHandIndexDistal";
case BoneId.Body_RightHandIndexTip:
return "Body_RightHandIndexTip";
case BoneId.Body_RightHandMiddleMetacarpal:
return "Body_RightHandMiddleMetacarpal";
case BoneId.Body_RightHandMiddleProximal:
return "Body_RightHandMiddleProximal";
case BoneId.Body_RightHandMiddleIntermediate:
return "Body_RightHandMiddleIntermediate";
case BoneId.Body_RightHandMiddleDistal:
return "Body_RightHandMiddleDistal";
case BoneId.Body_RightHandMiddleTip:
return "Body_RightHandMiddleTip";
case BoneId.Body_RightHandRingMetacarpal:
return "Body_RightHandRingMetacarpal";
case BoneId.Body_RightHandRingProximal:
return "Body_RightHandRingProximal";
case BoneId.Body_RightHandRingIntermediate:
return "Body_RightHandRingIntermediate";
case BoneId.Body_RightHandRingDistal:
return "Body_RightHandRingDistal";
case BoneId.Body_RightHandRingTip:
return "Body_RightHandRingTip";
case BoneId.Body_RightHandLittleMetacarpal:
return "Body_RightHandLittleMetacarpal";
case BoneId.Body_RightHandLittleProximal:
return "Body_RightHandLittleProximal";
case BoneId.Body_RightHandLittleIntermediate:
return "Body_RightHandLittleIntermediate";
case BoneId.Body_RightHandLittleDistal:
return "Body_RightHandLittleDistal";
case BoneId.Body_RightHandLittleTip:
return "Body_RightHandLittleTip";
default:
return "Body_Unknown";
}
}
else if (IsHandSkeleton(skeletonType))
{
switch (boneId)
{
case OVRSkeleton.BoneId.Hand_WristRoot:
return "Hand_WristRoot";
case OVRSkeleton.BoneId.Hand_ForearmStub:
return "Hand_ForearmStub";
case OVRSkeleton.BoneId.Hand_Thumb0:
return "Hand_Thumb0";
case OVRSkeleton.BoneId.Hand_Thumb1:
return "Hand_Thumb1";
case OVRSkeleton.BoneId.Hand_Thumb2:
return "Hand_Thumb2";
case OVRSkeleton.BoneId.Hand_Thumb3:
return "Hand_Thumb3";
case OVRSkeleton.BoneId.Hand_Index1:
return "Hand_Index1";
case OVRSkeleton.BoneId.Hand_Index2:
return "Hand_Index2";
case OVRSkeleton.BoneId.Hand_Index3:
return "Hand_Index3";
case OVRSkeleton.BoneId.Hand_Middle1:
return "Hand_Middle1";
case OVRSkeleton.BoneId.Hand_Middle2:
return "Hand_Middle2";
case OVRSkeleton.BoneId.Hand_Middle3:
return "Hand_Middle3";
case OVRSkeleton.BoneId.Hand_Ring1:
return "Hand_Ring1";
case OVRSkeleton.BoneId.Hand_Ring2:
return "Hand_Ring2";
case OVRSkeleton.BoneId.Hand_Ring3:
return "Hand_Ring3";
case OVRSkeleton.BoneId.Hand_Pinky0:
return "Hand_Pinky0";
case OVRSkeleton.BoneId.Hand_Pinky1:
return "Hand_Pinky1";
case OVRSkeleton.BoneId.Hand_Pinky2:
return "Hand_Pinky2";
case OVRSkeleton.BoneId.Hand_Pinky3:
return "Hand_Pinky3";
case OVRSkeleton.BoneId.Hand_ThumbTip:
return "Hand_ThumbTip";
case OVRSkeleton.BoneId.Hand_IndexTip:
return "Hand_IndexTip";
case OVRSkeleton.BoneId.Hand_MiddleTip:
return "Hand_MiddleTip";
case OVRSkeleton.BoneId.Hand_RingTip:
return "Hand_RingTip";
case OVRSkeleton.BoneId.Hand_PinkyTip:
return "Hand_PinkyTip";
default:
return "Hand_Unknown";
}
}
else
{
return "Skeleton_Unknown";
}
}
internal static bool IsBodySkeleton(SkeletonType type) => type == SkeletonType.Body;
private static bool IsHandSkeleton(SkeletonType type) =>
type == SkeletonType.HandLeft || type == SkeletonType.HandRight;
}
public class OVRBone
{
public OVRSkeleton.BoneId Id { get; set; }
public short ParentBoneIndex { get; set; }
public Transform Transform { get; set; }
public OVRBone()
{
}
public OVRBone(OVRSkeleton.BoneId id, short parentBoneIndex, Transform trans)
{
Id = id;
ParentBoneIndex = parentBoneIndex;
Transform = trans;
}
}
public class OVRBoneCapsule
{
public short BoneIndex { get; set; }
public Rigidbody CapsuleRigidbody { get; set; }
public CapsuleCollider CapsuleCollider { get; set; }
public OVRBoneCapsule()
{
}
public OVRBoneCapsule(short boneIndex, Rigidbody capsuleRigidBody, CapsuleCollider capsuleCollider)
{
BoneIndex = boneIndex;
CapsuleRigidbody = capsuleRigidBody;
CapsuleCollider = capsuleCollider;
}
}