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