erebus

annotate liberebus/src/camera.cc @ 48:9971a08f4104

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