-
Notifications
You must be signed in to change notification settings - Fork 3
/
CameraScript.js
165 lines (143 loc) · 4.84 KB
/
CameraScript.js
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
155
156
157
158
159
160
161
162
163
164
165
// This script should be attached to a Camera object
// in Unity. Once a Plane object is specified as the
// "projectionScreen", the script computes a suitable
// view and projection matrix for the camera.
// The code is based on Robert Kooima's publication
// "Generalized Perspective Projection," 2009,
// http://csc.lsu.edu/~kooima/pdfs/gen-perspective.pdf
#pragma strict
public var projectionScreen : GameObject;
public var estimateViewFrustum : boolean = true;
function LateUpdate() {
if (null != projectionScreen)
{
var pa : Vector3 =
projectionScreen.transform.TransformPoint(
Vector3(-5.0, 0.0, -5.0));
// lower left corner in world coordinates
var pb : Vector3 =
projectionScreen.transform.TransformPoint(
Vector3(5.0, 0.0, -5.0));
// lower right corner
var pc : Vector3 =
projectionScreen.transform.TransformPoint(
Vector3(-5.0, 0.0, 5.0));
// upper left corner
var pe : Vector3 = transform.position;
// eye position
var n : float = GetComponent.<Camera>().nearClipPlane;
// distance of near clipping plane
var f : float = GetComponent.<Camera>().farClipPlane;
// distance of far clipping plane
var va : Vector3; // from pe to pa
var vb : Vector3; // from pe to pb
var vc : Vector3; // from pe to pc
var vr : Vector3; // right axis of screen
var vu : Vector3; // up axis of screen
var vn : Vector3; // normal vector of screen
var l : float; // distance to left screen edge
var r : float; // distance to right screen edge
var b : float; // distance to bottom screen edge
var t : float; // distance to top screen edge
var d : float; // distance from eye to screen
vr = pb - pa;
vu = pc - pa;
vr.Normalize();
vu.Normalize();
vn = -Vector3.Cross(vr, vu);
// we need the minus sign because Unity
// uses a left-handed coordinate system
vn.Normalize();
va = pa - pe;
vb = pb - pe;
vc = pc - pe;
d = -Vector3.Dot(va, vn);
l = Vector3.Dot(vr, va) * n / d;
r = Vector3.Dot(vr, vb) * n / d;
b = Vector3.Dot(vu, va) * n / d;
t = Vector3.Dot(vu, vc) * n / d;
var p : Matrix4x4; // projection matrix
p[0,0] = 2.0*n/(r-l);
p[0,1] = 0.0;
p[0,2] = (r+l)/(r-l);
p[0,3] = 0.0;
p[1,0] = 0.0;
p[1,1] = 2.0*n/(t-b);
p[1,2] = (t+b)/(t-b);
p[1,3] = 0.0;
p[2,0] = 0.0;
p[2,1] = 0.0;
p[2,2] = (f+n)/(n-f);
p[2,3] = 2.0*f*n/(n-f);
p[3,0] = 0.0;
p[3,1] = 0.0;
p[3,2] = -1.0;
p[3,3] = 0.0;
var rm : Matrix4x4; // rotation matrix;
rm[0,0] = vr.x;
rm[0,1] = vr.y;
rm[0,2] = vr.z;
rm[0,3] = 0.0;
rm[1,0] = vu.x;
rm[1,1] = vu.y;
rm[1,2] = vu.z;
rm[1,3] = 0.0;
rm[2,0] = vn.x;
rm[2,1] = vn.y;
rm[2,2] = vn.z;
rm[2,3] = 0.0;
rm[3,0] = 0.0;
rm[3,1] = 0.0;
rm[3,2] = 0.0;
rm[3,3] = 1.0;
var tm : Matrix4x4; // translation matrix;
tm[0,0] = 1.0;
tm[0,1] = 0.0;
tm[0,2] = 0.0;
tm[0,3] = -pe.x;
tm[1,0] = 0.0;
tm[1,1] = 1.0;
tm[1,2] = 0.0;
tm[1,3] = -pe.y;
tm[2,0] = 0.0;
tm[2,1] = 0.0;
tm[2,2] = 1.0;
tm[2,3] = -pe.z;
tm[3,0] = 0.0;
tm[3,1] = 0.0;
tm[3,2] = 0.0;
tm[3,3] = 1.0;
// set matrices
GetComponent.<Camera>().projectionMatrix = p;
GetComponent.<Camera>().worldToCameraMatrix = rm * tm;
// The original paper puts everything into the projection
// matrix (i.e. sets it to p * rm * tm and the other
// matrix to the identity), but this doesn't appear to
// work with Unity's shadow maps.
if (estimateViewFrustum)
{
// rotate camera to screen for culling to work
var q : Quaternion;
q.SetLookRotation((0.5 * (pb + pc) - pe), vu);
// look at center of screen
GetComponent.<Camera>().transform.rotation = q;
// set fieldOfView to a conservative estimate
// to make frustum tall enough
if (GetComponent.<Camera>().aspect >= 1.0)
{
GetComponent.<Camera>().fieldOfView = Mathf.Rad2Deg *
Mathf.Atan(((pb-pa).magnitude + (pc-pa).magnitude)
/ va.magnitude);
}
else
{
// take the camera aspect into account to
// make the frustum wide enough
GetComponent.<Camera>().fieldOfView =
Mathf.Rad2Deg / GetComponent.<Camera>().aspect *
Mathf.Atan(((pb-pa).magnitude + (pc-pa).magnitude)
/ va.magnitude);
}
}
}
}