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