Skip to content

Instantly share code, notes, and snippets.

@tangentstorm
Created December 5, 2017 16:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tangentstorm/f7d98f506c1314c060db26988aaa4cb0 to your computer and use it in GitHub Desktop.
Save tangentstorm/f7d98f506c1314c060db26988aaa4cb0 to your computer and use it in GitHub Desktop.
BeaconTeleport for unity3d / VRTK
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VRTK;
/* This class lets you leave a beacon in the scene and teleport to it later.
*
* It should be attached to an object that also has a VRTK_ControllerEvents
* component attached.
*
* You also have to supply a transform to use as the beacon.
*/
public class BeaconTeleport : VRTK_BasicTeleport {
public Transform beacon;
// same as basicteleport, but move the beacon instead of the playArea
protected override Vector3 SetNewPosition(Vector3 position, Transform target, bool forceDestinationPosition) {
if (ValidRigObjects()) {
beacon.position = CheckTerrainCollision(position, target, forceDestinationPosition);
return beacon.position;
}
return Vector3.zero;
}
// same as basicteleport, but rotate the beacon instead of the playArea
// !! (I think this only actually does anything if you're using a rotated
// destination marker?? not sure. actual rotation is handled
// by ProcessOrientation, below)
protected override Quaternion SetNewRotation(Quaternion? rotation) {
if (ValidRigObjects()) {
if (rotation != null) {
beacon.rotation = (Quaternion)rotation;
}
return beacon.rotation;
}
return Quaternion.identity;
}
// this does the work of moving the player to the beacon
public void TeleportToBeacon() {
Blink(blinkTransitionSpeed);
playArea.SetPositionAndRotation(beacon.position, beacon.rotation);
}
public void Start() {
var ce = GetComponent<VRTK_ControllerEvents>();
if (ce == null) Debug.LogError("You need to add a VRTK_ControllerEvents!");
else {
ce.TriggerClicked += OnTeleportButton;
ce.GripPressed += OnResetBeaconRotationButton;
}
}
private void OnResetBeaconRotationButton(object sender, ControllerInteractionEventArgs e) {
print("resetting beacon rotation");
beacon.rotation = Quaternion.identity;
}
private void OnTeleportButton(object sender, ControllerInteractionEventArgs e) {
TeleportToBeacon();
}
// the beacon's new position is the exact point of contact from the raycast.
// the new rotation brings the beacon's "up" in line with the surface normal.
protected override void DoTeleport(object sender, DestinationMarkerEventArgs e) {
if (enableTeleport && ValidLocation(e.target, e.destinationPosition) && e.enableTeleport) {
StartTeleport(sender, e);
// Quaternion updatedRotation = SetNewRotation(e.destinationRotation);
// Vector3 newPosition = e.destinationPosition; // GetNewPosition(e.destinationPosition, e.target, e.forceDestinationPosition);
// Vector3 updatedPosition = SetNewPosition(newPosition, e.target, e.forceDestinationPosition);
// ProcessOrientation(sender, e, updatedPosition, updatedRotation);
// first, move beacon to right place:
beacon.position = e.destinationPosition;
// align the beacon to the new "floor"
// beacon.rotation = Quaternion.identity;
beacon.rotation = Quaternion.FromToRotation(Vector3.up, e.raycastHit.normal);
// beacon.rotation = Quaternion.FromToRotation(beacon.forward, headset.forward);
// align beacon with player's gaze
// beacon.rotation = Quaternion.LookRotation(headset.forward, e.raycastHit.normal);
// There is probably a simpler way to do this with trig or quaternions, but
// I can't figure it out right now, so let's just use geometry.
//
// Let's pretend that the headset and the controller are the same point, because
// that's close enough. This is point P, for player.
//
// We have a line segment from P to D (the teleport destination), and an imaginary
// ray starting at P and following the vector in headset.forward (F).
//
// Right now, the beacon is aligned so that its y axis (up) matches the
// destination's surface normal, and its x and z axes are parallel to the
// global x and z axes. We want to rotate the beacon around its y axis so that
// the z axis (forward.. or possibly backward?) is parallel to headset.forward.
//
// So we need to construct a point that starts at D and follows F, and then
// pivot the beacon around its y axis so that it looks at that point.
//
// Quaternion.LookRotation does this, but the problem is that it needs the
// up and forward vectors to be perpendicular.
//
// The cross product of the normal and headset.right should give a new
// forward vector. (it could also come up with a backward vector, but in
// practice, it doesn't seem to.. we might need to do a sign flip here
// or something.
Vector3 temp = Vector3.Cross(e.raycastHit.normal, headset.right);
beacon.rotation = Quaternion.LookRotation(temp, e.raycastHit.normal);
EndTeleport(sender, e);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment