summaryrefslogblamecommitdiff
path: root/hw2/src/camera.cpp
blob: 2e8daaa4ada327dd1bac326ae7dad8affb20a8b2 (plain) (tree)





















































































































































                                                                                                                                          
/******************************************************************/
/* 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 <cmath>

#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;
}