IMHOTEP Framework
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Pages
SteamVR_Frustum.cs
1 //======= Copyright (c) Valve Corporation, All rights reserved. ===============
2 //
3 // Purpose: Generates a mesh based on field of view.
4 //
5 //=============================================================================
6 
7 using UnityEngine;
8 using Valve.VR;
9 
10 [ExecuteInEditMode, RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
11 public class SteamVR_Frustum : MonoBehaviour
12 {
13  public SteamVR_TrackedObject.EIndex index;
14 
15  public float fovLeft = 45, fovRight = 45, fovTop = 45, fovBottom = 45, nearZ = 0.5f, farZ = 2.5f;
16 
17  public void UpdateModel()
18  {
19  fovLeft = Mathf.Clamp(fovLeft, 1, 89);
20  fovRight = Mathf.Clamp(fovRight, 1, 89);
21  fovTop = Mathf.Clamp(fovTop, 1, 89);
22  fovBottom = Mathf.Clamp(fovBottom, 1, 89);
23  farZ = Mathf.Max(farZ, nearZ + 0.01f);
24  nearZ = Mathf.Clamp(nearZ, 0.01f, farZ - 0.01f);
25 
26  var lsin = Mathf.Sin(-fovLeft * Mathf.Deg2Rad);
27  var rsin = Mathf.Sin(fovRight * Mathf.Deg2Rad);
28  var tsin = Mathf.Sin(fovTop * Mathf.Deg2Rad);
29  var bsin = Mathf.Sin(-fovBottom * Mathf.Deg2Rad);
30 
31  var lcos = Mathf.Cos(-fovLeft * Mathf.Deg2Rad);
32  var rcos = Mathf.Cos(fovRight * Mathf.Deg2Rad);
33  var tcos = Mathf.Cos(fovTop * Mathf.Deg2Rad);
34  var bcos = Mathf.Cos(-fovBottom * Mathf.Deg2Rad);
35 
36  var corners = new Vector3[] {
37  new Vector3(lsin * nearZ / lcos, tsin * nearZ / tcos, nearZ), //tln
38  new Vector3(rsin * nearZ / rcos, tsin * nearZ / tcos, nearZ), //trn
39  new Vector3(rsin * nearZ / rcos, bsin * nearZ / bcos, nearZ), //brn
40  new Vector3(lsin * nearZ / lcos, bsin * nearZ / bcos, nearZ), //bln
41  new Vector3(lsin * farZ / lcos, tsin * farZ / tcos, farZ ), //tlf
42  new Vector3(rsin * farZ / rcos, tsin * farZ / tcos, farZ ), //trf
43  new Vector3(rsin * farZ / rcos, bsin * farZ / bcos, farZ ), //brf
44  new Vector3(lsin * farZ / lcos, bsin * farZ / bcos, farZ ), //blf
45  };
46 
47  var triangles = new int[] {
48  // 0, 1, 2, 0, 2, 3, // near
49  // 0, 2, 1, 0, 3, 2, // near
50  // 4, 5, 6, 4, 6, 7, // far
51  // 4, 6, 5, 4, 7, 6, // far
52  0, 4, 7, 0, 7, 3, // left
53  0, 7, 4, 0, 3, 7, // left
54  1, 5, 6, 1, 6, 2, // right
55  1, 6, 5, 1, 2, 6, // right
56  0, 4, 5, 0, 5, 1, // top
57  0, 5, 4, 0, 1, 5, // top
58  2, 3, 7, 2, 7, 6, // bottom
59  2, 7, 3, 2, 6, 7, // bottom
60  };
61 
62  int j = 0;
63  var vertices = new Vector3[triangles.Length];
64  var normals = new Vector3[triangles.Length];
65  for (int i = 0; i < triangles.Length / 3; i++)
66  {
67  var a = corners[triangles[i * 3 + 0]];
68  var b = corners[triangles[i * 3 + 1]];
69  var c = corners[triangles[i * 3 + 2]];
70  var n = Vector3.Cross(b - a, c - a).normalized;
71  normals[i * 3 + 0] = n;
72  normals[i * 3 + 1] = n;
73  normals[i * 3 + 2] = n;
74  vertices[i * 3 + 0] = a;
75  vertices[i * 3 + 1] = b;
76  vertices[i * 3 + 2] = c;
77  triangles[i * 3 + 0] = j++;
78  triangles[i * 3 + 1] = j++;
79  triangles[i * 3 + 2] = j++;
80  }
81 
82  var mesh = new Mesh();
83  mesh.vertices = vertices;
84  mesh.normals = normals;
85  mesh.triangles = triangles;
86 
87  GetComponent<MeshFilter>().mesh = mesh;
88  }
89 
90  private void OnDeviceConnected(int i, bool connected)
91  {
92  if (i != (int)index)
93  return;
94 
95  GetComponent<MeshFilter>().mesh = null;
96 
97  if (connected)
98  {
99  var system = OpenVR.System;
100  if (system != null && system.GetTrackedDeviceClass((uint)i) == ETrackedDeviceClass.TrackingReference)
101  {
102  var error = ETrackedPropertyError.TrackedProp_Success;
103  var result = system.GetFloatTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_FieldOfViewLeftDegrees_Float, ref error);
104  if (error == ETrackedPropertyError.TrackedProp_Success)
105  fovLeft = result;
106 
107  result = system.GetFloatTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_FieldOfViewRightDegrees_Float, ref error);
108  if (error == ETrackedPropertyError.TrackedProp_Success)
109  fovRight = result;
110 
111  result = system.GetFloatTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_FieldOfViewTopDegrees_Float, ref error);
112  if (error == ETrackedPropertyError.TrackedProp_Success)
113  fovTop = result;
114 
115  result = system.GetFloatTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_FieldOfViewBottomDegrees_Float, ref error);
116  if (error == ETrackedPropertyError.TrackedProp_Success)
117  fovBottom = result;
118 
119  result = system.GetFloatTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_TrackingRangeMinimumMeters_Float, ref error);
120  if (error == ETrackedPropertyError.TrackedProp_Success)
121  nearZ = result;
122 
123  result = system.GetFloatTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_TrackingRangeMaximumMeters_Float, ref error);
124  if (error == ETrackedPropertyError.TrackedProp_Success)
125  farZ = result;
126 
127  UpdateModel();
128  }
129  }
130  }
131 
132  void OnEnable()
133  {
134  GetComponent<MeshFilter>().mesh = null;
135  SteamVR_Events.DeviceConnected.Listen(OnDeviceConnected);
136  }
137 
138  void OnDisable()
139  {
140  SteamVR_Events.DeviceConnected.Remove(OnDeviceConnected);
141  GetComponent<MeshFilter>().mesh = null;
142  }
143 
144 #if UNITY_EDITOR
145  void Update()
146  {
147  if (!Application.isPlaying)
148  UpdateModel();
149  }
150 #endif
151 }