gpuray_glsl

view src/camera.cc @ 0:f234630e38ff

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 09 Nov 2014 13:03:36 +0200
parents
children
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 = 0;
14 }
16 Camera::Camera(const Vector3 &p)
17 : pos(p)
18 {
19 vfov = M_PI / 4.0;
20 cached_matrix_valid = false;
22 rdir_cache_width = rdir_cache_height = 0;
23 rdir_cache = 0;
24 }
26 Camera::~Camera()
27 {
28 delete [] rdir_cache;
29 }
31 void Camera::set_fov(float vfov)
32 {
33 this->vfov = vfov;
35 // invalidate the dir cache
36 delete [] rdir_cache;
37 }
39 float Camera::get_fov() const
40 {
41 return vfov;
42 }
44 void Camera::set_position(const Vector3 &pos)
45 {
46 this->pos = pos;
47 cached_matrix_valid = false; // invalidate the cached matrix
48 }
50 const Vector3 &Camera::get_position() const
51 {
52 return pos;
53 }
55 const Matrix4x4 &Camera::get_matrix() const
56 {
57 if(!cached_matrix_valid) {
58 calc_matrix(&cached_matrix);
59 cached_matrix_valid = true;
60 }
61 return cached_matrix;
62 }
64 Vector2 Camera::calc_sample_pos(int x, int y, int xsz, int ysz, int sample) const
65 {
66 float ppos[2];
67 float aspect = (float)xsz / (float)ysz;
69 float pwidth = 2.0 * aspect / (float)xsz;
70 float pheight = 2.0 / (float)ysz;
72 ppos[0] = (float)x * pwidth - aspect;
73 ppos[1] = 1.0 - (float)y * pheight;
75 calc_sample_pos_rec(sample, pwidth, pheight, ppos);
76 return Vector2(ppos[0], ppos[1]);
77 }
79 Ray Camera::get_primary_ray(int x, int y, int xsz, int ysz, int sample) const
80 {
81 if(!rdir_cache || rdir_cache_width != xsz || rdir_cache_height != ysz) {
82 printf("calculating primary ray direction cache\n");
84 delete [] rdir_cache;
85 rdir_cache = new Vector3[xsz * ysz];
87 for(int i=0; i<ysz; i++) {
88 Vector3 *rdir = rdir_cache + i * xsz;
89 for(int j=0; j<xsz; j++) {
90 Vector2 ppos = calc_sample_pos(j, i, xsz, ysz, 0);
92 rdir->x = ppos.x;
93 rdir->y = ppos.y;
94 rdir->z = 1.0 / tan(vfov / 2.0);
95 rdir->normalize();
97 rdir++;
98 }
99 }
100 rdir_cache_width = xsz;
101 rdir_cache_height = ysz;
102 }
104 Ray ray;
105 ray.origin = pos;
106 ray.dir = rdir_cache[y * xsz + x];
108 // transform the ray direction with the camera matrix
109 Matrix4x4 mat = get_matrix();
110 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;
111 mat.m[3][3] = 1.0;
113 ray.dir = ray.dir.transformed(mat);
114 return ray;
115 }
117 TargetCamera::TargetCamera() {}
119 TargetCamera::TargetCamera(const Vector3 &pos, const Vector3 &targ)
120 : Camera(pos), target(targ)
121 {
122 }
124 void TargetCamera::set_target(const Vector3 &targ)
125 {
126 target = targ;
127 cached_matrix_valid = false; // invalidate the cached matrix
128 }
130 const Vector3 &TargetCamera::get_target() const
131 {
132 return target;
133 }
135 void TargetCamera::calc_matrix(Matrix4x4 *mat) const
136 {
137 Vector3 up(0, 1, 0);
138 Vector3 dir = (target - pos).normalized();
139 Vector3 right = cross_product(up, dir);
140 up = cross_product(dir, right);
142 *mat = Matrix4x4(
143 right.x, up.x, dir.x, pos.x,
144 right.y, up.y, dir.y, pos.y,
145 right.z, up.z, dir.z, pos.z,
146 0.0, 0.0, 0.0, 1.0);
147 }
149 void FlyCamera::input_move(float x, float y, float z)
150 {
151 static const Vector3 vfwd(0, 0, 1), vright(1, 0, 0);
153 Vector3 k = vfwd.transformed(rot);
154 Vector3 i = vright.transformed(rot);
155 Vector3 j = cross_product(k, i);
157 pos += i * x + j * y + k * z;
158 cached_matrix_valid = false;
159 }
161 void FlyCamera::input_rotate(float x, float y, float z)
162 {
163 Vector3 axis(x, y, z);
164 float axis_len = axis.length();
165 if(fabs(axis_len) < 1e-5) {
166 return;
167 }
168 rot.rotate(axis / axis_len, -axis_len);
169 rot.normalize();
171 cached_matrix_valid = false;
172 }
174 void FlyCamera::calc_matrix(Matrix4x4 *mat) const
175 {
176 Matrix3x3 rmat = rot.get_rotation_matrix();
177 *mat = rmat;
178 }
180 /* generates a sample position for sample number sidx, in the unit square
181 * by recursive subdivision and jittering
182 */
183 static void calc_sample_pos_rec(int sidx, float xsz, float ysz, float *pos)
184 {
185 static const float subpt[4][2] = {
186 {-0.25, -0.25}, {0.25, -0.25}, {-0.25, 0.25}, {0.25, 0.25}
187 };
189 if(!sidx) {
190 return;
191 }
193 /* determine which quadrant to recurse into */
194 int quadrant = ((sidx - 1) % 4);
195 pos[0] += subpt[quadrant][0] * xsz;
196 pos[1] += subpt[quadrant][1] * ysz;
198 calc_sample_pos_rec((sidx - 1) / 4, xsz / 2, ysz / 2, pos);
199 }