erebus

view liberebus/src/camera.cc @ 46:c4d48a21bc4a

in the middle of the vmath->gph-math port
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 24 Feb 2016 00:26:50 +0200
parents d15ee526daa6
children
line source
1 #include <stdio.h>
2 #include <math.h>
3 #include "camera.h"
5 #define DEFAULT_FOV DEG_TO_RAD(50)
7 static void calc_sample_pos_rec(int sidx, float xsz, float ysz, float *pos);
9 Camera::Camera()
10 {
11 vfov = DEFAULT_FOV;
12 cached_matrix_valid = false;
13 }
15 Camera::Camera(const Vec3 &p)
16 : pos(p)
17 {
18 vfov = DEFAULT_FOV;
19 cached_matrix_valid = false;
20 }
22 Camera::~Camera()
23 {
24 }
26 void Camera::set_fov(float vfov)
27 {
28 this->vfov = vfov;
29 }
31 float Camera::get_fov() const
32 {
33 return vfov;
34 }
36 void Camera::set_position(const Vec3 &pos)
37 {
38 this->pos = pos;
39 cached_matrix_valid = false; // invalidate the cached matrix
40 }
42 const Vec3 &Camera::get_position() const
43 {
44 return pos;
45 }
47 const Mat4x4 &Camera::get_matrix() const
48 {
49 if(!cached_matrix_valid) {
50 calc_matrix(&cached_matrix);
51 cached_matrix_valid = true;
52 }
53 return cached_matrix;
54 }
56 Vec2 Camera::calc_sample_pos(int x, int y, int xsz, int ysz, int sample) const
57 {
58 float ppos[2];
59 float aspect = (float)xsz / (float)ysz;
61 float pwidth = 2.0 * aspect / (float)xsz;
62 float pheight = 2.0 / (float)ysz;
64 ppos[0] = (float)x * pwidth - aspect;
65 ppos[1] = 1.0 - (float)y * pheight;
67 calc_sample_pos_rec(sample, pwidth, pheight, ppos);
68 return Vec2(ppos[0], ppos[1]);
69 }
71 Ray Camera::get_primary_ray(int x, int y, int xsz, int ysz, int sample) const
72 {
73 Vec2 ppos = calc_sample_pos(x, y, xsz, ysz, sample);
75 Ray ray;
76 ray.origin = pos;
77 ray.dir.x = ppos.x;
78 ray.dir.y = ppos.y;
79 ray.dir.z = 1.0 / tan(vfov / 2.0);
80 ray.dir.normalize();
82 // transform the ray direction with the camera matrix
83 Mat4x4 mat = get_matrix();
84 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;
85 mat.m[3][3] = 1.0;
87 ray.dir = ray.dir.transformed(mat);
88 return ray;
89 }
91 TargetCamera::TargetCamera() {}
93 TargetCamera::TargetCamera(const Vec3 &pos, const Vec3 &targ)
94 : Camera(pos), target(targ)
95 {
96 }
98 void TargetCamera::set_target(const Vec3 &targ)
99 {
100 target = targ;
101 cached_matrix_valid = false; // invalidate the cached matrix
102 }
104 const Vec3 &TargetCamera::get_target() const
105 {
106 return target;
107 }
109 void TargetCamera::calc_matrix(Mat4x4 *mat) const
110 {
111 Vec3 up{0, 1, 0};
112 Vec3 dir = (target - pos).normalized();
114 if(1.0 - fabs(dot_product(dir, up)) < 1e-4) {
115 up = Vec3(0, 0, 1);
116 }
118 Vec3 right = cross_product(up, dir).normalized();
119 up = cross_product(dir, right);
121 *mat = Mat4x4(
122 right.x, up.x, dir.x, pos.x,
123 right.y, up.y, dir.y, pos.y,
124 right.z, up.z, dir.z, pos.z,
125 0.0, 0.0, 0.0, 1.0);
126 }
128 void FlyCamera::input_move(float x, float y, float z)
129 {
130 static const Vec3 vfwd(0, 0, 1), vright(1, 0, 0);
132 Vec3 k = vfwd.transformed(rot);
133 Vec3 i = vright.transformed(rot);
134 Vec3 j = cross_product(k, i);
136 pos += i * x + j * y + k * z;
137 cached_matrix_valid = false;
138 }
140 void FlyCamera::input_rotate(float x, float y, float z)
141 {
142 Vec3 axis(x, y, z);
143 float axis_len = axis.length();
144 if(fabs(axis_len) < 1e-5) {
145 return;
146 }
147 rot.rotate(axis / axis_len, -axis_len);
148 rot.normalize();
150 cached_matrix_valid = false;
151 }
153 void FlyCamera::calc_matrix(Mat4x4 *mat) const
154 {
155 Mat4x4 tmat;
156 tmat.set_translation(pos);
158 Mat3x3 rmat = rot.get_rotation_matrix();
160 *mat = tmat * Mat4x4(rmat);
161 }
163 /* generates a sample position for sample number sidx, in the unit square
164 * by recursive subdivision and jittering
165 */
166 static void calc_sample_pos_rec(int sidx, float xsz, float ysz, float *pos)
167 {
168 static const float subpt[4][2] = {
169 {-0.25, -0.25}, {0.25, -0.25}, {-0.25, 0.25}, {0.25, 0.25}
170 };
172 if(!sidx) {
173 return;
174 }
176 /* determine which quadrant to recurse into */
177 int quadrant = ((sidx - 1) % 4);
178 pos[0] += subpt[quadrant][0] * xsz;
179 pos[1] += subpt[quadrant][1] * ysz;
181 calc_sample_pos_rec((sidx - 1) / 4, xsz / 2, ysz / 2, pos);
182 }