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