/* * 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 { /// /// A serializable list of s, implicitly all associated with a single /// transform. /// /// /// Each TransformFeatureConfig describes only one aspect () of a transform, /// meaning multiple can be applicable at the same time; for example, the "stop" hand gesture must satisfy /// both and . A /// TransformFeatureConfigList can thus be thought of as a list of requirements, all of which must be /// satisfied in order for the transform to be acceptable for recognition. /// [Serializable] public class TransformFeatureConfigList { [SerializeField] private List _values; /// /// The list of s which must all be satisfied in order for the /// associated transform to be considered acceptable for recognition. /// public List Values => _values; /// /// Factory for TransformFeatureConfigLists, allowing them to be constructed from runtime-generated /// configurations. /// /// The s constituent to this list public static TransformFeatureConfigList Create(List values) { TransformFeatureConfigList list = new(); list._values = values; return list; } } /// /// Specializes (which simply stores information related to the /// state of a feature) for s. This is used by /// , among others, to assess whether a transform is acceptably /// posed for recognition. /// [Serializable] public class TransformFeatureConfig : FeatureConfigBase { } /// /// Used in hand pose detection (often as part of a to get the current state of the /// hand's Transforms and compare it to the required states. The "Transform states" in question broadly /// pertain to the hand's orientation in user-relative terms; see for details. /// If the current state of the hand transforms meets the specified requirements, is true. /// public class TransformRecognizerActiveState : MonoBehaviour, IActiveState { /// /// The hand to read for transform state data. /// [SerializeField, Interface(typeof(IHand))] private UnityEngine.Object _hand; /// /// The to be observed. While this hand adopts a pose which meets the requirements, /// will be true. /// public IHand Hand { get; private set; } /// /// An , which provides the current state of the tracked hand's transforms. /// [SerializeField, Interface(typeof(ITransformFeatureStateProvider))] private UnityEngine.Object _transformFeatureStateProvider; protected ITransformFeatureStateProvider TransformFeatureStateProvider; /// /// A list of required transforms that the tracked hand must match for the pose to become active (assuming all shapes are also active). /// Each transform is an orientation and a boolean (ex. PalmTowardsFace is True.) /// [SerializeField] private TransformFeatureConfigList _transformFeatureConfigs; /// /// Influences state transitions computed via . It becomes active whenever all of the listed transform states are active. /// State provider uses this to determine the state of features during real time, so edit at runtime at your own risk. /// [SerializeField] [Tooltip("State provider uses this to determine the state of features during real time, so" + " edit at runtime at your own risk.")] private TransformConfig _transformConfig; /// /// The list of s which must be satisfied for recognition by this TransformRecognizerActiveState. /// /// /// For an overview of the role of this list in shape recognition, see the remarks on /// . /// public IReadOnlyList FeatureConfigs => _transformFeatureConfigs.Values; /// /// The transform config used in conjunction with an and data from the /// to calculate whether or not this recognizer should be . /// public TransformConfig TransformConfig => _transformConfig; protected bool _started = false; protected virtual void Awake() { Hand = _hand as IHand; TransformFeatureStateProvider = _transformFeatureStateProvider as ITransformFeatureStateProvider; } protected virtual void Start() { this.BeginStart(ref _started); this.AssertField(Hand, nameof(Hand)); this.AssertField(TransformFeatureStateProvider, nameof(TransformFeatureStateProvider)); this.AssertField(_transformFeatureConfigs, nameof(_transformFeatureConfigs)); this.AssertField(_transformConfig, nameof(_transformConfig)); _transformConfig.InstanceId = GetInstanceID(); this.EndStart(ref _started); } protected virtual void OnEnable() { if (_started) { TransformFeatureStateProvider.RegisterConfig(_transformConfig); // Warm up the proactive evaluation InitStateProvider(); } } protected virtual void OnDisable() { if (_started) { TransformFeatureStateProvider.UnRegisterConfig(_transformConfig); } } private void InitStateProvider() { foreach (var featureConfig in FeatureConfigs) { TransformFeatureStateProvider.GetCurrentState(_transformConfig, featureConfig.Feature, out _); } } /// /// Retrieves the feature vector for the given inputs, invoking the internal 's /// /// method with the and the provided arguments. /// /// /// A "feature vector" in this case is simply a Vector3 whose value should be interpreted in some specific way depending on which /// . This is an internal API which you should not invoke directly in typical usage. /// /// The for which to retrieve the vector. /// A boolean indicating whether the feature is being requested for a hand or for a controller. /// Output parameter to be populated with the requested feature vector. /// Output parameter to be populated with the wrist position to which the feature vector is related. public void GetFeatureVectorAndWristPos(TransformFeature feature, bool isHandVector, ref Vector3? featureVec, ref Vector3? wristPos) { TransformFeatureStateProvider.GetFeatureVectorAndWristPos( TransformConfig, feature, isHandVector, ref featureVec, ref wristPos); } /// /// Implements , in this case indicating whether the monitored transform currently /// satisfies the recognition conditions specified in the and . /// public bool Active { get { if (!isActiveAndEnabled) { return false; } foreach (var featureConfig in FeatureConfigs) { if (!TransformFeatureStateProvider.IsStateActive( _transformConfig, featureConfig.Feature, featureConfig.Mode, featureConfig.State)) { return false; } } return true; } } #region Inject /// /// Sets all required dependencies for a dynamically instantiated TransformRecognizerActiveState. This is a convenience /// method which wraps invocations of , /// , /// m and . /// This method exists to support Interaction SDK's dependency injection pattern and is not needed for typical Unity Editor-based /// usage. /// public void InjectAllTransformRecognizerActiveState(IHand hand, ITransformFeatureStateProvider transformFeatureStateProvider, TransformFeatureConfigList transformFeatureList, TransformConfig transformConfig) { InjectHand(hand); InjectTransformFeatureStateProvider(transformFeatureStateProvider); InjectTransformFeatureList(transformFeatureList); InjectTransformConfig(transformConfig); } /// /// Sets an as the for a dynamically instantiated /// TransformRecognizerActiveState. This method exists to support Interaction SDK's dependency injection pattern and is not needed for /// typical Unity Editor-based usage. /// public void InjectHand(IHand hand) { _hand = hand as UnityEngine.Object; Hand = hand; } /// /// Sets an as the feature state provider (which assesses whether or not the monitored /// hand's transforms meet the requirements for recognition) for a dynamically instantiated /// TransformRecognizerActiveState. This method exists to support Interaction SDK's dependency injection pattern and is not needed for /// typical Unity Editor-based usage. /// public void InjectTransformFeatureStateProvider(ITransformFeatureStateProvider transformFeatureStateProvider) { TransformFeatureStateProvider = transformFeatureStateProvider; _transformFeatureStateProvider = transformFeatureStateProvider as UnityEngine.Object; } /// /// Sets a as the for a dynamically instantiated /// TransformRecognizerActiveState. This method exists to support Interaction SDK's dependency injection pattern and is not needed for /// typical Unity Editor-based usage. /// public void InjectTransformFeatureList(TransformFeatureConfigList transformFeatureList) { _transformFeatureConfigs = transformFeatureList; } /// /// Sets a as the for a dynamically instantiated /// TransformRecognizerActiveState. This method exists to support Interaction SDK's dependency injection pattern and is not needed for /// typical Unity Editor-based usage. /// public void InjectTransformConfig(TransformConfig transformConfig) { _transformConfig = transformConfig; } #endregion } }