erebus

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