Advertisement
Trainerlord

Teleport Vive

Jan 16th, 2019
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.34 KB | None | 0 0
  1. using UnityEngine;
  2. using Valve.VR;
  3.  
  4. [AddComponentMenu("Vive Teleporter/Vive Teleporter")]
  5. [RequireComponent(typeof(Camera), typeof(BorderRenderer))]
  6. public class TeleportVive : MonoBehaviour
  7. {
  8. [Tooltip("Parabolic Pointer object to pull destination points from, and to assign to each controller.")]
  9. public ParabolicPointer Pointer;
  10. /// Origin of SteamVR tracking space
  11. [Tooltip("Origin of the SteamVR tracking space")]
  12. public Transform OriginTransform;
  13. /// Origin of the player's head
  14. [Tooltip("Transform of the player's head")]
  15. public Transform HeadTransform;
  16.  
  17. /// How long, in seconds, the fade-in/fade-out animation should take
  18. [Tooltip("Duration of the \"blink\" animation (fading in and out upon teleport) in seconds.")]
  19. public float TeleportFadeDuration = 0.2f;
  20. /// Measure in degrees of how often the controller should respond with a haptic click. Smaller value=faster clicks
  21. [Tooltip("The player feels a haptic pulse in the controller when they raise / lower the controller by this many degrees. Lower value = faster pulses.")]
  22. public float HapticClickAngleStep = 10;
  23.  
  24. /// BorderRenderer to render the chaperone bounds (when choosing a location to teleport to)
  25. private BorderRenderer RoomBorder;
  26.  
  27. /// Animator used to fade in/out the teleport area. This should have a boolean parameter "Enabled" where if true
  28. /// the selectable area is displayed on the ground.
  29. [SerializeField]
  30. [Tooltip("Animator with a boolean \"Enabled\" parameter that is set to true when the player is choosing a place to teleport.")]
  31. private Animator NavmeshAnimator;
  32. private int EnabledAnimatorID;
  33.  
  34. /// Material used to render the fade in/fade out quad
  35. [Tooltip("Material used to render the fade in/fade out quad.")]
  36. [SerializeField]
  37. private Material FadeMaterial;
  38. private Material FadeMaterialInstance;
  39. private int MaterialFadeID;
  40.  
  41. /// SteamVR controllers that should be polled.
  42. [Tooltip("Array of SteamVR controllers that may used to select a teleport destination.")]
  43. public ViveHand[] Controller;
  44. [HideInInspector]
  45. public int currentSource = 0;
  46.  
  47. /// Indicates the current use of teleportation.
  48. /// None: The player is not using teleportation right now
  49. /// Selecting: The player is currently selecting a teleport destination (holding down on touchpad)
  50. /// Teleporting: The player has selected a teleport destination and is currently teleporting now (fading in/out)
  51. public TeleportState CurrentTeleportState { get; private set; }
  52.  
  53. private Vector3 LastClickAngle = Vector3.zero;
  54. private bool IsClicking = false;
  55.  
  56. private bool FadingIn = false;
  57. private float TeleportTimeMarker = -1;
  58.  
  59. private Mesh PlaneMesh;
  60.  
  61. // new pescu for input
  62. [SteamVR_DefaultAction("Teleport")]
  63. public SteamVR_Action_Boolean teleport;
  64. [SteamVR_DefaultAction("stopAction")]
  65. public SteamVR_Action_Boolean stopAction;
  66.  
  67. // new pescu for output haptic
  68. [SteamVR_DefaultAction("Haptic")]
  69. public SteamVR_Action_Vibration hapticAction;
  70.  
  71. void Start()
  72. {
  73. int round = 0;
  74. foreach (ViveHand controls in Controller)
  75. {
  76. controls.SourceNumber = round;
  77. round += 1;
  78. }
  79. // Disable the pointer graphic (until the user holds down on the touchpad)
  80. Pointer.enabled = false;
  81.  
  82. // Ensure we mark the player as not teleporting
  83. CurrentTeleportState = TeleportState.None;
  84.  
  85. // Standard plane mesh used for "fade out" graphic when you teleport
  86. // This way you don't need to supply a simple plane mesh in the inspector
  87. PlaneMesh = new Mesh();
  88. Vector3[] verts = new Vector3[]
  89. {
  90. new Vector3(-1, -1, 0),
  91. new Vector3(-1, 1, 0),
  92. new Vector3(1, 1, 0),
  93. new Vector3(1, -1, 0)
  94. };
  95. int[] elts = new int[] { 0, 1, 2, 0, 2, 3 };
  96. PlaneMesh.vertices = verts;
  97. PlaneMesh.triangles = elts;
  98. PlaneMesh.RecalculateBounds();
  99.  
  100. if (FadeMaterial != null)
  101. FadeMaterialInstance = new Material(FadeMaterial);
  102. // Set some standard variables
  103. MaterialFadeID = Shader.PropertyToID("_Fade");
  104. EnabledAnimatorID = Animator.StringToHash("Enabled");
  105.  
  106. RoomBorder = GetComponent<BorderRenderer>();
  107.  
  108. Vector3 p0, p1, p2, p3;
  109. if (GetChaperoneBounds(out p0, out p1, out p2, out p3))
  110. {
  111. // Rotate to match camera rig rotation
  112. var originRotationMatrix = Matrix4x4.TRS(Vector3.zero, OriginTransform.rotation, Vector3.one);
  113.  
  114. BorderPointSet p = new BorderPointSet(new Vector3[] {
  115. originRotationMatrix * p0,
  116. originRotationMatrix * p1,
  117. originRotationMatrix * p2,
  118. originRotationMatrix * p3,
  119. originRotationMatrix * p0,
  120. });
  121. RoomBorder.Points = new BorderPointSet[]
  122. {
  123. p
  124. };
  125. }
  126.  
  127. RoomBorder.enabled = false;
  128. }
  129.  
  130. /// \brief Requests the chaperone boundaries of the SteamVR play area. This doesn't work if you haven't performed
  131. /// Room Setup.
  132. /// \param p0, p1, p2, p3 Points that make up the chaperone boundaries.
  133. ///
  134. /// \returns If the play area retrieval was successful
  135. public static bool GetChaperoneBounds(out Vector3 p0, out Vector3 p1, out Vector3 p2, out Vector3 p3)
  136. {
  137. var initOpenVR = (!SteamVR.active && !SteamVR.usingNativeSupport);
  138. if (initOpenVR)
  139. {
  140. var error = EVRInitError.None;
  141. OpenVR.Init(ref error, EVRApplicationType.VRApplication_Other);
  142. }
  143.  
  144. var chaperone = OpenVR.Chaperone;
  145. HmdQuad_t rect = new HmdQuad_t();
  146. bool success = (chaperone != null) && chaperone.GetPlayAreaRect(ref rect);
  147. p0 = new Vector3(rect.vCorners0.v0, rect.vCorners0.v1, rect.vCorners0.v2);
  148. p1 = new Vector3(rect.vCorners1.v0, rect.vCorners1.v1, rect.vCorners1.v2);
  149. p2 = new Vector3(rect.vCorners2.v0, rect.vCorners2.v1, rect.vCorners2.v2);
  150. p3 = new Vector3(rect.vCorners3.v0, rect.vCorners3.v1, rect.vCorners3.v2);
  151. if (!success)
  152. Debug.LogWarning("Failed to get Calibrated Play Area bounds! Make sure you have tracking first, and that your space is calibrated.");
  153.  
  154. if (initOpenVR)
  155. OpenVR.Shutdown();
  156.  
  157. return success;
  158. }
  159.  
  160. void OnPostRender()
  161. {
  162. if (CurrentTeleportState == TeleportState.Teleporting)
  163. {
  164. // Perform the fading in/fading out animation, if we are teleporting. This is essentially a triangle wave
  165. // in/out, and the user teleports when it is fully black.
  166. float alpha = Mathf.Clamp01((Time.time - TeleportTimeMarker) / (TeleportFadeDuration / 2));
  167. if (FadingIn)
  168. alpha = 1 - alpha;
  169.  
  170. Matrix4x4 local = Matrix4x4.TRS(Vector3.forward * 0.3f, Quaternion.identity, Vector3.one);
  171. FadeMaterialInstance.SetPass(0);
  172. FadeMaterialInstance.SetFloat(MaterialFadeID, alpha);
  173. Graphics.DrawMeshNow(PlaneMesh, transform.localToWorldMatrix * local);
  174. }
  175. }
  176.  
  177.  
  178. void Update()
  179. {
  180. int handNumber = 0;
  181. foreach (ViveHand hand in Controller)
  182. {
  183. if (teleport.GetState(hand.hand))
  184. {
  185. currentSource = handNumber;
  186. }
  187. handNumber += 1;
  188. }
  189. // If we are currently teleporting (ie handling the fade in/out transition)...
  190. if (CurrentTeleportState == TeleportState.Teleporting)
  191. {
  192. // Wait until half of the teleport time has passed before the next event (note: both the switch from fade
  193. // out to fade in and the switch from fade in to stop the animation is half of the fade duration)
  194. if (Time.time - TeleportTimeMarker >= TeleportFadeDuration / 2)
  195. {
  196. if (FadingIn)
  197. {
  198. // We have finished fading in
  199. CurrentTeleportState = TeleportState.None;
  200. }
  201. else
  202. {
  203. // We have finished fading out - time to teleport!
  204. Vector3 offset = OriginTransform.position - HeadTransform.position;
  205. offset.y = 0;
  206. OriginTransform.position = Pointer.SelectedPoint + offset;
  207. }
  208.  
  209. TeleportTimeMarker = Time.time;
  210. FadingIn = !FadingIn;
  211. }
  212. }
  213. // At this point, we are NOT actively teleporting. So now we care about controller input.
  214. else if (CurrentTeleportState == TeleportState.Selecting)
  215. {
  216. // Here, there is an active controller - that is, the user is holding down on the trackpad.
  217. // Poll controller for pertinent button data
  218.  
  219. bool shouldTeleport = !teleport.GetState(Controller[currentSource].hand);
  220. bool shouldCancel = stopAction.GetState(Controller[currentSource].hand);
  221. if (shouldTeleport || shouldCancel)
  222. {
  223. print("Teleport end");
  224. // If the user has decided to teleport (ie lets go of touchpad) then remove all visual indicators
  225. // related to selecting things and actually teleport
  226. // If the user has decided to cancel (ie squeezes grip button) then remove visual indicators and do nothing
  227. if (shouldTeleport && Pointer.PointOnNavMesh)
  228. {
  229. // Begin teleport sequence
  230. CurrentTeleportState = TeleportState.Teleporting;
  231. TeleportTimeMarker = Time.time;
  232. }
  233. else
  234. CurrentTeleportState = TeleportState.None;
  235.  
  236. // Reset active controller, disable pointer, disable visual indicators
  237. Pointer.enabled = false;
  238. RoomBorder.enabled = false;
  239. //RoomBorder.Transpose = Matrix4x4.TRS(OriginTransform.position, Quaternion.identity, Vector3.one);
  240. if (NavmeshAnimator != null)
  241. NavmeshAnimator.SetBool(EnabledAnimatorID, false);
  242.  
  243. Pointer.transform.parent = null;
  244. Pointer.transform.position = Vector3.zero;
  245. Pointer.transform.rotation = Quaternion.identity;
  246. Pointer.transform.localScale = Vector3.one;
  247. }
  248. else
  249. {
  250. // The user is still deciding where to teleport and has the touchpad held down.
  251. // Note: rendering of the parabolic pointer / marker is done in ParabolicPointer
  252. Vector3 offset = HeadTransform.position - OriginTransform.position;
  253. offset.y = 0;
  254.  
  255. // Render representation of where the chaperone bounds will be after teleporting
  256. RoomBorder.enabled = Pointer.PointOnNavMesh;
  257. RoomBorder.Transpose = Matrix4x4.TRS(Pointer.SelectedPoint - offset, Quaternion.identity, Vector3.one);
  258.  
  259. // Haptic feedback click every [HaptickClickAngleStep] degrees
  260. if (Pointer.CurrentParabolaAngleY >= 45) // Don't click when at max degrees
  261. LastClickAngle = Pointer.CurrentPointVector;
  262.  
  263. float angleClickDiff = Vector3.Angle(LastClickAngle, Pointer.CurrentPointVector);
  264. if (IsClicking && Mathf.Abs(angleClickDiff) > HapticClickAngleStep)
  265. {
  266. LastClickAngle = Pointer.CurrentPointVector;
  267. if (Pointer.PointOnNavMesh)
  268. {
  269. Pulse(0.1f, 1, 75, Controller[currentSource].hand);
  270. }
  271. }
  272.  
  273. // Trigger a stronger haptic pulse when "entering" a teleportable surface
  274. if (Pointer.PointOnNavMesh && !IsClicking)
  275. {
  276. IsClicking = true;
  277. Pulse(1, 1, 75, Controller[currentSource].hand);
  278. LastClickAngle = Pointer.CurrentPointVector;
  279. }
  280. else if (!Pointer.PointOnNavMesh && IsClicking)
  281. IsClicking = false;
  282. }
  283. }
  284. else //CurrentTeleportState == TeleportState.None
  285. {
  286. // At this point the user is not holding down on the touchpad at all or has canceled a teleport and hasn't
  287. // let go of the touchpad. So we wait for the user to press the touchpad and enable visual indicators
  288. // if necessary.
  289.  
  290.  
  291. //if (device.GetPressDown(SteamVR_Controller.ButtonMask.Touchpad))
  292. if (teleport.GetState(Controller[currentSource].hand))
  293. {
  294. print("Teleport start");
  295. // Set active controller to this controller, and enable the parabolic pointer and visual indicators
  296. // that the user can use to determine where they are able to teleport.
  297.  
  298. Pointer.transform.parent = Controller[currentSource].GetComponent<Transform>();
  299. Pointer.transform.localPosition = Vector3.zero;
  300. Pointer.transform.localRotation = Quaternion.identity;
  301. Pointer.transform.localScale = Vector3.one;
  302. Pointer.enabled = true;
  303.  
  304. CurrentTeleportState = TeleportState.Selecting;
  305.  
  306. if (NavmeshAnimator != null)
  307. NavmeshAnimator.SetBool(EnabledAnimatorID, true);
  308.  
  309. Pointer.ForceUpdateCurrentAngle();
  310. LastClickAngle = Pointer.CurrentPointVector;
  311. IsClicking = Pointer.PointOnNavMesh;
  312. }
  313. }
  314. }
  315.  
  316. private void Pulse(float duration, float frequency, float amplitude, SteamVR_Input_Sources source)
  317. {
  318. hapticAction.Execute(0, duration, frequency, amplitude, source);
  319. }
  320. }
  321.  
  322. /// \brief Represents the player's current use of the teleport machanic.
  323. public enum TeleportState
  324. {
  325. /// The player is not using teleportation right now
  326. None,
  327. /// The player is currently selecting a teleport destination (holding down on touchpad)
  328. Selecting,
  329. /// The player has selected a teleport destination and is currently teleporting now (fading in/out)
  330. Teleporting
  331. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement