clean project
This commit is contained in:
163
Assets/Oculus/Interaction/Runtime/Scripts/Grab/FingerGrabAPI.cs
Normal file
163
Assets/Oculus/Interaction/Runtime/Scripts/Grab/FingerGrabAPI.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
/************************************************************************************
|
||||
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.Input;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.GrabAPI
|
||||
{
|
||||
public class FingerGrabAPI : IFingerAPI
|
||||
{
|
||||
private Vector3 _poseVolumeCenterOffset = Vector3.zero;
|
||||
private Vector3 _poseVolumeCenter = Vector3.zero;
|
||||
|
||||
private static readonly float START_THRESHOLD = 0.75f;
|
||||
private static readonly float RELEASE_THRESHOLD = 0.25f;
|
||||
private static readonly float FINGER_TIP_RADIUS = 0.01f;
|
||||
private static readonly float POSE_VOLUME_RADIUS = 0.05f;
|
||||
private static readonly Vector3 POSE_VOLUME_OFFSET_RIGHT = new Vector3(0.07f, -0.03f, 0.0f);
|
||||
private static readonly Vector3 POSE_VOLUME_OFFSET_LEFT = new Vector3(-0.07f, 0.03f, 0.0f);
|
||||
|
||||
private class FingerGrabData
|
||||
{
|
||||
private readonly HandJointId _tipId;
|
||||
private Vector3 _tipPosition;
|
||||
|
||||
public float GrabStrength;
|
||||
public bool IsGrabbing;
|
||||
public bool IsGrabbingChanged;
|
||||
|
||||
public FingerGrabData(HandFinger fingerId)
|
||||
{
|
||||
_tipId = HandJointUtils.GetHandFingerTip(fingerId);
|
||||
}
|
||||
|
||||
public void UpdateTipValues(IHand hand)
|
||||
{
|
||||
if (hand.GetJointPoseFromWrist(_tipId, out Pose pose))
|
||||
{
|
||||
_tipPosition = pose.position;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateGrabStrength(Vector3 poseVolumeCenter)
|
||||
{
|
||||
float outsidePoseVolumeRadius = POSE_VOLUME_RADIUS + FINGER_TIP_RADIUS;
|
||||
float insidePoseVolumeRadius = POSE_VOLUME_RADIUS - FINGER_TIP_RADIUS;
|
||||
float sqrOutsidePoseVolume = outsidePoseVolumeRadius * outsidePoseVolumeRadius;
|
||||
float sqrInsidePoseVolume = insidePoseVolumeRadius * insidePoseVolumeRadius;
|
||||
|
||||
float sqrDist = (poseVolumeCenter - _tipPosition).sqrMagnitude;
|
||||
if (sqrDist >= sqrOutsidePoseVolume)
|
||||
{
|
||||
GrabStrength = 0.0f;
|
||||
}
|
||||
else if (sqrDist <= sqrInsidePoseVolume)
|
||||
{
|
||||
GrabStrength = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
float distance = Mathf.Sqrt(sqrDist);
|
||||
GrabStrength = 1.0f - Mathf.Clamp01(
|
||||
(distance - insidePoseVolumeRadius) / (2.0f * FINGER_TIP_RADIUS));
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateIsGrabbing()
|
||||
{
|
||||
IsGrabbingChanged = false;
|
||||
if (GrabStrength > START_THRESHOLD)
|
||||
{
|
||||
if (!IsGrabbing)
|
||||
{
|
||||
IsGrabbing = true;
|
||||
IsGrabbingChanged = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (GrabStrength < RELEASE_THRESHOLD)
|
||||
{
|
||||
if (IsGrabbing)
|
||||
{
|
||||
IsGrabbing = false;
|
||||
IsGrabbingChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly FingerGrabData[] _fingersGrabData = {
|
||||
new FingerGrabData(HandFinger.Thumb),
|
||||
new FingerGrabData(HandFinger.Index),
|
||||
new FingerGrabData(HandFinger.Middle),
|
||||
new FingerGrabData(HandFinger.Ring),
|
||||
new FingerGrabData(HandFinger.Pinky)
|
||||
};
|
||||
|
||||
public bool GetFingerIsGrabbing(HandFinger finger)
|
||||
{
|
||||
return _fingersGrabData[(int)finger].IsGrabbing;
|
||||
}
|
||||
|
||||
public bool GetFingerIsGrabbingChanged(HandFinger finger, bool targetGrabState)
|
||||
{
|
||||
return _fingersGrabData[(int)finger].IsGrabbingChanged &&
|
||||
_fingersGrabData[(int)finger].IsGrabbing == targetGrabState;
|
||||
}
|
||||
|
||||
|
||||
public float GetFingerGrabStrength(HandFinger finger)
|
||||
{
|
||||
return _fingersGrabData[(int)finger].GrabStrength;
|
||||
}
|
||||
|
||||
|
||||
public Vector3 GetCenterOffset()
|
||||
{
|
||||
return _poseVolumeCenterOffset;
|
||||
}
|
||||
|
||||
public void Update(IHand hand)
|
||||
{
|
||||
if (hand == null || !hand.IsTrackedDataValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateVolumeCenter(hand);
|
||||
for (int i = 0; i < Constants.NUM_FINGERS; ++i)
|
||||
{
|
||||
_fingersGrabData[i].UpdateTipValues(hand);
|
||||
_fingersGrabData[i].UpdateGrabStrength(_poseVolumeCenter);
|
||||
_fingersGrabData[i].UpdateIsGrabbing();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateVolumeCenter(IHand hand)
|
||||
{
|
||||
if (!hand.GetJointPoseFromWrist(HandJointId.HandWristRoot, out var wristPose))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4x4 wristPoseMat = Matrix4x4.TRS(wristPose.position, wristPose.rotation, Vector3.one);
|
||||
_poseVolumeCenterOffset = hand.Handedness == Handedness.Left
|
||||
? POSE_VOLUME_OFFSET_LEFT
|
||||
: POSE_VOLUME_OFFSET_RIGHT;
|
||||
|
||||
_poseVolumeCenter = wristPose.position +
|
||||
wristPoseMat.MultiplyVector(_poseVolumeCenterOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df4b2f3ffa2d8a04eb0badc7bfd33a41
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
271
Assets/Oculus/Interaction/Runtime/Scripts/Grab/FingerPinchAPI.cs
Normal file
271
Assets/Oculus/Interaction/Runtime/Scripts/Grab/FingerPinchAPI.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
/************************************************************************************
|
||||
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.Input;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.GrabAPI
|
||||
{
|
||||
public class FingerPinchAPI : IFingerAPI
|
||||
{
|
||||
private bool _isPinchVisibilityGood;
|
||||
private float DistanceStart => _isPinchVisibilityGood ? PINCH_HQ_DISTANCE_START : PINCH_DISTANCE_START;
|
||||
private float DistanceStopMax => _isPinchVisibilityGood ? PINCH_HQ_DISTANCE_STOP_MAX : PINCH_DISTANCE_STOP_MAX;
|
||||
private float DistanceStopOffset => _isPinchVisibilityGood ? PINCH_HQ_DISTANCE_STOP_OFFSET : PINCH_DISTANCE_STOP_OFFSET;
|
||||
|
||||
private const float PINCH_DISTANCE_START = 0.03f;
|
||||
private const float PINCH_DISTANCE_STOP_MAX = 0.1f;
|
||||
private const float PINCH_DISTANCE_STOP_OFFSET = 0.04f;
|
||||
|
||||
private const float PINCH_HQ_DISTANCE_START = 0.016f;
|
||||
private const float PINCH_HQ_DISTANCE_STOP_MAX = 0.1f;
|
||||
private const float PINCH_HQ_DISTANCE_STOP_OFFSET = 0.016f;
|
||||
|
||||
private const float PINCH_HQ_VIEW_ANGLE_THRESHOLD = 40f;
|
||||
|
||||
private HandJointId[] thumbJointList = new[]
|
||||
{
|
||||
HandJointId.HandThumb0,
|
||||
HandJointId.HandThumb1,
|
||||
HandJointId.HandThumb2,
|
||||
HandJointId.HandThumb3,
|
||||
HandJointId.HandThumbTip
|
||||
};
|
||||
|
||||
private class FingerPinchData
|
||||
{
|
||||
private readonly HandJointId _tipId;
|
||||
private float _minPinchDistance;
|
||||
|
||||
public Vector3 TipPosition { get; private set; }
|
||||
public float PinchStrength;
|
||||
public bool IsPinching;
|
||||
public bool IsPinchingChanged;
|
||||
|
||||
public FingerPinchData(HandFinger fingerId)
|
||||
{
|
||||
_tipId = HandJointUtils.GetHandFingerTip(fingerId);
|
||||
}
|
||||
|
||||
public void UpdateTipPosition(IHand hand)
|
||||
{
|
||||
if (hand.GetJointPoseFromWrist(_tipId, out Pose pose))
|
||||
{
|
||||
TipPosition = pose.position;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateIsPinching(float distance, float start, float stopOffset, float stopMax)
|
||||
{
|
||||
IsPinchingChanged = false;
|
||||
if (!IsPinching)
|
||||
{
|
||||
if (distance < start)
|
||||
{
|
||||
IsPinching = true;
|
||||
IsPinchingChanged = true;
|
||||
_minPinchDistance = distance;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_minPinchDistance = Mathf.Min(_minPinchDistance, distance);
|
||||
if (distance > stopMax ||
|
||||
distance > _minPinchDistance + stopOffset)
|
||||
{
|
||||
IsPinching = false;
|
||||
IsPinchingChanged = true;
|
||||
_minPinchDistance = float.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly FingerPinchData[] _fingersPinchData =
|
||||
{
|
||||
new FingerPinchData(HandFinger.Thumb),
|
||||
new FingerPinchData(HandFinger.Index),
|
||||
new FingerPinchData(HandFinger.Middle),
|
||||
new FingerPinchData(HandFinger.Ring),
|
||||
new FingerPinchData(HandFinger.Pinky)
|
||||
};
|
||||
|
||||
public bool GetFingerIsGrabbing(HandFinger finger)
|
||||
{
|
||||
if (finger == HandFinger.Thumb)
|
||||
{
|
||||
for (int i = 1; i < Constants.NUM_FINGERS; ++i)
|
||||
{
|
||||
if (_fingersPinchData[i].IsPinching)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return _fingersPinchData[(int)finger].IsPinching;
|
||||
}
|
||||
|
||||
public Vector3 GetCenterOffset()
|
||||
{
|
||||
float maxStrength = float.NegativeInfinity;
|
||||
Vector3 thumbTip = _fingersPinchData[0].TipPosition;
|
||||
Vector3 center = thumbTip;
|
||||
|
||||
for (int i = 1; i < Constants.NUM_FINGERS; ++i)
|
||||
{
|
||||
float strength = _fingersPinchData[i].PinchStrength;
|
||||
if (strength > maxStrength)
|
||||
{
|
||||
maxStrength = strength;
|
||||
Vector3 fingerTip = _fingersPinchData[i].TipPosition;
|
||||
center = (thumbTip + fingerTip) * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
return center;
|
||||
}
|
||||
|
||||
public bool GetFingerIsGrabbingChanged(HandFinger finger, bool targetPinchState)
|
||||
{
|
||||
if (finger == HandFinger.Thumb)
|
||||
{
|
||||
// Thumb pinching changed logic only happens on
|
||||
// the first finger pinching changed when pinching,
|
||||
// or any finger pinching changed when not pinching
|
||||
bool pinching = GetFingerIsGrabbing(finger);
|
||||
if (pinching != targetPinchState)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pinching)
|
||||
{
|
||||
for (int i = 1; i < Constants.NUM_FINGERS; ++i)
|
||||
{
|
||||
if (_fingersPinchData[i].IsPinching == pinching &&
|
||||
!_fingersPinchData[i].IsPinchingChanged)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 1; i < Constants.NUM_FINGERS; ++i)
|
||||
{
|
||||
if (_fingersPinchData[i].IsPinchingChanged)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return _fingersPinchData[(int)finger].IsPinchingChanged &&
|
||||
_fingersPinchData[(int)finger].IsPinching == targetPinchState;
|
||||
}
|
||||
|
||||
public float GetFingerGrabStrength(HandFinger finger)
|
||||
{
|
||||
if (finger == HandFinger.Thumb)
|
||||
{
|
||||
float max = 0.0f;
|
||||
for (int i = 1; i < Constants.NUM_FINGERS; ++i)
|
||||
{
|
||||
max = Mathf.Max(max, _fingersPinchData[i].PinchStrength);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
return _fingersPinchData[(int)finger].PinchStrength;
|
||||
}
|
||||
|
||||
public void Update(IHand hand)
|
||||
{
|
||||
_isPinchVisibilityGood = PinchHasGoodVisibility(hand);
|
||||
for (int i = 0; i < Constants.NUM_FINGERS; ++i)
|
||||
{
|
||||
_fingersPinchData[i].UpdateTipPosition(hand);
|
||||
}
|
||||
|
||||
Vector3 thumbTipPosition = _fingersPinchData[0].TipPosition;
|
||||
for (int i = 1; i < Constants.NUM_FINGERS; ++i)
|
||||
{
|
||||
float distance = GetClosestDistanceToThumb(hand, _fingersPinchData[i].TipPosition);
|
||||
_fingersPinchData[i].UpdateIsPinching(distance,
|
||||
DistanceStart, DistanceStopOffset, DistanceStopMax);
|
||||
float pinchPercent = (distance - DistanceStart) /
|
||||
(DistanceStopMax - DistanceStart);
|
||||
|
||||
_fingersPinchData[i].PinchStrength = 1f - Mathf.Clamp01(pinchPercent);
|
||||
}
|
||||
}
|
||||
|
||||
private float GetClosestDistanceToThumb(IHand hand, Vector3 position)
|
||||
{
|
||||
float minDistance = float.MaxValue;
|
||||
for (int i = 0; i < thumbJointList.Length - 1; i++)
|
||||
{
|
||||
if (!hand.GetJointPoseFromWrist(thumbJointList[i], out Pose pose0))
|
||||
{
|
||||
return float.MaxValue;
|
||||
}
|
||||
if (!hand.GetJointPoseFromWrist(thumbJointList[i+1], out Pose pose1))
|
||||
{
|
||||
return float.MaxValue;
|
||||
}
|
||||
|
||||
minDistance = Mathf.Min(minDistance,
|
||||
ClosestDistanceToLineSegment(position, pose0.position, pose1.position));
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
private float ClosestDistanceToLineSegment(Vector3 position, Vector3 p0, Vector3 p1)
|
||||
{
|
||||
Vector3 lineVec = p1 - p0;
|
||||
Vector3 fromP0 = position - p0;
|
||||
float normalizedProjection = Vector3.Dot(fromP0, lineVec) / Vector3.Dot(lineVec, lineVec);
|
||||
float closestT = Mathf.Clamp01(normalizedProjection);
|
||||
Vector3 closestPoint = p0 + closestT * lineVec;
|
||||
return (closestPoint - position).magnitude;
|
||||
}
|
||||
|
||||
private bool PinchHasGoodVisibility(IHand hand)
|
||||
{
|
||||
if (!hand.GetJointPose(HandJointId.HandWristRoot, out Pose wristPose)
|
||||
|| !hand.GetCenterEyePose(out Pose centerEyePose))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector3 handVector = -1.0f * wristPose.forward;
|
||||
Vector3 targetVector = -1.0f * centerEyePose.forward;
|
||||
|
||||
if (hand.Handedness == Handedness.Right)
|
||||
{
|
||||
handVector = -handVector;
|
||||
}
|
||||
|
||||
float angle = Vector3.Angle(handVector, targetVector);
|
||||
return angle <= PINCH_HQ_VIEW_ANGLE_THRESHOLD;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 983d470de27b8db4aae01497168de89f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,108 @@
|
||||
/************************************************************************************
|
||||
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.Input;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.GrabAPI
|
||||
{
|
||||
public class FingerRawPinchAPI : IFingerAPI
|
||||
{
|
||||
private class FingerPinchData
|
||||
{
|
||||
private readonly HandFinger _finger;
|
||||
private readonly HandJointId _tipId;
|
||||
|
||||
public float PinchStrength;
|
||||
public bool IsPinching;
|
||||
public bool IsPinchingChanged;
|
||||
|
||||
public Vector3 TipPosition { get; private set; }
|
||||
|
||||
public FingerPinchData(HandFinger fingerId)
|
||||
{
|
||||
_finger = fingerId;
|
||||
_tipId = HandJointUtils.GetHandFingerTip(fingerId);
|
||||
}
|
||||
|
||||
public void UpdateTipPosition(IHand hand)
|
||||
{
|
||||
if (hand.GetJointPoseFromWrist(_tipId, out Pose pose))
|
||||
{
|
||||
TipPosition = pose.position;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateIsPinching(IHand hand)
|
||||
{
|
||||
PinchStrength = hand.GetFingerPinchStrength(_finger);
|
||||
bool isPinching = hand.GetFingerIsPinching(_finger);
|
||||
IsPinchingChanged = isPinching != IsPinching;
|
||||
IsPinching = isPinching;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly FingerPinchData[] _fingersPinchData =
|
||||
{
|
||||
new FingerPinchData(HandFinger.Thumb),
|
||||
new FingerPinchData(HandFinger.Index),
|
||||
new FingerPinchData(HandFinger.Middle),
|
||||
new FingerPinchData(HandFinger.Ring),
|
||||
new FingerPinchData(HandFinger.Pinky)
|
||||
};
|
||||
|
||||
public bool GetFingerIsGrabbing(HandFinger finger)
|
||||
{
|
||||
return _fingersPinchData[(int)finger].IsPinching;
|
||||
}
|
||||
|
||||
public Vector3 GetCenterOffset()
|
||||
{
|
||||
float maxStrength = float.NegativeInfinity;
|
||||
Vector3 thumbTip = _fingersPinchData[0].TipPosition;
|
||||
Vector3 center = thumbTip;
|
||||
|
||||
for (int i = 1; i < Constants.NUM_FINGERS; ++i)
|
||||
{
|
||||
float strength = _fingersPinchData[i].PinchStrength;
|
||||
if (strength > maxStrength)
|
||||
{
|
||||
maxStrength = strength;
|
||||
Vector3 fingerTip = _fingersPinchData[i].TipPosition;
|
||||
center = (thumbTip + fingerTip) * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
return center;
|
||||
}
|
||||
|
||||
public bool GetFingerIsGrabbingChanged(HandFinger finger, bool targetPinchState)
|
||||
{
|
||||
return _fingersPinchData[(int)finger].IsPinchingChanged &&
|
||||
_fingersPinchData[(int)finger].IsPinching == targetPinchState;
|
||||
}
|
||||
|
||||
public float GetFingerGrabStrength(HandFinger finger)
|
||||
{
|
||||
return _fingersPinchData[(int)finger].PinchStrength;
|
||||
}
|
||||
|
||||
public void Update(IHand hand)
|
||||
{
|
||||
for (int i = 0; i < Constants.NUM_FINGERS; ++i)
|
||||
{
|
||||
_fingersPinchData[i].UpdateIsPinching(hand);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e600c87acd7d57041b18b00b86842221
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,27 @@
|
||||
/************************************************************************************
|
||||
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.GrabAPI
|
||||
{
|
||||
public class FingerRawPinchInjector : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
private HandGrabAPI _handGrabAPI;
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
_handGrabAPI.InjectOptionalFingerPinchAPI(new FingerRawPinchAPI());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77279ac005404794d8e29e385f50c9c2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,26 @@
|
||||
/************************************************************************************
|
||||
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.Grab
|
||||
{
|
||||
[Flags]
|
||||
public enum GrabTypeFlags
|
||||
{
|
||||
None = 0,
|
||||
Pinch = 1 << 0,
|
||||
Palm = 1 << 1,
|
||||
All = (1 << 2) - 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 654ba27bf15ed6b40a251d7b6baafd79
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
157
Assets/Oculus/Interaction/Runtime/Scripts/Grab/GrabbingRule.cs
Normal file
157
Assets/Oculus/Interaction/Runtime/Scripts/Grab/GrabbingRule.cs
Normal 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 Oculus.Interaction.Input;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.GrabAPI
|
||||
{
|
||||
public enum FingerRequirement
|
||||
{
|
||||
Ignored,
|
||||
Optional,
|
||||
Required
|
||||
}
|
||||
|
||||
public enum FingerUnselectMode
|
||||
{
|
||||
AllReleased,
|
||||
AnyReleased
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public struct GrabbingRule
|
||||
{
|
||||
[SerializeField]
|
||||
private FingerRequirement _thumbRequirement;
|
||||
[SerializeField]
|
||||
private FingerRequirement _indexRequirement;
|
||||
[SerializeField]
|
||||
private FingerRequirement _middleRequirement;
|
||||
[SerializeField]
|
||||
private FingerRequirement _ringRequirement;
|
||||
[SerializeField]
|
||||
private FingerRequirement _pinkyRequirement;
|
||||
|
||||
[SerializeField]
|
||||
private FingerUnselectMode _unselectMode;
|
||||
|
||||
public FingerUnselectMode UnselectMode => _unselectMode;
|
||||
|
||||
public bool SelectsWithOptionals
|
||||
{
|
||||
get
|
||||
{
|
||||
return _thumbRequirement != FingerRequirement.Required
|
||||
&& _indexRequirement != FingerRequirement.Required
|
||||
&& _middleRequirement != FingerRequirement.Required
|
||||
&& _ringRequirement != FingerRequirement.Required
|
||||
&& _pinkyRequirement != FingerRequirement.Required;
|
||||
}
|
||||
}
|
||||
|
||||
public FingerRequirement this[HandFinger fingerID]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (fingerID)
|
||||
{
|
||||
case HandFinger.Thumb: return _thumbRequirement;
|
||||
case HandFinger.Index: return _indexRequirement;
|
||||
case HandFinger.Middle: return _middleRequirement;
|
||||
case HandFinger.Ring: return _ringRequirement;
|
||||
case HandFinger.Pinky: return _pinkyRequirement;
|
||||
}
|
||||
return FingerRequirement.Ignored;
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (fingerID)
|
||||
{
|
||||
case HandFinger.Thumb: _thumbRequirement = value; break;
|
||||
case HandFinger.Index: _indexRequirement = value; break;
|
||||
case HandFinger.Middle: _middleRequirement = value; break;
|
||||
case HandFinger.Ring: _ringRequirement = value; break;
|
||||
case HandFinger.Pinky: _pinkyRequirement = value; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void StripIrrelevant(ref HandFingerFlags fingerFlags)
|
||||
{
|
||||
for (int i = 0; i < Constants.NUM_FINGERS; i++)
|
||||
{
|
||||
HandFinger finger = (HandFinger)i;
|
||||
if (this[finger] == FingerRequirement.Ignored)
|
||||
{
|
||||
fingerFlags = (HandFingerFlags)((int)fingerFlags & ~(1 << i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GrabbingRule(HandFingerFlags mask, in GrabbingRule otherRule)
|
||||
{
|
||||
_thumbRequirement = (mask & HandFingerFlags.Thumb) != 0 ?
|
||||
otherRule._thumbRequirement : FingerRequirement.Ignored;
|
||||
|
||||
_indexRequirement = (mask & HandFingerFlags.Index) != 0 ?
|
||||
otherRule._indexRequirement : FingerRequirement.Ignored;
|
||||
|
||||
_middleRequirement = (mask & HandFingerFlags.Middle) != 0 ?
|
||||
otherRule._middleRequirement : FingerRequirement.Ignored;
|
||||
|
||||
_ringRequirement = (mask & HandFingerFlags.Ring) != 0 ?
|
||||
otherRule._ringRequirement : FingerRequirement.Ignored;
|
||||
|
||||
_pinkyRequirement = (mask & HandFingerFlags.Pinky) != 0 ?
|
||||
otherRule._pinkyRequirement : FingerRequirement.Ignored;
|
||||
|
||||
_unselectMode = otherRule.UnselectMode;
|
||||
}
|
||||
|
||||
#region Defaults
|
||||
|
||||
public static GrabbingRule DefaultPalmRule { get; } = new GrabbingRule()
|
||||
{
|
||||
_thumbRequirement = FingerRequirement.Optional,
|
||||
_indexRequirement = FingerRequirement.Required,
|
||||
_middleRequirement = FingerRequirement.Required,
|
||||
_ringRequirement = FingerRequirement.Required,
|
||||
_pinkyRequirement = FingerRequirement.Optional,
|
||||
|
||||
_unselectMode = FingerUnselectMode.AllReleased
|
||||
};
|
||||
|
||||
public static GrabbingRule DefaultPinchRule { get; } = new GrabbingRule()
|
||||
{
|
||||
_thumbRequirement = FingerRequirement.Required,
|
||||
_indexRequirement = FingerRequirement.Optional,
|
||||
_middleRequirement = FingerRequirement.Optional,
|
||||
_ringRequirement = FingerRequirement.Optional,
|
||||
_pinkyRequirement = FingerRequirement.Optional,
|
||||
|
||||
_unselectMode = FingerUnselectMode.AllReleased
|
||||
};
|
||||
|
||||
public static GrabbingRule FullGrab { get; } = new GrabbingRule()
|
||||
{
|
||||
_thumbRequirement = FingerRequirement.Required,
|
||||
_indexRequirement = FingerRequirement.Required,
|
||||
_middleRequirement = FingerRequirement.Required,
|
||||
_ringRequirement = FingerRequirement.Required,
|
||||
_pinkyRequirement = FingerRequirement.Required,
|
||||
|
||||
_unselectMode = FingerUnselectMode.AllReleased
|
||||
};
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73275021f6e6b1444b1fed2f2dab865e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
228
Assets/Oculus/Interaction/Runtime/Scripts/Grab/HandGrab.cs
Normal file
228
Assets/Oculus/Interaction/Runtime/Scripts/Grab/HandGrab.cs
Normal file
@@ -0,0 +1,228 @@
|
||||
/************************************************************************************
|
||||
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.GrabAPI;
|
||||
using Oculus.Interaction.Input;
|
||||
|
||||
namespace Oculus.Interaction.Grab
|
||||
{
|
||||
public enum GrabType
|
||||
{
|
||||
PinchGrab = 1 << 0,
|
||||
PalmGrab = 1 << 1
|
||||
}
|
||||
|
||||
public interface IHandGrabInteractor
|
||||
{
|
||||
HandGrabAPI HandGrabApi { get; }
|
||||
GrabTypeFlags SupportedGrabTypes { get; }
|
||||
IHandGrabInteractable TargetInteractable { get; }
|
||||
}
|
||||
|
||||
public interface IHandGrabInteractable
|
||||
{
|
||||
GrabTypeFlags SupportedGrabTypes { get; }
|
||||
GrabbingRule PinchGrabRules { get; }
|
||||
GrabbingRule PalmGrabRules { get; }
|
||||
}
|
||||
|
||||
public class HandGrabInteractableData : IHandGrabInteractable
|
||||
{
|
||||
public GrabTypeFlags SupportedGrabTypes { get; set; } = GrabTypeFlags.All;
|
||||
public GrabbingRule PinchGrabRules { get; set; } = GrabbingRule.DefaultPinchRule;
|
||||
public GrabbingRule PalmGrabRules { get; set; } = GrabbingRule.DefaultPalmRule;
|
||||
}
|
||||
|
||||
public static class HandGrab
|
||||
{
|
||||
public static void StoreGrabData(IHandGrabInteractor interactor,
|
||||
IHandGrabInteractable interactable, ref HandGrabInteractableData cache)
|
||||
{
|
||||
HandGrabAPI api = interactor.HandGrabApi;
|
||||
|
||||
cache.SupportedGrabTypes = GrabTypeFlags.None;
|
||||
|
||||
if (SupportsPinch(interactor, interactable))
|
||||
{
|
||||
HandFingerFlags pinchFingers = api.HandPinchingFinger();
|
||||
if (api.IsSustainingGrab(interactable.PinchGrabRules, pinchFingers))
|
||||
{
|
||||
cache.SupportedGrabTypes |= GrabTypeFlags.Pinch;
|
||||
cache.PinchGrabRules = new GrabbingRule(pinchFingers, interactable.PinchGrabRules);
|
||||
}
|
||||
}
|
||||
if (SupportsPalm(interactor, interactable))
|
||||
{
|
||||
HandFingerFlags palmFingers = api.HandPalmGrabbingFingers();
|
||||
if(api.IsSustainingGrab(interactable.PalmGrabRules, palmFingers))
|
||||
{
|
||||
cache.SupportedGrabTypes |= GrabTypeFlags.Palm;
|
||||
cache.PalmGrabRules = new GrabbingRule(palmFingers, interactable.PalmGrabRules);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static float ComputeHoverStrength(IHandGrabInteractor interactor,
|
||||
IHandGrabInteractable interactable, out GrabTypeFlags hoveringGrabTypes)
|
||||
{
|
||||
HandGrabAPI api = interactor.HandGrabApi;
|
||||
hoveringGrabTypes = GrabTypeFlags.None;
|
||||
float hoverStrength = 0f;
|
||||
|
||||
if (SupportsPinch(interactor, interactable))
|
||||
{
|
||||
float pinchStrength = api.GetHandPinchStrength(interactable.PinchGrabRules, false);
|
||||
if (pinchStrength > hoverStrength)
|
||||
{
|
||||
hoverStrength = pinchStrength;
|
||||
hoveringGrabTypes = GrabTypeFlags.Pinch;
|
||||
}
|
||||
}
|
||||
|
||||
if (SupportsPalm(interactor, interactable))
|
||||
{
|
||||
float palmStrength = api.GetHandPalmStrength(interactable.PalmGrabRules, false);
|
||||
if (palmStrength > hoverStrength)
|
||||
{
|
||||
hoverStrength = palmStrength;
|
||||
hoveringGrabTypes = GrabTypeFlags.Palm;
|
||||
}
|
||||
}
|
||||
|
||||
return hoverStrength;
|
||||
}
|
||||
|
||||
public static bool ComputeShouldSelect(IHandGrabInteractor interactor,
|
||||
IHandGrabInteractable interactable, out GrabTypeFlags selectingGrabTypes)
|
||||
{
|
||||
if (interactable == null)
|
||||
{
|
||||
selectingGrabTypes = GrabTypeFlags.None;
|
||||
return false;
|
||||
}
|
||||
|
||||
HandGrabAPI api = interactor.HandGrabApi;
|
||||
selectingGrabTypes = GrabTypeFlags.None;
|
||||
if (SupportsPinch(interactor, interactable) &&
|
||||
api.IsHandSelectPinchFingersChanged(interactable.PinchGrabRules))
|
||||
{
|
||||
selectingGrabTypes |= GrabTypeFlags.Pinch;
|
||||
}
|
||||
|
||||
if (SupportsPalm(interactor, interactable) &&
|
||||
api.IsHandSelectPalmFingersChanged(interactable.PalmGrabRules))
|
||||
{
|
||||
selectingGrabTypes |= GrabTypeFlags.Palm;
|
||||
}
|
||||
|
||||
return selectingGrabTypes != GrabTypeFlags.None;
|
||||
}
|
||||
|
||||
public static bool ComputeShouldUnselect(IHandGrabInteractor interactor,
|
||||
IHandGrabInteractable interactable)
|
||||
{
|
||||
HandGrabAPI api = interactor.HandGrabApi;
|
||||
HandFingerFlags pinchFingers = api.HandPinchingFinger();
|
||||
HandFingerFlags palmFingers = api.HandPalmGrabbingFingers();
|
||||
|
||||
if (interactable.SupportedGrabTypes == GrabTypeFlags.None)
|
||||
{
|
||||
if (!api.IsSustainingGrab(GrabbingRule.FullGrab, pinchFingers) &&
|
||||
!api.IsSustainingGrab(GrabbingRule.FullGrab, palmFingers))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pinchHolding = false;
|
||||
bool palmHolding = false;
|
||||
bool pinchReleased = false;
|
||||
bool palmReleased = false;
|
||||
|
||||
if (SupportsPinch(interactor, interactable.SupportedGrabTypes))
|
||||
{
|
||||
pinchHolding = api.IsSustainingGrab(interactable.PinchGrabRules, pinchFingers);
|
||||
|
||||
if (api.IsHandUnselectPinchFingersChanged(interactable.PinchGrabRules))
|
||||
{
|
||||
pinchReleased = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (SupportsPalm(interactor, interactable.SupportedGrabTypes))
|
||||
{
|
||||
palmHolding = api.IsSustainingGrab(interactable.PalmGrabRules, palmFingers);
|
||||
if (api.IsHandUnselectPalmFingersChanged(interactable.PalmGrabRules))
|
||||
{
|
||||
palmReleased = true;
|
||||
}
|
||||
}
|
||||
|
||||
return !pinchHolding && !palmHolding && (pinchReleased || palmReleased);
|
||||
}
|
||||
|
||||
public static HandFingerFlags GrabbingFingers(IHandGrabInteractor interactor,
|
||||
IHandGrabInteractable interactable)
|
||||
{
|
||||
HandGrabAPI api = interactor.HandGrabApi;
|
||||
if (interactable == null)
|
||||
{
|
||||
return HandFingerFlags.None;
|
||||
}
|
||||
|
||||
HandFingerFlags fingers = HandFingerFlags.None;
|
||||
|
||||
if (SupportsPinch(interactor, interactable))
|
||||
{
|
||||
HandFingerFlags pinchingFingers = api.HandPinchingFinger();
|
||||
interactable.PinchGrabRules.StripIrrelevant(ref pinchingFingers);
|
||||
fingers = fingers | pinchingFingers;
|
||||
}
|
||||
|
||||
if (SupportsPalm(interactor, interactable))
|
||||
{
|
||||
HandFingerFlags grabbingFingers = api.HandPalmGrabbingFingers();
|
||||
interactable.PalmGrabRules.StripIrrelevant(ref grabbingFingers);
|
||||
fingers = fingers | grabbingFingers;
|
||||
}
|
||||
|
||||
return fingers;
|
||||
}
|
||||
|
||||
private static bool SupportsPinch(IHandGrabInteractor interactor,
|
||||
IHandGrabInteractable interactable)
|
||||
{
|
||||
return SupportsPinch(interactor, interactable.SupportedGrabTypes);
|
||||
}
|
||||
|
||||
private static bool SupportsPalm(IHandGrabInteractor interactor,
|
||||
IHandGrabInteractable interactable)
|
||||
{
|
||||
return SupportsPalm(interactor, interactable.SupportedGrabTypes);
|
||||
}
|
||||
|
||||
private static bool SupportsPinch(IHandGrabInteractor interactor,
|
||||
GrabTypeFlags grabTypes)
|
||||
{
|
||||
return (interactor.SupportedGrabTypes & GrabTypeFlags.Pinch) != 0 &&
|
||||
(grabTypes & GrabTypeFlags.Pinch) != 0;
|
||||
}
|
||||
|
||||
private static bool SupportsPalm(IHandGrabInteractor interactor,
|
||||
GrabTypeFlags grabTypes)
|
||||
{
|
||||
return (interactor.SupportedGrabTypes & GrabTypeFlags.Palm) != 0 &&
|
||||
(grabTypes & GrabTypeFlags.Palm) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11ab679e1e048cf46b1357b0d4c1c824
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
337
Assets/Oculus/Interaction/Runtime/Scripts/Grab/HandGrabAPI.cs
Normal file
337
Assets/Oculus/Interaction/Runtime/Scripts/Grab/HandGrabAPI.cs
Normal file
@@ -0,0 +1,337 @@
|
||||
/************************************************************************************
|
||||
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.Input;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace Oculus.Interaction.GrabAPI
|
||||
{
|
||||
public class HandGrabAPI : MonoBehaviour
|
||||
{
|
||||
[SerializeField, Interface(typeof(IHand))]
|
||||
private MonoBehaviour _hand;
|
||||
|
||||
public IHand Hand { get; private set; }
|
||||
|
||||
private IFingerAPI _fingerPinchAPI = new FingerPinchAPI();
|
||||
private IFingerAPI _fingerPalmAPI = new FingerGrabAPI();
|
||||
|
||||
private bool _started;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
Hand = _hand as IHand;
|
||||
}
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
this.BeginStart(ref _started);
|
||||
Assert.IsNotNull(Hand);
|
||||
Assert.IsNotNull(_fingerPinchAPI);
|
||||
Assert.IsNotNull(_fingerPalmAPI);
|
||||
this.EndStart(ref _started);
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
_fingerPinchAPI.Update(Hand);
|
||||
_fingerPalmAPI.Update(Hand);
|
||||
}
|
||||
|
||||
public HandFingerFlags HandPinchingFinger()
|
||||
{
|
||||
return HandGrabbingFingers(_fingerPinchAPI);
|
||||
}
|
||||
|
||||
public HandFingerFlags HandPalmGrabbingFingers()
|
||||
{
|
||||
return HandGrabbingFingers(_fingerPalmAPI);
|
||||
}
|
||||
|
||||
private HandFingerFlags HandGrabbingFingers(IFingerAPI fingerAPI)
|
||||
{
|
||||
HandFingerFlags grabbingFingers = HandFingerFlags.None;
|
||||
|
||||
for (int i = 0; i < Constants.NUM_FINGERS; i++)
|
||||
{
|
||||
HandFinger finger = (HandFinger)i;
|
||||
|
||||
bool isGrabbing = fingerAPI.GetFingerIsGrabbing(finger);
|
||||
if (isGrabbing)
|
||||
{
|
||||
grabbingFingers |= (HandFingerFlags)(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
return grabbingFingers;
|
||||
}
|
||||
|
||||
public bool IsHandPinchGrabbing(in GrabbingRule fingers)
|
||||
{
|
||||
HandFingerFlags pinchFingers = HandPinchingFinger();
|
||||
return IsSustainingGrab(fingers, pinchFingers);
|
||||
}
|
||||
|
||||
public bool IsHandPalmGrabbing(in GrabbingRule fingers)
|
||||
{
|
||||
HandFingerFlags palmFingers = HandPalmGrabbingFingers();
|
||||
return IsSustainingGrab(fingers, palmFingers);
|
||||
}
|
||||
|
||||
public bool IsSustainingGrab(in GrabbingRule fingers, HandFingerFlags grabbingFingers)
|
||||
{
|
||||
for (int i = 0; i < Constants.NUM_FINGERS; i++)
|
||||
{
|
||||
HandFinger finger = (HandFinger)i;
|
||||
HandFingerFlags fingerFlag = (HandFingerFlags)(1 << i);
|
||||
|
||||
bool isFingerGrabbing = (grabbingFingers & fingerFlag) != 0;
|
||||
if (fingers[finger] == FingerRequirement.Required)
|
||||
{
|
||||
if (fingers.UnselectMode == FingerUnselectMode.AnyReleased
|
||||
&& !isFingerGrabbing)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(fingers.UnselectMode == FingerUnselectMode.AllReleased
|
||||
&& isFingerGrabbing)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (fingers[finger] == FingerRequirement.Optional)
|
||||
{
|
||||
if (fingers.UnselectMode == FingerUnselectMode.AnyReleased
|
||||
&& !isFingerGrabbing)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fingers.UnselectMode == FingerUnselectMode.AllReleased
|
||||
&& isFingerGrabbing)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine whether the state of any of the finger pinches have changed this frame to
|
||||
/// the target pinching state (on/off).
|
||||
/// </summary>
|
||||
/// <param name="fingers">Finger rules to check.</param>
|
||||
public bool IsHandSelectPinchFingersChanged(in GrabbingRule fingers)
|
||||
{
|
||||
return IsHandSelectFingersChanged(fingers, _fingerPinchAPI);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine whether the state of any of the finger grabs have changed this frame to
|
||||
/// the target grabbing state (on/off).
|
||||
/// </summary>
|
||||
/// <param name="fingers">Finger rules to check.</param>
|
||||
public bool IsHandSelectPalmFingersChanged(in GrabbingRule fingers)
|
||||
{
|
||||
return IsHandSelectFingersChanged(fingers, _fingerPalmAPI);
|
||||
}
|
||||
|
||||
public bool IsHandUnselectPinchFingersChanged(in GrabbingRule fingers)
|
||||
{
|
||||
return IsHandUnselectFingersChanged(fingers, _fingerPinchAPI);
|
||||
}
|
||||
|
||||
public bool IsHandUnselectPalmFingersChanged(in GrabbingRule fingers)
|
||||
{
|
||||
return IsHandUnselectFingersChanged(fingers, _fingerPalmAPI);
|
||||
}
|
||||
|
||||
private bool IsHandSelectFingersChanged(in GrabbingRule fingers, IFingerAPI fingerAPI)
|
||||
{
|
||||
bool selectsWithOptionals = fingers.SelectsWithOptionals;
|
||||
bool aFingerGrabbed = false;
|
||||
|
||||
for (int i = 0; i < Constants.NUM_FINGERS; i++)
|
||||
{
|
||||
HandFinger finger = (HandFinger)i;
|
||||
if (fingers[finger] == FingerRequirement.Required)
|
||||
{
|
||||
if (!fingerAPI.GetFingerIsGrabbing(finger))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fingerAPI.GetFingerIsGrabbingChanged(finger, true))
|
||||
{
|
||||
aFingerGrabbed = true;
|
||||
}
|
||||
}
|
||||
else if (selectsWithOptionals
|
||||
&& fingers[finger] == FingerRequirement.Optional)
|
||||
{
|
||||
if (fingerAPI.GetFingerIsGrabbingChanged(finger, true))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return aFingerGrabbed;
|
||||
}
|
||||
|
||||
private bool IsHandUnselectFingersChanged(in GrabbingRule fingers, IFingerAPI fingerAPI)
|
||||
{
|
||||
bool isAnyFingerGrabbing = false;
|
||||
bool aFingerUngrabbed = false;
|
||||
bool selectsWithOptionals = fingers.SelectsWithOptionals;
|
||||
for (int i = 0; i < Constants.NUM_FINGERS; i++)
|
||||
{
|
||||
HandFinger finger = (HandFinger)i;
|
||||
if (fingers[finger] == FingerRequirement.Ignored)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
isAnyFingerGrabbing |= fingerAPI.GetFingerIsGrabbing(finger);
|
||||
if (fingers[finger] == FingerRequirement.Required)
|
||||
{
|
||||
if (fingerAPI.GetFingerIsGrabbingChanged(finger, false))
|
||||
{
|
||||
aFingerUngrabbed = true;
|
||||
if (fingers.UnselectMode == FingerUnselectMode.AnyReleased)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fingers[finger] == FingerRequirement.Optional)
|
||||
{
|
||||
if (fingerAPI.GetFingerIsGrabbingChanged(finger, false))
|
||||
{
|
||||
aFingerUngrabbed = true;
|
||||
if (fingers.UnselectMode == FingerUnselectMode.AnyReleased
|
||||
&& selectsWithOptionals)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !isAnyFingerGrabbing && aFingerUngrabbed;
|
||||
}
|
||||
|
||||
public Vector3 GetPinchCenter()
|
||||
{
|
||||
return WristOffsetToWorldPoint(_fingerPinchAPI.GetCenterOffset());
|
||||
}
|
||||
|
||||
public Vector3 GetPalmCenter()
|
||||
{
|
||||
return WristOffsetToWorldPoint(_fingerPalmAPI.GetCenterOffset());
|
||||
}
|
||||
|
||||
private Vector3 WristOffsetToWorldPoint(Vector3 offset)
|
||||
{
|
||||
if (!Hand.GetJointPose(HandJointId.HandWristRoot, out Pose wristPose))
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
return wristPose.position + wristPose.rotation * offset;
|
||||
}
|
||||
|
||||
public float GetHandPinchStrength(in GrabbingRule fingers,
|
||||
bool includePinching = true)
|
||||
{
|
||||
return GetHandStrength(fingers, includePinching, _fingerPinchAPI);
|
||||
}
|
||||
|
||||
public float GetHandPalmStrength(in GrabbingRule fingers,
|
||||
bool includeGrabbing = true)
|
||||
{
|
||||
return GetHandStrength(fingers, includeGrabbing, _fingerPalmAPI);
|
||||
}
|
||||
|
||||
public float GetFingerPinchStrength(HandFinger finger)
|
||||
{
|
||||
return _fingerPinchAPI.GetFingerGrabStrength(finger);
|
||||
}
|
||||
|
||||
public float GetFingerPalmStrength(HandFinger finger)
|
||||
{
|
||||
return _fingerPalmAPI.GetFingerGrabStrength(finger);
|
||||
}
|
||||
|
||||
private float GetHandStrength(in GrabbingRule fingers,
|
||||
bool includeGrabbing, IFingerAPI fingerAPI)
|
||||
{
|
||||
float requiredMin = 1.0f;
|
||||
float optionalMax = 0f;
|
||||
for (int i = 0; i < Constants.NUM_FINGERS; i++)
|
||||
{
|
||||
HandFinger finger = (HandFinger)i;
|
||||
if (!includeGrabbing && fingerAPI.GetFingerIsGrabbing((HandFinger)i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fingers[finger] == FingerRequirement.Ignored)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fingers[finger] == FingerRequirement.Optional)
|
||||
{
|
||||
optionalMax = Mathf.Max(optionalMax, fingerAPI.GetFingerGrabStrength((HandFinger)i));
|
||||
}
|
||||
|
||||
if (fingers[finger] == FingerRequirement.Required)
|
||||
{
|
||||
requiredMin = Mathf.Min(requiredMin, fingerAPI.GetFingerGrabStrength((HandFinger)i));
|
||||
}
|
||||
|
||||
}
|
||||
return Mathf.Min(requiredMin, optionalMax);
|
||||
}
|
||||
|
||||
#region Inject
|
||||
|
||||
public void InjectAllHandGrabAPI(IHand hand)
|
||||
{
|
||||
InjectHand(hand);
|
||||
}
|
||||
|
||||
public void InjectHand(IHand hand)
|
||||
{
|
||||
_hand = hand as MonoBehaviour;
|
||||
Hand = hand;
|
||||
}
|
||||
|
||||
public void InjectOptionalFingerPinchAPI(IFingerAPI fingerPinchAPI)
|
||||
{
|
||||
_fingerPinchAPI = fingerPinchAPI;
|
||||
}
|
||||
|
||||
public void InjectOptionalFingerGrabAPI(IFingerAPI fingerGrabAPI)
|
||||
{
|
||||
_fingerPalmAPI = fingerGrabAPI;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae43f25c06eb2d9408a201216b4c3ed7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
26
Assets/Oculus/Interaction/Runtime/Scripts/Grab/IFingerAPI.cs
Normal file
26
Assets/Oculus/Interaction/Runtime/Scripts/Grab/IFingerAPI.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
/************************************************************************************
|
||||
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.Input;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.GrabAPI
|
||||
{
|
||||
public interface IFingerAPI
|
||||
{
|
||||
bool GetFingerIsGrabbing(HandFinger finger);
|
||||
bool GetFingerIsGrabbingChanged(HandFinger finger, bool targetPinchState);
|
||||
float GetFingerGrabStrength(HandFinger finger);
|
||||
Vector3 GetCenterOffset();
|
||||
void Update(IHand hand);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 629a079b5a23e404faee62377bf2620d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user