123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686 |
- //======= Copyright (c) Valve Corporation, All rights reserved. ===============
- //
- // Purpose: The hands used by the player in the vr interaction system
- //
- //=============================================================================
- using UnityEngine;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using UnityEngine.Events;
- using System.Threading;
- namespace Valve.VR.InteractionSystem
- {
- //-------------------------------------------------------------------------
- // Links with an appropriate SteamVR controller and facilitates
- // interactions with objects in the virtual world.
- //-------------------------------------------------------------------------
- public class Hand : MonoBehaviour
- {
- // The flags used to determine how an object is attached to the hand.
- [Flags]
- public enum AttachmentFlags
- {
- SnapOnAttach = 1 << 0, // The object should snap to the position of the specified attachment point on the hand.
- DetachOthers = 1 << 1, // Other objects attached to this hand will be detached.
- DetachFromOtherHand = 1 << 2, // This object will be detached from the other hand.
- ParentToHand = 1 << 3, // The object will be parented to the hand.
- VelocityMovement = 1 << 4, // The object will attempt to move to match the position and rotation of the hand.
- TurnOnKinematic = 1 << 5, // The object will not respond to external physics.
- TurnOffGravity = 1 << 6, // The object will not respond to external physics.
- AllowSidegrade = 1 << 7, // The object is able to switch from a pinch grab to a grip grab. Decreases likelyhood of a good throw but also decreases likelyhood of accidental drop
- };
- public const AttachmentFlags defaultAttachmentFlags = AttachmentFlags.ParentToHand |
- AttachmentFlags.DetachOthers |
- AttachmentFlags.DetachFromOtherHand |
- AttachmentFlags.TurnOnKinematic |
- AttachmentFlags.SnapOnAttach;
- public Hand otherHand;
- public SteamVR_Input_Sources handType;
- public SteamVR_Behaviour_Pose trackedObject;
- public SteamVR_Action_Boolean grabPinchAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("GrabPinch");
- public SteamVR_Action_Boolean grabGripAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("GrabGrip");
- public SteamVR_Action_Vibration hapticAction = SteamVR_Input.GetAction<SteamVR_Action_Vibration>("Haptic");
- public SteamVR_Action_Boolean uiInteractAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("InteractUI");
- public bool useHoverSphere = true;
- public Transform hoverSphereTransform;
- public float hoverSphereRadius = 0.05f;
- public LayerMask hoverLayerMask = -1;
- public float hoverUpdateInterval = 0.1f;
- public bool useControllerHoverComponent = true;
- public string controllerHoverComponent = "tip";
- public float controllerHoverRadius = 0.075f;
- public bool useFingerJointHover = true;
- public SteamVR_Skeleton_JointIndexEnum fingerJointHover = SteamVR_Skeleton_JointIndexEnum.indexTip;
- public float fingerJointHoverRadius = 0.025f;
- [Tooltip("A transform on the hand to center attached objects on")]
- public Transform objectAttachmentPoint;
- public Camera noSteamVRFallbackCamera;
- public float noSteamVRFallbackMaxDistanceNoItem = 10.0f;
- public float noSteamVRFallbackMaxDistanceWithItem = 0.5f;
- private float noSteamVRFallbackInteractorDistance = -1.0f;
- public GameObject renderModelPrefab;
- [HideInInspector]
- public List<RenderModel> renderModels = new List<RenderModel>();
- [HideInInspector]
- public RenderModel mainRenderModel;
- [HideInInspector]
- public RenderModel hoverhighlightRenderModel;
- public bool showDebugText = false;
- public bool spewDebugText = false;
- public bool showDebugInteractables = false;
- public struct AttachedObject
- {
- public GameObject attachedObject;
- public Interactable interactable;
- public Rigidbody attachedRigidbody;
- public CollisionDetectionMode collisionDetectionMode;
- public bool attachedRigidbodyWasKinematic;
- public bool attachedRigidbodyUsedGravity;
- public GameObject originalParent;
- public bool isParentedToHand;
- public GrabTypes grabbedWithType;
- public AttachmentFlags attachmentFlags;
- public Vector3 initialPositionalOffset;
- public Quaternion initialRotationalOffset;
- public Transform attachedOffsetTransform;
- public Transform handAttachmentPointTransform;
- public Vector3 easeSourcePosition;
- public Quaternion easeSourceRotation;
- public float attachTime;
- public AllowTeleportWhileAttachedToHand allowTeleportWhileAttachedToHand;
- public bool HasAttachFlag(AttachmentFlags flag)
- {
- return (attachmentFlags & flag) == flag;
- }
- }
- private List<AttachedObject> attachedObjects = new List<AttachedObject>();
- public ReadOnlyCollection<AttachedObject> AttachedObjects
- {
- get { return attachedObjects.AsReadOnly(); }
- }
- public bool hoverLocked { get; private set; }
- private Interactable _hoveringInteractable;
- private TextMesh debugText;
- private int prevOverlappingColliders = 0;
- private const int ColliderArraySize = 32;
- private Collider[] overlappingColliders;
- private Player playerInstance;
- private GameObject applicationLostFocusObject;
- private SteamVR_Events.Action inputFocusAction;
- public bool isActive
- {
- get
- {
- if (trackedObject != null)
- return trackedObject.isActive;
- return this.gameObject.activeInHierarchy;
- }
- }
- public bool isPoseValid
- {
- get
- {
- return trackedObject.isValid;
- }
- }
- //-------------------------------------------------
- // The Interactable object this Hand is currently hovering over
- //-------------------------------------------------
- public Interactable hoveringInteractable
- {
- get { return _hoveringInteractable; }
- set
- {
- if (_hoveringInteractable != value)
- {
- if (_hoveringInteractable != null)
- {
- if (spewDebugText)
- HandDebugLog("HoverEnd " + _hoveringInteractable.gameObject);
- _hoveringInteractable.SendMessage("OnHandHoverEnd", this, SendMessageOptions.DontRequireReceiver);
- //Note: The _hoveringInteractable can change after sending the OnHandHoverEnd message so we need to check it again before broadcasting this message
- if (_hoveringInteractable != null)
- {
- this.BroadcastMessage("OnParentHandHoverEnd", _hoveringInteractable, SendMessageOptions.DontRequireReceiver); // let objects attached to the hand know that a hover has ended
- }
- }
- _hoveringInteractable = value;
- if (_hoveringInteractable != null)
- {
- if (spewDebugText)
- HandDebugLog("HoverBegin " + _hoveringInteractable.gameObject);
- _hoveringInteractable.SendMessage("OnHandHoverBegin", this, SendMessageOptions.DontRequireReceiver);
- //Note: The _hoveringInteractable can change after sending the OnHandHoverBegin message so we need to check it again before broadcasting this message
- if (_hoveringInteractable != null)
- {
- this.BroadcastMessage("OnParentHandHoverBegin", _hoveringInteractable, SendMessageOptions.DontRequireReceiver); // let objects attached to the hand know that a hover has begun
- }
- }
- }
- }
- }
- //-------------------------------------------------
- // Active GameObject attached to this Hand
- //-------------------------------------------------
- public GameObject currentAttachedObject
- {
- get
- {
- CleanUpAttachedObjectStack();
- if (attachedObjects.Count > 0)
- {
- return attachedObjects[attachedObjects.Count - 1].attachedObject;
- }
- return null;
- }
- }
- public AttachedObject? currentAttachedObjectInfo
- {
- get
- {
- CleanUpAttachedObjectStack();
- if (attachedObjects.Count > 0)
- {
- return attachedObjects[attachedObjects.Count - 1];
- }
- return null;
- }
- }
- public AllowTeleportWhileAttachedToHand currentAttachedTeleportManager
- {
- get
- {
- if (currentAttachedObjectInfo.HasValue)
- return currentAttachedObjectInfo.Value.allowTeleportWhileAttachedToHand;
- return null;
- }
- }
- public SteamVR_Behaviour_Skeleton skeleton
- {
- get
- {
- if (mainRenderModel != null)
- return mainRenderModel.GetSkeleton();
- return null;
- }
- }
- public void ShowController(bool permanent = false)
- {
- if (mainRenderModel != null)
- mainRenderModel.SetControllerVisibility(true, permanent);
- if (hoverhighlightRenderModel != null)
- hoverhighlightRenderModel.SetControllerVisibility(true, permanent);
- }
- public void HideController(bool permanent = false)
- {
- if (mainRenderModel != null)
- mainRenderModel.SetControllerVisibility(false, permanent);
- if (hoverhighlightRenderModel != null)
- hoverhighlightRenderModel.SetControllerVisibility(false, permanent);
- }
- public void ShowSkeleton(bool permanent = false)
- {
- if (mainRenderModel != null)
- mainRenderModel.SetHandVisibility(true, permanent);
- if (hoverhighlightRenderModel != null)
- hoverhighlightRenderModel.SetHandVisibility(true, permanent);
- }
- public void HideSkeleton(bool permanent = false)
- {
- if (mainRenderModel != null)
- mainRenderModel.SetHandVisibility(false, permanent);
- if (hoverhighlightRenderModel != null)
- hoverhighlightRenderModel.SetHandVisibility(false, permanent);
- }
- public bool HasSkeleton()
- {
- return mainRenderModel != null && mainRenderModel.GetSkeleton() != null;
- }
- public void Show()
- {
- SetVisibility(true);
- }
- public void Hide()
- {
- SetVisibility(false);
- }
- public void SetVisibility(bool visible)
- {
- if (mainRenderModel != null)
- mainRenderModel.SetVisibility(visible);
- }
- public void SetSkeletonRangeOfMotion(EVRSkeletalMotionRange newRangeOfMotion, float blendOverSeconds = 0.1f)
- {
- for (int renderModelIndex = 0; renderModelIndex < renderModels.Count; renderModelIndex++)
- {
- renderModels[renderModelIndex].SetSkeletonRangeOfMotion(newRangeOfMotion, blendOverSeconds);
- }
- }
- public void SetTemporarySkeletonRangeOfMotion(SkeletalMotionRangeChange temporaryRangeOfMotionChange, float blendOverSeconds = 0.1f)
- {
- for (int renderModelIndex = 0; renderModelIndex < renderModels.Count; renderModelIndex++)
- {
- renderModels[renderModelIndex].SetTemporarySkeletonRangeOfMotion(temporaryRangeOfMotionChange, blendOverSeconds);
- }
- }
- public void ResetTemporarySkeletonRangeOfMotion(float blendOverSeconds = 0.1f)
- {
- for (int renderModelIndex = 0; renderModelIndex < renderModels.Count; renderModelIndex++)
- {
- renderModels[renderModelIndex].ResetTemporarySkeletonRangeOfMotion(blendOverSeconds);
- }
- }
- public void SetAnimationState(int stateValue)
- {
- for (int renderModelIndex = 0; renderModelIndex < renderModels.Count; renderModelIndex++)
- {
- renderModels[renderModelIndex].SetAnimationState(stateValue);
- }
- }
- public void StopAnimation()
- {
- for (int renderModelIndex = 0; renderModelIndex < renderModels.Count; renderModelIndex++)
- {
- renderModels[renderModelIndex].StopAnimation();
- }
- }
- //-------------------------------------------------
- // Attach a GameObject to this GameObject
- //
- // objectToAttach - The GameObject to attach
- // flags - The flags to use for attaching the object
- // attachmentPoint - Name of the GameObject in the hierarchy of this Hand which should act as the attachment point for this GameObject
- //-------------------------------------------------
- public void AttachObject(GameObject objectToAttach, GrabTypes grabbedWithType, AttachmentFlags flags = defaultAttachmentFlags, Transform attachmentOffset = null)
- {
- AttachedObject attachedObject = new AttachedObject();
- attachedObject.attachmentFlags = flags;
- attachedObject.attachedOffsetTransform = attachmentOffset;
- attachedObject.attachTime = Time.time;
- if (flags == 0)
- {
- flags = defaultAttachmentFlags;
- }
- //Make sure top object on stack is non-null
- CleanUpAttachedObjectStack();
- //Detach the object if it is already attached so that it can get re-attached at the top of the stack
- if (ObjectIsAttached(objectToAttach))
- DetachObject(objectToAttach);
- //Detach from the other hand if requested
- if (attachedObject.HasAttachFlag(AttachmentFlags.DetachFromOtherHand))
- {
- if (otherHand != null)
- otherHand.DetachObject(objectToAttach);
- }
- if (attachedObject.HasAttachFlag(AttachmentFlags.DetachOthers))
- {
- //Detach all the objects from the stack
- while (attachedObjects.Count > 0)
- {
- DetachObject(attachedObjects[0].attachedObject);
- }
- }
- if (currentAttachedObject)
- {
- currentAttachedObject.SendMessage("OnHandFocusLost", this, SendMessageOptions.DontRequireReceiver);
- }
- attachedObject.attachedObject = objectToAttach;
- attachedObject.interactable = objectToAttach.GetComponent<Interactable>();
- attachedObject.allowTeleportWhileAttachedToHand = objectToAttach.GetComponent<AllowTeleportWhileAttachedToHand>();
- attachedObject.handAttachmentPointTransform = this.transform;
- if (attachedObject.interactable != null)
- {
- if (attachedObject.interactable.attachEaseIn)
- {
- attachedObject.easeSourcePosition = attachedObject.attachedObject.transform.position;
- attachedObject.easeSourceRotation = attachedObject.attachedObject.transform.rotation;
- attachedObject.interactable.snapAttachEaseInCompleted = false;
- }
- if (attachedObject.interactable.useHandObjectAttachmentPoint)
- attachedObject.handAttachmentPointTransform = objectAttachmentPoint;
- if (attachedObject.interactable.hideHandOnAttach)
- Hide();
- if (attachedObject.interactable.hideSkeletonOnAttach && mainRenderModel != null && mainRenderModel.displayHandByDefault)
- HideSkeleton();
- if (attachedObject.interactable.hideControllerOnAttach && mainRenderModel != null && mainRenderModel.displayControllerByDefault)
- HideController();
- if (attachedObject.interactable.handAnimationOnPickup != 0)
- SetAnimationState(attachedObject.interactable.handAnimationOnPickup);
- if (attachedObject.interactable.setRangeOfMotionOnPickup != SkeletalMotionRangeChange.None)
- SetTemporarySkeletonRangeOfMotion(attachedObject.interactable.setRangeOfMotionOnPickup);
- }
- attachedObject.originalParent = objectToAttach.transform.parent != null ? objectToAttach.transform.parent.gameObject : null;
- attachedObject.attachedRigidbody = objectToAttach.GetComponent<Rigidbody>();
- if (attachedObject.attachedRigidbody != null)
- {
- if (attachedObject.interactable.attachedToHand != null) //already attached to another hand
- {
- //if it was attached to another hand, get the flags from that hand
- for (int attachedIndex = 0; attachedIndex < attachedObject.interactable.attachedToHand.attachedObjects.Count; attachedIndex++)
- {
- AttachedObject attachedObjectInList = attachedObject.interactable.attachedToHand.attachedObjects[attachedIndex];
- if (attachedObjectInList.interactable == attachedObject.interactable)
- {
- attachedObject.attachedRigidbodyWasKinematic = attachedObjectInList.attachedRigidbodyWasKinematic;
- attachedObject.attachedRigidbodyUsedGravity = attachedObjectInList.attachedRigidbodyUsedGravity;
- attachedObject.originalParent = attachedObjectInList.originalParent;
- }
- }
- }
- else
- {
- attachedObject.attachedRigidbodyWasKinematic = attachedObject.attachedRigidbody.isKinematic;
- attachedObject.attachedRigidbodyUsedGravity = attachedObject.attachedRigidbody.useGravity;
- }
- }
- attachedObject.grabbedWithType = grabbedWithType;
- if (attachedObject.HasAttachFlag(AttachmentFlags.ParentToHand))
- {
- //Parent the object to the hand
- objectToAttach.transform.parent = this.transform;
- attachedObject.isParentedToHand = true;
- }
- else
- {
- attachedObject.isParentedToHand = false;
- }
- if (attachedObject.HasAttachFlag(AttachmentFlags.SnapOnAttach))
- {
- if (attachedObject.interactable != null && attachedObject.interactable.skeletonPoser != null && HasSkeleton())
- {
- SteamVR_Skeleton_PoseSnapshot pose = attachedObject.interactable.skeletonPoser.GetBlendedPose(skeleton);
- //snap the object to the center of the attach point
- objectToAttach.transform.position = this.transform.TransformPoint(pose.position);
- objectToAttach.transform.rotation = this.transform.rotation * pose.rotation;
- attachedObject.initialPositionalOffset = attachedObject.handAttachmentPointTransform.InverseTransformPoint(objectToAttach.transform.position);
- attachedObject.initialRotationalOffset = Quaternion.Inverse(attachedObject.handAttachmentPointTransform.rotation) * objectToAttach.transform.rotation;
- }
- else
- {
- if (attachmentOffset != null)
- {
- //offset the object from the hand by the positional and rotational difference between the offset transform and the attached object
- Quaternion rotDiff = Quaternion.Inverse(attachmentOffset.transform.rotation) * objectToAttach.transform.rotation;
- objectToAttach.transform.rotation = attachedObject.handAttachmentPointTransform.rotation * rotDiff;
- Vector3 posDiff = objectToAttach.transform.position - attachmentOffset.transform.position;
- objectToAttach.transform.position = attachedObject.handAttachmentPointTransform.position + posDiff;
- }
- else
- {
- //snap the object to the center of the attach point
- objectToAttach.transform.rotation = attachedObject.handAttachmentPointTransform.rotation;
- objectToAttach.transform.position = attachedObject.handAttachmentPointTransform.position;
- }
- Transform followPoint = objectToAttach.transform;
- attachedObject.initialPositionalOffset = attachedObject.handAttachmentPointTransform.InverseTransformPoint(followPoint.position);
- attachedObject.initialRotationalOffset = Quaternion.Inverse(attachedObject.handAttachmentPointTransform.rotation) * followPoint.rotation;
- }
- }
- else
- {
- if (attachedObject.interactable != null && attachedObject.interactable.skeletonPoser != null && HasSkeleton())
- {
- attachedObject.initialPositionalOffset = attachedObject.handAttachmentPointTransform.InverseTransformPoint(objectToAttach.transform.position);
- attachedObject.initialRotationalOffset = Quaternion.Inverse(attachedObject.handAttachmentPointTransform.rotation) * objectToAttach.transform.rotation;
- }
- else
- {
- if (attachmentOffset != null)
- {
- //get the initial positional and rotational offsets between the hand and the offset transform
- Quaternion rotDiff = Quaternion.Inverse(attachmentOffset.transform.rotation) * objectToAttach.transform.rotation;
- Quaternion targetRotation = attachedObject.handAttachmentPointTransform.rotation * rotDiff;
- Quaternion rotationPositionBy = targetRotation * Quaternion.Inverse(objectToAttach.transform.rotation);
- Vector3 posDiff = (rotationPositionBy * objectToAttach.transform.position) - (rotationPositionBy * attachmentOffset.transform.position);
- attachedObject.initialPositionalOffset = attachedObject.handAttachmentPointTransform.InverseTransformPoint(attachedObject.handAttachmentPointTransform.position + posDiff);
- attachedObject.initialRotationalOffset = Quaternion.Inverse(attachedObject.handAttachmentPointTransform.rotation) * (attachedObject.handAttachmentPointTransform.rotation * rotDiff);
- }
- else
- {
- attachedObject.initialPositionalOffset = attachedObject.handAttachmentPointTransform.InverseTransformPoint(objectToAttach.transform.position);
- attachedObject.initialRotationalOffset = Quaternion.Inverse(attachedObject.handAttachmentPointTransform.rotation) * objectToAttach.transform.rotation;
- }
- }
- }
- if (attachedObject.HasAttachFlag(AttachmentFlags.TurnOnKinematic))
- {
- if (attachedObject.attachedRigidbody != null)
- {
- attachedObject.collisionDetectionMode = attachedObject.attachedRigidbody.collisionDetectionMode;
- if (attachedObject.collisionDetectionMode == CollisionDetectionMode.Continuous)
- attachedObject.attachedRigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete;
- attachedObject.attachedRigidbody.isKinematic = true;
- }
- }
- if (attachedObject.HasAttachFlag(AttachmentFlags.TurnOffGravity))
- {
- if (attachedObject.attachedRigidbody != null)
- {
- attachedObject.attachedRigidbody.useGravity = false;
- }
- }
- if (attachedObject.interactable != null && attachedObject.interactable.attachEaseIn)
- {
- attachedObject.attachedObject.transform.position = attachedObject.easeSourcePosition;
- attachedObject.attachedObject.transform.rotation = attachedObject.easeSourceRotation;
- }
- attachedObjects.Add(attachedObject);
- UpdateHovering();
- if (spewDebugText)
- HandDebugLog("AttachObject " + objectToAttach);
- objectToAttach.SendMessage("OnAttachedToHand", this, SendMessageOptions.DontRequireReceiver);
- }
- public bool ObjectIsAttached(GameObject go)
- {
- for (int attachedIndex = 0; attachedIndex < attachedObjects.Count; attachedIndex++)
- {
- if (attachedObjects[attachedIndex].attachedObject == go)
- return true;
- }
- return false;
- }
- public void ForceHoverUnlock()
- {
- hoverLocked = false;
- }
- //-------------------------------------------------
- // Detach this GameObject from the attached object stack of this Hand
- //
- // objectToDetach - The GameObject to detach from this Hand
- //-------------------------------------------------
- public void DetachObject(GameObject objectToDetach, bool restoreOriginalParent = true)
- {
- int index = attachedObjects.FindIndex(l => l.attachedObject == objectToDetach);
- if (index != -1)
- {
- if (spewDebugText)
- HandDebugLog("DetachObject " + objectToDetach);
- GameObject prevTopObject = currentAttachedObject;
- if (attachedObjects[index].interactable != null)
- {
- if (attachedObjects[index].interactable.hideHandOnAttach)
- Show();
- if (attachedObjects[index].interactable.hideSkeletonOnAttach && mainRenderModel != null && mainRenderModel.displayHandByDefault)
- ShowSkeleton();
- if (attachedObjects[index].interactable.hideControllerOnAttach && mainRenderModel != null && mainRenderModel.displayControllerByDefault)
- ShowController();
- if (attachedObjects[index].interactable.handAnimationOnPickup != 0)
- StopAnimation();
- if (attachedObjects[index].interactable.setRangeOfMotionOnPickup != SkeletalMotionRangeChange.None)
- ResetTemporarySkeletonRangeOfMotion();
- }
- Transform parentTransform = null;
- if (attachedObjects[index].isParentedToHand)
- {
- if (restoreOriginalParent && (attachedObjects[index].originalParent != null))
- {
- parentTransform = attachedObjects[index].originalParent.transform;
- }
- if (attachedObjects[index].attachedObject != null)
- {
- attachedObjects[index].attachedObject.transform.parent = parentTransform;
- }
- }
- if (attachedObjects[index].HasAttachFlag(AttachmentFlags.TurnOnKinematic))
- {
- if (attachedObjects[index].attachedRigidbody != null)
- {
- attachedObjects[index].attachedRigidbody.isKinematic = attachedObjects[index].attachedRigidbodyWasKinematic;
- attachedObjects[index].attachedRigidbody.collisionDetectionMode = attachedObjects[index].collisionDetectionMode;
- }
- }
- if (attachedObjects[index].HasAttachFlag(AttachmentFlags.TurnOffGravity))
- {
- if (attachedObjects[index].attachedObject != null)
- {
- if (attachedObjects[index].attachedRigidbody != null)
- attachedObjects[index].attachedRigidbody.useGravity = attachedObjects[index].attachedRigidbodyUsedGravity;
- }
- }
- if (attachedObjects[index].interactable != null && attachedObjects[index].interactable.handFollowTransform && HasSkeleton())
- {
- skeleton.transform.localPosition = Vector3.zero;
- skeleton.transform.localRotation = Quaternion.identity;
- }
- if (attachedObjects[index].attachedObject != null)
- {
- if (attachedObjects[index].interactable == null || (attachedObjects[index].interactable != null && attachedObjects[index].interactable.isDestroying == false))
- attachedObjects[index].attachedObject.SetActive(true);
- attachedObjects[index].attachedObject.SendMessage("OnDetachedFromHand", this, SendMessageOptions.DontRequireReceiver);
- }
- attachedObjects.RemoveAt(index);
- CleanUpAttachedObjectStack();
- GameObject newTopObject = currentAttachedObject;
- hoverLocked = false;
- //Give focus to the top most object on the stack if it changed
- if (newTopObject != null && newTopObject != prevTopObject)
- {
- newTopObject.SetActive(true);
- newTopObject.SendMessage("OnHandFocusAcquired", this, SendMessageOptions.DontRequireReceiver);
- }
- }
- CleanUpAttachedObjectStack();
- if (mainRenderModel != null)
- mainRenderModel.MatchHandToTransform(mainRenderModel.transform);
- if (hoverhighlightRenderModel != null)
- hoverhighlightRenderModel.MatchHandToTransform(hoverhighlightRenderModel.transform);
- }
- //-------------------------------------------------
- // Get the world velocity of the VR Hand.
- //-------------------------------------------------
- public Vector3 GetTrackedObjectVelocity(float timeOffset = 0)
- {
- if (trackedObject == null)
- {
- Vector3 velocityTarget, angularTarget;
- GetUpdatedAttachedVelocities(currentAttachedObjectInfo.Value, out velocityTarget, out angularTarget);
- return velocityTarget;
- }
- if (isActive)
- {
- if (timeOffset == 0)
- return Player.instance.trackingOriginTransform.TransformVector(trackedObject.GetVelocity());
- else
- {
- Vector3 velocity;
- Vector3 angularVelocity;
- trackedObject.GetVelocitiesAtTimeOffset(timeOffset, out velocity, out angularVelocity);
- return Player.instance.trackingOriginTransform.TransformVector(velocity);
- }
- }
- return Vector3.zero;
- }
- //-------------------------------------------------
- // Get the world space angular velocity of the VR Hand.
- //-------------------------------------------------
- public Vector3 GetTrackedObjectAngularVelocity(float timeOffset = 0)
- {
- if (trackedObject == null)
- {
- Vector3 velocityTarget, angularTarget;
- GetUpdatedAttachedVelocities(currentAttachedObjectInfo.Value, out velocityTarget, out angularTarget);
- return angularTarget;
- }
- if (isActive)
- {
- if (timeOffset == 0)
- return Player.instance.trackingOriginTransform.TransformDirection(trackedObject.GetAngularVelocity());
- else
- {
- Vector3 velocity;
- Vector3 angularVelocity;
- trackedObject.GetVelocitiesAtTimeOffset(timeOffset, out velocity, out angularVelocity);
- return Player.instance.trackingOriginTransform.TransformDirection(angularVelocity);
- }
- }
- return Vector3.zero;
- }
- public void GetEstimatedPeakVelocities(out Vector3 velocity, out Vector3 angularVelocity)
- {
- trackedObject.GetEstimatedPeakVelocities(out velocity, out angularVelocity);
- velocity = Player.instance.trackingOriginTransform.TransformVector(velocity);
- angularVelocity = Player.instance.trackingOriginTransform.TransformDirection(angularVelocity);
- }
- //-------------------------------------------------
- private void CleanUpAttachedObjectStack()
- {
- attachedObjects.RemoveAll(l => l.attachedObject == null);
- }
- //-------------------------------------------------
- protected virtual void Awake()
- {
- inputFocusAction = SteamVR_Events.InputFocusAction(OnInputFocus);
- if (hoverSphereTransform == null)
- hoverSphereTransform = this.transform;
- if (objectAttachmentPoint == null)
- objectAttachmentPoint = this.transform;
- applicationLostFocusObject = new GameObject("_application_lost_focus");
- applicationLostFocusObject.transform.parent = transform;
- applicationLostFocusObject.SetActive(false);
- if (trackedObject == null)
- {
- trackedObject = this.gameObject.GetComponent<SteamVR_Behaviour_Pose>();
- if (trackedObject != null)
- trackedObject.onTransformUpdatedEvent += OnTransformUpdated;
- }
- }
- protected virtual void OnDestroy()
- {
- if (trackedObject != null)
- {
- trackedObject.onTransformUpdatedEvent -= OnTransformUpdated;
- }
- }
- protected virtual void OnTransformUpdated(SteamVR_Behaviour_Pose updatedPose, SteamVR_Input_Sources updatedSource)
- {
- HandFollowUpdate();
- }
- //-------------------------------------------------
- protected virtual IEnumerator Start()
- {
- // save off player instance
- playerInstance = Player.instance;
- if (!playerInstance)
- {
- Debug.LogError("<b>[SteamVR Interaction]</b> No player instance found in Hand Start()", this);
- }
- if (this.gameObject.layer == 0)
- Debug.LogWarning("<b>[SteamVR Interaction]</b> Hand is on default layer. This puts unnecessary strain on hover checks as it is always true for hand colliders (which are then ignored).", this);
- else
- hoverLayerMask &= ~(1 << this.gameObject.layer); //ignore self for hovering
- // allocate array for colliders
- overlappingColliders = new Collider[ColliderArraySize];
- // We are a "no SteamVR fallback hand" if we have this camera set
- // we'll use the right mouse to look around and left mouse to interact
- // - don't need to find the device
- if (noSteamVRFallbackCamera)
- {
- yield break;
- }
- //Debug.Log( "<b>[SteamVR Interaction]</b> Hand - initializing connection routine" );
- while (true)
- {
- if (isPoseValid)
- {
- InitController();
- break;
- }
- yield return null;
- }
- }
- //-------------------------------------------------
- protected virtual void UpdateHovering()
- {
- if ((noSteamVRFallbackCamera == null) && (isActive == false))
- {
- return;
- }
- if (hoverLocked)
- return;
- if (applicationLostFocusObject.activeSelf)
- return;
- float closestDistance = float.MaxValue;
- Interactable closestInteractable = null;
- if (useHoverSphere)
- {
- float scaledHoverRadius = hoverSphereRadius * Mathf.Abs(SteamVR_Utils.GetLossyScale(hoverSphereTransform));
- CheckHoveringForTransform(hoverSphereTransform.position, scaledHoverRadius, ref closestDistance, ref closestInteractable, Color.green);
- }
- if (useControllerHoverComponent && mainRenderModel != null && mainRenderModel.IsControllerVisibile())
- {
- float scaledHoverRadius = controllerHoverRadius * Mathf.Abs(SteamVR_Utils.GetLossyScale(this.transform));
- CheckHoveringForTransform(mainRenderModel.GetControllerPosition(controllerHoverComponent), scaledHoverRadius / 2f, ref closestDistance, ref closestInteractable, Color.blue);
- }
- if (useFingerJointHover && mainRenderModel != null && mainRenderModel.IsHandVisibile())
- {
- float scaledHoverRadius = fingerJointHoverRadius * Mathf.Abs(SteamVR_Utils.GetLossyScale(this.transform));
- CheckHoveringForTransform(mainRenderModel.GetBonePosition((int)fingerJointHover), scaledHoverRadius / 2f, ref closestDistance, ref closestInteractable, Color.yellow);
- }
- // Hover on this one
- hoveringInteractable = closestInteractable;
- }
- protected virtual bool CheckHoveringForTransform(Vector3 hoverPosition, float hoverRadius, ref float closestDistance, ref Interactable closestInteractable, Color debugColor)
- {
- bool foundCloser = false;
- // null out old vals
- for (int i = 0; i < overlappingColliders.Length; ++i)
- {
- overlappingColliders[i] = null;
- }
- int numColliding = Physics.OverlapSphereNonAlloc(hoverPosition, hoverRadius, overlappingColliders, hoverLayerMask.value);
- if (numColliding >= ColliderArraySize)
- Debug.LogWarning("<b>[SteamVR Interaction]</b> This hand is overlapping the max number of colliders: " + ColliderArraySize + ". Some collisions may be missed. Increase ColliderArraySize on Hand.cs");
- // DebugVar
- int iActualColliderCount = 0;
- // Pick the closest hovering
- for (int colliderIndex = 0; colliderIndex < overlappingColliders.Length; colliderIndex++)
- {
- Collider collider = overlappingColliders[colliderIndex];
- if (collider == null)
- continue;
- Interactable contacting = collider.GetComponentInParent<Interactable>();
- // Yeah, it's null, skip
- if (contacting == null)
- continue;
- // Ignore this collider for hovering
- IgnoreHovering ignore = collider.GetComponent<IgnoreHovering>();
- if (ignore != null)
- {
- if (ignore.onlyIgnoreHand == null || ignore.onlyIgnoreHand == this)
- {
- continue;
- }
- }
- // Can't hover over the object if it's attached
- bool hoveringOverAttached = false;
- for (int attachedIndex = 0; attachedIndex < attachedObjects.Count; attachedIndex++)
- {
- if (attachedObjects[attachedIndex].attachedObject == contacting.gameObject)
- {
- hoveringOverAttached = true;
- break;
- }
- }
- if (hoveringOverAttached)
- continue;
- // Best candidate so far...
- float distance = Vector3.Distance(contacting.transform.position, hoverPosition);
- //float distance = Vector3.Distance(collider.bounds.center, hoverPosition);
- bool lowerPriority = false;
- if (closestInteractable != null)
- { // compare to closest interactable to check priority
- lowerPriority = contacting.hoverPriority < closestInteractable.hoverPriority;
- }
- bool isCloser = (distance < closestDistance);
- if (isCloser && !lowerPriority)
- {
- closestDistance = distance;
- closestInteractable = contacting;
- foundCloser = true;
- }
- iActualColliderCount++;
- }
- if (showDebugInteractables && foundCloser)
- {
- Debug.DrawLine(hoverPosition, closestInteractable.transform.position, debugColor, .05f, false);
- }
- if (iActualColliderCount > 0 && iActualColliderCount != prevOverlappingColliders)
- {
- prevOverlappingColliders = iActualColliderCount;
- if (spewDebugText)
- HandDebugLog("Found " + iActualColliderCount + " overlapping colliders.");
- }
- return foundCloser;
- }
- //-------------------------------------------------
- protected virtual void UpdateNoSteamVRFallback()
- {
- if (noSteamVRFallbackCamera)
- {
- Ray ray = noSteamVRFallbackCamera.ScreenPointToRay(Input.mousePosition);
- if (attachedObjects.Count > 0)
- {
- // Holding down the mouse:
- // move around a fixed distance from the camera
- transform.position = ray.origin + noSteamVRFallbackInteractorDistance * ray.direction;
- }
- else
- {
- // Not holding down the mouse:
- // cast out a ray to see what we should mouse over
- // Don't want to hit the hand and anything underneath it
- // So move it back behind the camera when we do the raycast
- Vector3 oldPosition = transform.position;
- transform.position = noSteamVRFallbackCamera.transform.forward * (-1000.0f);
- RaycastHit raycastHit;
- if (Physics.Raycast(ray, out raycastHit, noSteamVRFallbackMaxDistanceNoItem))
- {
- transform.position = raycastHit.point;
- // Remember this distance in case we click and drag the mouse
- noSteamVRFallbackInteractorDistance = Mathf.Min(noSteamVRFallbackMaxDistanceNoItem, raycastHit.distance);
- }
- else if (noSteamVRFallbackInteractorDistance > 0.0f)
- {
- // Move it around at the distance we last had a hit
- transform.position = ray.origin + Mathf.Min(noSteamVRFallbackMaxDistanceNoItem, noSteamVRFallbackInteractorDistance) * ray.direction;
- }
- else
- {
- // Didn't hit, just leave it where it was
- transform.position = oldPosition;
- }
- }
- }
- }
- //-------------------------------------------------
- private void UpdateDebugText()
- {
- if (showDebugText)
- {
- if (debugText == null)
- {
- debugText = new GameObject("_debug_text").AddComponent<TextMesh>();
- debugText.fontSize = 120;
- debugText.characterSize = 0.001f;
- debugText.transform.parent = transform;
- debugText.transform.localRotation = Quaternion.Euler(90.0f, 0.0f, 0.0f);
- }
- if (handType == SteamVR_Input_Sources.RightHand)
- {
- debugText.transform.localPosition = new Vector3(-0.05f, 0.0f, 0.0f);
- debugText.alignment = TextAlignment.Right;
- debugText.anchor = TextAnchor.UpperRight;
- }
- else
- {
- debugText.transform.localPosition = new Vector3(0.05f, 0.0f, 0.0f);
- debugText.alignment = TextAlignment.Left;
- debugText.anchor = TextAnchor.UpperLeft;
- }
- debugText.text = string.Format(
- "Hovering: {0}\n" +
- "Hover Lock: {1}\n" +
- "Attached: {2}\n" +
- "Total Attached: {3}\n" +
- "Type: {4}\n",
- (hoveringInteractable ? hoveringInteractable.gameObject.name : "null"),
- hoverLocked,
- (currentAttachedObject ? currentAttachedObject.name : "null"),
- attachedObjects.Count,
- handType.ToString());
- }
- else
- {
- if (debugText != null)
- {
- Destroy(debugText.gameObject);
- }
- }
- }
- //-------------------------------------------------
- protected virtual void OnEnable()
- {
- inputFocusAction.enabled = true;
- // Stagger updates between hands
- float hoverUpdateBegin = ((otherHand != null) && (otherHand.GetInstanceID() < GetInstanceID())) ? (0.5f * hoverUpdateInterval) : (0.0f);
- InvokeRepeating("UpdateHovering", hoverUpdateBegin, hoverUpdateInterval);
- InvokeRepeating("UpdateDebugText", hoverUpdateBegin, hoverUpdateInterval);
- }
- //-------------------------------------------------
- protected virtual void OnDisable()
- {
- inputFocusAction.enabled = false;
- CancelInvoke();
- }
- //-------------------------------------------------
- protected virtual void Update()
- {
- UpdateNoSteamVRFallback();
- GameObject attachedObject = currentAttachedObject;
- if (attachedObject != null)
- {
- attachedObject.SendMessage("HandAttachedUpdate", this, SendMessageOptions.DontRequireReceiver);
- }
- if (hoveringInteractable)
- {
- hoveringInteractable.SendMessage("HandHoverUpdate", this, SendMessageOptions.DontRequireReceiver);
- }
- }
- /// <summary>
- /// Returns true when the hand is currently hovering over the interactable passed in
- /// </summary>
- public bool IsStillHovering(Interactable interactable)
- {
- return hoveringInteractable == interactable;
- }
- protected virtual void HandFollowUpdate()
- {
- GameObject attachedObject = currentAttachedObject;
- if (attachedObject != null)
- {
- if (currentAttachedObjectInfo.Value.interactable != null)
- {
- SteamVR_Skeleton_PoseSnapshot pose = null;
- if (currentAttachedObjectInfo.Value.interactable.skeletonPoser != null && HasSkeleton())
- {
- pose = currentAttachedObjectInfo.Value.interactable.skeletonPoser.GetBlendedPose(skeleton);
- }
- if (currentAttachedObjectInfo.Value.interactable.handFollowTransform)
- {
- Quaternion targetHandRotation;
- Vector3 targetHandPosition;
- if (pose == null)
- {
- Quaternion offset = Quaternion.Inverse(this.transform.rotation) * currentAttachedObjectInfo.Value.handAttachmentPointTransform.rotation;
- targetHandRotation = currentAttachedObjectInfo.Value.interactable.transform.rotation * Quaternion.Inverse(offset);
- Vector3 worldOffset = (this.transform.position - currentAttachedObjectInfo.Value.handAttachmentPointTransform.position);
- Quaternion rotationDiff = mainRenderModel.GetHandRotation() * Quaternion.Inverse(this.transform.rotation);
- Vector3 localOffset = rotationDiff * worldOffset;
- targetHandPosition = currentAttachedObjectInfo.Value.interactable.transform.position + localOffset;
- }
- else
- {
- Transform objectT = currentAttachedObjectInfo.Value.attachedObject.transform;
- Vector3 oldItemPos = objectT.position;
- Quaternion oldItemRot = objectT.transform.rotation;
- objectT.position = TargetItemPosition(currentAttachedObjectInfo.Value);
- objectT.rotation = TargetItemRotation(currentAttachedObjectInfo.Value);
- Vector3 localSkelePos = objectT.InverseTransformPoint(transform.position);
- Quaternion localSkeleRot = Quaternion.Inverse(objectT.rotation) * transform.rotation;
- objectT.position = oldItemPos;
- objectT.rotation = oldItemRot;
- targetHandPosition = objectT.TransformPoint(localSkelePos);
- targetHandRotation = objectT.rotation * localSkeleRot;
- }
- if (mainRenderModel != null)
- mainRenderModel.SetHandRotation(targetHandRotation);
- if (hoverhighlightRenderModel != null)
- hoverhighlightRenderModel.SetHandRotation(targetHandRotation);
- if (mainRenderModel != null)
- mainRenderModel.SetHandPosition(targetHandPosition);
- if (hoverhighlightRenderModel != null)
- hoverhighlightRenderModel.SetHandPosition(targetHandPosition);
- }
- }
- }
- }
- protected virtual void FixedUpdate()
- {
- if (currentAttachedObject != null)
- {
- AttachedObject attachedInfo = currentAttachedObjectInfo.Value;
- if (attachedInfo.attachedObject != null)
- {
- if (attachedInfo.HasAttachFlag(AttachmentFlags.VelocityMovement))
- {
- if (attachedInfo.interactable.attachEaseIn == false || attachedInfo.interactable.snapAttachEaseInCompleted)
- UpdateAttachedVelocity(attachedInfo);
- /*if (attachedInfo.interactable.handFollowTransformPosition)
- {
- skeleton.transform.position = TargetSkeletonPosition(attachedInfo);
- skeleton.transform.rotation = attachedInfo.attachedObject.transform.rotation * attachedInfo.skeletonLockRotation;
- }*/
- }
- else
- {
- if (attachedInfo.HasAttachFlag(AttachmentFlags.ParentToHand))
- {
- attachedInfo.attachedObject.transform.position = TargetItemPosition(attachedInfo);
- attachedInfo.attachedObject.transform.rotation = TargetItemRotation(attachedInfo);
- }
- }
- if (attachedInfo.interactable.attachEaseIn)
- {
- float t = Util.RemapNumberClamped(Time.time, attachedInfo.attachTime, attachedInfo.attachTime + attachedInfo.interactable.snapAttachEaseInTime, 0.0f, 1.0f);
- if (t < 1.0f)
- {
- if (attachedInfo.HasAttachFlag(AttachmentFlags.VelocityMovement))
- {
- attachedInfo.attachedRigidbody.velocity = Vector3.zero;
- attachedInfo.attachedRigidbody.angularVelocity = Vector3.zero;
- }
- t = attachedInfo.interactable.snapAttachEaseInCurve.Evaluate(t);
- attachedInfo.attachedObject.transform.position = Vector3.Lerp(attachedInfo.easeSourcePosition, TargetItemPosition(attachedInfo), t);
- attachedInfo.attachedObject.transform.rotation = Quaternion.Lerp(attachedInfo.easeSourceRotation, TargetItemRotation(attachedInfo), t);
- }
- else if (!attachedInfo.interactable.snapAttachEaseInCompleted)
- {
- attachedInfo.interactable.gameObject.SendMessage("OnThrowableAttachEaseInCompleted", this, SendMessageOptions.DontRequireReceiver);
- attachedInfo.interactable.snapAttachEaseInCompleted = true;
- }
- }
- }
- }
- }
- protected const float MaxVelocityChange = 10f;
- protected const float VelocityMagic = 6000f;
- protected const float AngularVelocityMagic = 50f;
- protected const float MaxAngularVelocityChange = 20f;
- protected void UpdateAttachedVelocity(AttachedObject attachedObjectInfo)
- {
- Vector3 velocityTarget, angularTarget;
- bool success = GetUpdatedAttachedVelocities(attachedObjectInfo, out velocityTarget, out angularTarget);
- if (success)
- {
- float scale = SteamVR_Utils.GetLossyScale(currentAttachedObjectInfo.Value.handAttachmentPointTransform);
- float maxAngularVelocityChange = MaxAngularVelocityChange * scale;
- float maxVelocityChange = MaxVelocityChange * scale;
- attachedObjectInfo.attachedRigidbody.velocity = Vector3.MoveTowards(attachedObjectInfo.attachedRigidbody.velocity, velocityTarget, maxVelocityChange);
- attachedObjectInfo.attachedRigidbody.angularVelocity = Vector3.MoveTowards(attachedObjectInfo.attachedRigidbody.angularVelocity, angularTarget, maxAngularVelocityChange);
- }
- }
- /// <summary>
- /// Snap an attached object to its target position and rotation. Good for error correction.
- /// </summary>
- public void ResetAttachedTransform(AttachedObject attachedObject)
- {
- attachedObject.attachedObject.transform.position = TargetItemPosition(attachedObject);
- attachedObject.attachedObject.transform.rotation = TargetItemRotation(attachedObject);
- }
- protected Vector3 TargetItemPosition(AttachedObject attachedObject)
- {
- if (attachedObject.interactable != null && attachedObject.interactable.skeletonPoser != null && HasSkeleton())
- {
- Vector3 tp = attachedObject.handAttachmentPointTransform.InverseTransformPoint(transform.TransformPoint(attachedObject.interactable.skeletonPoser.GetBlendedPose(skeleton).position));
- //tp.x *= -1;
- return currentAttachedObjectInfo.Value.handAttachmentPointTransform.TransformPoint(tp);
- }
- else
- {
- return currentAttachedObjectInfo.Value.handAttachmentPointTransform.TransformPoint(attachedObject.initialPositionalOffset);
- }
- }
- protected Quaternion TargetItemRotation(AttachedObject attachedObject)
- {
- if (attachedObject.interactable != null && attachedObject.interactable.skeletonPoser != null && HasSkeleton())
- {
- Quaternion tr = Quaternion.Inverse(attachedObject.handAttachmentPointTransform.rotation) * (transform.rotation * attachedObject.interactable.skeletonPoser.GetBlendedPose(skeleton).rotation);
- return currentAttachedObjectInfo.Value.handAttachmentPointTransform.rotation * tr;
- }
- else
- {
- return currentAttachedObjectInfo.Value.handAttachmentPointTransform.rotation * attachedObject.initialRotationalOffset;
- }
- }
- protected bool GetUpdatedAttachedVelocities(AttachedObject attachedObjectInfo, out Vector3 velocityTarget, out Vector3 angularTarget)
- {
- bool realNumbers = false;
- float velocityMagic = VelocityMagic;
- float angularVelocityMagic = AngularVelocityMagic;
- Vector3 targetItemPosition = TargetItemPosition(attachedObjectInfo);
- Vector3 positionDelta = (targetItemPosition - attachedObjectInfo.attachedRigidbody.position);
- velocityTarget = (positionDelta * velocityMagic * Time.deltaTime);
- if (float.IsNaN(velocityTarget.x) == false && float.IsInfinity(velocityTarget.x) == false)
- {
- if (noSteamVRFallbackCamera)
- velocityTarget /= 10; //hacky fix for fallback
- realNumbers = true;
- }
- else
- velocityTarget = Vector3.zero;
- Quaternion targetItemRotation = TargetItemRotation(attachedObjectInfo);
- Quaternion rotationDelta = targetItemRotation * Quaternion.Inverse(attachedObjectInfo.attachedObject.transform.rotation);
- float angle;
- Vector3 axis;
- rotationDelta.ToAngleAxis(out angle, out axis);
- if (angle > 180)
- angle -= 360;
- if (angle != 0 && float.IsNaN(axis.x) == false && float.IsInfinity(axis.x) == false)
- {
- angularTarget = angle * axis * angularVelocityMagic * Time.deltaTime;
- if (noSteamVRFallbackCamera)
- angularTarget /= 10; //hacky fix for fallback
- realNumbers &= true;
- }
- else
- angularTarget = Vector3.zero;
- return realNumbers;
- }
- //-------------------------------------------------
- protected virtual void OnInputFocus(bool hasFocus)
- {
- if (hasFocus)
- {
- DetachObject(applicationLostFocusObject, true);
- applicationLostFocusObject.SetActive(false);
- UpdateHovering();
- BroadcastMessage("OnParentHandInputFocusAcquired", SendMessageOptions.DontRequireReceiver);
- }
- else
- {
- applicationLostFocusObject.SetActive(true);
- AttachObject(applicationLostFocusObject, GrabTypes.Scripted, AttachmentFlags.ParentToHand);
- BroadcastMessage("OnParentHandInputFocusLost", SendMessageOptions.DontRequireReceiver);
- }
- }
- //-------------------------------------------------
- protected virtual void OnDrawGizmos()
- {
- if (useHoverSphere && hoverSphereTransform != null)
- {
- Gizmos.color = Color.green;
- float scaledHoverRadius = hoverSphereRadius * Mathf.Abs(SteamVR_Utils.GetLossyScale(hoverSphereTransform));
- Gizmos.DrawWireSphere(hoverSphereTransform.position, scaledHoverRadius / 2);
- }
- if (useControllerHoverComponent && mainRenderModel != null && mainRenderModel.IsControllerVisibile())
- {
- Gizmos.color = Color.blue;
- float scaledHoverRadius = controllerHoverRadius * Mathf.Abs(SteamVR_Utils.GetLossyScale(this.transform));
- Gizmos.DrawWireSphere(mainRenderModel.GetControllerPosition(controllerHoverComponent), scaledHoverRadius / 2);
- }
- if (useFingerJointHover && mainRenderModel != null && mainRenderModel.IsHandVisibile())
- {
- Gizmos.color = Color.yellow;
- float scaledHoverRadius = fingerJointHoverRadius * Mathf.Abs(SteamVR_Utils.GetLossyScale(this.transform));
- Gizmos.DrawWireSphere(mainRenderModel.GetBonePosition((int)fingerJointHover), scaledHoverRadius / 2);
- }
- }
- //-------------------------------------------------
- private void HandDebugLog(string msg)
- {
- if (spewDebugText)
- {
- Debug.Log("<b>[SteamVR Interaction]</b> Hand (" + this.name + "): " + msg);
- }
- }
- //-------------------------------------------------
- // Continue to hover over this object indefinitely, whether or not the Hand moves out of its interaction trigger volume.
- //
- // interactable - The Interactable to hover over indefinitely.
- //-------------------------------------------------
- public void HoverLock(Interactable interactable)
- {
- if (spewDebugText)
- HandDebugLog("HoverLock " + interactable);
- hoverLocked = true;
- hoveringInteractable = interactable;
- }
- //-------------------------------------------------
- // Stop hovering over this object indefinitely.
- //
- // interactable - The hover-locked Interactable to stop hovering over indefinitely.
- //-------------------------------------------------
- public void HoverUnlock(Interactable interactable)
- {
- if (spewDebugText)
- HandDebugLog("HoverUnlock " + interactable);
- if (hoveringInteractable == interactable)
- {
- hoverLocked = false;
- }
- }
- public void TriggerHapticPulse(ushort microSecondsDuration)
- {
- float seconds = (float)microSecondsDuration / 1000000f;
- hapticAction.Execute(0, seconds, 1f / seconds, 1, handType);
- }
- public void TriggerHapticPulse(float duration, float frequency, float amplitude)
- {
- hapticAction.Execute(0, duration, frequency, amplitude, handType);
- }
- public void ShowGrabHint()
- {
- ControllerButtonHints.ShowButtonHint(this, grabGripAction); //todo: assess
- }
- public void HideGrabHint()
- {
- ControllerButtonHints.HideButtonHint(this, grabGripAction); //todo: assess
- }
- public void ShowGrabHint(string text)
- {
- ControllerButtonHints.ShowTextHint(this, grabGripAction, text);
- }
- public GrabTypes GetGrabStarting(GrabTypes explicitType = GrabTypes.None)
- {
- if (explicitType != GrabTypes.None)
- {
- if (noSteamVRFallbackCamera)
- {
- if (Input.GetMouseButtonDown(0))
- return explicitType;
- else
- return GrabTypes.None;
- }
- if (explicitType == GrabTypes.Pinch && grabPinchAction.GetStateDown(handType))
- return GrabTypes.Pinch;
- if (explicitType == GrabTypes.Grip && grabGripAction.GetStateDown(handType))
- return GrabTypes.Grip;
- }
- else
- {
- if (noSteamVRFallbackCamera)
- {
- if (Input.GetMouseButtonDown(0))
- return GrabTypes.Grip;
- else
- return GrabTypes.None;
- }
- if (grabPinchAction != null && grabPinchAction.GetStateDown(handType))
- return GrabTypes.Pinch;
- if (grabGripAction != null && grabGripAction.GetStateDown(handType))
- return GrabTypes.Grip;
- }
- return GrabTypes.None;
- }
- public GrabTypes GetGrabEnding(GrabTypes explicitType = GrabTypes.None)
- {
- if (explicitType != GrabTypes.None)
- {
- if (noSteamVRFallbackCamera)
- {
- if (Input.GetMouseButtonUp(0))
- return explicitType;
- else
- return GrabTypes.None;
- }
- if (explicitType == GrabTypes.Pinch && grabPinchAction.GetStateUp(handType))
- return GrabTypes.Pinch;
- if (explicitType == GrabTypes.Grip && grabGripAction.GetStateUp(handType))
- return GrabTypes.Grip;
- }
- else
- {
- if (noSteamVRFallbackCamera)
- {
- if (Input.GetMouseButtonUp(0))
- return GrabTypes.Grip;
- else
- return GrabTypes.None;
- }
- if (grabPinchAction.GetStateUp(handType))
- return GrabTypes.Pinch;
- if (grabGripAction.GetStateUp(handType))
- return GrabTypes.Grip;
- }
- return GrabTypes.None;
- }
- public bool IsGrabEnding(GameObject attachedObject)
- {
- for (int attachedObjectIndex = 0; attachedObjectIndex < attachedObjects.Count; attachedObjectIndex++)
- {
- if (attachedObjects[attachedObjectIndex].attachedObject == attachedObject)
- {
- return IsGrabbingWithType(attachedObjects[attachedObjectIndex].grabbedWithType) == false;
- }
- }
- return false;
- }
- public bool IsGrabbingWithType(GrabTypes type)
- {
- if (noSteamVRFallbackCamera)
- {
- if (Input.GetMouseButton(0))
- return true;
- else
- return false;
- }
- switch (type)
- {
- case GrabTypes.Pinch:
- return grabPinchAction.GetState(handType);
- case GrabTypes.Grip:
- return grabGripAction.GetState(handType);
- default:
- return false;
- }
- }
- public bool IsGrabbingWithOppositeType(GrabTypes type)
- {
- if (noSteamVRFallbackCamera)
- {
- if (Input.GetMouseButton(0))
- return true;
- else
- return false;
- }
- switch (type)
- {
- case GrabTypes.Pinch:
- return grabGripAction.GetState(handType);
- case GrabTypes.Grip:
- return grabPinchAction.GetState(handType);
- default:
- return false;
- }
- }
- public GrabTypes GetBestGrabbingType()
- {
- return GetBestGrabbingType(GrabTypes.None);
- }
- public GrabTypes GetBestGrabbingType(GrabTypes preferred, bool forcePreference = false)
- {
- if (noSteamVRFallbackCamera)
- {
- if (Input.GetMouseButton(0))
- return preferred;
- else
- return GrabTypes.None;
- }
- if (preferred == GrabTypes.Pinch)
- {
- if (grabPinchAction.GetState(handType))
- return GrabTypes.Pinch;
- else if (forcePreference)
- return GrabTypes.None;
- }
- if (preferred == GrabTypes.Grip)
- {
- if (grabGripAction.GetState(handType))
- return GrabTypes.Grip;
- else if (forcePreference)
- return GrabTypes.None;
- }
- if (grabPinchAction.GetState(handType))
- return GrabTypes.Pinch;
- if (grabGripAction.GetState(handType))
- return GrabTypes.Grip;
- return GrabTypes.None;
- }
- //-------------------------------------------------
- private void InitController()
- {
- if (spewDebugText)
- HandDebugLog("Hand " + name + " connected with type " + handType.ToString());
- bool hadOldRendermodel = mainRenderModel != null;
- EVRSkeletalMotionRange oldRM_rom = EVRSkeletalMotionRange.WithController;
- if (hadOldRendermodel)
- oldRM_rom = mainRenderModel.GetSkeletonRangeOfMotion;
- foreach (RenderModel r in renderModels)
- {
- if (r != null)
- Destroy(r.gameObject);
- }
- renderModels.Clear();
- GameObject renderModelInstance = GameObject.Instantiate(renderModelPrefab);
- renderModelInstance.layer = gameObject.layer;
- renderModelInstance.tag = gameObject.tag;
- renderModelInstance.transform.parent = this.transform;
- renderModelInstance.transform.localPosition = Vector3.zero;
- renderModelInstance.transform.localRotation = Quaternion.identity;
- renderModelInstance.transform.localScale = renderModelPrefab.transform.localScale;
- //TriggerHapticPulse(800); //pulse on controller init
- int deviceIndex = trackedObject.GetDeviceIndex();
- mainRenderModel = renderModelInstance.GetComponent<RenderModel>();
- renderModels.Add(mainRenderModel);
- if (hadOldRendermodel)
- mainRenderModel.SetSkeletonRangeOfMotion(oldRM_rom);
- this.BroadcastMessage("SetInputSource", handType, SendMessageOptions.DontRequireReceiver); // let child objects know we've initialized
- this.BroadcastMessage("OnHandInitialized", deviceIndex, SendMessageOptions.DontRequireReceiver); // let child objects know we've initialized
- }
- public void SetRenderModel(GameObject prefab)
- {
- renderModelPrefab = prefab;
- if (mainRenderModel != null && isPoseValid)
- InitController();
- }
- public void SetHoverRenderModel(RenderModel hoverRenderModel)
- {
- hoverhighlightRenderModel = hoverRenderModel;
- renderModels.Add(hoverRenderModel);
- }
- public int GetDeviceIndex()
- {
- return trackedObject.GetDeviceIndex();
- }
- }
- [System.Serializable]
- public class HandEvent : UnityEvent<Hand> { }
- }
|