/* * 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 System.Linq; using TMPro; using UnityEngine; using UnityEngine.Assertions; namespace Oculus.Interaction.PoseDetection.Debug { public class HandShapeDebugVisual : MonoBehaviour { [SerializeField, Interface(typeof(IFingerFeatureStateProvider))] private UnityEngine.Object _fingerFeatureStateProvider; private IFingerFeatureStateProvider FingerFeatureStateProvider; [SerializeField] private ShapeRecognizerActiveState _shapeRecognizerActiveState; [SerializeField] private Renderer _target; [SerializeField] private Color _normalColor = Color.red; [SerializeField] private Color _activeColor = Color.green; [SerializeField] private GameObject _fingerFeatureDebugVisualPrefab; [SerializeField] private Transform _fingerFeatureParent; [SerializeField] private Vector3 _fingerSpacingVec = new Vector3(0.0f, -1.0f, 0.0f); [SerializeField] private Vector3 _fingerFeatureSpacingVec = new Vector3(1.0f, 0.0f, 0.0f); [SerializeField] private Vector3 _fingerFeatureDebugLocalScale = new Vector3(0.3f, 0.3f, 0.3f); [SerializeField] private TextMeshPro _targetText; private Material _material; private bool _lastActiveValue = false; protected virtual void Awake() { FingerFeatureStateProvider = _fingerFeatureStateProvider as IFingerFeatureStateProvider; this.AssertField(_shapeRecognizerActiveState, nameof(_shapeRecognizerActiveState)); this.AssertField(_target, nameof(_target)); this.AssertField(_fingerFeatureDebugVisualPrefab, nameof(_fingerFeatureDebugVisualPrefab)); this.AssertField(_targetText, nameof(_targetText)); _material = _target.material; _material.color = _lastActiveValue ? _activeColor : _normalColor; if (_fingerFeatureParent == null) { _fingerFeatureParent = transform; } } protected virtual void Start() { this.AssertField(FingerFeatureStateProvider, nameof(FingerFeatureStateProvider)); Vector3 fingerOffset = Vector3.zero; var statesByFinger = AllFeatureStates() .GroupBy(s => s.Item1) .Select(group => new { HandFinger = group.Key, FingerFeatures = group.SelectMany(item => item.Item2) }); foreach (var g in statesByFinger) { Vector3 fingerDebugFeatureTotalDisp = fingerOffset; foreach (var config in g.FingerFeatures) { var fingerFeatureDebugVisInst = Instantiate(_fingerFeatureDebugVisualPrefab, _fingerFeatureParent); var debugVisComp = fingerFeatureDebugVisInst.GetComponent(); debugVisComp.Initialize(g.HandFinger, config, FingerFeatureStateProvider); var debugVisTransform = debugVisComp.transform; debugVisTransform.localScale = _fingerFeatureDebugLocalScale; debugVisTransform.localRotation = Quaternion.identity; debugVisTransform.localPosition = fingerDebugFeatureTotalDisp; fingerDebugFeatureTotalDisp += _fingerFeatureSpacingVec; } fingerOffset += _fingerSpacingVec; } string shapeNames = ""; foreach (ShapeRecognizer shapeRecognizer in _shapeRecognizerActiveState.Shapes) { shapeNames += shapeRecognizer.ShapeName; } _targetText.text = $"{_shapeRecognizerActiveState.Handedness} Hand: {shapeNames} "; } private IEnumerable>> AllFeatureStates() { foreach (ShapeRecognizer shapeRecognizer in _shapeRecognizerActiveState.Shapes) { foreach (var handFingerConfigs in shapeRecognizer.GetFingerFeatureConfigs()) { yield return handFingerConfigs; } } } protected virtual void OnDestroy() { Destroy(_material); } protected virtual void Update() { bool isActive = _shapeRecognizerActiveState.Active; if (_lastActiveValue != isActive) { _material.color = isActive ? _activeColor : _normalColor; _lastActiveValue = isActive; } } } }