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
1.5.6