erebus
diff liberebus/src/camera.cc @ 0:4abdce1361b9
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 27 Apr 2014 16:02:47 +0300 |
parents | |
children | 9621beb22694 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/liberebus/src/camera.cc Sun Apr 27 16:02:47 2014 +0300 1.3 @@ -0,0 +1,207 @@ 1.4 +#include <stdio.h> 1.5 +#include <math.h> 1.6 +#include "camera.h" 1.7 + 1.8 +static void calc_sample_pos_rec(int sidx, float xsz, float ysz, float *pos); 1.9 + 1.10 +Camera::Camera() 1.11 +{ 1.12 + vfov = M_PI / 4.0; 1.13 + cached_matrix_valid = false; 1.14 + 1.15 + rdir_cache_width = rdir_cache_height = 0; 1.16 + rdir_cache = 0; 1.17 +} 1.18 + 1.19 +Camera::Camera(const Vector3 &p) 1.20 + : pos(p) 1.21 +{ 1.22 + vfov = M_PI / 4.0; 1.23 + cached_matrix_valid = false; 1.24 + 1.25 + rdir_cache_width = rdir_cache_height = 0; 1.26 + rdir_cache = 0; 1.27 +} 1.28 + 1.29 +Camera::~Camera() 1.30 +{ 1.31 + delete [] rdir_cache; 1.32 +} 1.33 + 1.34 +void Camera::set_fov(float vfov) 1.35 +{ 1.36 + this->vfov = vfov; 1.37 + 1.38 + // invalidate the dir cache 1.39 + delete [] rdir_cache; 1.40 +} 1.41 + 1.42 +float Camera::get_fov() const 1.43 +{ 1.44 + return vfov; 1.45 +} 1.46 + 1.47 +void Camera::set_position(const Vector3 &pos) 1.48 +{ 1.49 + this->pos = pos; 1.50 + cached_matrix_valid = false; // invalidate the cached matrix 1.51 +} 1.52 + 1.53 +const Vector3 &Camera::get_position() const 1.54 +{ 1.55 + return pos; 1.56 +} 1.57 + 1.58 +const Matrix4x4 &Camera::get_matrix() const 1.59 +{ 1.60 + if(!cached_matrix_valid) { 1.61 + calc_matrix(&cached_matrix); 1.62 + cached_matrix_valid = true; 1.63 + } 1.64 + return cached_matrix; 1.65 +} 1.66 + 1.67 +Vector2 Camera::calc_sample_pos(int x, int y, int xsz, int ysz, int sample) const 1.68 +{ 1.69 + float ppos[2]; 1.70 + float aspect = (float)xsz / (float)ysz; 1.71 + 1.72 + float pwidth = 2.0 * aspect / (float)xsz; 1.73 + float pheight = 2.0 / (float)ysz; 1.74 + 1.75 + ppos[0] = (float)x * pwidth - aspect; 1.76 + ppos[1] = 1.0 - (float)y * pheight; 1.77 + 1.78 + calc_sample_pos_rec(sample, pwidth, pheight, ppos); 1.79 + return Vector2(ppos[0], ppos[1]); 1.80 +} 1.81 + 1.82 +Ray Camera::get_primary_ray(int x, int y, int xsz, int ysz, int sample) const 1.83 +{ 1.84 +#pragma omp single 1.85 + { 1.86 + if(!rdir_cache || rdir_cache_width != xsz || rdir_cache_height != ysz) { 1.87 + printf("calculating primary ray direction cache\n"); 1.88 + 1.89 + delete [] rdir_cache; 1.90 + rdir_cache = new Vector3[xsz * ysz]; 1.91 + 1.92 +#pragma omp parallel for 1.93 + for(int i=0; i<ysz; i++) { 1.94 + Vector3 *rdir = rdir_cache + i * xsz; 1.95 + for(int j=0; j<xsz; j++) { 1.96 + Vector2 ppos = calc_sample_pos(j, i, xsz, ysz, 0); 1.97 + 1.98 + rdir->x = ppos.x; 1.99 + rdir->y = ppos.y; 1.100 + rdir->z = 1.0 / tan(vfov / 2.0); 1.101 + rdir->normalize(); 1.102 + 1.103 + rdir++; 1.104 + } 1.105 + } 1.106 + rdir_cache_width = xsz; 1.107 + rdir_cache_height = ysz; 1.108 + } 1.109 + } 1.110 + 1.111 + Ray ray; 1.112 + ray.origin = pos; 1.113 + ray.dir = rdir_cache[y * xsz + x]; 1.114 + 1.115 + // transform the ray direction with the camera matrix 1.116 + Matrix4x4 mat = get_matrix(); 1.117 + 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; 1.118 + mat.m[3][3] = 1.0; 1.119 + 1.120 + ray.dir = ray.dir.transformed(mat); 1.121 + return ray; 1.122 +} 1.123 + 1.124 +TargetCamera::TargetCamera() {} 1.125 + 1.126 +TargetCamera::TargetCamera(const Vector3 &pos, const Vector3 &targ) 1.127 + : Camera(pos), target(targ) 1.128 +{ 1.129 +} 1.130 + 1.131 +void TargetCamera::set_target(const Vector3 &targ) 1.132 +{ 1.133 + target = targ; 1.134 + cached_matrix_valid = false; // invalidate the cached matrix 1.135 +} 1.136 + 1.137 +const Vector3 &TargetCamera::get_target() const 1.138 +{ 1.139 + return target; 1.140 +} 1.141 + 1.142 +void TargetCamera::calc_matrix(Matrix4x4 *mat) const 1.143 +{ 1.144 + Vector3 up(0, 1, 0); 1.145 + Vector3 dir = (target - pos).normalized(); 1.146 + Vector3 right = cross_product(up, dir); 1.147 + up = cross_product(dir, right); 1.148 + 1.149 + *mat = Matrix4x4( 1.150 + right.x, up.x, dir.x, pos.x, 1.151 + right.y, up.y, dir.y, pos.y, 1.152 + right.z, up.z, dir.z, pos.z, 1.153 + 0.0, 0.0, 0.0, 1.0); 1.154 +} 1.155 + 1.156 +void FlyCamera::input_move(float x, float y, float z) 1.157 +{ 1.158 + static const Vector3 vfwd(0, 0, 1), vright(1, 0, 0); 1.159 + 1.160 + Vector3 k = vfwd.transformed(rot); 1.161 + Vector3 i = vright.transformed(rot); 1.162 + Vector3 j = cross_product(k, i); 1.163 + 1.164 + pos += i * x + j * y + k * z; 1.165 + cached_matrix_valid = false; 1.166 +} 1.167 + 1.168 +void FlyCamera::input_rotate(float x, float y, float z) 1.169 +{ 1.170 + Vector3 axis(x, y, z); 1.171 + float axis_len = axis.length(); 1.172 + if(fabs(axis_len) < 1e-5) { 1.173 + return; 1.174 + } 1.175 + rot.rotate(axis / axis_len, -axis_len); 1.176 + rot.normalize(); 1.177 + 1.178 + cached_matrix_valid = false; 1.179 +} 1.180 + 1.181 +void FlyCamera::calc_matrix(Matrix4x4 *mat) const 1.182 +{ 1.183 + Matrix4x4 tmat; 1.184 + tmat.set_translation(pos); 1.185 + 1.186 + Matrix3x3 rmat = rot.get_rotation_matrix(); 1.187 + 1.188 + *mat = tmat * Matrix4x4(rmat); 1.189 +} 1.190 + 1.191 +/* generates a sample position for sample number sidx, in the unit square 1.192 + * by recursive subdivision and jittering 1.193 + */ 1.194 +static void calc_sample_pos_rec(int sidx, float xsz, float ysz, float *pos) 1.195 +{ 1.196 + static const float subpt[4][2] = { 1.197 + {-0.25, -0.25}, {0.25, -0.25}, {-0.25, 0.25}, {0.25, 0.25} 1.198 + }; 1.199 + 1.200 + if(!sidx) { 1.201 + return; 1.202 + } 1.203 + 1.204 + /* determine which quadrant to recurse into */ 1.205 + int quadrant = ((sidx - 1) % 4); 1.206 + pos[0] += subpt[quadrant][0] * xsz; 1.207 + pos[1] += subpt[quadrant][1] * ysz; 1.208 + 1.209 + calc_sample_pos_rec((sidx - 1) / 4, xsz / 2, ysz / 2, pos); 1.210 +}