ThinLensCamera.cpp

Go to the documentation of this file.
00001 /**<!-------------------------------------------------------------------->
00002    @file   ThinLensCamera.cpp
00003    @author Travis Fischer (fisch0920@gmail.com)
00004    @date   January 2008
00005    
00006    @brief
00007       Thin lens camera approximation supporting common camera inputs and 
00008    allowing for depth of field
00009    
00010    @param
00011       aperture - diameter of the aperature of the lens in mm (eg. 35mm, 50mm)
00012    @param
00013       fstop    - (aka F number), is defined as the unitless ratio of the focal 
00014                  length to the diameter of the aperture of the lens
00015    @param
00016       focalDistance - the distance in meters between the lens and the focal 
00017                       plane (objects lying on the focal plane will be in 
00018                       perfect focus)
00019    @param
00020       focalPoint    - (optional) user may specify a focalPoint in NDC on the 
00021                       film-plane instead of specifying a focalDistance to 
00022                       "auto-focus" the object intersected by a ray traced 
00023                       through the corresponding pixel, whose distance away 
00024                       from the lens will be used as the focalDistance.
00025                       @note focalPoint is expressed as a vector2 in the unit 
00026                       square [0,1]^2, where [0,0] is the lower left corner 
00027                       of the image, and [1,1] is the upper-right corner
00028    
00029    (focal length is derived from fstop and aperture)
00030    
00031    @see http://www.eecs.berkeley.edu/~barsky/VisRendPapers/survey1.pdf
00032    <!-------------------------------------------------------------------->**/
00033 
00034 #include "ThinLensCamera.h"
00035 #include <ResourceManager.h>
00036 #include <Material.h>
00037 #include <Viewport.h>
00038 #include <Scene.h>
00039 #include <algebra.h>
00040 #include <QtCore>
00041 
00042 ThinLensCamera::ThinLensCamera() 
00043    : Camera()
00044 {
00045    m_aspect = 1.0;
00046    m_hAngle = 45.0;
00047    m_near   = .05;
00048    m_far    = 50.0;
00049    
00050    Point3 eye(2, 2, 2);
00051    Point3 origin;
00052    
00053    // TODO: dangerous calling virtual method in constructor...
00054    setOrientation(eye, origin - eye, Vector3(0, 1, 0));
00055 }
00056 
00057 ThinLensCamera::~ThinLensCamera()
00058 { }
00059 
00060 void ThinLensCamera::init(Scene *scene) {
00061    { // initialize normal camera orientation / position parameters
00062       const Point3 &eye   = getValue<Point3> ("eye",  m_eye);
00063       const Point3 &focus = getValue<Point3> ("focus", Point3());
00064       const Vector3 &look = getValue<Vector3>("look", (focus - eye).getNormalized());
00065       Vector3 up          = getValue<Vector3>("up",   m_v);
00066       
00067       if (EQ(ABS(look.dot(up)), 1)) {
00068          dprintf("Error: look vector collinear to up vector; switching to default up\n");
00069          
00070          if (up != Vector3(0, 1, 0))
00071             up = Vector3(0, 1, 0);
00072          else up = Vector3(0, 0, 1);
00073       }
00074       
00075       m_aspect = getValue<real_t>("aspectRatio", m_aspect);
00076       m_hAngle = getValue<real_t>("heightAngle", m_hAngle);
00077       
00078       // near and far clipping planes are for OpenGL preview only
00079       m_near   = getValue<real_t>("near", m_near);
00080       m_far    = getValue<real_t>("far",  m_far);
00081       
00082       // initialize camera's internal orthonormal basis
00083       setOrientation(eye, look, up);
00084    }
00085    
00086    { // initialize thin lens parameters
00087       // parse thin lens inputs (defaults to a 35mm camera whose focal length is 
00088       // .49m); convert aperture to meters for all internal computations
00089       m_aperture    = getValue<real_t>("aperture", create_real(35.0)) / 1000.0;
00090       m_fstop       = getValue<real_t>("fstop",    create_real(14));
00091       
00092       // fstop is defined as the ratio of focalLength to aperture diameter
00093       m_focalLength = m_fstop * m_aperture;
00094       bool autoFocus = false;
00095       
00096       if (contains("focalPoint") || !contains("focalDistance")) {
00097          static real_t defaultTarget[] = { create_real(0.5), create_real(0.5) };
00098          
00099          // automatically calculate focal distance ("autofocus")
00100          const real_t *target = getValue<real_t*>("focalPoint", defaultTarget);
00101          const Point3 fp(CAP(target[0], 0, 1) - 0.5, .5 - CAP(target[1], 0, 1), -1);
00102          
00103          const Vector3 &direction = (m_filmToWorld * fp - m_eye).getNormalized();
00104          Ray ray(m_eye, direction);
00105          SurfacePoint pt;
00106          
00107          ASSERT(scene);
00108          if (scene->isInitialized()) {
00109             m_focalDistance = scene->getIntersection(ray, pt);
00110             
00111             autoFocus = Ray::isValid(m_focalDistance);
00112          }
00113       }
00114       
00115       if (!autoFocus)
00116          m_focalDistance = getValue<real_t>("focalDistance", 1);
00117       
00118       ResourceManager::log << "ThinLensCamera: aperture      = " << 
00119          m_aperture * 1000.0 << " mm" << endl;
00120       ResourceManager::log << "ThinLensCamera: fstop         = " << 
00121          m_fstop << endl;
00122       ResourceManager::log << "ThinLensCamera: focalLength   = " << 
00123          m_focalLength << " m" << endl;
00124       ResourceManager::log << "ThinLensCamera: focalDistance = " << 
00125          m_focalDistance << " m" << (autoFocus ? " (autofocused)" : "") << endl;
00126    }
00127 }
00128 
00129 Ray ThinLensCamera::getWorldRay(const Point2 &pt) const {
00130    const Point3 ndc(2 * pt[0] - 1, 1 - 2 * pt[1], -1);
00131    const Vector3 &direction = (m_filmToWorld * ndc - m_eye).getNormalized();
00132    
00133    Ray ray(m_eye, direction);
00134    
00135    // compute circle of confusion and shift ray proportionately if this camera 
00136    // has a non-zero aperture (if it's a pinhole, the aperture is infinitesmal 
00137    // s.t. all rays are in focus and the ray's origin and direction are 
00138    // deterministic)
00139    if (m_aperture > 0) {
00140       // compute intersection with focal plane at distance m_focalDistance
00141       const real_t t = -m_focalDistance / (direction.dot(m_n));
00142       ASSERT(t >= -EPSILON);
00143       
00144       if (t == m_focalLength)
00145          return ray;
00146       
00147       // calculate new focal point for this ray where it would intersect the 
00148       // look vector after being "refracted"
00149       const Point3 &focus = ray.origin + direction * t;
00150       
00151       // distance between lens and actual film plane
00152       const real_t dImage = m_focalDistance;
00153       
00154       // distance between lens and perfect film plane on image side for this ray
00155       const real_t lImage = m_focalLength * t / 
00156          (t - m_focalLength);
00157       
00158       // radius of circle of confusion on image plane
00159       const real_t cofRadius = m_aperture * (lImage - dImage) / lImage;
00160       
00161       // sample uniformly within disc defined by circle of confusion
00162       const real_t e1 = Random::sample(0, M_PI / 2);
00163       const real_t e2 = Random::sample(0, 2 * M_PI);
00164       const real_t r  = cofRadius * sin(e1);
00165       
00166       // shift ray origin and compute new ray direction
00167       ray.origin += r * cos(e2) * m_u + r * sin(e2) * m_v;
00168       ray.direction = (focus - ray.origin).getNormalized();
00169       ASSERT(ray.direction.isUnit());
00170    }
00171    
00172    return ray;
00173 }
00174 
00175 void ThinLensCamera::fillGLMatrix(real_t *buffer) {
00176    m_worldToFilm.fillGLMatrix(buffer);
00177 }
00178 
00179 void ThinLensCamera::_computeMatrix() {
00180    ASSERT(m_far > 0 && m_near < m_far);
00181    const real_t farInv = 1.0 / m_far;
00182    const real_t k = m_near * farInv;
00183    
00184    const Matrix4x4 A(1, 0, 0, 0,
00185                      0, 1, 0, 0,
00186                      0, 0, 1 / (k - 1), k / (k - 1),
00187                      0, 0, -1, 0);
00188    
00189    const Matrix4x4 B(farInv, 0, 0, 0,
00190                      0, farInv, 0, 0,
00191                      0, 0, farInv, 0,
00192                      0, 0, 0, 1);
00193    
00194    const real_t vert_angle = m_hAngle * (M_PI / 180);
00195    
00196    real_t cot_h, cot_w, tan_h, tan_w;
00197    cot_h = 1.0f / tan(vert_angle / 2);
00198    cot_w = cot_h / m_aspect;
00199    
00200    tan_h = tan(vert_angle / 2);
00201    tan_w = m_aspect * tan_h;
00202    
00203    const Matrix4x4 C(cot_w, 0, 0, 0,
00204                      0, cot_h, 0, 0,
00205                      0, 0,     1, 0,
00206                      0, 0,     0, 1);
00207 
00208    const Matrix4x4 D(m_u[0], m_u[1], m_u[2], 0,
00209                      m_v[0], m_v[1], m_v[2], 0,
00210                      m_n[0], m_n[1], m_n[2], 0,
00211                      0, 0, 0, 1);
00212 
00213    const Matrix4x4 E(1, 0, 0, -(m_eye[0]),
00214                      0, 1, 0, -(m_eye[1]),
00215                      0, 0, 1, -(m_eye[2]),
00216                      0, 0, 0, 1);
00217    
00218    m_worldToFilm = (A * B * C * D * E);
00219    
00220    m_filmToWorld =
00221       Matrix4x4(1, 0, 0, m_eye[0],
00222                 0, 1, 0, m_eye[1],
00223                 0, 0, 1, m_eye[2],
00224                 0, 0, 0, 1) *
00225       Matrix4x4(m_u[0], m_v[0], m_n[0], 0,
00226                 m_u[1], m_v[1], m_n[1], 0,
00227                 m_u[2], m_v[2], m_n[2], 0,
00228                 0, 0, 0, 1) *
00229       Matrix4x4(tan_w, 0, 0, 0,
00230                 0, tan_h, 0, 0,
00231                 0, 0, 1, 0,
00232                 0, 0, 0, 1) *
00233       Matrix4x4(m_far, 0, 0, 0,
00234                 0, m_far, 0, 0,
00235                 0, 0, m_far, 0,
00236                 0, 0, 0, 1);
00237 }
00238 
00239 void ThinLensCamera::setOrientation(const Point3 &p, const Vector3 &l, 
00240                                     const Vector3 &up)
00241 {
00242    m_eye = p;
00243    m_n = -l;
00244    m_u = up.cross(m_n);
00245    m_n.normalize();
00246    m_u.normalize();
00247    m_v = m_n.cross(m_u);
00248    
00249    ASSERT(m_u.isUnit());
00250    ASSERT(m_v.isUnit());
00251    ASSERT(m_n.isUnit());
00252    ASSERT(EQ(m_n.dot(m_u), 0));
00253    ASSERT(EQ(m_n.dot(m_v), 0));
00254    ASSERT(EQ(m_u.dot(m_v), 0));
00255    
00256    _computeMatrix();
00257 }
00258 
00259 real_t ThinLensCamera::getIntersection(const Ray &ray, SurfacePoint &pt) {
00260    return INFINITY;
00261 }
00262  
00263 Point2 ThinLensCamera::getProjection(const Point3 &p) const {
00264    Point3 p1 = m_worldToFilm * p;
00265    
00266    homogenize(p1);
00267    return Point2((p1[0] + 1) * .5, (1 - p1[1]) * .5);
00268 }
00269 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6