/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* Licensed under the Oculus SDK License Agreement (the "License");
* you may not use the Oculus SDK except in compliance with the License,
* which is provided at the time of installation or download, or which
* otherwise accompanies this software in either electronic or hard copy form.
*
* You may obtain a copy of the License at
*
* https://developer.oculus.com/licenses/oculussdk/
*
* Unless required by applicable law or agreed to in writing, the Oculus SDK
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using Oculus.Interaction.Input;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Oculus.Interaction.PoseDetection
{
///
/// Asset characterizing a "hand shape" which can be recognized.
///
///
/// Despite its name, this type does not actively recognize anything but merely stores the data, in the form
/// of per-finger s, which is needed for a
/// to perform the calculations needed to determine whether the
/// described hand shape has been recognized or not. In this sense, ShapeRecognizer might be thought of as
/// a definition or descriptor of a hand shape.
///
[CreateAssetMenu(menuName = "Meta/Interaction/SDK/Pose Detection/Shape")]
public class ShapeRecognizer : ScriptableObject
{
///
/// A serializable list of s, implicitly all associated with a single
/// finger.
///
///
/// Each FingerFeatureConfig describes only one aspect () of a finger, meaning
/// multiple can be applicable at the same time; for example, the index finger in the "scissors" hand
/// shape (as in "rock, paper, scissors") must have both low and high
/// . A FingerFeatureConfigList can thus be thought of as a list of
/// requirements, all of which must be satisfied in order for a finger's shape to be acceptable for
/// recognition.
///
[Serializable]
public class FingerFeatureConfigList
{
[SerializeField]
private List _value;
///
/// The list of s which collectively describe the requirements for a
/// specific finger in a .
///
///
/// For an overview of the role of this list in shape recognition, see the remarks on
/// .
///
public IReadOnlyList Value => _value;
///
/// Constructs a FingerFeatureConfigList with an empty list. Because that list
/// is the set of all requirements which must be met for a finger to be acceptable in a ShapeRecognizer,
/// an empty list indicates that there are no requirements and the finger is always acceptable.
///
public FingerFeatureConfigList() { }
///
/// Constructs a FingerFeatureConfigList with the provided to be assigned to
/// .
///
/// The list of required s
public FingerFeatureConfigList(List value)
{
_value = value;
}
}
///
/// Specializes (which simply stores information related to the
/// state of a feature) for s. This is used by
/// and other consumers of ShapeRecognizer to assess whether individual fingers are acceptably posed for
/// recognition.
///
[Serializable]
public class FingerFeatureConfig : FeatureConfigBase
{
}
[SerializeField]
private string _shapeName;
[SerializeField]
private FingerFeatureConfigList _thumbFeatureConfigs = new FingerFeatureConfigList();
[SerializeField]
private FingerFeatureConfigList _indexFeatureConfigs = new FingerFeatureConfigList();
[SerializeField]
private FingerFeatureConfigList _middleFeatureConfigs = new FingerFeatureConfigList();
[SerializeField]
private FingerFeatureConfigList _ringFeatureConfigs = new FingerFeatureConfigList();
[SerializeField]
private FingerFeatureConfigList _pinkyFeatureConfigs = new FingerFeatureConfigList();
///
/// The list of s which must be satisfied for the thumb to be acceptable
/// for recognition by this ShapeRecognizer.
///
///
/// For an overview of the role of this list in shape recognition, see the remarks on
/// .
///
public IReadOnlyList ThumbFeatureConfigs => _thumbFeatureConfigs.Value;
///
/// The list of s which must be satisfied for the index finger to be acceptable
/// for recognition by this ShapeRecognizer.
///
///
/// For an overview of the role of this list in shape recognition, see the remarks on
/// .
///
public IReadOnlyList IndexFeatureConfigs => _indexFeatureConfigs.Value;
///
/// The list of s which must be satisfied for the middle finger to be acceptable
/// for recognition by this ShapeRecognizer.
///
///
/// For an overview of the role of this list in shape recognition, see the remarks on
/// .
///
public IReadOnlyList MiddleFeatureConfigs => _middleFeatureConfigs.Value;
///
/// The list of s which must be satisfied for the ring finger to be acceptable
/// for recognition by this ShapeRecognizer.
///
///
/// For an overview of the role of this list in shape recognition, see the remarks on
/// .
///
public IReadOnlyList RingFeatureConfigs => _ringFeatureConfigs.Value;
///
/// The list of s which must be satisfied for the pinky finger to be acceptable
/// for recognition by this ShapeRecognizer.
///
///
/// For an overview of the role of this list in shape recognition, see the remarks on
/// .
///
public IReadOnlyList PinkyFeatureConfigs => _pinkyFeatureConfigs.Value;
///
/// The human-readable name assigned to this hand shape.
///
public string ShapeName => _shapeName;
///
/// Retrieves the list of s which must be satisfied for the provided
/// to be acceptable for recognition by this ShapeRecognizer. This is a
/// equivalent to calling //etc. for the
/// finger in question.
///
/// The finger for which to retrieve the list of required s.
/// The list of required s for .
public IReadOnlyList GetFingerFeatureConfigs(HandFinger finger)
{
switch (finger)
{
case HandFinger.Thumb:
return ThumbFeatureConfigs;
case HandFinger.Index:
return IndexFeatureConfigs;
case HandFinger.Middle:
return MiddleFeatureConfigs;
case HandFinger.Ring:
return RingFeatureConfigs;
case HandFinger.Pinky:
return PinkyFeatureConfigs;
default:
throw new ArgumentException("must be a HandFinger enum value",
nameof(finger));
}
}
///
/// Enumerates the required s for each finger in this ShapeRecognizer.
/// This is a convenience method equivalent to calling
/// for every finger in turn.
///
///
/// An iterator exposing, in turn, each finger and its associated s
/// as a tuple.
///
public IEnumerable>>
GetFingerFeatureConfigs()
{
for (var fingerIdx = 0; fingerIdx < Constants.NUM_FINGERS; ++fingerIdx)
{
HandFinger finger = (HandFinger)fingerIdx;
var configs = GetFingerFeatureConfigs(finger);
if (configs.Count == 0)
{
continue;
}
yield return new ValueTuple>(finger,
configs);
}
}
#region Inject
///
/// Sets the s for all fingers for a dynamically instantiated ShapeRecognizer. This method
/// exists to support Interaction SDK's dependency injection pattern and is not needed for typical Unity Editor-based
/// usage.
///
public void InjectAllShapeRecognizer(IDictionary fingerFeatureConfigs)
{
FingerFeatureConfigList ReadFeatureConfigs(HandFinger finger)
{
if (!fingerFeatureConfigs.TryGetValue(finger, out FingerFeatureConfig[] configs))
{
configs = Array.Empty();
}
return new FingerFeatureConfigList(new List(configs));
}
_thumbFeatureConfigs = ReadFeatureConfigs(HandFinger.Thumb);
_indexFeatureConfigs = ReadFeatureConfigs(HandFinger.Index);
_middleFeatureConfigs = ReadFeatureConfigs(HandFinger.Middle);
_ringFeatureConfigs = ReadFeatureConfigs(HandFinger.Ring);
_pinkyFeatureConfigs = ReadFeatureConfigs(HandFinger.Pinky);
}
///
/// Sets the s for the thumb for a dynamically instantiated ShapeRecognizer. This method
/// exists to support Interaction SDK's dependency injection pattern and is not needed for typical Unity Editor-based
/// usage.
///
public void InjectThumbFeatureConfigs(FingerFeatureConfig[] configs)
{
_thumbFeatureConfigs = new FingerFeatureConfigList(new List(configs));
}
///
/// Sets the s for the index finger for a dynamically instantiated ShapeRecognizer. This
/// method exists to support Interaction SDK's dependency injection pattern and is not needed for typical Unity Editor-based
/// usage.
///
public void InjectIndexFeatureConfigs(FingerFeatureConfig[] configs)
{
_indexFeatureConfigs = new FingerFeatureConfigList(new List(configs));
}
///
/// Sets the s for the middle finger for a dynamically instantiated ShapeRecognizer. This
/// method exists to support Interaction SDK's dependency injection pattern and is not needed for typical Unity Editor-based
/// usage.
///
public void InjectMiddleFeatureConfigs(FingerFeatureConfig[] configs)
{
_middleFeatureConfigs = new FingerFeatureConfigList(new List(configs));
}
///
/// Sets the s for the ring finger for a dynamically instantiated ShapeRecognizer. This
/// method exists to support Interaction SDK's dependency injection pattern and is not needed for typical Unity Editor-based
/// usage.
///
public void InjectRingFeatureConfigs(FingerFeatureConfig[] configs)
{
_ringFeatureConfigs = new FingerFeatureConfigList(new List(configs));
}
///
/// Sets the s for the pinky finger for a dynamically instantiated ShapeRecognizer. This
/// method exists to support Interaction SDK's dependency injection pattern and is not needed for typical Unity Editor-based
/// usage.
///
public void InjectPinkyFeatureConfigs(FingerFeatureConfig[] configs)
{
_pinkyFeatureConfigs = new FingerFeatureConfigList(new List(configs));
}
///
/// Sets the for a dynamically instantiated ShapeRecognizer. This method exists to support
/// Interaction SDK's dependency injection pattern and is not needed for typical Unity Editor-based usage.
///
public void InjectShapeName(string shapeName)
{
_shapeName = shapeName;
}
#endregion
}
}