Panda3D
fisheyeLens.cxx
1 // Filename: fisheyeLens.cxx
2 // Created by: drose (12Dec01)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "fisheyeLens.h"
16 #include "deg_2_rad.h"
17 
18 TypeHandle FisheyeLens::_type_handle;
19 
20 // This is the focal-length constant for fisheye lenses. The focal
21 // length of a fisheye lens relates to its fov by the equation:
22 
23 // w = Fd/k
24 
25 // Where w is the width of the negative, F is the focal length, and d
26 // is the total field of view in degrees.
27 
28 // k is chosen to make the focal lengths for a fisheye lens roughly
29 // correspond to the equivalent field of view for a conventional,
30 // perspective lens. It was determined empirically by simple
31 // examination of a couple of actual lenses for 35mm film. I don't
32 // know how well this extends to other lenses and other negative
33 // sizes.
34 
35 static const PN_stdfloat fisheye_k = 60.0f;
36 // focal_length = film_size * fisheye_k / fov;
37 
38 
39 ////////////////////////////////////////////////////////////////////
40 // Function: FisheyeLens::make_copy
41 // Access: Public, Virtual
42 // Description: Allocates a new Lens just like this one.
43 ////////////////////////////////////////////////////////////////////
44 PT(Lens) FisheyeLens::
45 make_copy() const {
46  return new FisheyeLens(*this);
47 }
48 
49 ////////////////////////////////////////////////////////////////////
50 // Function: FisheyeLens::do_extrude
51 // Access: Protected, Virtual
52 // Description: Given a 2-d point in the range (-1,1) in both
53 // dimensions, where (0,0) is the center of the
54 // lens and (-1,-1) is the lower-left corner,
55 // compute the corresponding vector in space that maps
56 // to this point, if such a vector can be determined.
57 // The vector is returned by indicating the points on
58 // the near plane and far plane that both map to the
59 // indicated 2-d point.
60 //
61 // The z coordinate of the 2-d point is ignored.
62 //
63 // Returns true if the vector is defined, or false
64 // otherwise.
65 ////////////////////////////////////////////////////////////////////
66 bool FisheyeLens::
67 do_extrude(const Lens::CData *lens_cdata,
68  const LPoint3 &point2d, LPoint3 &near_point, LPoint3 &far_point) const {
69  // Undo the shifting from film offsets, etc. This puts the point
70  // into the range [-film_size/2, film_size/2] in x and y.
71  LPoint3 f = point2d * do_get_film_mat_inv(lens_cdata);
72 
73  // First, get the vector from the center of the film to the point,
74  // and normalize it.
75  LVector2 v2(f[0], f[1]);
76 
77  LPoint3 v;
78 
79  PN_stdfloat r = v2.length();
80  if (r == 0.0f) {
81  // Special case: directly forward.
82  v.set(0.0f, 1.0f, 0.0f);
83 
84  } else {
85  v2 /= r;
86 
87  // Now get the point r units around the circle in the YZ plane.
88  PN_stdfloat focal_length = do_get_focal_length(lens_cdata);
89  PN_stdfloat angle = r * fisheye_k / focal_length;
90  PN_stdfloat sinAngle, cosAngle;
91  csincos(deg_2_rad(angle), &sinAngle, &cosAngle);
92 
93  LVector3 p(0.0, cosAngle, sinAngle);
94 
95  // And rotate this point around the Y axis.
96  v.set(p[0]*v2[1] + p[2]*v2[0],
97  p[1],
98  p[2]*v2[1] - p[0]*v2[0]);
99  }
100 
101  // And we'll need to account for the lens's rotations, etc. at the
102  // end of the day.
103  const LMatrix4 &lens_mat = do_get_lens_mat(lens_cdata);
104  const LMatrix4 &proj_inv_mat = do_get_projection_mat_inv(lens_cdata);
105 
106  near_point = (v * do_get_near(lens_cdata)) * proj_inv_mat * lens_mat;
107  far_point = (v * do_get_far(lens_cdata)) * proj_inv_mat * lens_mat;
108  return true;
109 }
110 
111 ////////////////////////////////////////////////////////////////////
112 // Function: FisheyeLens::do_extrude_vec
113 // Access: Protected, Virtual
114 // Description: Given a 2-d point in the range (-1,1) in both
115 // dimensions, where (0,0) is the center of the
116 // lens and (-1,-1) is the lower-left corner,
117 // compute the vector that corresponds to the view
118 // direction. This will be parallel to the normal on
119 // the surface (the far plane) corresponding to the lens
120 // shape at this point.
121 //
122 // See the comment block on Lens::extrude_vec_impl() for
123 // a more in-depth comment on the meaning of this
124 // vector.
125 //
126 // The z coordinate of the 2-d point is ignored.
127 //
128 // Returns true if the vector is defined, or false
129 // otherwise.
130 ////////////////////////////////////////////////////////////////////
131 bool FisheyeLens::
132 do_extrude_vec(const Lens::CData *lens_cdata, const LPoint3 &point2d, LVector3 &vec) const {
133  LPoint3 near_point, far_point;
134  if (!do_extrude(lens_cdata, point2d, near_point, far_point)) {
135  return false;
136  }
137 
138  vec = far_point - near_point;
139 
140  return true;
141 }
142 
143 ////////////////////////////////////////////////////////////////////
144 // Function: FisheyeLens::do_project
145 // Access: Protected, Virtual
146 // Description: Given a 3-d point in space, determine the 2-d point
147 // this maps to, in the range (-1,1) in both dimensions,
148 // where (0,0) is the center of the lens and
149 // (-1,-1) is the lower-left corner.
150 //
151 // Some lens types also set the z coordinate of the 2-d
152 // point to a value in the range (-1, 1), where -1
153 // represents a point on the near plane, and 1
154 // represents a point on the far plane.
155 //
156 // Returns true if the 3-d point is in front of the lens
157 // and within the viewing frustum (in which case point2d
158 // is filled in), or false otherwise.
159 ////////////////////////////////////////////////////////////////////
160 bool FisheyeLens::
161 do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point2d) const {
162  // First, account for any rotations, etc. on the lens.
163  LVector3 v2 = point3d * do_get_lens_mat_inv(lens_cdata) * do_get_projection_mat(lens_cdata);
164 
165  // A fisheye lens projection has the property that the distance from
166  // the center point to any other point on the projection is
167  // proportional to the actual distance on the sphere along the great
168  // circle. Also, the angle to the point on the projection is equal
169  // to the angle to the point on the sphere.
170 
171  // First, get the straight-line distance from the lens, and use it
172  // to normalize the vector.
173  PN_stdfloat dist = v2.length();
174  v2 /= dist;
175 
176  // Now, project the point into the XZ plane and measure its angle
177  // to the Z axis. This is the same angle it will have to the
178  // vertical axis on the film.
179  LVector2 y(v2[0], v2[2]);
180  y.normalize();
181 
182  if (y == LVector2(0.0f, 0.0f)) {
183  // Special case. This point is either directly ahead or directly
184  // behind.
185  point2d.set(0.0f, 0.0f,
186  (do_get_near(lens_cdata) - dist) / (do_get_far(lens_cdata) - do_get_near(lens_cdata)));
187  return v2[1] >= 0.0f;
188  }
189 
190  // Now bring the vector into the YZ plane by rotating about the Y
191  // axis.
192  LVector2 x(v2[1], v2[0]*y[0]+v2[2]*y[1]);
193 
194  // Now the angle of x to the forward vector represents the distance
195  // along the great circle to the point.
196  PN_stdfloat r = 90.0f - rad_2_deg(catan2(x[0], x[1]));
197 
198  PN_stdfloat focal_length = do_get_focal_length(lens_cdata);
199  PN_stdfloat factor = r * focal_length / fisheye_k;
200 
201  // Compute the depth as a linear distance in the range 0 .. 1.
202  PN_stdfloat z = (dist - do_get_near(lens_cdata)) / (do_get_far(lens_cdata) - do_get_near(lens_cdata));
203 
204  point2d.set
205  (y[0] * factor,
206  y[1] * factor,
207  // Z is the distance scaled into the range -1 .. 1.
208  2.0 * z - 1.0
209  );
210 
211  // Now we have to transform the point according to the film
212  // adjustments.
213  point2d = point2d * do_get_film_mat(lens_cdata);
214 
215  return
216  point2d[0] >= -1.0f && point2d[0] <= 1.0f &&
217  point2d[1] >= -1.0f && point2d[1] <= 1.0f;
218 }
219 
220 ////////////////////////////////////////////////////////////////////
221 // Function: FisheyeLens::fov_to_film
222 // Access: Protected, Virtual
223 // Description: Given a field of view in degrees and a focal length,
224 // compute the correspdonding width (or height) on the
225 // film. If horiz is true, this is in the horizontal
226 // direction; otherwise, it is in the vertical direction
227 // (some lenses behave differently in each direction).
228 ////////////////////////////////////////////////////////////////////
229 PN_stdfloat FisheyeLens::
230 fov_to_film(PN_stdfloat fov, PN_stdfloat focal_length, bool) const {
231  return focal_length * fov / fisheye_k;
232 }
233 
234 ////////////////////////////////////////////////////////////////////
235 // Function: FisheyeLens::fov_to_focal_length
236 // Access: Protected, Virtual
237 // Description: Given a field of view in degrees and a width (or
238 // height) on the film, compute the focal length of the
239 // lens. If horiz is true, this is in the horizontal
240 // direction; otherwise, it is in the vertical direction
241 // (some lenses behave differently in each direction).
242 ////////////////////////////////////////////////////////////////////
243 PN_stdfloat FisheyeLens::
244 fov_to_focal_length(PN_stdfloat fov, PN_stdfloat film_size, bool) const {
245  return film_size * fisheye_k / fov;
246 }
247 
248 ////////////////////////////////////////////////////////////////////
249 // Function: FisheyeLens::film_to_fov
250 // Access: Protected, Virtual
251 // Description: Given a width (or height) on the film and a focal
252 // length, compute the field of view in degrees. If
253 // horiz is true, this is in the horizontal direction;
254 // otherwise, it is in the vertical direction (some
255 // lenses behave differently in each direction).
256 ////////////////////////////////////////////////////////////////////
257 PN_stdfloat FisheyeLens::
258 film_to_fov(PN_stdfloat film_size, PN_stdfloat focal_length, bool) const {
259  return film_size * fisheye_k / focal_length;
260 }
261 
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:45
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:99
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
A fisheye lens.
Definition: fisheyeLens.h:30
float length() const
Returns the length of the vector, by the Pythagorean theorem.
Definition: lvecBase3.h:766
This is a two-component vector offset.
Definition: lvector2.h:91
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85