123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- //======= Copyright (c) Valve Corporation, All rights reserved. ===============
- //
- // Purpose: This object will get hover events and can be attached to the hands
- //
- //=============================================================================
- using UnityEngine;
- using UnityEngine.Events;
- using System.Collections;
- using System.Collections.Generic;
- namespace Valve.VR.InteractionSystem
- {
- //-------------------------------------------------------------------------
- public class Interactable : MonoBehaviour
- {
- [Tooltip("Activates an action set on attach and deactivates on detach")]
- public SteamVR_ActionSet activateActionSetOnAttach;
- [Tooltip("Hide the whole hand on attachment and show on detach")]
- public bool hideHandOnAttach = true;
- [Tooltip("Hide the skeleton part of the hand on attachment and show on detach")]
- public bool hideSkeletonOnAttach = false;
- [Tooltip("Hide the controller part of the hand on attachment and show on detach")]
- public bool hideControllerOnAttach = false;
- [Tooltip("The integer in the animator to trigger on pickup. 0 for none")]
- public int handAnimationOnPickup = 0;
- [Tooltip("The range of motion to set on the skeleton. None for no change.")]
- public SkeletalMotionRangeChange setRangeOfMotionOnPickup = SkeletalMotionRangeChange.None;
- public delegate void OnAttachedToHandDelegate(Hand hand);
- public delegate void OnDetachedFromHandDelegate(Hand hand);
- public event OnAttachedToHandDelegate onAttachedToHand;
- public event OnDetachedFromHandDelegate onDetachedFromHand;
- [Tooltip("Specify whether you want to snap to the hand's object attachment point, or just the raw hand")]
- public bool useHandObjectAttachmentPoint = true;
- public bool attachEaseIn = false;
- [HideInInspector]
- public AnimationCurve snapAttachEaseInCurve = AnimationCurve.EaseInOut(0.0f, 0.0f, 1.0f, 1.0f);
- public float snapAttachEaseInTime = 0.15f;
- public bool snapAttachEaseInCompleted = false;
- // [Tooltip("The skeleton pose to apply when grabbing. Can only set this or handFollowTransform.")]
- [HideInInspector]
- public SteamVR_Skeleton_Poser skeletonPoser;
- [Tooltip("Should the rendered hand lock on to and follow the object")]
- public bool handFollowTransform= true;
- [Tooltip("Set whether or not you want this interactible to highlight when hovering over it")]
- public bool highlightOnHover = true;
- protected MeshRenderer[] highlightRenderers;
- protected MeshRenderer[] existingRenderers;
- protected GameObject highlightHolder;
- protected SkinnedMeshRenderer[] highlightSkinnedRenderers;
- protected SkinnedMeshRenderer[] existingSkinnedRenderers;
- protected static Material highlightMat;
- [Tooltip("An array of child gameObjects to not render a highlight for. Things like transparent parts, vfx, etc.")]
- public GameObject[] hideHighlight;
- [Tooltip("Higher is better")]
- public int hoverPriority = 0;
- [System.NonSerialized]
- public Hand attachedToHand;
- [System.NonSerialized]
- public List<Hand> hoveringHands = new List<Hand>();
- public Hand hoveringHand
- {
- get
- {
- if (hoveringHands.Count > 0)
- return hoveringHands[0];
- return null;
- }
- }
- public bool isDestroying { get; protected set; }
- public bool isHovering { get; protected set; }
- public bool wasHovering { get; protected set; }
- private void Awake()
- {
- skeletonPoser = GetComponent<SteamVR_Skeleton_Poser>();
- }
- protected virtual void Start()
- {
- if (highlightMat == null)
- #if UNITY_URP
- highlightMat = (Material)Resources.Load("SteamVR_HoverHighlight_URP", typeof(Material));
- #else
- highlightMat = (Material)Resources.Load("SteamVR_HoverHighlight", typeof(Material));
- #endif
- if (highlightMat == null)
- Debug.LogError("<b>[SteamVR Interaction]</b> Hover Highlight Material is missing. Please create a material named 'SteamVR_HoverHighlight' and place it in a Resources folder", this);
- if (skeletonPoser != null)
- {
- if (useHandObjectAttachmentPoint)
- {
- //Debug.LogWarning("<b>[SteamVR Interaction]</b> SkeletonPose and useHandObjectAttachmentPoint both set at the same time. Ignoring useHandObjectAttachmentPoint.");
- useHandObjectAttachmentPoint = false;
- }
- }
- }
- protected virtual bool ShouldIgnoreHighlight(Component component)
- {
- return ShouldIgnore(component.gameObject);
- }
- protected virtual bool ShouldIgnore(GameObject check)
- {
- for (int ignoreIndex = 0; ignoreIndex < hideHighlight.Length; ignoreIndex++)
- {
- if (check == hideHighlight[ignoreIndex])
- return true;
- }
- return false;
- }
- protected virtual void CreateHighlightRenderers()
- {
- existingSkinnedRenderers = this.GetComponentsInChildren<SkinnedMeshRenderer>(true);
- highlightHolder = new GameObject("Highlighter");
- highlightSkinnedRenderers = new SkinnedMeshRenderer[existingSkinnedRenderers.Length];
- for (int skinnedIndex = 0; skinnedIndex < existingSkinnedRenderers.Length; skinnedIndex++)
- {
- SkinnedMeshRenderer existingSkinned = existingSkinnedRenderers[skinnedIndex];
- if (ShouldIgnoreHighlight(existingSkinned))
- continue;
- GameObject newSkinnedHolder = new GameObject("SkinnedHolder");
- newSkinnedHolder.transform.parent = highlightHolder.transform;
- SkinnedMeshRenderer newSkinned = newSkinnedHolder.AddComponent<SkinnedMeshRenderer>();
- Material[] materials = new Material[existingSkinned.sharedMaterials.Length];
- for (int materialIndex = 0; materialIndex < materials.Length; materialIndex++)
- {
- materials[materialIndex] = highlightMat;
- }
- newSkinned.sharedMaterials = materials;
- newSkinned.sharedMesh = existingSkinned.sharedMesh;
- newSkinned.rootBone = existingSkinned.rootBone;
- newSkinned.updateWhenOffscreen = existingSkinned.updateWhenOffscreen;
- newSkinned.bones = existingSkinned.bones;
- highlightSkinnedRenderers[skinnedIndex] = newSkinned;
- }
- MeshFilter[] existingFilters = this.GetComponentsInChildren<MeshFilter>(true);
- existingRenderers = new MeshRenderer[existingFilters.Length];
- highlightRenderers = new MeshRenderer[existingFilters.Length];
- for (int filterIndex = 0; filterIndex < existingFilters.Length; filterIndex++)
- {
- MeshFilter existingFilter = existingFilters[filterIndex];
- MeshRenderer existingRenderer = existingFilter.GetComponent<MeshRenderer>();
- if (existingFilter == null || existingRenderer == null || ShouldIgnoreHighlight(existingFilter))
- continue;
- GameObject newFilterHolder = new GameObject("FilterHolder");
- newFilterHolder.transform.parent = highlightHolder.transform;
- MeshFilter newFilter = newFilterHolder.AddComponent<MeshFilter>();
- newFilter.sharedMesh = existingFilter.sharedMesh;
- MeshRenderer newRenderer = newFilterHolder.AddComponent<MeshRenderer>();
- Material[] materials = new Material[existingRenderer.sharedMaterials.Length];
- for (int materialIndex = 0; materialIndex < materials.Length; materialIndex++)
- {
- materials[materialIndex] = highlightMat;
- }
- newRenderer.sharedMaterials = materials;
- highlightRenderers[filterIndex] = newRenderer;
- existingRenderers[filterIndex] = existingRenderer;
- }
- }
- protected virtual void UpdateHighlightRenderers()
- {
- if (highlightHolder == null)
- return;
- for (int skinnedIndex = 0; skinnedIndex < existingSkinnedRenderers.Length; skinnedIndex++)
- {
- SkinnedMeshRenderer existingSkinned = existingSkinnedRenderers[skinnedIndex];
- SkinnedMeshRenderer highlightSkinned = highlightSkinnedRenderers[skinnedIndex];
- if (existingSkinned != null && highlightSkinned != null && attachedToHand == false)
- {
- highlightSkinned.transform.position = existingSkinned.transform.position;
- highlightSkinned.transform.rotation = existingSkinned.transform.rotation;
- highlightSkinned.transform.localScale = existingSkinned.transform.lossyScale;
- highlightSkinned.localBounds = existingSkinned.localBounds;
- highlightSkinned.enabled = isHovering && existingSkinned.enabled && existingSkinned.gameObject.activeInHierarchy;
- int blendShapeCount = existingSkinned.sharedMesh.blendShapeCount;
- for (int blendShapeIndex = 0; blendShapeIndex < blendShapeCount; blendShapeIndex++)
- {
- highlightSkinned.SetBlendShapeWeight(blendShapeIndex, existingSkinned.GetBlendShapeWeight(blendShapeIndex));
- }
- }
- else if (highlightSkinned != null)
- highlightSkinned.enabled = false;
- }
- for (int rendererIndex = 0; rendererIndex < highlightRenderers.Length; rendererIndex++)
- {
- MeshRenderer existingRenderer = existingRenderers[rendererIndex];
- MeshRenderer highlightRenderer = highlightRenderers[rendererIndex];
- if (existingRenderer != null && highlightRenderer != null && attachedToHand == false)
- {
- highlightRenderer.transform.position = existingRenderer.transform.position;
- highlightRenderer.transform.rotation = existingRenderer.transform.rotation;
- highlightRenderer.transform.localScale = existingRenderer.transform.lossyScale;
- highlightRenderer.enabled = isHovering && existingRenderer.enabled && existingRenderer.gameObject.activeInHierarchy;
- }
- else if (highlightRenderer != null)
- highlightRenderer.enabled = false;
- }
- }
- /// <summary>
- /// Called when a Hand starts hovering over this object
- /// </summary>
- protected virtual void OnHandHoverBegin(Hand hand)
- {
- wasHovering = isHovering;
- isHovering = true;
- hoveringHands.Add(hand);
- if (highlightOnHover == true && wasHovering == false)
- {
- CreateHighlightRenderers();
- UpdateHighlightRenderers();
- }
- }
- /// <summary>
- /// Called when a Hand stops hovering over this object
- /// </summary>
- protected virtual void OnHandHoverEnd(Hand hand)
- {
- wasHovering = isHovering;
- hoveringHands.Remove(hand);
- if (hoveringHands.Count == 0)
- {
- isHovering = false;
- if (highlightOnHover && highlightHolder != null)
- Destroy(highlightHolder);
- }
- }
- protected virtual void Update()
- {
- if (highlightOnHover)
- {
- UpdateHighlightRenderers();
- if (isHovering == false && highlightHolder != null)
- Destroy(highlightHolder);
- }
- }
- protected float blendToPoseTime = 0.1f;
- protected float releasePoseBlendTime = 0.2f;
- protected virtual void OnAttachedToHand(Hand hand)
- {
- if (activateActionSetOnAttach != null)
- activateActionSetOnAttach.Activate(hand.handType);
- if (onAttachedToHand != null)
- {
- onAttachedToHand.Invoke(hand);
- }
- if (skeletonPoser != null && hand.skeleton != null)
- {
- hand.skeleton.BlendToPoser(skeletonPoser, blendToPoseTime);
- }
- attachedToHand = hand;
- }
- protected virtual void OnDetachedFromHand(Hand hand)
- {
- if (activateActionSetOnAttach != null)
- {
- if (hand.otherHand == null || hand.otherHand.currentAttachedObjectInfo.HasValue == false ||
- (hand.otherHand.currentAttachedObjectInfo.Value.interactable != null &&
- hand.otherHand.currentAttachedObjectInfo.Value.interactable.activateActionSetOnAttach != this.activateActionSetOnAttach))
- {
- activateActionSetOnAttach.Deactivate(hand.handType);
- }
- }
- if (onDetachedFromHand != null)
- {
- onDetachedFromHand.Invoke(hand);
- }
- if (skeletonPoser != null)
- {
- if (hand.skeleton != null)
- hand.skeleton.BlendToSkeleton(releasePoseBlendTime);
- }
- attachedToHand = null;
- }
- protected virtual void OnDestroy()
- {
- isDestroying = true;
- if (attachedToHand != null)
- {
- attachedToHand.DetachObject(this.gameObject, false);
- attachedToHand.skeleton.BlendToSkeleton(0.1f);
- }
- if (highlightHolder != null)
- Destroy(highlightHolder);
- }
- protected virtual void OnDisable()
- {
- isDestroying = true;
- if (attachedToHand != null)
- {
- attachedToHand.ForceHoverUnlock();
- }
- if (highlightHolder != null)
- Destroy(highlightHolder);
- }
- }
- }
|