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