vrchess

diff src/camera.cc @ 0:b326d53321f7

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 25 Apr 2014 05:20:53 +0300
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/camera.cc	Fri Apr 25 05:20:53 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 +}