/* * 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 } }