clean project

This commit is contained in:
Helar Jaadla
2022-03-07 17:52:41 +02:00
parent a174b45bd2
commit cbeb10ec35
5100 changed files with 837159 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4b1422466b455b248ad5e0e27e1e043e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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 UnityEngine;
namespace Oculus.Interaction.Input
{
public class DummyDataModifier : Hand
{
public Vector3 offset;
public float animationTime;
#region IHandInputDataModifier Implementation
protected override void Apply(HandDataAsset handDataAsset)
{
if (!handDataAsset.IsTracked)
{
return;
}
var interpolant = Mathf.Sin(Mathf.PI * 2.0f * (Time.time % animationTime) / animationTime) * 0.5f + 0.5f;
handDataAsset.Root.position = handDataAsset.Root.position + interpolant * offset + offset * -0.5f;
ref var joint = ref handDataAsset.Joints[(int)HandJointId.HandIndex1];
var rot = Quaternion.AngleAxis(interpolant * 90 - 45, Vector3.forward);
joint = joint * rot;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2d9aa5fe07a77244d89c6c80b08b33ab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,48 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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 UnityEngine;
namespace Oculus.Interaction.Input
{
public class FixedScaleDataModifier : Hand
{
[SerializeField]
private float _scale = 1f;
#region DataModifier Implementation
protected override void Apply(HandDataAsset data)
{
Pose rootToPointer = PoseUtils.RelativeOffset(data.PointerPose, data.Root);
rootToPointer.position = (rootToPointer.position / data.HandScale) * _scale;
PoseUtils.Multiply(data.Root, rootToPointer, ref data.PointerPose);
data.HandScale = _scale;
}
#endregion
#region Inject
public void InjectAllFixedScaleDataModifier(UpdateModeFlags updateMode, IDataSource updateAfter,
DataModifier<HandDataAsset, HandDataSourceConfig> modifyDataFromSource, bool applyModifier,
Component[] aspects, float scale)
{
base.InjectAllHand(updateMode, updateAfter, modifyDataFromSource, applyModifier, aspects);
InjectScale(scale);
}
public void InjectScale(float scale)
{
_scale = scale;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b927808915b4eba41b76168390b99c24
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,101 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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 Oculus.Interaction.Throw;
using UnityEngine;
using UnityEngine.Serialization;
namespace Oculus.Interaction.Input
{
/// <summary>
/// Tracks the history of finger rotations and can be set to use the joint
/// rotations from some number of frames ago.
/// </summary>
public class JointRotationHistoryModifier : Hand
{
[SerializeField]
private int _historyLength = 60;
[SerializeField]
private int _historyOffset = 5;
private Quaternion[][] _jointHistory = new Quaternion[(int)HandJointId.HandMaxSkinnable][];
private int _historyIndex = 0;
private int _capturedDataVersion;
protected override void Start()
{
base.Start();
for (int i = 0; i < _jointHistory.Length; i++)
{
_jointHistory[i] = new Quaternion[_historyLength];
for (int j = 0; j < _historyLength; j++)
{
_jointHistory[i][j] = Quaternion.identity;
}
}
}
#region DataModifier Implementation
protected override void Apply(HandDataAsset data)
{
if (!data.IsDataValid)
{
return;
}
if (_capturedDataVersion != ModifyDataFromSource.CurrentDataVersion)
{
_capturedDataVersion = ModifyDataFromSource.CurrentDataVersion;
_historyIndex = (_historyIndex + 1) % _historyLength;
for (int i = 0; i < _jointHistory.Length; i++)
{
_jointHistory[i][_historyIndex] = data.Joints[i];
}
}
_historyOffset = Mathf.Clamp(_historyOffset, 0, _historyLength);
int index = (_historyIndex + _historyLength - _historyOffset) % _historyLength;
for (int i = 0; i < _jointHistory.Length; i++)
{
data.Joints[i] = _jointHistory[i][index];
}
}
#endregion
public void SetHistoryOffset(int offset)
{
_historyOffset = offset;
MarkInputDataRequiresUpdate();
}
#region Inject
public void InjectAllJointRotationHistoryModifier(UpdateModeFlags updateMode, IDataSource updateAfter,
DataModifier<HandDataAsset, HandDataSourceConfig> modifyDataFromSource, bool applyModifier,
Component[] aspects, int historyLength, int historyOffset)
{
base.InjectAllHand(updateMode, updateAfter, modifyDataFromSource, applyModifier, aspects);
InjectHistoryLength(historyLength);
SetHistoryOffset(historyOffset);
}
public void InjectHistoryLength(int historyLength)
{
_historyLength = historyLength;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4b5d61cebc8bc2644b45d6034694ea8f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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.
************************************************************************************/
namespace Oculus.Interaction.Input
{
public class LastKnownGoodDataModifier : Hand
{
private readonly HandDataAsset _lastState = new HandDataAsset();
#region DataModifier Implementation
protected override void Apply(HandDataAsset data)
{
bool shouldUseData = data.IsHighConfidence ||
data.RootPoseOrigin == PoseOrigin.FilteredTrackedPose ||
data.RootPoseOrigin == PoseOrigin.SyntheticPose;
if (data.IsDataValid && data.IsTracked && shouldUseData)
{
_lastState.CopyFrom(data);
}
else if (_lastState.IsDataValid && data.IsConnected)
{
// No high confidence data, use last known good.
// Only copy pose data, not confidence/tracked flags.
data.CopyPosesFrom(_lastState);
data.RootPoseOrigin = PoseOrigin.SyntheticPose;
data.IsDataValid = true;
data.IsTracked = true;
data.IsHighConfidence = true;
}
else
{
// This hand is not connected, or has never seen valid data.
data.IsTracked = false;
data.IsHighConfidence = false;
data.RootPoseOrigin = PoseOrigin.None;
}
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7daff26e66096cd49a253ca3ab592c03
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,83 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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 UnityEngine;
using UnityEngine.Profiling;
namespace Oculus.Interaction.Input
{
public class OneEuroFilterPositionDataModifier : Hand
{
[Header("Wrist")]
[SerializeField]
private OneEuroFilterPropertyBlock _wristFilterProperties =
new OneEuroFilterPropertyBlock(2f, 10f);
private IOneEuroFilter<Vector3> _wristFilter;
private int _lastFrameUpdated;
private Pose _lastSmoothedPose;
protected override void Start()
{
base.Start();
_lastFrameUpdated = 0;
_wristFilter = OneEuroFilter.CreateVector3();
}
#region IHandInputDataModifier Implementation
protected override void Apply(HandDataAsset handDataAsset)
{
if (!handDataAsset.IsTracked)
{
return;
}
Profiler.BeginSample($"{nameof(OneEuroFilterPositionDataModifier)}." +
$"{nameof(OneEuroFilterPositionDataModifier.Apply)}");
if (Time.frameCount > _lastFrameUpdated)
{
_lastFrameUpdated = Time.frameCount;
_lastSmoothedPose = ApplyFilter(handDataAsset.Root);
}
handDataAsset.Root = _lastSmoothedPose;
handDataAsset.RootPoseOrigin = PoseOrigin.FilteredTrackedPose;
Profiler.EndSample();
}
#endregion
private Pose ApplyFilter(Pose pose)
{
_wristFilter.SetProperties(_wristFilterProperties);
pose.position = _wristFilter.Step(pose.position, Time.fixedDeltaTime);
return pose;
}
#region Inject
public void InjectAllOneEuroFilterPositionDataModifier(UpdateModeFlags updateMode, IDataSource updateAfter,
DataModifier<HandDataAsset, HandDataSourceConfig> modifyDataFromSource, bool applyModifier,
Component[] aspects, OneEuroFilterPropertyBlock wristFilterProperties)
{
base.InjectAllHand(updateMode, updateAfter, modifyDataFromSource, applyModifier, aspects);
InjectWristFilterProperties(wristFilterProperties);
}
public void InjectWristFilterProperties(OneEuroFilterPropertyBlock wristFilterProperties)
{
_wristFilterProperties = wristFilterProperties;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 77f93b4928ccdb2448c377308b7f4731
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,162 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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;
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Profiling;
namespace Oculus.Interaction.Input
{
/// <summary>
/// Data Modifier use to apply the One Euro Filter to a hand pose.
/// Filtering can be applied to the wrist and any number of finger joints.
/// </summary>
public class OneEuroFilterRotationDataModifier : Hand
{
[Header("Wrist")]
[SerializeField]
private bool _wristFilterEnabled = true;
[SerializeField]
private OneEuroFilterPropertyBlock _wristFilterProperties =
new OneEuroFilterPropertyBlock(2f, 3f);
[Header("Fingers")]
[SerializeField]
private bool _fingerFiltersEnabled = true;
[SerializeField]
private HandFingerJointFlags _fingerJoints = HandFingerJointFlags.None;
[SerializeField]
private OneEuroFilterPropertyBlock _fingerFilterProperties =
new OneEuroFilterPropertyBlock(1f, 2f);
private IOneEuroFilter<Quaternion> _wristFilter;
private List<JointFilter> _fingerJointFilters;
private HandDataAsset _lastFiltered;
private int _lastFrameUpdated;
protected override void Start()
{
base.Start();
InitFingerJointFilters();
_lastFrameUpdated = 0;
_lastFiltered = new HandDataAsset();
_wristFilter = OneEuroFilter.CreateQuaternion();
}
private void InitFingerJointFilters()
{
_fingerJointFilters = new List<JointFilter>();
if (_fingerJoints == HandFingerJointFlags.None)
{
return;
}
foreach (var jointId in HandJointUtils.JointIds)
{
HandFingerJointFlags jointFlag = (HandFingerJointFlags)(1 << (int)jointId);
if (!Enum.IsDefined(typeof(HandFingerJointFlags), jointFlag))
{
continue;
}
if (_fingerJoints.HasFlag(jointFlag))
{
_fingerJointFilters.Add(new JointFilter(jointId));
}
}
}
#region IHandInputDataModifier Implementation
protected override void Apply(HandDataAsset handDataAsset)
{
if (!handDataAsset.IsTracked)
{
return;
}
Profiler.BeginSample($"{nameof(OneEuroFilterRotationDataModifier)}." +
$"{nameof(OneEuroFilterRotationDataModifier.Apply)}");
if (Time.frameCount > _lastFrameUpdated)
{
_lastFrameUpdated = Time.frameCount;
ApplyFilters(handDataAsset);
_lastFiltered.CopyFrom(handDataAsset);
}
else
{
handDataAsset.CopyFrom(_lastFiltered);
}
handDataAsset.RootPoseOrigin = PoseOrigin.FilteredTrackedPose;
Profiler.EndSample();
}
#endregion
private void ApplyFilters(HandDataAsset handDataAsset)
{
if (_wristFilterEnabled)
{
Pose rootPose = handDataAsset.Root;
_wristFilter.SetProperties(_wristFilterProperties);
rootPose.rotation = _wristFilter.Step(rootPose.rotation, Time.fixedDeltaTime);
handDataAsset.Root = rootPose;
}
if (_fingerFiltersEnabled)
{
foreach (var joint in _fingerJointFilters)
{
joint.Filter.SetProperties(_fingerFilterProperties);
handDataAsset.Joints[(int)joint.JointId] =
joint.Filter.Step(handDataAsset.Joints[(int)joint.JointId], Time.fixedDeltaTime);
}
}
}
private class JointFilter
{
public HandJointId JointId => _jointId;
public IOneEuroFilter<Quaternion> Filter => _filter;
private readonly HandJointId _jointId;
private readonly IOneEuroFilter<Quaternion> _filter;
public JointFilter(HandJointId jointId)
{
_jointId = jointId;
_filter = OneEuroFilter.CreateQuaternion();
}
}
#region Inject
public void InjectAllOneEuroFilterRotationDataModifier(UpdateModeFlags updateMode, IDataSource updateAfter,
DataModifier<HandDataAsset, HandDataSourceConfig> modifyDataFromSource, bool applyModifier,
Component[] aspects, OneEuroFilterPropertyBlock wristFilterProperties)
{
base.InjectAllHand(updateMode, updateAfter, modifyDataFromSource, applyModifier, aspects);
InjectWristFilterProperties(wristFilterProperties);
}
public void InjectWristFilterProperties(OneEuroFilterPropertyBlock wristFilterProperties)
{
_wristFilterProperties = wristFilterProperties;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e410712d2f3ef084daeb2eac77899ce2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,508 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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 UnityEngine;
namespace Oculus.Interaction.Input
{
/// <summary>
/// Alters hand data piped into this modifier to lock and unlock joints (wrist position and rotation,
/// finger joint rotations) When switching between locked and unlocked states, additionally smooths
/// out transitions by easing between source hand data and target hand data.
/// </summary>
public class SyntheticHandModifier : Hand
{
[System.Flags]
public enum WristLockMode
{
Position = 1 << 0,
Rotation = 1 << 1,
Full = (1 << 2) - 1
}
[SerializeField]
private ProgressCurve _wristPositionLockCurve = new ProgressCurve();
[SerializeField]
private ProgressCurve _wristPositionUnlockCurve;
[SerializeField]
private ProgressCurve _wristRotationLockCurve;
[SerializeField]
private ProgressCurve _wristRotationUnlockCurve;
[SerializeField]
private ProgressCurve _jointLockCurve;
[SerializeField]
private ProgressCurve _jointUnlockCurve;
/// <summary>
/// Use this factor to control how much the fingers can spread when nearby a constrained pose.
/// </summary>
[SerializeField]
[Tooltip("Use this factor to control how much the fingers can spread when nearby a constrained pose.")]
private float _spreadAllowance = 5f;
public System.Action UpdateRequired = delegate { };
private readonly HandDataAsset _lastStates = new HandDataAsset();
private float _wristPositionOverrideFactor;
private float _wristRotationOverrideFactor;
private float[] _jointsOverrideFactor = new float[FingersMetadata.HAND_JOINT_IDS.Length];
private ProgressCurve[] _jointLockProgressCurves = new ProgressCurve[FingersMetadata.HAND_JOINT_IDS.Length];
private ProgressCurve[] _jointUnlockProgressCurves = new ProgressCurve[FingersMetadata.HAND_JOINT_IDS.Length];
private Pose _desiredWristPose;
private bool _wristPositionLocked;
private bool _wristRotationLocked;
private Pose _constrainedWristPose;
private Pose _lastWristPose;
private Quaternion[] _desiredJointsRotation = new Quaternion[FingersMetadata.HAND_JOINT_IDS.Length];
private Quaternion[] _constrainedJointRotations = new Quaternion[FingersMetadata.HAND_JOINT_IDS.Length];
private Quaternion[] _lastSyntheticRotation = new Quaternion[FingersMetadata.HAND_JOINT_IDS.Length];
private JointFreedom[] _jointsFreedomLevels = new JointFreedom[FingersMetadata.HAND_JOINT_IDS.Length];
private bool _hasConnectedData;
protected override void Start()
{
base.Start();
for (int i = 0; i < FingersMetadata.HAND_JOINT_IDS.Length; i++)
{
_jointLockProgressCurves[i] = new ProgressCurve(_jointLockCurve);
_jointUnlockProgressCurves[i] = new ProgressCurve(_jointUnlockCurve);
}
}
protected override void Apply(HandDataAsset data)
{
if (!data.IsDataValid || !data.IsTracked || !data.IsHighConfidence)
{
data.IsConnected = false;
data.RootPoseOrigin = PoseOrigin.None;
_hasConnectedData = false;
return;
}
UpdateRequired.Invoke();
_lastStates.CopyFrom(data);
if (!_hasConnectedData)
{
_constrainedWristPose = data.Root;
_hasConnectedData = true;
}
UpdateJointsRotation(data);
UpdateRootPose(ref data.Root);
data.RootPoseOrigin = PoseOrigin.SyntheticPose;
}
/// <summary>
/// Updates the pose of the root of the hand
/// using the visual provided values. Sometimes this
/// might require lerping between the tracked pose
/// and the provided one to improve the movement of the hand
/// without worrying about when the overwrite value was written.
///
/// During this update, the modifier also ensures the unlocking
/// animations are executed.
/// </summary>
/// <param name="root">The tracked root value to modify</param>
private void UpdateRootPose(ref Pose root)
{
float smoothPositionFactor = _wristPositionLocked ? _wristPositionLockCurve.Progress() : _wristPositionUnlockCurve.Progress();
Vector3 position = Vector3.Lerp(root.position, _desiredWristPose.position, _wristPositionOverrideFactor);
root.position = Vector3.Lerp(_constrainedWristPose.position, position, smoothPositionFactor);
float smoothRotationFactor = _wristRotationLocked ? _wristRotationLockCurve.Progress() : _wristRotationUnlockCurve.Progress();
Quaternion rotation = Quaternion.Lerp(root.rotation, _desiredWristPose.rotation, _wristRotationOverrideFactor);
root.rotation = Quaternion.Lerp(_constrainedWristPose.rotation, rotation, smoothRotationFactor);
_lastWristPose.CopyFrom(root);
}
/// <summary>
/// Updates the rotation of the joints in the hand
/// using the visual provided values. Sometimes this
/// might require lerping between the tracked pose
/// and the provided ones to improve the movement of the fingers
/// without worrying about when the overwrite values were written.
///
/// During this update the modifier also ensures that fingers that disallow
/// some movement (locked or constrained) have their values properly set, and
/// when there is an unlock event the finger values are smoothly animated back to
/// their tracked rotations.
/// </summary>
/// <param name="data">The entire hand data structure to read and write the joints rotations from</param>
private void UpdateJointsRotation(HandDataAsset data)
{
float extraRotationAllowance = 0f;
Quaternion[] jointRotations = data.Joints;
for (int i = 0; i < FingersMetadata.HAND_JOINT_IDS.Length; ++i)
{
JointFreedom freedomLevel = _jointsFreedomLevels[i];
Quaternion desiredRotation = _desiredJointsRotation[i];
float overrideFactor = _jointsOverrideFactor[i];
int rawJointIndex = (int)FingersMetadata.HAND_JOINT_IDS[i];
if (freedomLevel == JointFreedom.Free)
{
//nothing to do, we move the finger freely
}
else if (freedomLevel == JointFreedom.Locked)
{
jointRotations[rawJointIndex] = Quaternion.Slerp(
jointRotations[rawJointIndex],
desiredRotation,
overrideFactor);
}
else if (freedomLevel == JointFreedom.Constrained)
{
bool jointCanSpread = false;
if (FingersMetadata.HAND_JOINT_CAN_SPREAD[i])
{
jointCanSpread = true;
extraRotationAllowance = 0f;
}
Quaternion maxRotation = desiredRotation * Quaternion.Euler(0f, 0f, -90f * extraRotationAllowance);
float overRotation = OverFlex(jointRotations[rawJointIndex], maxRotation);
extraRotationAllowance = Mathf.Max(extraRotationAllowance, overRotation);
if (overRotation < 0f)
{
jointRotations[rawJointIndex] = Quaternion.Slerp(
jointRotations[rawJointIndex],
maxRotation,
overrideFactor);
}
else if (jointCanSpread)
{
Quaternion trackedRotation = jointRotations[rawJointIndex];
float spreadAngle = Vector3.SignedAngle(
trackedRotation * Vector3.forward,
maxRotation * Vector3.forward,
trackedRotation * Vector3.up);
float spreadFactor = 1f - Mathf.Clamp01(overRotation * _spreadAllowance);
trackedRotation = trackedRotation * Quaternion.Euler(0f, spreadAngle * spreadFactor, 0f);
jointRotations[rawJointIndex] = trackedRotation;
}
}
float smoothFactor = _jointsFreedomLevels[i] == JointFreedom.Free ?
_jointUnlockProgressCurves[i].Progress()
: _jointLockProgressCurves[i].Progress();
jointRotations[rawJointIndex] = Quaternion.Slerp(
_constrainedJointRotations[i],
jointRotations[rawJointIndex],
smoothFactor);
_lastSyntheticRotation[i] = jointRotations[rawJointIndex];
}
}
/// <summary>
/// Stores the rotation data for all joints in the hand, to be applied during the ApplyHand event.
/// </summary>
/// <param name="jointRotations">The joint rotations following the FingersMetadata.HAND_JOINT_IDS format.</param>
/// <param name="overrideFactor">How much to lerp the fingers from the tracked (raw) state to the provided one.</param>
public void OverrideAllJoints(in Quaternion[] jointRotations, float overrideFactor)
{
for (int i = 0; i < FingersMetadata.HAND_JOINT_IDS.Length; ++i)
{
_desiredJointsRotation[i] = jointRotations[i];
_jointsOverrideFactor[i] = overrideFactor;
}
}
/// <summary>
/// Stores the rotation data for all joints for the given finger, to be applied during the ApplyHand event.
/// </summary>
/// <param name="finger">The finger for which to lock joints.</param>
/// <param name="rotations">The joint rotations for each joint on the finger</param>
/// <param name="overrideFactor">How much to lerp the fingers from the tracked (raw) state to the provided one.</param>
public void OverrideFingerRotations(HandFinger finger, Quaternion[] rotations, float overrideFactor)
{
int[] jointIndices = FingersMetadata.FINGER_TO_JOINT_INDEX[(int)finger];
for (int i = 0; i < jointIndices.Length; i++)
{
OverrideJointRotationAtIndex(jointIndices[i], rotations[i], overrideFactor);
}
}
public void OverrideJointRotation(HandJointId jointId, Quaternion rotation, float overrideFactor)
{
int jointIndex = FingersMetadata.HandJointIdToIndex(jointId);
OverrideJointRotationAtIndex(jointIndex, rotation, overrideFactor);
}
private void OverrideJointRotationAtIndex(int jointIndex, Quaternion rotation, float overrideFactor)
{
_desiredJointsRotation[jointIndex] = rotation;
_jointsOverrideFactor[jointIndex] = overrideFactor;
}
/// <summary>
/// Immediately locks an individual finger (all its internal joints) at the last known value.
/// </summary>
/// <param name="finger">The finger for which to lock joints.</param>
public void LockFingerAtCurrent(in HandFinger finger)
{
SetFingerFreedom(finger, JointFreedom.Locked);
int fingerIndex = (int)finger;
int[] jointIndexes = FingersMetadata.FINGER_TO_JOINT_INDEX[fingerIndex];
for (int i = 0; i < jointIndexes.Length; ++i)
{
int jointIndex = jointIndexes[i];
int rawJointIndex = (int)FingersMetadata.HAND_JOINT_IDS[jointIndex];
_desiredJointsRotation[jointIndex] = _lastStates.Joints[rawJointIndex];
_jointsOverrideFactor[jointIndex] = 1f;
}
}
public void LockJoint(in HandJointId jointId, Quaternion rotation, float overrideFactor = 1f)
{
int jointIndex = FingersMetadata.HandJointIdToIndex(jointId);
_desiredJointsRotation[jointIndex] = rotation;
_jointsOverrideFactor[jointIndex] = 1f;
SetJointFreedomAtIndex(jointIndex, JointFreedom.Locked);
}
/// <summary>
/// To use in conjunction with OverrideAllJoints, it sets the freedom state for a provided finger.
/// Opposite to LockFingerAtCurrent, this method uses the data provided in OverrideAllJoints instead
/// of the last known state.
/// </summary>
/// <param name="freedomLevel">The freedom level for the finger</param>
public void SetFingerFreedom(in HandFinger finger, in JointFreedom freedomLevel, bool skipAnimation = false)
{
int[] jointIndexes = FingersMetadata.FINGER_TO_JOINT_INDEX[(int)finger];
for (int i = 0; i < jointIndexes.Length; ++i)
{
SetJointFreedomAtIndex(jointIndexes[i], freedomLevel, skipAnimation);
}
}
public void SetJointFreedom(in HandJointId jointId, in JointFreedom freedomLevel, bool skipAnimation = false)
{
int jointIndex = FingersMetadata.HandJointIdToIndex(jointId);
SetJointFreedomAtIndex(jointIndex, freedomLevel, skipAnimation);
}
/// <summary>
/// Short-hand method for setting the freedom level of all fingers in a hand to Free.
/// Similar to calling SetFingerFreedom for each single finger in the hand
/// with a value of FingerFreedom.Free for the freedomLevel
/// </summary>
public void FreeAllJoints()
{
for (int i = 0; i < FingersMetadata.HAND_JOINT_IDS.Length; ++i)
{
SetJointFreedomAtIndex(i, JointFreedom.Free);
}
}
private void SetJointFreedomAtIndex(int jointId, in JointFreedom freedomLevel, bool skipAnimation = false)
{
JointFreedom currentFreedom = _jointsFreedomLevels[jointId];
if (currentFreedom != freedomLevel)
{
bool locked = freedomLevel == JointFreedom.Locked
|| freedomLevel == JointFreedom.Constrained;
UpdateProgressCurve(ref _jointLockProgressCurves[jointId],
ref _jointUnlockProgressCurves[jointId],
locked, skipAnimation);
_constrainedJointRotations[jointId] = _lastSyntheticRotation[jointId];
}
_jointsFreedomLevels[jointId] = freedomLevel;
}
/// <summary>
/// Stores the desired pose to set the wrist of the hand to.
/// This is not necessarily the final pose of the hand, as it allows
/// lerping between the tracked and provided one during the ApplyHand phase.
///
/// To ensure the hand is locked at the desired pose, pass a value of 1 in the overrideFactor
/// </summary>
/// <param name="wristPose">The final pose desired for the wrist</param>
/// <param name="lockMode">Either lock the position, rotation or both (default)</param>
/// <param name="overrideFactor">How much to lerp between the tracked and the provided pose</param>
/// <param name="skipAnimation">Whether to skip the animation curve for this override.</param>
public void LockWristPose(Pose wristPose, float overrideFactor = 1f, WristLockMode lockMode = WristLockMode.Full, bool worldPose = false, bool skipAnimation = false)
{
Pose desiredWristPose = worldPose ? TrackingToWorldTransformer.ToTrackingPose(wristPose) : wristPose;
if ((lockMode & WristLockMode.Position) != 0)
{
LockWristPosition(desiredWristPose.position, overrideFactor, skipAnimation);
}
if ((lockMode & WristLockMode.Rotation) != 0)
{
LockWristRotation(desiredWristPose.rotation, overrideFactor, skipAnimation);
}
}
public void LockWristPosition(Vector3 position, float overrideFactor = 1f, bool skipAnimation = false)
{
_wristPositionOverrideFactor = overrideFactor;
_desiredWristPose.position = position;
if (!_wristPositionLocked)
{
SyntheticWristLockChangedState(WristLockMode.Position, skipAnimation);
_wristPositionLocked = true;
}
}
public void LockWristRotation(Quaternion rotation, float overrideFactor = 1f, bool skipAnimation = false)
{
_wristRotationOverrideFactor = overrideFactor;
_desiredWristPose.rotation = rotation;
if (!_wristRotationLocked)
{
SyntheticWristLockChangedState(WristLockMode.Rotation, skipAnimation);
_wristRotationLocked = true;
}
}
/// <summary>
/// Unlocks the hand (locked at the OverrideWristPose method) starting
/// a timer for the smooth release animation.
/// </summary>
public void FreeWrist(WristLockMode lockMode = WristLockMode.Full)
{
if ((lockMode & WristLockMode.Position) != 0
&& _wristPositionLocked)
{
_wristPositionOverrideFactor = 0f;
_wristPositionLocked = false;
SyntheticWristLockChangedState(WristLockMode.Position);
}
if ((lockMode & WristLockMode.Rotation) != 0
&& _wristRotationLocked)
{
_wristRotationOverrideFactor = 0f;
_wristRotationLocked = false;
SyntheticWristLockChangedState(WristLockMode.Rotation);
}
}
private void SyntheticWristLockChangedState(WristLockMode lockMode, bool skipAnimation = false)
{
if ((lockMode & WristLockMode.Position) != 0)
{
UpdateProgressCurve(ref _wristPositionLockCurve, ref _wristPositionUnlockCurve,
_wristPositionLocked, skipAnimation);
_constrainedWristPose.position = _lastWristPose.position;
}
if ((lockMode & WristLockMode.Rotation) != 0)
{
UpdateProgressCurve(ref _wristRotationLockCurve, ref _wristRotationUnlockCurve,
_wristRotationLocked, skipAnimation);
_constrainedWristPose.rotation = _lastWristPose.rotation;
}
}
/// <summary>
/// Indicates whether a joint's tracked rotation is past a given rotation.
/// Works in local Unity Joint coordinates.
/// This is useful for blocking fingers past the snapping point.
/// </summary>
/// <param name="desiredLocalRot">The known local rotation of the joint. </param>
/// <param name="maxLocalRot">The desired max local rotation of the joint.</param>
/// <returns>A negative scalar proportional to how much the rotation is over the max one, a proportional positive scalar if under.</returns>
private static float OverFlex(in Quaternion desiredLocalRot, in Quaternion maxLocalRot)
{
Vector3 jointDir = desiredLocalRot * Vector3.right;
Vector3 jointTan = desiredLocalRot * Vector3.back;
Vector3 maxDir = maxLocalRot * Vector3.right;
Vector3 difference = Vector3.Cross(jointDir, maxDir);
return Vector3.Dot(jointTan, difference);
}
private static void UpdateProgressCurve(ref ProgressCurve lockProgress, ref ProgressCurve unlockProgress, bool locked, bool skipAnimation)
{
ProgressCurve progress = locked ? lockProgress : unlockProgress;
if (skipAnimation)
{
progress.End();
}
else
{
progress.Start();
}
}
#region Inject
public void InjectAllSyntheticHandModifier(UpdateModeFlags updateMode, IDataSource updateAfter,
DataModifier<HandDataAsset, HandDataSourceConfig> modifyDataFromSource, bool applyModifier,
Component[] aspects,
ProgressCurve wristPositionLockCurve, ProgressCurve wristPositionUnlockCurve,
ProgressCurve wristRotationLockCurve, ProgressCurve wristRotationUnlockCurve,
ProgressCurve jointLockCurve, ProgressCurve jointUnlockCurve,
float spreadAllowance)
{
base.InjectAllHand(updateMode, updateAfter, modifyDataFromSource, applyModifier, aspects);
InjectWristPositionLockCurve(wristPositionLockCurve);
InjectWristPositionUnlockCurve(wristPositionUnlockCurve);
InjectWristRotationLockCurve(wristRotationLockCurve);
InjectWristRotationUnlockCurve(wristRotationUnlockCurve);
InjectJointLockCurve(jointLockCurve);
InjectJointUnlockCurve(jointUnlockCurve);
InjectSpreadAllowance(spreadAllowance);
}
public void InjectWristPositionLockCurve(ProgressCurve wristPositionLockCurve) {
_wristPositionLockCurve = wristPositionLockCurve;
}
public void InjectWristPositionUnlockCurve(ProgressCurve wristPositionUnlockCurve) {
_wristPositionUnlockCurve = wristPositionUnlockCurve;
}
public void InjectWristRotationLockCurve(ProgressCurve wristRotationLockCurve) {
_wristRotationLockCurve = wristRotationLockCurve;
}
public void InjectWristRotationUnlockCurve(ProgressCurve wristRotationUnlockCurve) {
_wristRotationUnlockCurve = wristRotationUnlockCurve;
}
public void InjectJointLockCurve(ProgressCurve jointLockCurve) {
_jointLockCurve = jointLockCurve;
}
public void InjectJointUnlockCurve(ProgressCurve jointUnlockCurve) {
_jointUnlockCurve = jointUnlockCurve;
}
public void InjectSpreadAllowance(float spreadAllowance) {
_spreadAllowance = spreadAllowance;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c67033f580359c4581dff1ccffcca91
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,137 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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.
************************************************************************************/
namespace Oculus.Interaction.Input
{
public enum JointFreedom
{
Free,
Constrained,
Locked
}
/// <summary>
/// This class contains a series of useful fingers-related data structures
/// to be used for optimal calculations without relying in dictionaries.
///
/// Since we always assume the hand pose information to be sorted in
/// the HAND_JOINT_IDS order, we can align multiple data structures
/// that follow that convention.
/// </summary>
public class FingersMetadata
{
public static JointFreedom[] DefaultFingersFreedom()
{
return new JointFreedom[Constants.NUM_FINGERS]
{
JointFreedom.Locked,
JointFreedom.Locked,
JointFreedom.Constrained,
JointFreedom.Constrained,
JointFreedom.Free
};
}
public static int HandJointIdToIndex(HandJointId id)
{
return (int)id - (int)HandJointId.HandThumb0;
}
/// <summary>
/// Valid identifiers for the i-bone of a hand.
/// </summary>
public static readonly HandJointId[] HAND_JOINT_IDS = new HandJointId[]
{
HandJointId.HandThumb0,
HandJointId.HandThumb1,
HandJointId.HandThumb2,
HandJointId.HandThumb3,
HandJointId.HandIndex1,
HandJointId.HandIndex2,
HandJointId.HandIndex3,
HandJointId.HandMiddle1,
HandJointId.HandMiddle2,
HandJointId.HandMiddle3,
HandJointId.HandRing1,
HandJointId.HandRing2,
HandJointId.HandRing3,
HandJointId.HandPinky0,
HandJointId.HandPinky1,
HandJointId.HandPinky2,
HandJointId.HandPinky3
};
/// <summary>
/// This array is used to convert from Finger id to the list indices
/// of its joint in the HAND_JOINT_IDS list.
/// </summary>
public static readonly int[][] FINGER_TO_JOINT_INDEX = new int[][]
{
new[] {0,1,2,3},
new[] {4,5,6},
new[] {7,8,9},
new[] {10,11,12},
new[] {13,14,15,16}
};
/// <summary>
/// Array order following HAND_JOINT_IDS that indicates if the i joint
/// can spread (rotate around Y). Should be true for the root of the fingers
/// but Pink and Thumb are special cases
/// </summary>
public static readonly bool[] HAND_JOINT_CAN_SPREAD = new bool[]
{
true, //HandJointId.HandThumb0
true, //HandJointId.HandThumb1
false,//HandJointId.HandThumb2
false,//HandJointId.HandThumb3
true, //HandJointId.HandIndex1
false,//HandJointId.HandIndex2
false,//HandJointId.HandIndex3
true, //HandJointId.HandMiddle1
false,//HandJointId.HandMiddle2
false,//HandJointId.HandMiddle3
true, //HandJointId.HandRing1
false,//HandJointId.HandRing2
false,//HandJointId.HandRing3
true, //HandJointId.HandPinky0
true, //HandJointId.HandPinky1
false,//HandJointId.HandPinky2
false //HandJointId.HandPinky3
};
/// <summary>
/// Sorted like HAND_JOINT_IDS, this array is used to retrieve the finger
/// each joint belongs to.
/// </summary>
public static readonly HandFinger[] HAND_FINGER_ID = new HandFinger[]
{
HandFinger.Thumb,
HandFinger.Thumb,
HandFinger.Thumb,
HandFinger.Thumb,
HandFinger.Index,
HandFinger.Index,
HandFinger.Index,
HandFinger.Middle,
HandFinger.Middle,
HandFinger.Middle,
HandFinger.Ring,
HandFinger.Ring,
HandFinger.Ring,
HandFinger.Pinky,
HandFinger.Pinky,
HandFinger.Pinky,
HandFinger.Pinky
};
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9c86919be0f18a54b8706542dc38dede
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,274 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
namespace Oculus.Interaction.Input
{
// A top level component that provides hand pose data, pinch states, and more.
// Rather than sourcing data directly from the runtime layer, provides one
// level of abstraction so that the aforementioned data can be injected
// from other sources.
public class Hand : DataModifier<HandDataAsset, HandDataSourceConfig>, IHand
{
[SerializeField]
[Tooltip("Provides access to additional functionality on top of what the IHand interface provides." +
"For example, this list can be used to provide access to the SkinnedMeshRenderer through " +
"the IHand.GetHandAspect method.")]
private Component[] _aspects;
public IReadOnlyList<Component> Aspects => _aspects;
public ITrackingToWorldTransformer TrackingToWorldTransformer =>
Config.TrackingToWorldTransformer;
private HandJointCache _jointPosesCache;
public event Action HandUpdated = delegate { };
public bool IsConnected => GetData().IsDataValidAndConnected;
public bool IsHighConfidence => GetData().IsHighConfidence;
public bool IsDominantHand => GetData().IsDominantHand;
public Handedness Handedness => Config.Handedness;
public float Scale => GetData().HandScale * TrackingToWorldTransformer.Transform.localScale.x;
private static readonly Vector3 PALM_LOCAL_OFFSET = new Vector3(0.08f, -0.01f, 0.0f);
protected override void Apply(HandDataAsset data)
{
// Default implementation does nothing, to allow instantiation of this modifier directly
}
public override void MarkInputDataRequiresUpdate()
{
base.MarkInputDataRequiresUpdate();
if (Started)
{
InitializeJointPosesCache();
HandUpdated.Invoke();
}
}
private void InitializeJointPosesCache()
{
if (_jointPosesCache == null && GetData().IsDataValidAndConnected)
{
_jointPosesCache = new HandJointCache(Config.HandSkeleton);
}
}
private void CheckJointPosesCacheUpdate()
{
if (_jointPosesCache != null
&& CurrentDataVersion != _jointPosesCache.LocalDataVersion)
{
_jointPosesCache.Update(GetData(), CurrentDataVersion);
}
}
#region IHandState implementation
public bool GetFingerIsPinching(HandFinger finger)
{
HandDataAsset currentData = GetData();
return currentData.IsConnected && currentData.IsFingerPinching[(int)finger];
}
public bool GetIndexFingerIsPinching()
{
return GetFingerIsPinching(HandFinger.Index);
}
public bool IsPointerPoseValid => IsPoseOriginAllowed(GetData().PointerPoseOrigin);
public bool GetPointerPose(out Pose pose)
{
HandDataAsset currentData = GetData();
return ValidatePose(currentData.PointerPose, currentData.PointerPoseOrigin,
out pose);
}
public bool GetJointPose(HandJointId handJointId, out Pose pose)
{
pose = Pose.identity;
if (!IsTrackedDataValid
|| _jointPosesCache == null
|| !GetRootPose(out Pose rootPose))
{
return false;
}
CheckJointPosesCacheUpdate();
pose = _jointPosesCache.WorldJointPose(handJointId, rootPose, Scale);
return true;
}
public bool GetJointPoseLocal(HandJointId handJointId, out Pose pose)
{
pose = Pose.identity;
if (!GetJointPosesLocal(out ReadOnlyHandJointPoses localJointPoses))
{
return false;
}
pose = localJointPoses[(int)handJointId];
return true;
}
public bool GetJointPosesLocal(out ReadOnlyHandJointPoses localJointPoses)
{
if (!IsTrackedDataValid || _jointPosesCache == null)
{
localJointPoses = ReadOnlyHandJointPoses.Empty;
return false;
}
CheckJointPosesCacheUpdate();
return _jointPosesCache.GetAllLocalPoses(out localJointPoses);
}
public bool GetJointPoseFromWrist(HandJointId handJointId, out Pose pose)
{
pose = Pose.identity;
if (!GetJointPosesFromWrist(out ReadOnlyHandJointPoses jointPosesFromWrist))
{
return false;
}
pose = jointPosesFromWrist[(int)handJointId];
return true;
}
public bool GetJointPosesFromWrist(out ReadOnlyHandJointPoses jointPosesFromWrist)
{
if (!IsTrackedDataValid || _jointPosesCache == null)
{
jointPosesFromWrist = ReadOnlyHandJointPoses.Empty;
return false;
}
CheckJointPosesCacheUpdate();
return _jointPosesCache.GetAllPosesFromWrist(out jointPosesFromWrist);
}
public bool GetPalmPoseLocal(out Pose pose)
{
Quaternion rotationQuat = Quaternion.identity;
Vector3 offset = PALM_LOCAL_OFFSET;
if (Handedness == Handedness.Left)
{
offset = -offset;
}
pose = new Pose(offset * Scale, rotationQuat);
return true;
}
public bool GetFingerIsHighConfidence(HandFinger finger)
{
return GetData().IsFingerHighConfidence[(int)finger];
}
public float GetFingerPinchStrength(HandFinger finger)
{
return GetData().FingerPinchStrength[(int)finger];
}
public bool IsTrackedDataValid => IsPoseOriginAllowed(GetData().RootPoseOrigin);
public bool GetRootPose(out Pose pose)
{
HandDataAsset currentData = GetData();
return ValidatePose(currentData.Root, currentData.RootPoseOrigin, out pose);
}
public bool IsCenterEyePoseValid => Config.HmdData.GetData().IsTracked;
public bool GetCenterEyePose(out Pose pose)
{
HmdDataAsset hmd = Config.HmdData.GetData();
if (!hmd.IsTracked)
{
pose = new Pose();
return false;
}
pose = TrackingToWorldTransformer.ToWorldPose(hmd.Root);
return true;
}
#endregion
public Transform TrackingToWorldSpace
{
get
{
return TrackingToWorldTransformer.Transform;
}
}
private bool ValidatePose(in Pose sourcePose, PoseOrigin sourcePoseOrigin, out Pose pose)
{
if (IsPoseOriginDisallowed(sourcePoseOrigin))
{
pose = Pose.identity;
return false;
}
pose = TrackingToWorldTransformer.ToWorldPose(sourcePose);
return true;
}
private bool IsPoseOriginAllowed(PoseOrigin poseOrigin)
{
return poseOrigin != PoseOrigin.None;
}
private bool IsPoseOriginDisallowed(PoseOrigin poseOrigin)
{
return poseOrigin == PoseOrigin.None;
}
public bool GetHandAspect<TComponent>(out TComponent foundComponent) where TComponent : class
{
foreach (Component aspect in _aspects)
{
foundComponent = aspect as TComponent;
if (foundComponent != null)
{
return true;
}
}
foundComponent = null;
return false;
}
#region Inject
public void InjectAllHand(UpdateModeFlags updateMode, IDataSource updateAfter,
DataModifier<HandDataAsset, HandDataSourceConfig> modifyDataFromSource, bool applyModifier,
Component[] aspects)
{
base.InjectAllDataModifier(updateMode, updateAfter, modifyDataFromSource, applyModifier);
InjectAspects(aspects);
}
public void InjectAspects(Component[] aspects)
{
_aspects = aspects;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1a379f34d4f4f2e408d34f14bfb753ce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,62 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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;
using UnityEngine;
namespace Oculus.Interaction.Input
{
[Serializable]
public class HandDataAsset : ICopyFrom<HandDataAsset>
{
public bool IsDataValid;
public bool IsConnected;
public bool IsTracked;
public Pose Root;
public PoseOrigin RootPoseOrigin;
public Quaternion[] Joints = new Quaternion[Constants.NUM_HAND_JOINTS];
public bool IsHighConfidence;
public bool[] IsFingerPinching = new bool[Constants.NUM_FINGERS];
public bool[] IsFingerHighConfidence = new bool[Constants.NUM_FINGERS];
public float[] FingerPinchStrength = new float[Constants.NUM_FINGERS];
public float HandScale;
public Pose PointerPose;
public PoseOrigin PointerPoseOrigin;
public bool IsDominantHand;
public bool IsDataValidAndConnected => IsDataValid && IsConnected;
public void CopyFrom(HandDataAsset source)
{
IsDataValid = source.IsDataValid;
IsConnected = source.IsConnected;
IsTracked = source.IsTracked;
IsHighConfidence = source.IsHighConfidence;
IsDominantHand = source.IsDominantHand;
CopyPosesFrom(source);
}
public void CopyPosesFrom(HandDataAsset source)
{
Root = source.Root;
RootPoseOrigin = source.RootPoseOrigin;
Array.Copy(source.Joints, Joints, Constants.NUM_HAND_JOINTS);
Array.Copy(source.IsFingerPinching, IsFingerPinching, IsFingerPinching.Length);
Array.Copy(source.IsFingerHighConfidence, IsFingerHighConfidence,
IsFingerHighConfidence.Length);
Array.Copy(source.FingerPinchStrength, FingerPinchStrength, FingerPinchStrength.Length);
HandScale = source.HandScale;
PointerPose = source.PointerPose;
PointerPoseOrigin = source.PointerPoseOrigin;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 24ccc8fce03318d4fb4fbd8bb782ded2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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.
************************************************************************************/
namespace Oculus.Interaction.Input
{
/// <summary>
/// A set of constants that are passed to each child of a Hand modifier tree from the root DataSource.
/// </summary>
public class HandDataSourceConfig
{
public Handedness Handedness { get; set; }
public ITrackingToWorldTransformer TrackingToWorldTransformer { get; set; }
public HandSkeleton HandSkeleton { get; set; }
public IDataSource<HmdDataAsset, HmdDataSourceConfig> HmdData { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cf1f3c380e869844ba59339cad4a325c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,145 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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 UnityEngine;
namespace Oculus.Interaction.Input
{
public class HandJointCache
{
private Pose[] _localPoses = new Pose[Constants.NUM_HAND_JOINTS];
private Pose[] _posesFromWrist = new Pose[Constants.NUM_HAND_JOINTS];
private Pose[] _worldPoses = new Pose[Constants.NUM_HAND_JOINTS];
private ReadOnlyHandJointPoses _posesFromWristCollection;
private ReadOnlyHandJointPoses _localPosesCollection;
private IReadOnlyHandSkeletonJointList _originalJoints;
private int _dirtyWorldJoints = 0;
private int _dirtyWristJoints = 0;
public int LocalDataVersion { get; private set; } = -1;
public HandJointCache(IReadOnlyHandSkeleton handSkeleton)
{
LocalDataVersion = -1;
_posesFromWrist[0] = Pose.identity;
_posesFromWristCollection = new ReadOnlyHandJointPoses(_posesFromWrist);
_localPosesCollection = new ReadOnlyHandJointPoses(_localPoses);
_originalJoints = handSkeleton.Joints;
}
public void Update(HandDataAsset data, int dataVersion)
{
_dirtyWorldJoints = _dirtyWristJoints = (1 << (int)HandJointId.HandEnd) - 1; //set all dirty
if (!data.IsDataValidAndConnected)
{
return;
}
LocalDataVersion = dataVersion;
UpdateAllLocalPoses(data);
}
public bool GetAllLocalPoses(out ReadOnlyHandJointPoses localJointPoses)
{
localJointPoses = _localPosesCollection;
return _posesFromWristCollection.Count > 0;
}
public bool GetAllPosesFromWrist(out ReadOnlyHandJointPoses jointPosesFromWrist)
{
UpdateAllPosesFromWrist();
jointPosesFromWrist = _posesFromWristCollection;
return _posesFromWristCollection.Count > 0;
}
public Pose LocalJointPose(HandJointId jointid)
{
return _localPoses[(int)jointid];
}
public Pose PoseFromWrist(HandJointId jointid)
{
Pose pose = _posesFromWrist[(int)jointid];
UpdateWristJoint(jointid, ref pose);
return pose;
}
public Pose WorldJointPose(HandJointId jointid, Pose rootPose, float handScale)
{
int jointIndex = (int)jointid;
if ((_dirtyWorldJoints & (1 << jointIndex)) != 0) //its dirty
{
Pose wristPose = Pose.identity;
UpdateWristJoint(jointid, ref wristPose);
PoseUtils.Multiply(_localPoses[0], wristPose, ref _worldPoses[jointIndex]);
_worldPoses[jointIndex].position *= handScale;
_worldPoses[jointIndex].Postmultiply(rootPose);
_dirtyWorldJoints = _dirtyWorldJoints & ~(1 << jointIndex); //set clean
}
return _worldPoses[jointIndex];
}
private void UpdateAllLocalPoses(HandDataAsset data)
{
for (int i = 0; i < Constants.NUM_HAND_JOINTS; ++i)
{
HandSkeletonJoint originalJoint = _originalJoints[i];
_localPoses[i].position = originalJoint.pose.position;
_localPoses[i].rotation = data.Joints[i];
}
}
private void UpdateAllPosesFromWrist()
{
if (_dirtyWristJoints == 0) //its completely clean
{
return;
}
for (int jointIndex = 0; jointIndex < Constants.NUM_HAND_JOINTS; ++jointIndex)
{
if ((_dirtyWristJoints & (1 << jointIndex)) == 0) //its clean
{
continue;
}
HandSkeletonJoint originalJoint = _originalJoints[jointIndex];
if (originalJoint.parent >= 0)
{
PoseUtils.Multiply(_posesFromWrist[originalJoint.parent],
_localPoses[jointIndex], ref _posesFromWrist[jointIndex]);
}
}
_dirtyWristJoints = 0; //set all clean
}
private void UpdateWristJoint(HandJointId jointid, ref Pose pose)
{
int jointIndex = (int)jointid;
if ((_dirtyWristJoints & (1 << jointIndex)) != 0)// its dirty
{
if (jointid > HandJointId.HandWristRoot)
{
UpdateWristJoint((HandJointId)_originalJoints[jointIndex].parent, ref pose);
PoseUtils.Multiply(pose, _localPoses[jointIndex], ref _posesFromWrist[jointIndex]);
}
_dirtyWristJoints = _dirtyWristJoints & ~(1 << jointIndex); //set clean
}
pose.CopyFrom(_posesFromWrist[jointIndex]);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f06ae507a1989e04daeeedc9859327ff
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,245 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Primitive type serialization
/// </summary>
namespace Oculus.Interaction.Input
{
public static class Constants
{
public const int NUM_HAND_JOINTS = (int)HandJointId.HandEnd;
public const int NUM_FINGERS = 5;
}
public enum Handedness
{
Left = 0,
Right = 1,
}
public enum HandFinger
{
Thumb = 0,
Index = 1,
Middle = 2,
Ring = 3,
Pinky = 4,
}
[Flags]
public enum HandFingerFlags
{
None = 0,
Thumb = 1 << 0,
Index = 1 << 1,
Middle = 1 << 2,
Ring = 1 << 3,
Pinky = 1 << 4,
All = (1 << 5) - 1
}
[Flags]
public enum HandFingerJointFlags
{
None = 0,
Thumb0 = 1 << HandJointId.HandThumb0,
Thumb1 = 1 << HandJointId.HandThumb1,
Thumb2 = 1 << HandJointId.HandThumb2,
Thumb3 = 1 << HandJointId.HandThumb3,
Index1 = 1 << HandJointId.HandIndex1,
Index2 = 1 << HandJointId.HandIndex2,
Index3 = 1 << HandJointId.HandIndex3,
Middle1 = 1 << HandJointId.HandMiddle1,
Middle2 = 1 << HandJointId.HandMiddle2,
Middle3 = 1 << HandJointId.HandMiddle3,
Ring1 = 1 << HandJointId.HandRing1,
Ring2 = 1 << HandJointId.HandRing2,
Ring3 = 1 << HandJointId.HandRing3,
Pinky0 = 1 << HandJointId.HandPinky0,
Pinky1 = 1 << HandJointId.HandPinky1,
Pinky2 = 1 << HandJointId.HandPinky2,
Pinky3 = 1 << HandJointId.HandPinky3,
}
public static class HandFingerUtils
{
public static HandFingerFlags ToFlags(HandFinger handFinger)
{
return (HandFingerFlags)(1 << (int)handFinger);
}
}
public enum HandJointId
{
Invalid = -1,
// hand bones
HandStart = 0,
HandWristRoot = HandStart + 0, // root frame of the hand, where the wrist is located
HandForearmStub = HandStart + 1, // frame for user's forearm
HandThumb0 = HandStart + 2, // thumb trapezium bone
HandThumb1 = HandStart + 3, // thumb metacarpal bone
HandThumb2 = HandStart + 4, // thumb proximal phalange bone
HandThumb3 = HandStart + 5, // thumb distal phalange bone
HandIndex1 = HandStart + 6, // index proximal phalange bone
HandIndex2 = HandStart + 7, // index intermediate phalange bone
HandIndex3 = HandStart + 8, // index distal phalange bone
HandMiddle1 = HandStart + 9, // middle proximal phalange bone
HandMiddle2 = HandStart + 10, // middle intermediate phalange bone
HandMiddle3 = HandStart + 11, // middle distal phalange bone
HandRing1 = HandStart + 12, // ring proximal phalange bone
HandRing2 = HandStart + 13, // ring intermediate phalange bone
HandRing3 = HandStart + 14, // ring distal phalange bone
HandPinky0 = HandStart + 15, // pinky metacarpal bone
HandPinky1 = HandStart + 16, // pinky proximal phalange bone
HandPinky2 = HandStart + 17, // pinky intermediate phalange bone
HandPinky3 = HandStart + 18, // pinky distal phalange bone
HandMaxSkinnable = HandStart + 19,
// Bone tips are position only.
// They are not used for skinning but are useful for hit-testing.
// NOTE: HandThumbTip == HandMaxSkinnable since the extended tips need to be contiguous
HandThumbTip = HandMaxSkinnable + 0, // tip of the thumb
HandIndexTip = HandMaxSkinnable + 1, // tip of the index finger
HandMiddleTip = HandMaxSkinnable + 2, // tip of the middle finger
HandRingTip = HandMaxSkinnable + 3, // tip of the ring finger
HandPinkyTip = HandMaxSkinnable + 4, // tip of the pinky
HandEnd = HandMaxSkinnable + 5,
}
public class HandJointUtils
{
public static List<HandJointId[]> FingerToJointList = new List<HandJointId[]>()
{
new[] {HandJointId.HandThumb0,HandJointId.HandThumb1,HandJointId.HandThumb2,HandJointId.HandThumb3},
new[] {HandJointId.HandIndex1, HandJointId.HandIndex2, HandJointId.HandIndex3},
new[] {HandJointId.HandMiddle1, HandJointId.HandMiddle2, HandJointId.HandMiddle3},
new[] {HandJointId.HandRing1,HandJointId.HandRing2,HandJointId.HandRing3},
new[] {HandJointId.HandPinky0, HandJointId.HandPinky1, HandJointId.HandPinky2, HandJointId.HandPinky3}
};
public static List<HandJointId> JointIds = new List<HandJointId>()
{
HandJointId.HandIndex1,
HandJointId.HandIndex2,
HandJointId.HandIndex3,
HandJointId.HandMiddle1,
HandJointId.HandMiddle2,
HandJointId.HandMiddle3,
HandJointId.HandRing1,
HandJointId.HandRing2,
HandJointId.HandRing3,
HandJointId.HandPinky0,
HandJointId.HandPinky1,
HandJointId.HandPinky2,
HandJointId.HandPinky3,
HandJointId.HandThumb0,
HandJointId.HandThumb1,
HandJointId.HandThumb2,
HandJointId.HandThumb3
};
private static readonly HandJointId[] _handFingerProximals =
{
HandJointId.HandThumb2, HandJointId.HandIndex1, HandJointId.HandMiddle1,
HandJointId.HandRing1, HandJointId.HandPinky1
};
public static HandJointId GetHandFingerTip(HandFinger finger)
{
return HandJointId.HandMaxSkinnable + (int)finger;
}
/// <summary>
/// Returns the "proximal" JointId for the given finger.
/// This is commonly known as the Knuckle.
/// For fingers, proximal is the join with index 1; eg HandIndex1.
/// For thumb, proximal is the joint with index 2; eg HandThumb2.
/// </summary>
public static HandJointId GetHandFingerProximal(HandFinger finger)
{
return _handFingerProximals[(int)finger];
}
}
public struct HandSkeletonJoint
{
/// <summary>
/// Id of the parent joint in the skeleton hierarchy. Must always have a lower index than
/// this joint.
/// </summary>
public int parent;
/// <summary>
/// Stores the pose of the joint, in local space.
/// </summary>
public Pose pose;
}
public interface IReadOnlyHandSkeletonJointList
{
ref readonly HandSkeletonJoint this[int jointId] { get; }
}
public interface IReadOnlyHandSkeleton
{
IReadOnlyHandSkeletonJointList Joints { get; }
}
public interface ICopyFrom<in TSelfType>
{
void CopyFrom(TSelfType source);
}
public class ReadOnlyHandJointPoses : IReadOnlyList<Pose>
{
private Pose[] _poses;
public ReadOnlyHandJointPoses(Pose[] poses)
{
_poses = poses;
}
public IEnumerator<Pose> GetEnumerator()
{
foreach (var pose in _poses)
{
yield return pose;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public static ReadOnlyHandJointPoses Empty { get; } = new ReadOnlyHandJointPoses(Array.Empty<Pose>());
public int Count => _poses.Length;
public Pose this[int index] => _poses[index];
public ref readonly Pose this[HandJointId index] => ref _poses[(int)index];
}
public class HandSkeleton : IReadOnlyHandSkeleton, IReadOnlyHandSkeletonJointList
{
public HandSkeletonJoint[] joints = new HandSkeletonJoint[Constants.NUM_HAND_JOINTS];
public IReadOnlyHandSkeletonJointList Joints => this;
public ref readonly HandSkeletonJoint this[int jointId] => ref joints[jointId];
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3140fee102ed8c2489e5442c16b1b36f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,150 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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;
using UnityEngine;
using UnityEngine.Assertions;
namespace Oculus.Interaction.Input
{
/// <summary>
/// HandRef is a utility component that delegates all of its IHand implementation
/// to the provided Hand object.
/// </summary>
public class HandRef : MonoBehaviour, IHand, IActiveState
{
[SerializeField, Interface(typeof(IHand))]
private MonoBehaviour _hand;
public IHand Hand { get; private set; }
public Handedness Handedness => Hand.Handedness;
public bool IsConnected => Hand.IsConnected;
public bool IsHighConfidence => Hand.IsHighConfidence;
public bool IsDominantHand => Hand.IsDominantHand;
public float Scale => Hand.Scale;
public bool IsPointerPoseValid => Hand.IsPointerPoseValid;
public bool IsTrackedDataValid => Hand.IsTrackedDataValid;
public bool IsCenterEyePoseValid => Hand.IsCenterEyePoseValid;
public Transform TrackingToWorldSpace => Hand.TrackingToWorldSpace;
public int CurrentDataVersion => Hand.CurrentDataVersion;
public event Action HandUpdated
{
add => Hand.HandUpdated += value;
remove => Hand.HandUpdated -= value;
}
public bool Active => IsConnected;
protected virtual void Awake()
{
Hand = _hand as IHand;
}
protected virtual void Start()
{
Assert.IsNotNull(Hand);
}
public bool GetFingerIsPinching(HandFinger finger)
{
return Hand.GetFingerIsPinching(finger);
}
public bool GetIndexFingerIsPinching()
{
return Hand.GetIndexFingerIsPinching();
}
public bool GetPointerPose(out Pose pose)
{
return Hand.GetPointerPose(out pose);
}
public bool GetJointPose(HandJointId handJointId, out Pose pose)
{
return Hand.GetJointPose(handJointId, out pose);
}
public bool GetJointPoseLocal(HandJointId handJointId, out Pose pose)
{
return Hand.GetJointPoseLocal(handJointId, out pose);
}
public bool GetJointPosesLocal(out ReadOnlyHandJointPoses jointPosesLocal)
{
return Hand.GetJointPosesLocal(out jointPosesLocal);
}
public bool GetJointPoseFromWrist(HandJointId handJointId, out Pose pose)
{
return Hand.GetJointPoseFromWrist(handJointId, out pose);
}
public bool GetJointPosesFromWrist(out ReadOnlyHandJointPoses jointPosesFromWrist)
{
return Hand.GetJointPosesFromWrist(out jointPosesFromWrist);
}
public bool GetPalmPoseLocal(out Pose pose)
{
return Hand.GetPalmPoseLocal(out pose);
}
public bool GetFingerIsHighConfidence(HandFinger finger)
{
return Hand.GetFingerIsHighConfidence(finger);
}
public float GetFingerPinchStrength(HandFinger finger)
{
return Hand.GetFingerPinchStrength(finger);
}
public bool GetRootPose(out Pose pose)
{
return Hand.GetRootPose(out pose);
}
public bool GetCenterEyePose(out Pose pose)
{
return Hand.GetCenterEyePose(out pose);
}
public bool GetHandAspect<TComponent>(out TComponent foundComponent) where TComponent : class
{
return Hand.GetHandAspect(out foundComponent);
}
#region Inject
public void InjectAllHandRef(IHand hand)
{
InjectHand(hand);
}
public void InjectHand(IHand hand)
{
_hand = hand as MonoBehaviour;
Hand = hand;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b14164f8f23faae4293baeb84485b3d6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,157 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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 UnityEngine;
using System;
namespace Oculus.Interaction.Input
{
public interface IHand
{
Handedness Handedness { get; }
bool IsConnected { get; }
/// <summary>
/// The hand is connected and tracked, and the root pose's tracking data is marked as
/// high confidence.
/// If this is true, then it implies that IsConnected and IsRootPoseValid are also true,
/// so they don't need to be checked in addition to this.
/// </summary>
bool IsHighConfidence { get; }
bool IsDominantHand { get; }
float Scale { get; }
bool GetFingerIsPinching(HandFinger finger);
bool GetIndexFingerIsPinching();
/// <summary>
/// Will return true if a pointer pose is available, that can be retrieved via
/// <see cref="GetPointerPose"/>
/// </summary>
bool IsPointerPoseValid { get; }
/// <summary>
/// Attempts to calculate the pose that can be used as a root for raycasting, in world space
/// Returns false if there is no valid tracking data.
/// </summary>
bool GetPointerPose(out Pose pose);
/// <summary>
/// Attempts to calculate the pose of the requested hand joint, in world space.
/// Returns false if the skeleton is not yet initialized, or there is no valid
/// tracking data.
/// </summary>
bool GetJointPose(HandJointId handJointId, out Pose pose);
/// <summary>
/// Attempts to calculate the pose of the requested hand joint, in local space.
/// Returns false if the skeleton is not yet initialized, or there is no valid
/// tracking data.
/// </summary>
bool GetJointPoseLocal(HandJointId handJointId, out Pose pose);
/// <summary>
/// Returns an array containing the local pose of each joint. The poses
/// do not have the root pose applied, nor the hand scale. It is in the same coordinate
/// system as the hand skeleton.
/// </summary>
/// <param name="localJointPoses">The array with the local joint poses.
/// It will be empty if no poses where found</param>
/// <returns>
/// True if the poses collection was correctly populated. False otherwise.
/// </returns>
bool GetJointPosesLocal(out ReadOnlyHandJointPoses localJointPoses);
/// <summary>
/// Attempts to calculate the pose of the requested hand joint relative to the wrist.
/// Returns false if the skeleton is not yet initialized, or there is no valid
/// tracking data.
/// </summary>
bool GetJointPoseFromWrist(HandJointId handJointId, out Pose pose);
/// <summary>
/// Returns an array containing the pose of each joint relative to the wrist. The poses
/// do not have the root pose applied, nor the hand scale. It is in the same coordinate
/// system as the hand skeleton.
/// </summary>
/// <param name="jointPosesFromWrist">The array with the joint poses from the wrist.
/// It will be empty if no poses where found</param>
/// <returns>
/// True if the poses collection was correctly populated. False otherwise.
/// </returns>
bool GetJointPosesFromWrist(out ReadOnlyHandJointPoses jointPosesFromWrist);
/// <summary>
/// Obtains palm pose in local space.
/// </summary>
/// <param name="pose">The pose to populate</param>
/// <returns>
/// True if pose was obtained.
/// </returns>
bool GetPalmPoseLocal(out Pose pose);
bool GetFingerIsHighConfidence(HandFinger finger);
float GetFingerPinchStrength(HandFinger finger);
/// <summary>
/// True if the hand is currently tracked, thus tracking poses are available for the hand
/// root and finger joints.
/// This property does not indicate pointing pose validity, which has its own property:
/// <see cref="IsPointerPoseValid"/>.
/// </summary>
bool IsTrackedDataValid { get; }
/// <summary>
/// Gets the root pose of the wrist, in world space.
/// Will return true if a pose was available; false otherwise.
/// Confidence level of the pose is exposed via <see cref="IsHighConfidence"/>.
/// </summary>
bool GetRootPose(out Pose pose);
/// <summary>
/// Will return true if an HMD Center Eye pose available, that can be retrieved via
/// <see cref="GetCenterEyePose"/>
/// </summary>
bool IsCenterEyePoseValid { get; }
/// <summary>
/// Gets the pose of the center eye (HMD), in world space.
/// Will return true if a pose was available; false otherwise.
/// </summary>
bool GetCenterEyePose(out Pose pose);
/// <summary>
/// The transform that was applied to all tracking space poses to convert them to world
/// space.
/// </summary>
Transform TrackingToWorldSpace { get; }
/// <summary>
/// Incremented every time the source tracking or state data changes.
/// </summary>
int CurrentDataVersion { get; }
/// <summary>
/// An Aspect provides additional functionality on top of what the HandState provides.
/// The underlying hand is responsible for finding the most appropriate component.
/// It is usually, but not necessarily, located within the same GameObject as the
/// underlying hand.
/// For example, this method can be used to source the SkinnedMeshRenderer representing the
/// hand, if one exists.
/// <returns>true if an aspect of the requested type was found, false otherwise</returns>
/// </summary>
bool GetHandAspect<TComponent>(out TComponent foundComponent) where TComponent : class;
event Action HandUpdated;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e500f060fe544c21b9b8892fb57511e1
timeCreated: 1630518667

View File

@@ -0,0 +1,19 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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.
************************************************************************************/
namespace Oculus.Interaction.Input
{
public interface IHandSkeletonProvider
{
HandSkeleton this[Handedness handedness] { get; }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: be3974c2b13042ecb43558bf99c1603b
timeCreated: 1629410878

View File

@@ -0,0 +1,131 @@
/************************************************************************************
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
https://developer.oculus.com/licenses/oculussdk/
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;
using System.Collections.Generic;
using UnityEngine;
namespace Oculus.Interaction.Input
{
public class JointLock
{
public HandJointId JointId;
public bool Locked;
public Quaternion SourceRotation;
public Quaternion AnimationStartRotation;
public Quaternion AnimationTargetRotation;
public float AnimationTime = 0f;
public Quaternion OutputRotation;
}
public class JointLocking
{
public static void Initialize(HandDataAsset data,
out Dictionary<HandJointId, JointLock> jointMap)
{
jointMap = new Dictionary<HandJointId, JointLock>();
foreach (HandJointId jointId in HandJointUtils.JointIds)
{
JointLock jointLock = new JointLock()
{
JointId = jointId,
SourceRotation = data.Joints[(int)jointId],
AnimationTargetRotation = data.Joints[(int)jointId],
OutputRotation = data.Joints[(int)jointId],
AnimationTime = 0f,
Locked = false
};
jointMap.Add(jointId, jointLock);
}
}
public static void UpdateLockedJoints(
HandDataAsset data,
Dictionary<HandJointId, JointLock> jointMap,
float totalEaseTime,
AnimationCurve animationCurve)
{
foreach (JointLock angleLock in jointMap.Values)
{
angleLock.SourceRotation = data.Joints[(int)angleLock.JointId];
if (!angleLock.Locked)
{
angleLock.AnimationTargetRotation = data.Joints[(int)angleLock.JointId];
}
angleLock.AnimationTime = Math.Min(angleLock.AnimationTime + Time.deltaTime /
totalEaseTime, 1.0f);
float easeTime = animationCurve.Evaluate(angleLock.AnimationTime);
angleLock.OutputRotation = Quaternion.Slerp(angleLock.AnimationStartRotation,
angleLock.AnimationTargetRotation, easeTime);
data.Joints[(int)angleLock.JointId] = angleLock.OutputRotation;
}
}
public static void LockJoint(
HandJointId jointId,
Quaternion targetRotation,
Dictionary<HandJointId, JointLock> jointMap)
{
if (jointMap[jointId].Locked)
{
return;
}
jointMap[jointId].Locked = true;
jointMap[jointId].AnimationTargetRotation = targetRotation;
jointMap[jointId].AnimationStartRotation = jointMap[jointId].OutputRotation;
jointMap[jointId].AnimationTime = 0f;
}
public static void UnlockJoint(HandJointId jointId,
Dictionary<HandJointId, JointLock> jointMap)
{
if (!jointMap[jointId].Locked) return;
jointMap[jointId].Locked = false;
jointMap[jointId].AnimationStartRotation = jointMap[jointId].OutputRotation;
jointMap[jointId].AnimationTime = 0f;
}
public static void UnlockAllJoints(Dictionary<HandJointId, JointLock> jointMap)
{
foreach (var jointId in jointMap.Keys)
{
UnlockJoint(jointId, jointMap);
}
}
public static void LockByFingerId(HandFinger finger,
Dictionary<HandJointId, JointLock> jointMap)
{
HandJointId[] joints = HandJointUtils.FingerToJointList[(int)finger];
foreach (var jointId in joints)
{
LockJoint(jointId, jointMap[jointId].SourceRotation, jointMap);
}
}
public static void UnlockByFingerId(HandFinger finger,
Dictionary<HandJointId, JointLock> jointMap)
{
HandJointId[] joints = HandJointUtils.FingerToJointList[(int)finger];
foreach (var jointId in joints)
{
UnlockJoint(jointId, jointMap);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d043893ca7b199f42a4d1c3785a23d02
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: