Panda3D
 All Classes Functions Variables Enumerations
fisheyeLens.cxx
00001 // Filename: fisheyeLens.cxx
00002 // Created by:  drose (12Dec01)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "fisheyeLens.h"
00016 #include "deg_2_rad.h"
00017 
00018 TypeHandle FisheyeLens::_type_handle;
00019 
00020 // This is the focal-length constant for fisheye lenses.  The focal
00021 // length of a fisheye lens relates to its fov by the equation:
00022 
00023 //   w = Fd/k
00024 
00025 // Where w is the width of the negative, F is the focal length, and d
00026 // is the total field of view in degrees.
00027 
00028 // k is chosen to make the focal lengths for a fisheye lens roughly
00029 // correspond to the equivalent field of view for a conventional,
00030 // perspective lens.  It was determined empirically by simple
00031 // examination of a couple of actual lenses for 35mm film.  I don't
00032 // know how well this extends to other lenses and other negative
00033 // sizes.
00034 
00035 static const PN_stdfloat fisheye_k = 60.0f;
00036 // focal_length = film_size * fisheye_k / fov;
00037 
00038 
00039 ////////////////////////////////////////////////////////////////////
00040 //     Function: FisheyeLens::make_copy
00041 //       Access: Public, Virtual
00042 //  Description: Allocates a new Lens just like this one.
00043 ////////////////////////////////////////////////////////////////////
00044 PT(Lens) FisheyeLens::
00045 make_copy() const {
00046   return new FisheyeLens(*this);
00047 }
00048 
00049 ////////////////////////////////////////////////////////////////////
00050 //     Function: FisheyeLens::do_extrude
00051 //       Access: Protected, Virtual
00052 //  Description: Given a 2-d point in the range (-1,1) in both
00053 //               dimensions, where (0,0) is the center of the
00054 //               lens and (-1,-1) is the lower-left corner,
00055 //               compute the corresponding vector in space that maps
00056 //               to this point, if such a vector can be determined.
00057 //               The vector is returned by indicating the points on
00058 //               the near plane and far plane that both map to the
00059 //               indicated 2-d point.
00060 //
00061 //               The z coordinate of the 2-d point is ignored.
00062 //
00063 //               Returns true if the vector is defined, or false
00064 //               otherwise.
00065 ////////////////////////////////////////////////////////////////////
00066 bool FisheyeLens::
00067 do_extrude(const Lens::CData *lens_cdata, 
00068            const LPoint3 &point2d, LPoint3 &near_point, LPoint3 &far_point) const {
00069   // Undo the shifting from film offsets, etc.  This puts the point
00070   // into the range [-film_size/2, film_size/2] in x and y.
00071   LPoint3 f = point2d * do_get_film_mat_inv(lens_cdata);
00072 
00073   // First, get the vector from the center of the film to the point,
00074   // and normalize it.
00075   LVector2 v2(f[0], f[1]);
00076 
00077   LPoint3 v;
00078 
00079   PN_stdfloat r = v2.length();
00080   if (r == 0.0f) {
00081     // Special case: directly forward.
00082     v.set(0.0f, 1.0f, 0.0f);
00083 
00084   } else {
00085     v2 /= r;
00086 
00087     // Now get the point r units around the circle in the YZ plane.
00088     PN_stdfloat focal_length = do_get_focal_length(lens_cdata);
00089     PN_stdfloat angle = r * fisheye_k / focal_length;
00090     PN_stdfloat sinAngle, cosAngle;
00091     csincos(deg_2_rad(angle), &sinAngle, &cosAngle);
00092 
00093     LVector3 p(0.0, cosAngle, sinAngle);
00094 
00095     // And rotate this point around the Y axis.
00096     v.set(p[0]*v2[1] + p[2]*v2[0],
00097           p[1],
00098           p[2]*v2[1] - p[0]*v2[0]);
00099   }
00100 
00101   // And we'll need to account for the lens's rotations, etc. at the
00102   // end of the day.
00103   const LMatrix4 &lens_mat = do_get_lens_mat(lens_cdata);
00104   const LMatrix4 &proj_inv_mat = do_get_projection_mat_inv(lens_cdata);
00105 
00106   near_point = (v * do_get_near(lens_cdata)) * proj_inv_mat * lens_mat;
00107   far_point = (v * do_get_far(lens_cdata)) * proj_inv_mat * lens_mat;
00108   return true;
00109 }
00110 
00111 ////////////////////////////////////////////////////////////////////
00112 //     Function: FisheyeLens::do_extrude_vec
00113 //       Access: Protected, Virtual
00114 //  Description: Given a 2-d point in the range (-1,1) in both
00115 //               dimensions, where (0,0) is the center of the
00116 //               lens and (-1,-1) is the lower-left corner,
00117 //               compute the vector that corresponds to the view
00118 //               direction.  This will be parallel to the normal on
00119 //               the surface (the far plane) corresponding to the lens
00120 //               shape at this point.
00121 //
00122 //               See the comment block on Lens::extrude_vec_impl() for
00123 //               a more in-depth comment on the meaning of this
00124 //               vector.
00125 //
00126 //               The z coordinate of the 2-d point is ignored.
00127 //
00128 //               Returns true if the vector is defined, or false
00129 //               otherwise.
00130 ////////////////////////////////////////////////////////////////////
00131 bool FisheyeLens::
00132 do_extrude_vec(const Lens::CData *lens_cdata, const LPoint3 &point2d, LVector3 &vec) const {
00133   LPoint3 near_point, far_point;
00134   if (!do_extrude(lens_cdata, point2d, near_point, far_point)) {
00135     return false;
00136   }
00137 
00138   vec = far_point - near_point;
00139 
00140   return true;
00141 }
00142 
00143 ////////////////////////////////////////////////////////////////////
00144 //     Function: FisheyeLens::do_project
00145 //       Access: Protected, Virtual
00146 //  Description: Given a 3-d point in space, determine the 2-d point
00147 //               this maps to, in the range (-1,1) in both dimensions,
00148 //               where (0,0) is the center of the lens and
00149 //               (-1,-1) is the lower-left corner.
00150 //
00151 //               Some lens types also set the z coordinate of the 2-d
00152 //               point to a value in the range (-1, 1), where 1
00153 //               represents a point on the near plane, and -1
00154 //               represents a point on the far plane.
00155 //
00156 //               Returns true if the 3-d point is in front of the lens
00157 //               and within the viewing frustum (in which case point2d
00158 //               is filled in), or false otherwise.
00159 ////////////////////////////////////////////////////////////////////
00160 bool FisheyeLens::
00161 do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point2d) const {
00162   // First, account for any rotations, etc. on the lens.
00163   LVector3 v2 = point3d * do_get_lens_mat_inv(lens_cdata) * do_get_projection_mat(lens_cdata);
00164 
00165   // A fisheye lens projection has the property that the distance from
00166   // the center point to any other point on the projection is
00167   // proportional to the actual distance on the sphere along the great
00168   // circle.  Also, the angle to the point on the projection is equal
00169   // to the angle to the point on the sphere.
00170 
00171   // First, get the straight-line distance from the lens, and use it
00172   // to normalize the vector.
00173   PN_stdfloat dist = v2.length();
00174   v2 /= dist;
00175 
00176   // Now, project the point into the XZ plane and measure its angle
00177   // to the Z axis.  This is the same angle it will have to the
00178   // vertical axis on the film.
00179   LVector2 y(v2[0], v2[2]);
00180   y.normalize();
00181 
00182   if (y == LVector2(0.0f, 0.0f)) {
00183     // Special case.  This point is either directly ahead or directly
00184     // behind.
00185     point2d.set(0.0f, 0.0f, 
00186                 (do_get_near(lens_cdata) - dist) / (do_get_far(lens_cdata) - do_get_near(lens_cdata)));
00187     return v2[1] >= 0.0f;
00188   }
00189 
00190   // Now bring the vector into the YZ plane by rotating about the Y
00191   // axis.
00192   LVector2 x(v2[1], v2[0]*y[0]+v2[2]*y[1]);
00193 
00194   // Now the angle of x to the forward vector represents the distance
00195   // along the great circle to the point.
00196   PN_stdfloat r = 90.0f - rad_2_deg(catan2(x[0], x[1]));
00197 
00198   PN_stdfloat focal_length = do_get_focal_length(lens_cdata);
00199   PN_stdfloat factor = r * focal_length / fisheye_k;
00200 
00201   point2d.set
00202     (y[0] * factor,
00203      y[1] * factor,
00204      // Z is the distance scaled into the range (1, -1).
00205      (do_get_near(lens_cdata) - dist) / (do_get_far(lens_cdata) - do_get_near(lens_cdata))
00206      );
00207 
00208   // Now we have to transform the point according to the film
00209   // adjustments.
00210   point2d = point2d * do_get_film_mat(lens_cdata);
00211 
00212   return
00213     point2d[0] >= -1.0f && point2d[0] <= 1.0f && 
00214     point2d[1] >= -1.0f && point2d[1] <= 1.0f;
00215 }
00216 
00217 ////////////////////////////////////////////////////////////////////
00218 //     Function: FisheyeLens::fov_to_film
00219 //       Access: Protected, Virtual
00220 //  Description: Given a field of view in degrees and a focal length,
00221 //               compute the correspdonding width (or height) on the
00222 //               film.  If horiz is true, this is in the horizontal
00223 //               direction; otherwise, it is in the vertical direction
00224 //               (some lenses behave differently in each direction).
00225 ////////////////////////////////////////////////////////////////////
00226 PN_stdfloat FisheyeLens::
00227 fov_to_film(PN_stdfloat fov, PN_stdfloat focal_length, bool) const {
00228   return focal_length * fov / fisheye_k;
00229 }
00230 
00231 ////////////////////////////////////////////////////////////////////
00232 //     Function: FisheyeLens::fov_to_focal_length
00233 //       Access: Protected, Virtual
00234 //  Description: Given a field of view in degrees and a width (or
00235 //               height) on the film, compute the focal length of the
00236 //               lens.  If horiz is true, this is in the horizontal
00237 //               direction; otherwise, it is in the vertical direction
00238 //               (some lenses behave differently in each direction).
00239 ////////////////////////////////////////////////////////////////////
00240 PN_stdfloat FisheyeLens::
00241 fov_to_focal_length(PN_stdfloat fov, PN_stdfloat film_size, bool) const {
00242   return film_size * fisheye_k / fov;
00243 }
00244 
00245 ////////////////////////////////////////////////////////////////////
00246 //     Function: FisheyeLens::film_to_fov
00247 //       Access: Protected, Virtual
00248 //  Description: Given a width (or height) on the film and a focal
00249 //               length, compute the field of view in degrees.  If
00250 //               horiz is true, this is in the horizontal direction;
00251 //               otherwise, it is in the vertical direction (some
00252 //               lenses behave differently in each direction).
00253 ////////////////////////////////////////////////////////////////////
00254 PN_stdfloat FisheyeLens::
00255 film_to_fov(PN_stdfloat film_size, PN_stdfloat focal_length, bool) const {
00256   return film_size * fisheye_k / focal_length;
00257 }
00258 
 All Classes Functions Variables Enumerations