void Start() { // Disable the pointer graphic (until the user holds down on the touchpad) Pointer.enabled = false; // Standard plane mesh used for "fade out" graphic when you teleport // This way you don't need to supply a simple plane mesh in the inspector PlaneMesh = new Mesh(); Vector3[] verts = new Vector3[] { new Vector3(-1, -1, 0), new Vector3(-1, 1, 0), new Vector3(1, 1, 0), new Vector3(1, -1, 0) }; int[] elts = new int[] { 0, 1, 2, 0, 2, 3 }; PlaneMesh.vertices = verts; PlaneMesh.triangles = elts; PlaneMesh.RecalculateBounds(); // Set some standard variables MaterialFadeID = Shader.PropertyToID("_Fade"); EnabledAnimatorID = Animator.StringToHash("Enabled"); RoomBorder = GetComponent<BorderRenderer>(); Vector3 p0, p1, p2, p3; if (GetChaperoneBounds(out p0, out p1, out p2, out p3)) { BorderPointSet p = new BorderPointSet(new Vector3[] { p0, p1, p2, p3, p0 }); RoomBorder.Points = new BorderPointSet[] { p }; } RoomBorder.enabled = false; }
void Start() { int round = 0; foreach (ViveHand controls in Controller) { controls.SourceNumber = round; round += 1; } // Disable the pointer graphic (until the user holds down on the touchpad) Pointer.enabled = false; // Ensure we mark the player as not teleporting CurrentTeleportState = TeleportState.None; // Standard plane mesh used for "fade out" graphic when you teleport // This way you don't need to supply a simple plane mesh in the inspector PlaneMesh = new Mesh(); Vector3[] verts = new Vector3[] { new Vector3(-1, -1, 0), new Vector3(-1, 1, 0), new Vector3(1, 1, 0), new Vector3(1, -1, 0) }; int[] elts = new int[] { 0, 1, 2, 0, 2, 3 }; PlaneMesh.vertices = verts; PlaneMesh.triangles = elts; PlaneMesh.RecalculateBounds(); if (FadeMaterial != null) { FadeMaterialInstance = new Material(FadeMaterial); } // Set some standard variables MaterialFadeID = Shader.PropertyToID("_Fade"); EnabledAnimatorID = Animator.StringToHash("Enabled"); RoomBorder = GetComponent <BorderRenderer>(); Vector3 p0, p1, p2, p3; if (GetChaperoneBounds(out p0, out p1, out p2, out p3)) { // Rotate to match camera rig rotation var originRotationMatrix = Matrix4x4.TRS(Vector3.zero, OriginTransform.rotation, Vector3.one); BorderPointSet p = new BorderPointSet(new Vector3[] { originRotationMatrix *p0, originRotationMatrix *p1, originRotationMatrix *p2, originRotationMatrix *p3, originRotationMatrix *p0, }); RoomBorder.Points = new BorderPointSet[] { p }; } RoomBorder.enabled = false; }
void Update() { //if (isLocalPlayer) //{ // If we are currently teleporting (ie handling the fade in/out transition)... if (CurrentTeleportState == TeleportState.Teleporting) { // Wait until half of the teleport time has passed before the next event (note: both the switch from fade // out to fade in and the switch from fade in to stop the animation is half of the fade duration) if (Time.time - TeleportTimeMarker >= TeleportFadeDuration / 2) { if (FadingIn) { // We have finished fading in CurrentTeleportState = TeleportState.None; } else { // We have finished fading out - time to teleport! Vector3 offset = OriginTransform.position - HeadTransform.position; offset.y = 0; OriginTransform.position = Pointer.SelectedPoint + offset; //OriginTransform.GetComponent<NavMeshAgent>().destination = OriginTransform.position; //control direction youre looking if (heldLong) { OriginTransform.localEulerAngles = viewController.localEulerAngles; heldLong = false; firstPadPress = true; } } TeleportTimeMarker = Time.time; FadingIn = !FadingIn; } } // At this point, we are NOT actively teleporting. So now we care about controller input. else if (CurrentTeleportState == TeleportState.Selecting) { Debug.Assert(ActiveController != null); // Here, there is an active controller - that is, the user is holding down on the trackpad. // Poll controller for pertinent button data int index = (int)ActiveController.index; var device = SteamVR_Controller.Input(index); bool shouldTeleport = device.GetPressUp(SteamVR_Controller.ButtonMask.Touchpad); bool shouldCancel = device.GetPressUp(SteamVR_Controller.ButtonMask.Grip); if (shouldTeleport || shouldCancel) { // If the user has decided to teleport (ie lets go of touchpad) then remove all visual indicators // related to selecting things and actually teleport // If the user has decided to cancel (ie squeezes grip button) then remove visual indicators and do nothing if (shouldTeleport && Pointer.PointOnNavMesh) { // Begin teleport sequence CurrentTeleportState = TeleportState.Teleporting; TeleportTimeMarker = Time.time; } else { CurrentTeleportState = TeleportState.None; heldLong = false; firstPadPress = true; } // Reset active controller, disable pointer, disable visual indicators ActiveController = null; Pointer.enabled = false; RoomBorder.enabled = false; //RoomBorder.Transpose = Matrix4x4.TRS(OriginTransform.position, Quaternion.identity, Vector3.one); if (NavmeshAnimator != null) { NavmeshAnimator.SetBool(EnabledAnimatorID, false); } Pointer.transform.parent = null; Pointer.transform.position = Vector3.zero; Pointer.transform.rotation = Quaternion.identity; Pointer.transform.localScale = Vector3.one; } else { // The user is still deciding where to teleport and has the touchpad held down. // Note: rendering of the parabolic pointer / marker is done in ParabolicPointer Vector3 offset = HeadTransform.position - OriginTransform.position; offset.y = 0; // Render representation of where the chaperone bounds will be after teleporting RoomBorder.enabled = Pointer.PointOnNavMesh; RoomBorder.Transpose = Matrix4x4.TRS(Pointer.SelectedPoint - offset, Quaternion.identity, Vector3.one); // Haptic feedback click every [HaptickClickAngleStep] degrees if (Pointer.CurrentParabolaAngleY >= 45) // Don't click when at max degrees { LastClickAngle = Pointer.CurrentPointVector; } float angleClickDiff = Vector3.Angle(LastClickAngle, Pointer.CurrentPointVector); if (IsClicking && Mathf.Abs(angleClickDiff) > HapticClickAngleStep) { LastClickAngle = Pointer.CurrentPointVector; if (Pointer.PointOnNavMesh) { device.TriggerHapticPulse(); } } // Trigger a stronger haptic pulse when "entering" a teleportable surface if (Pointer.PointOnNavMesh && !IsClicking) { IsClicking = true; device.TriggerHapticPulse(750); LastClickAngle = Pointer.CurrentPointVector; } else if (!Pointer.PointOnNavMesh && IsClicking) { IsClicking = false; } //control rotation of the box if (heldLong) { viewController.localEulerAngles = OriginTransform.localEulerAngles; newRotate = Mathf.Atan2(device.GetAxis().y, device.GetAxis().x) * Mathf.Rad2Deg - 90; viewController.localEulerAngles = new Vector3(0, ((viewController.localEulerAngles.y - newRotate)), 0); Vector3 p0, p1, p2, p3; if (GetChaperoneBounds(out p0, out p1, out p2, out p3)) { // Rotate to match camera rig rotation var originRotationMatrix = Matrix4x4.TRS(Vector3.zero, viewController.rotation, Vector3.one); BorderPointSet p = new BorderPointSet(new Vector3[] { originRotationMatrix *p0, originRotationMatrix *p1, originRotationMatrix *p2, originRotationMatrix *p3, originRotationMatrix *p0, }); RoomBorder.Points = new BorderPointSet[] { p }; } } if (firstPadPress) { StartCoroutine(WaitHold()); firstPadPress = false; } } } else //CurrentTeleportState == TeleportState.None { // At this point the user is not holding down on the touchpad at all or has canceled a teleport and hasn't // let go of the touchpad. So we wait for the user to press the touchpad and enable visual indicators // if necessary. foreach (SteamVR_TrackedObject obj in Controllers) { int index = (int)obj.index; if (index == -1) { continue; } var device = SteamVR_Controller.Input(index); if (device.GetPressDown(SteamVR_Controller.ButtonMask.Touchpad)) { // Set active controller to this controller, and enable the parabolic pointer and visual indicators // that the user can use to determine where they are able to teleport. ActiveController = obj; Pointer.transform.parent = obj.transform; Pointer.transform.localPosition = Vector3.zero; Pointer.transform.localRotation = Quaternion.identity; Pointer.transform.localScale = Vector3.one; Pointer.enabled = true; CurrentTeleportState = TeleportState.Selecting; if (NavmeshAnimator != null) { NavmeshAnimator.SetBool(EnabledAnimatorID, true); } Pointer.ForceUpdateCurrentAngle(); LastClickAngle = Pointer.CurrentPointVector; IsClicking = Pointer.PointOnNavMesh; } } } }
/// \brief Given some mesh m, calculates a number of polylines that border the mesh. This may return more than /// one polyline if, for example, the mesh has holes in it or if the mesh is separated in two pieces. /// \param m input mesh /// \returns array of cyclic polylines private static BorderPointSet[] FindBorderEdges(Mesh m) { // First, get together all the edges in the mesh and find out // how many times each edge is used. Edges that are only used // once are border edges. // Key: edges (note that because of how the hashcode / equals() is set up, two equivalent edges will effectively // be equal) // Value: How many times this edge shows up in the mesh. Any keys with a value of 1 are border edges. Dictionary <Edge, int> edges = new Dictionary <Edge, int>(); for (int x = 0; x < m.triangles.Length / 3; x++) { int p1 = m.triangles[x * 3]; int p2 = m.triangles[x * 3 + 1]; int p3 = m.triangles[x * 3 + 2]; Edge[] e = new Edge[3]; e[0] = new Edge(p1, p2); e[1] = new Edge(p2, p3); e[2] = new Edge(p3, p1); foreach (Edge d in e) { int curval; edges.TryGetValue(d, out curval); // 0 if nonexistant edges[d] = curval + 1; } } // Next, consolidate all of the border edges into one List<Edge> List <Edge> border = new List <Edge>(); foreach (KeyValuePair <Edge, int> p in edges) { if (p.Value == 1) // border edge == edge only used once. { border.Add(p.Key); } } // Perform the following routine: // 1. Pick any unvisited edge segment [v_start,v_next] and add these vertices to the polygon loop. // 2. Find the unvisited edge segment [v_i,v_j] that has either v_i = v_next or v_j = v_next and add the // other vertex (the one not equal to v_next) to the polygon loop. Reset v_next as this newly added vertex, // mark the edge as visited and continue from 2. // 3. Traversal is done when we get back to v_start. // Source: http://stackoverflow.com/questions/14108553/get-border-edges-of-mesh-in-winding-order bool[] visited = new bool[border.Count]; bool finished = false; int cur_index = 0; List <Vector3[]> ret = new List <Vector3[]>(); while (!finished) { int[] raw = FindPolylineFromEdges(cur_index, visited, border); Vector3[] fmt = new Vector3[raw.Length]; for (int x = 0; x < raw.Length; x++) { fmt[x] = m.vertices[raw[x]]; } ret.Add(fmt); finished = true; for (int x = 0; x < visited.Length; x++) { if (!visited[x]) { cur_index = x; finished = false; break; } } } BorderPointSet[] ret_set = new BorderPointSet[ret.Count]; for (int x = 0; x < ret.Count; x++) { ret_set[x] = new BorderPointSet(ret[x]); } return(ret_set); }
/// \brief Given some mesh m, calculates a number of polylines that border the mesh. This may return more than /// one polyline if, for example, the mesh has holes in it or if the mesh is separated in two pieces. /// /// \param m input mesh /// \returns array of cyclic polylines private static BorderPointSet[] FindBorderEdges(Mesh m) { // First, get together all the edges in the mesh and find out // how many times each edge is used. Edges that are only used // once are border edges. // Key: edges (note that because of how the hashcode / equals() is set up, two equivalent edges will effectively // be equal) // Value: How many times this edge shows up in the mesh. Any keys with a value of 1 are border edges. Dictionary<Edge, int> edges = new Dictionary<Edge, int>(); for (int x = 0; x < m.triangles.Length / 3; x++) { int p1 = m.triangles[x * 3]; int p2 = m.triangles[x * 3 + 1]; int p3 = m.triangles[x * 3 + 2]; Edge[] e = new Edge[3]; e[0] = new Edge(p1, p2); e[1] = new Edge(p2, p3); e[2] = new Edge(p3, p1); foreach (Edge d in e) { int curval; edges.TryGetValue(d, out curval); // 0 if nonexistant edges[d] = curval + 1; } } // Next, consolidate all of the border edges into one List<Edge> List<Edge> border = new List<Edge>(); foreach (KeyValuePair<Edge, int> p in edges) { if (p.Value == 1) // border edge == edge only used once. border.Add(p.Key); } // Perform the following routine: // 1. Pick any unvisited edge segment [v_start,v_next] and add these vertices to the polygon loop. // 2. Find the unvisited edge segment [v_i,v_j] that has either v_i = v_next or v_j = v_next and add the // other vertex (the one not equal to v_next) to the polygon loop. Reset v_next as this newly added vertex, // mark the edge as visited and continue from 2. // 3. Traversal is done when we get back to v_start. // Source: http://stackoverflow.com/questions/14108553/get-border-edges-of-mesh-in-winding-order bool[] visited = new bool[border.Count]; bool finished = false; int cur_index = 0; List<Vector3[]> ret = new List<Vector3[]>(); while(!finished) { int[] raw = FindPolylineFromEdges(cur_index, visited, border); Vector3[] fmt = new Vector3[raw.Length]; for (int x = 0; x < raw.Length; x++) fmt[x] = m.vertices[raw[x]]; ret.Add(fmt); finished = true; for (int x=0;x<visited.Length;x++) { if (!visited[x]) { cur_index = x; finished = false; break; } } } BorderPointSet[] ret_set = new BorderPointSet[ret.Count]; for (int x = 0; x < ret.Count; x++) { ret_set[x] = new BorderPointSet(ret[x]); } return ret_set; }