/* * 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.Grab; using Oculus.Interaction.HandGrab; using Oculus.Interaction.Input; using UnityEngine; namespace Oculus.Interaction { public class GrabStrengthIndicator : MonoBehaviour { [SerializeField, Interface(typeof(IHandGrabInteractor), typeof(IInteractor))] private UnityEngine.Object _handGrabInteractor; private IHandGrabInteractor HandGrab { get; set; } private IInteractor Interactor { get; set; } [SerializeField] private MaterialPropertyBlockEditor _handMaterialPropertyBlockEditor; [SerializeField] private float _glowLerpSpeed = 2f; [SerializeField] private float _glowColorLerpSpeed = 2f; [SerializeField] private Color _fingerGlowColorWithInteractable; [SerializeField] private Color _fingerGlowColorWithNoInteractable; [SerializeField] private Color _fingerGlowColorHover; #region public properties public float GlowLerpSpeed { get { return _glowLerpSpeed; } set { _glowLerpSpeed = value; } } public float GlowColorLerpSpeed { get { return _glowColorLerpSpeed; } set { _glowColorLerpSpeed = value; } } public Color FingerGlowColorWithInteractable { get { return _fingerGlowColorWithInteractable; } set { _fingerGlowColorWithInteractable = value; } } public Color FingerGlowColorWithNoInteractable { get { return _fingerGlowColorWithNoInteractable; } set { _fingerGlowColorWithNoInteractable = value; } } public Color FingerGlowColorHover { get { return _fingerGlowColorHover; } set { _fingerGlowColorHover = value; } } #endregion private readonly int[] _handShaderGlowPropertyIds = new int[] { Shader.PropertyToID("_ThumbGlowValue"), Shader.PropertyToID("_IndexGlowValue"), Shader.PropertyToID("_MiddleGlowValue"), Shader.PropertyToID("_RingGlowValue"), Shader.PropertyToID("_PinkyGlowValue"), }; private readonly int _fingerGlowColorPropertyId = Shader.PropertyToID("_FingerGlowColor"); private Color _currentGlowColor; protected bool _started = false; private void Awake() { HandGrab = _handGrabInteractor as IHandGrabInteractor; Interactor = _handGrabInteractor as IInteractor; } protected virtual void Start() { this.BeginStart(ref _started); this.AssertField(_handMaterialPropertyBlockEditor, nameof(_handMaterialPropertyBlockEditor)); this.AssertField(HandGrab, nameof(HandGrab)); this.AssertField(Interactor, nameof(Interactor)); this.EndStart(ref _started); } protected virtual void OnEnable() { if (_started) { Interactor.WhenPostprocessed += UpdateVisual; _currentGlowColor = _fingerGlowColorWithNoInteractable; } } protected virtual void OnDisable() { if (_started) { Interactor.WhenPostprocessed -= UpdateVisual; } } private void UpdateVisual() { bool isSelecting = Interactor.State == InteractorState.Select; bool isSelectingInteractable = Interactor.HasSelectedInteractable; bool hasHoverTarget = Interactor.HasCandidate; Color desiredGlowColor = _fingerGlowColorHover; if (isSelecting) { desiredGlowColor = isSelectingInteractable ? _fingerGlowColorWithInteractable : _fingerGlowColorWithNoInteractable; } _currentGlowColor = Color.Lerp(_currentGlowColor, desiredGlowColor, Time.deltaTime * _glowColorLerpSpeed); _handMaterialPropertyBlockEditor.MaterialPropertyBlock.SetColor(_fingerGlowColorPropertyId, _currentGlowColor); for (int i = 0; i < Constants.NUM_FINGERS; ++i) { if ((isSelecting && !isSelectingInteractable) || (!isSelecting && !hasHoverTarget)) { UpdateGlowValue(i, 0f); continue; } float glowValue = 0f; HandFinger finger = (HandFinger)i; if ((HandGrab.SupportedGrabTypes & GrabTypeFlags.Pinch) != 0 && HandGrab.TargetInteractable != null && (HandGrab.TargetInteractable.SupportedGrabTypes & GrabTypeFlags.Pinch) != 0 && HandGrab.TargetInteractable.PinchGrabRules[finger] != GrabAPI.FingerRequirement.Ignored) { glowValue = Mathf.Max(glowValue, HandGrab.HandGrabApi.GetFingerPinchStrength(finger)); } if ((HandGrab.SupportedGrabTypes & GrabTypeFlags.Palm) != 0 && HandGrab.TargetInteractable != null && (HandGrab.TargetInteractable.SupportedGrabTypes & GrabTypeFlags.Palm) != 0 && HandGrab.TargetInteractable.PalmGrabRules[finger] != GrabAPI.FingerRequirement.Ignored) { glowValue = Mathf.Max(glowValue, HandGrab.HandGrabApi.GetFingerPalmStrength(finger)); } UpdateGlowValue(i, glowValue); } _handMaterialPropertyBlockEditor.UpdateMaterialPropertyBlock(); } private void UpdateGlowValue(int fingerIndex, float glowValue) { float currentGlowValue = _handMaterialPropertyBlockEditor.MaterialPropertyBlock.GetFloat(_handShaderGlowPropertyIds[fingerIndex]); float newGlowValue = Mathf.MoveTowards(currentGlowValue, glowValue, _glowLerpSpeed * Time.deltaTime); _handMaterialPropertyBlockEditor.MaterialPropertyBlock.SetFloat(_handShaderGlowPropertyIds[fingerIndex], newGlowValue); } #region Inject public void InjectAllGrabStrengthIndicator(IHandGrabInteractor handGrabInteractor, MaterialPropertyBlockEditor handMaterialPropertyBlockEditor) { InjectHandGrab(handGrabInteractor); InjectHandMaterialPropertyBlockEditor(handMaterialPropertyBlockEditor); } public void InjectHandGrab(IHandGrabInteractor handGrab) { _handGrabInteractor = handGrab as UnityEngine.Object; HandGrab = handGrab; Interactor = handGrab as IInteractor; } public void InjectHandMaterialPropertyBlockEditor(MaterialPropertyBlockEditor handMaterialPropertyBlockEditor) { _handMaterialPropertyBlockEditor = handMaterialPropertyBlockEditor; } #endregion } }