gpuray_glsl
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/camera.cc Sun Nov 09 13:03:36 2014 +0200 1.3 @@ -0,0 +1,199 @@ 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 + if(!rdir_cache || rdir_cache_width != xsz || rdir_cache_height != ysz) { 1.85 + printf("calculating primary ray direction cache\n"); 1.86 + 1.87 + delete [] rdir_cache; 1.88 + rdir_cache = new Vector3[xsz * ysz]; 1.89 + 1.90 + for(int i=0; i<ysz; i++) { 1.91 + Vector3 *rdir = rdir_cache + i * xsz; 1.92 + for(int j=0; j<xsz; j++) { 1.93 + Vector2 ppos = calc_sample_pos(j, i, xsz, ysz, 0); 1.94 + 1.95 + rdir->x = ppos.x; 1.96 + rdir->y = ppos.y; 1.97 + rdir->z = 1.0 / tan(vfov / 2.0); 1.98 + rdir->normalize(); 1.99 + 1.100 + rdir++; 1.101 + } 1.102 + } 1.103 + rdir_cache_width = xsz; 1.104 + rdir_cache_height = ysz; 1.105 + } 1.106 + 1.107 + Ray ray; 1.108 + ray.origin = pos; 1.109 + ray.dir = rdir_cache[y * xsz + x]; 1.110 + 1.111 + // transform the ray direction with the camera matrix 1.112 + Matrix4x4 mat = get_matrix(); 1.113 + 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.114 + mat.m[3][3] = 1.0; 1.115 + 1.116 + ray.dir = ray.dir.transformed(mat); 1.117 + return ray; 1.118 +} 1.119 + 1.120 +TargetCamera::TargetCamera() {} 1.121 + 1.122 +TargetCamera::TargetCamera(const Vector3 &pos, const Vector3 &targ) 1.123 + : Camera(pos), target(targ) 1.124 +{ 1.125 +} 1.126 + 1.127 +void TargetCamera::set_target(const Vector3 &targ) 1.128 +{ 1.129 + target = targ; 1.130 + cached_matrix_valid = false; // invalidate the cached matrix 1.131 +} 1.132 + 1.133 +const Vector3 &TargetCamera::get_target() const 1.134 +{ 1.135 + return target; 1.136 +} 1.137 + 1.138 +void TargetCamera::calc_matrix(Matrix4x4 *mat) const 1.139 +{ 1.140 + Vector3 up(0, 1, 0); 1.141 + Vector3 dir = (target - pos).normalized(); 1.142 + Vector3 right = cross_product(up, dir); 1.143 + up = cross_product(dir, right); 1.144 + 1.145 + *mat = Matrix4x4( 1.146 + right.x, up.x, dir.x, pos.x, 1.147 + right.y, up.y, dir.y, pos.y, 1.148 + right.z, up.z, dir.z, pos.z, 1.149 + 0.0, 0.0, 0.0, 1.0); 1.150 +} 1.151 + 1.152 +void FlyCamera::input_move(float x, float y, float z) 1.153 +{ 1.154 + static const Vector3 vfwd(0, 0, 1), vright(1, 0, 0); 1.155 + 1.156 + Vector3 k = vfwd.transformed(rot); 1.157 + Vector3 i = vright.transformed(rot); 1.158 + Vector3 j = cross_product(k, i); 1.159 + 1.160 + pos += i * x + j * y + k * z; 1.161 + cached_matrix_valid = false; 1.162 +} 1.163 + 1.164 +void FlyCamera::input_rotate(float x, float y, float z) 1.165 +{ 1.166 + Vector3 axis(x, y, z); 1.167 + float axis_len = axis.length(); 1.168 + if(fabs(axis_len) < 1e-5) { 1.169 + return; 1.170 + } 1.171 + rot.rotate(axis / axis_len, -axis_len); 1.172 + rot.normalize(); 1.173 + 1.174 + cached_matrix_valid = false; 1.175 +} 1.176 + 1.177 +void FlyCamera::calc_matrix(Matrix4x4 *mat) const 1.178 +{ 1.179 + Matrix3x3 rmat = rot.get_rotation_matrix(); 1.180 + *mat = rmat; 1.181 +} 1.182 + 1.183 +/* generates a sample position for sample number sidx, in the unit square 1.184 + * by recursive subdivision and jittering 1.185 + */ 1.186 +static void calc_sample_pos_rec(int sidx, float xsz, float ysz, float *pos) 1.187 +{ 1.188 + static const float subpt[4][2] = { 1.189 + {-0.25, -0.25}, {0.25, -0.25}, {-0.25, 0.25}, {0.25, 0.25} 1.190 + }; 1.191 + 1.192 + if(!sidx) { 1.193 + return; 1.194 + } 1.195 + 1.196 + /* determine which quadrant to recurse into */ 1.197 + int quadrant = ((sidx - 1) % 4); 1.198 + pos[0] += subpt[quadrant][0] * xsz; 1.199 + pos[1] += subpt[quadrant][1] * ysz; 1.200 + 1.201 + calc_sample_pos_rec((sidx - 1) / 4, xsz / 2, ysz / 2, pos); 1.202 +}