rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <math.h>
|
nuclear@0
|
3 #include "camera.h"
|
nuclear@0
|
4
|
nuclear@0
|
5 static void calc_sample_pos_rec(int sidx, float xsz, float ysz, float *pos);
|
nuclear@0
|
6
|
nuclear@0
|
7 Camera::Camera()
|
nuclear@0
|
8 {
|
nuclear@0
|
9 vfov = M_PI / 4.0;
|
nuclear@0
|
10 cached_matrix_valid = false;
|
nuclear@0
|
11
|
nuclear@0
|
12 rdir_cache_width = rdir_cache_height = 0;
|
nuclear@0
|
13 rdir_cache = 0;
|
nuclear@0
|
14 }
|
nuclear@0
|
15
|
nuclear@0
|
16 Camera::Camera(const Vector3 &p)
|
nuclear@0
|
17 : pos(p)
|
nuclear@0
|
18 {
|
nuclear@0
|
19 vfov = M_PI / 4.0;
|
nuclear@0
|
20 cached_matrix_valid = false;
|
nuclear@0
|
21
|
nuclear@0
|
22 rdir_cache_width = rdir_cache_height = 0;
|
nuclear@0
|
23 rdir_cache = 0;
|
nuclear@0
|
24 }
|
nuclear@0
|
25
|
nuclear@0
|
26 Camera::~Camera()
|
nuclear@0
|
27 {
|
nuclear@0
|
28 delete [] rdir_cache;
|
nuclear@0
|
29 }
|
nuclear@0
|
30
|
nuclear@0
|
31 void Camera::set_fov(float vfov)
|
nuclear@0
|
32 {
|
nuclear@0
|
33 this->vfov = vfov;
|
nuclear@0
|
34
|
nuclear@0
|
35 // invalidate the dir cache
|
nuclear@0
|
36 delete [] rdir_cache;
|
nuclear@0
|
37 }
|
nuclear@0
|
38
|
nuclear@0
|
39 float Camera::get_fov() const
|
nuclear@0
|
40 {
|
nuclear@0
|
41 return vfov;
|
nuclear@0
|
42 }
|
nuclear@0
|
43
|
nuclear@0
|
44 void Camera::set_position(const Vector3 &pos)
|
nuclear@0
|
45 {
|
nuclear@0
|
46 this->pos = pos;
|
nuclear@0
|
47 cached_matrix_valid = false; // invalidate the cached matrix
|
nuclear@0
|
48 }
|
nuclear@0
|
49
|
nuclear@0
|
50 const Vector3 &Camera::get_position() const
|
nuclear@0
|
51 {
|
nuclear@0
|
52 return pos;
|
nuclear@0
|
53 }
|
nuclear@0
|
54
|
nuclear@0
|
55 const Matrix4x4 &Camera::get_matrix() const
|
nuclear@0
|
56 {
|
nuclear@0
|
57 if(!cached_matrix_valid) {
|
nuclear@0
|
58 calc_matrix(&cached_matrix);
|
nuclear@0
|
59 cached_matrix_valid = true;
|
nuclear@0
|
60 }
|
nuclear@0
|
61 return cached_matrix;
|
nuclear@0
|
62 }
|
nuclear@0
|
63
|
nuclear@0
|
64 Vector2 Camera::calc_sample_pos(int x, int y, int xsz, int ysz, int sample) const
|
nuclear@0
|
65 {
|
nuclear@0
|
66 float ppos[2];
|
nuclear@0
|
67 float aspect = (float)xsz / (float)ysz;
|
nuclear@0
|
68
|
nuclear@0
|
69 float pwidth = 2.0 * aspect / (float)xsz;
|
nuclear@0
|
70 float pheight = 2.0 / (float)ysz;
|
nuclear@0
|
71
|
nuclear@0
|
72 ppos[0] = (float)x * pwidth - aspect;
|
nuclear@0
|
73 ppos[1] = 1.0 - (float)y * pheight;
|
nuclear@0
|
74
|
nuclear@0
|
75 calc_sample_pos_rec(sample, pwidth, pheight, ppos);
|
nuclear@0
|
76 return Vector2(ppos[0], ppos[1]);
|
nuclear@0
|
77 }
|
nuclear@0
|
78
|
nuclear@0
|
79 Ray Camera::get_primary_ray(int x, int y, int xsz, int ysz, int sample) const
|
nuclear@0
|
80 {
|
nuclear@0
|
81 #pragma omp single
|
nuclear@0
|
82 {
|
nuclear@0
|
83 if(!rdir_cache || rdir_cache_width != xsz || rdir_cache_height != ysz) {
|
nuclear@0
|
84 printf("calculating primary ray direction cache\n");
|
nuclear@0
|
85
|
nuclear@0
|
86 delete [] rdir_cache;
|
nuclear@0
|
87 rdir_cache = new Vector3[xsz * ysz];
|
nuclear@0
|
88
|
nuclear@0
|
89 #pragma omp parallel for
|
nuclear@0
|
90 for(int i=0; i<ysz; i++) {
|
nuclear@0
|
91 Vector3 *rdir = rdir_cache + i * xsz;
|
nuclear@0
|
92 for(int j=0; j<xsz; j++) {
|
nuclear@0
|
93 Vector2 ppos = calc_sample_pos(j, i, xsz, ysz, 0);
|
nuclear@0
|
94
|
nuclear@0
|
95 rdir->x = ppos.x;
|
nuclear@0
|
96 rdir->y = ppos.y;
|
nuclear@0
|
97 rdir->z = 1.0 / tan(vfov / 2.0);
|
nuclear@0
|
98 rdir->normalize();
|
nuclear@0
|
99
|
nuclear@0
|
100 rdir++;
|
nuclear@0
|
101 }
|
nuclear@0
|
102 }
|
nuclear@0
|
103 rdir_cache_width = xsz;
|
nuclear@0
|
104 rdir_cache_height = ysz;
|
nuclear@0
|
105 }
|
nuclear@0
|
106 }
|
nuclear@0
|
107
|
nuclear@0
|
108 Ray ray;
|
nuclear@0
|
109 ray.origin = pos;
|
nuclear@0
|
110 ray.dir = rdir_cache[y * xsz + x];
|
nuclear@0
|
111
|
nuclear@0
|
112 // transform the ray direction with the camera matrix
|
nuclear@0
|
113 Matrix4x4 mat = get_matrix();
|
nuclear@0
|
114 mat.m[0][3] = mat.m[1][3] = mat.m[2][3] = mat.m[3][0] = mat.m[3][1] = mat.m[3][2] = 0.0;
|
nuclear@0
|
115 mat.m[3][3] = 1.0;
|
nuclear@0
|
116
|
nuclear@0
|
117 ray.dir = ray.dir.transformed(mat);
|
nuclear@0
|
118 return ray;
|
nuclear@0
|
119 }
|
nuclear@0
|
120
|
nuclear@0
|
121 TargetCamera::TargetCamera() {}
|
nuclear@0
|
122
|
nuclear@0
|
123 TargetCamera::TargetCamera(const Vector3 &pos, const Vector3 &targ)
|
nuclear@0
|
124 : Camera(pos), target(targ)
|
nuclear@0
|
125 {
|
nuclear@0
|
126 }
|
nuclear@0
|
127
|
nuclear@0
|
128 void TargetCamera::set_target(const Vector3 &targ)
|
nuclear@0
|
129 {
|
nuclear@0
|
130 target = targ;
|
nuclear@0
|
131 cached_matrix_valid = false; // invalidate the cached matrix
|
nuclear@0
|
132 }
|
nuclear@0
|
133
|
nuclear@0
|
134 const Vector3 &TargetCamera::get_target() const
|
nuclear@0
|
135 {
|
nuclear@0
|
136 return target;
|
nuclear@0
|
137 }
|
nuclear@0
|
138
|
nuclear@0
|
139 void TargetCamera::calc_matrix(Matrix4x4 *mat) const
|
nuclear@0
|
140 {
|
nuclear@0
|
141 Vector3 up(0, 1, 0);
|
nuclear@0
|
142 Vector3 dir = (target - pos).normalized();
|
nuclear@0
|
143 Vector3 right = cross_product(up, dir);
|
nuclear@0
|
144 up = cross_product(dir, right);
|
nuclear@0
|
145
|
nuclear@0
|
146 *mat = Matrix4x4(
|
nuclear@0
|
147 right.x, up.x, dir.x, pos.x,
|
nuclear@0
|
148 right.y, up.y, dir.y, pos.y,
|
nuclear@0
|
149 right.z, up.z, dir.z, pos.z,
|
nuclear@0
|
150 0.0, 0.0, 0.0, 1.0);
|
nuclear@0
|
151 }
|
nuclear@0
|
152
|
nuclear@0
|
153 void FlyCamera::input_move(float x, float y, float z)
|
nuclear@0
|
154 {
|
nuclear@0
|
155 static const Vector3 vfwd(0, 0, 1), vright(1, 0, 0);
|
nuclear@0
|
156
|
nuclear@0
|
157 Vector3 k = vfwd.transformed(rot);
|
nuclear@0
|
158 Vector3 i = vright.transformed(rot);
|
nuclear@0
|
159 Vector3 j = cross_product(k, i);
|
nuclear@0
|
160
|
nuclear@0
|
161 pos += i * x + j * y + k * z;
|
nuclear@0
|
162 cached_matrix_valid = false;
|
nuclear@0
|
163 }
|
nuclear@0
|
164
|
nuclear@0
|
165 void FlyCamera::input_rotate(float x, float y, float z)
|
nuclear@0
|
166 {
|
nuclear@0
|
167 Vector3 axis(x, y, z);
|
nuclear@0
|
168 float axis_len = axis.length();
|
nuclear@0
|
169 if(fabs(axis_len) < 1e-5) {
|
nuclear@0
|
170 return;
|
nuclear@0
|
171 }
|
nuclear@0
|
172 rot.rotate(axis / axis_len, -axis_len);
|
nuclear@0
|
173 rot.normalize();
|
nuclear@0
|
174
|
nuclear@0
|
175 cached_matrix_valid = false;
|
nuclear@0
|
176 }
|
nuclear@0
|
177
|
nuclear@0
|
178 void FlyCamera::calc_matrix(Matrix4x4 *mat) const
|
nuclear@0
|
179 {
|
nuclear@0
|
180 Matrix4x4 tmat;
|
nuclear@0
|
181 tmat.set_translation(pos);
|
nuclear@0
|
182
|
nuclear@0
|
183 Matrix3x3 rmat = rot.get_rotation_matrix();
|
nuclear@0
|
184
|
nuclear@0
|
185 *mat = tmat * Matrix4x4(rmat);
|
nuclear@0
|
186 }
|
nuclear@0
|
187
|
nuclear@0
|
188 /* generates a sample position for sample number sidx, in the unit square
|
nuclear@0
|
189 * by recursive subdivision and jittering
|
nuclear@0
|
190 */
|
nuclear@0
|
191 static void calc_sample_pos_rec(int sidx, float xsz, float ysz, float *pos)
|
nuclear@0
|
192 {
|
nuclear@0
|
193 static const float subpt[4][2] = {
|
nuclear@0
|
194 {-0.25, -0.25}, {0.25, -0.25}, {-0.25, 0.25}, {0.25, 0.25}
|
nuclear@0
|
195 };
|
nuclear@0
|
196
|
nuclear@0
|
197 if(!sidx) {
|
nuclear@0
|
198 return;
|
nuclear@0
|
199 }
|
nuclear@0
|
200
|
nuclear@0
|
201 /* determine which quadrant to recurse into */
|
nuclear@0
|
202 int quadrant = ((sidx - 1) % 4);
|
nuclear@0
|
203 pos[0] += subpt[quadrant][0] * xsz;
|
nuclear@0
|
204 pos[1] += subpt[quadrant][1] * ysz;
|
nuclear@0
|
205
|
nuclear@0
|
206 calc_sample_pos_rec((sidx - 1) / 4, xsz / 2, ysz / 2, pos);
|
nuclear@0
|
207 }
|