/******************************************************************/ /* This file is part of the homework assignments for CSCI-427/527 */ /* at The College of William & Mary and authored by Pieter Peers. */ /* No part of this file, whether altered or in original form, can */ /* be distributed or used outside the context of CSCI-427/527 */ /* without consent of either the College of William & Mary or */ /* Pieter Peers. */ /******************************************************************/ #include #include "constants.h" #include "camera.h" ///////////////// // Constructor // ///////////////// camera::camera(void) { _eye = vec3d(); _view = vec3d(0.0f, 0.0f, -1.0f); _up = vec3d(0.0f, 1.0f, 0.0f); _fov = 60.0f; _width = _height = 256; } camera::camera(const vec3d& eye, const vec3d& viewDirection, const vec3d& up, float fov, size_t xres, size_t yres) { _eye = eye; _view = normalize(viewDirection); _up = normalize(up); _fov = fov; _width = xres; _height = yres; // fix up if needed vec3d right = _view.cross(up).normalize(); _up = right.cross(_view).normalize(); } camera::camera(const camera& cam) { _eye = cam._eye; _view = cam._view; _up = cam._up; _fov = cam._fov; _width = cam._width; _height = cam._height; } /////////////// // Operators // /////////////// camera& camera::operator=(const camera& cam) { _assign(cam); return *this; } ray camera::operator()(float x, float y) const { vec3d right = _view.cross(_up).normalize(); // aspect ratio float aspect = (float)(_height) / (float)(_width); float tanFov = tan(_fov / 180.0f * M_PI); // compute view plane center, and U and V unnormalized axes. vec3d center = _eye + _view; vec3d U = 2.0f * tanFov * right; vec3d V = -2.0f * tanFov * aspect * _up; // y runs from top to bottom (opposite direction of up) // get point on view plane vec3d p = center + (x / (float)(_width) - 0.5f) * U + (y / (float)(_height) - 0.5f) * V; // Done. return ray(_eye, p - _eye); } ////////////// // Mutators // ////////////// void camera::frameBoundingBox(const boundingBox& bb) { // determine the best eye location, given the other parameters and a bounding box such that the bounding box maximally occupies the view vec3d right = _view.cross(_up).normalize(); _eye = 0.5f * (bb.corner(true,true,true) + bb.corner(false,false,false)); // => find max projection in up and right direction. float maxRight=-LARGE, maxUp=-LARGE, maxDepth=-LARGE; for(unsigned int i=0; i < 8; i++) { vec3d c = bb.corner( (i&1)==1, (i&2)==2, (i&4)==4 ) - _eye; float r = fabs(c.dot(right)); float u = fabs(c.dot(_up)); float d = fabs(c.dot(_view)); maxRight = std::max(maxRight, r); maxUp = std::max(maxUp, u); maxDepth = std::max(maxDepth, d); } // => compute optimal distance for up and right float aspect = (float)(_height) / (float)(_width); float tanFov = tan(_fov / 180.0f * M_PI); float optDistUp = fabs(maxUp / tanFov); float optDistRight = fabs(maxRight / (tanFov * aspect)); // => move _eye back based on (max) optimal distance _eye -= _view * (std::max(optDistUp, optDistRight) + maxDepth); } ///////////////////// // Private Methods // ///////////////////// void camera::_swap(camera& cam) { // sanity check if(&cam == this) return; // swap swap(_eye, cam._eye); swap(_view, cam._view); swap(_up, cam._up); std::swap(_fov, cam._fov); std::swap(_width, cam._width); std::swap(_height, cam._height); } void camera::_assign(const camera& cam) { // sanity check if(&cam == this) return; // copy _eye = cam._eye; _view = cam._view; _up = cam._up; _fov = cam._fov; _width = cam._width; _height = cam._height; }